mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Add the code for new Intel GPU driver, which supports GEM, KMS and
works with new generations of GPUs (IronLake, SandyBridge and supposedly IvyBridge). The driver is not connected to the build yet. Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
28d86329af
commit
e27f871969
81 changed files with 72060 additions and 0 deletions
1214
sys/dev/drm2/drm.h
Normal file
1214
sys/dev/drm2/drm.h
Normal file
File diff suppressed because it is too large
Load diff
1400
sys/dev/drm2/drmP.h
Normal file
1400
sys/dev/drm2/drmP.h
Normal file
File diff suppressed because it is too large
Load diff
434
sys/dev/drm2/drm_agpsupport.c
Normal file
434
sys/dev/drm2/drm_agpsupport.c
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
/*-
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_agpsupport.c
|
||||
* Support code for tying the kernel AGP support to DRM drivers and
|
||||
* the DRM's AGP ioctls.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
#include <dev/agp/agpreg.h>
|
||||
#include <dev/pci/pcireg.h>
|
||||
|
||||
/* Returns 1 if AGP or 0 if not. */
|
||||
static int
|
||||
drm_device_find_capability(struct drm_device *dev, int cap)
|
||||
{
|
||||
|
||||
return (pci_find_cap(dev->device, cap, NULL) == 0);
|
||||
}
|
||||
|
||||
int drm_device_is_agp(struct drm_device *dev)
|
||||
{
|
||||
if (dev->driver->device_is_agp != NULL) {
|
||||
int ret;
|
||||
|
||||
/* device_is_agp returns a tristate, 0 = not AGP, 1 = definitely
|
||||
* AGP, 2 = fall back to PCI capability
|
||||
*/
|
||||
ret = (*dev->driver->device_is_agp)(dev);
|
||||
if (ret != DRM_MIGHT_BE_AGP)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return (drm_device_find_capability(dev, PCIY_AGP));
|
||||
}
|
||||
|
||||
int drm_device_is_pcie(struct drm_device *dev)
|
||||
{
|
||||
return (drm_device_find_capability(dev, PCIY_EXPRESS));
|
||||
}
|
||||
|
||||
int drm_agp_info(struct drm_device * dev, struct drm_agp_info *info)
|
||||
{
|
||||
struct agp_info *kern;
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return EINVAL;
|
||||
|
||||
kern = &dev->agp->info;
|
||||
agp_get_info(dev->agp->agpdev, kern);
|
||||
info->agp_version_major = 1;
|
||||
info->agp_version_minor = 0;
|
||||
info->mode = kern->ai_mode;
|
||||
info->aperture_base = kern->ai_aperture_base;
|
||||
info->aperture_size = kern->ai_aperture_size;
|
||||
info->memory_allowed = kern->ai_memory_allowed;
|
||||
info->memory_used = kern->ai_memory_used;
|
||||
info->id_vendor = kern->ai_devid & 0xffff;
|
||||
info->id_device = kern->ai_devid >> 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_agp_info_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
int err;
|
||||
struct drm_agp_info info;
|
||||
|
||||
err = drm_agp_info(dev, &info);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
*(struct drm_agp_info *) data = info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
return drm_agp_acquire(dev);
|
||||
}
|
||||
|
||||
int drm_agp_acquire(struct drm_device *dev)
|
||||
{
|
||||
int retcode;
|
||||
|
||||
if (!dev->agp || dev->agp->acquired)
|
||||
return EINVAL;
|
||||
|
||||
retcode = agp_acquire(dev->agp->agpdev);
|
||||
if (retcode)
|
||||
return retcode;
|
||||
|
||||
dev->agp->acquired = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_agp_release_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
return drm_agp_release(dev);
|
||||
}
|
||||
|
||||
int drm_agp_release(struct drm_device * dev)
|
||||
{
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return EINVAL;
|
||||
agp_release(dev->agp->agpdev);
|
||||
dev->agp->acquired = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode)
|
||||
{
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return EINVAL;
|
||||
|
||||
dev->agp->mode = mode.mode;
|
||||
agp_enable(dev->agp->agpdev, mode.mode);
|
||||
dev->agp->enabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_agp_mode mode;
|
||||
|
||||
mode = *(struct drm_agp_mode *) data;
|
||||
|
||||
return drm_agp_enable(dev, mode);
|
||||
}
|
||||
|
||||
int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
|
||||
{
|
||||
drm_agp_mem_t *entry;
|
||||
void *handle;
|
||||
unsigned long pages;
|
||||
u_int32_t type;
|
||||
struct agp_memory_info info;
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return EINVAL;
|
||||
|
||||
entry = malloc(sizeof(*entry), DRM_MEM_AGPLISTS, M_NOWAIT | M_ZERO);
|
||||
if (entry == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
type = (u_int32_t) request->type;
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
handle = drm_agp_allocate_memory(pages, type);
|
||||
DRM_LOCK(dev);
|
||||
if (handle == NULL) {
|
||||
free(entry, DRM_MEM_AGPLISTS);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
entry->handle = handle;
|
||||
entry->bound = 0;
|
||||
entry->pages = pages;
|
||||
entry->prev = NULL;
|
||||
entry->next = dev->agp->memory;
|
||||
if (dev->agp->memory)
|
||||
dev->agp->memory->prev = entry;
|
||||
dev->agp->memory = entry;
|
||||
|
||||
agp_memory_info(dev->agp->agpdev, entry->handle, &info);
|
||||
|
||||
request->handle = (unsigned long) entry->handle;
|
||||
request->physical = info.ami_physical;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_agp_buffer request;
|
||||
int retcode;
|
||||
|
||||
request = *(struct drm_agp_buffer *) data;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
retcode = drm_agp_alloc(dev, &request);
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
*(struct drm_agp_buffer *) data = request;
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static drm_agp_mem_t * drm_agp_lookup_entry(struct drm_device *dev,
|
||||
void *handle)
|
||||
{
|
||||
drm_agp_mem_t *entry;
|
||||
|
||||
for (entry = dev->agp->memory; entry; entry = entry->next) {
|
||||
if (entry->handle == handle) return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
|
||||
{
|
||||
drm_agp_mem_t *entry;
|
||||
int retcode;
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return EINVAL;
|
||||
|
||||
entry = drm_agp_lookup_entry(dev, (void *)request->handle);
|
||||
if (entry == NULL || !entry->bound)
|
||||
return EINVAL;
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
retcode = drm_agp_unbind_memory(entry->handle);
|
||||
DRM_LOCK(dev);
|
||||
|
||||
if (retcode == 0)
|
||||
entry->bound = 0;
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_agp_binding request;
|
||||
int retcode;
|
||||
|
||||
request = *(struct drm_agp_binding *) data;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
retcode = drm_agp_unbind(dev, &request);
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
|
||||
{
|
||||
drm_agp_mem_t *entry;
|
||||
int retcode;
|
||||
int page;
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return EINVAL;
|
||||
|
||||
DRM_DEBUG("agp_bind, page_size=%x\n", (int)PAGE_SIZE);
|
||||
|
||||
entry = drm_agp_lookup_entry(dev, (void *)request->handle);
|
||||
if (entry == NULL || entry->bound)
|
||||
return EINVAL;
|
||||
|
||||
page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
retcode = drm_agp_bind_memory(entry->handle, page);
|
||||
DRM_LOCK(dev);
|
||||
if (retcode == 0)
|
||||
entry->bound = dev->agp->base + (page << PAGE_SHIFT);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_agp_binding request;
|
||||
int retcode;
|
||||
|
||||
request = *(struct drm_agp_binding *) data;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
retcode = drm_agp_bind(dev, &request);
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
|
||||
{
|
||||
drm_agp_mem_t *entry;
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return EINVAL;
|
||||
|
||||
entry = drm_agp_lookup_entry(dev, (void*)request->handle);
|
||||
if (entry == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
else
|
||||
dev->agp->memory = entry->next;
|
||||
if (entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
if (entry->bound)
|
||||
drm_agp_unbind_memory(entry->handle);
|
||||
drm_agp_free_memory(entry->handle);
|
||||
DRM_LOCK(dev);
|
||||
|
||||
free(entry, DRM_MEM_AGPLISTS);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int drm_agp_free_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_agp_buffer request;
|
||||
int retcode;
|
||||
|
||||
request = *(struct drm_agp_buffer *) data;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
retcode = drm_agp_free(dev, &request);
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
drm_agp_head_t *drm_agp_init(void)
|
||||
{
|
||||
device_t agpdev;
|
||||
drm_agp_head_t *head = NULL;
|
||||
int agp_available = 1;
|
||||
|
||||
agpdev = DRM_AGP_FIND_DEVICE();
|
||||
if (!agpdev)
|
||||
agp_available = 0;
|
||||
|
||||
DRM_DEBUG("agp_available = %d\n", agp_available);
|
||||
|
||||
if (agp_available) {
|
||||
head = malloc(sizeof(*head), DRM_MEM_AGPLISTS,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (head == NULL)
|
||||
return NULL;
|
||||
head->agpdev = agpdev;
|
||||
agp_get_info(agpdev, &head->info);
|
||||
head->base = head->info.ai_aperture_base;
|
||||
head->memory = NULL;
|
||||
DRM_INFO("AGP at 0x%08lx %dMB\n",
|
||||
(long)head->info.ai_aperture_base,
|
||||
(int)(head->info.ai_aperture_size >> 20));
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
void *drm_agp_allocate_memory(size_t pages, u32 type)
|
||||
{
|
||||
device_t agpdev;
|
||||
|
||||
agpdev = DRM_AGP_FIND_DEVICE();
|
||||
if (!agpdev)
|
||||
return NULL;
|
||||
|
||||
return agp_alloc_memory(agpdev, type, pages << AGP_PAGE_SHIFT);
|
||||
}
|
||||
|
||||
int drm_agp_free_memory(void *handle)
|
||||
{
|
||||
device_t agpdev;
|
||||
|
||||
agpdev = DRM_AGP_FIND_DEVICE();
|
||||
if (!agpdev || !handle)
|
||||
return 0;
|
||||
|
||||
agp_free_memory(agpdev, handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int drm_agp_bind_memory(void *handle, off_t start)
|
||||
{
|
||||
device_t agpdev;
|
||||
|
||||
agpdev = DRM_AGP_FIND_DEVICE();
|
||||
if (!agpdev || !handle)
|
||||
return EINVAL;
|
||||
|
||||
return agp_bind_memory(agpdev, handle, start * PAGE_SIZE);
|
||||
}
|
||||
|
||||
int drm_agp_unbind_memory(void *handle)
|
||||
{
|
||||
device_t agpdev;
|
||||
|
||||
agpdev = DRM_AGP_FIND_DEVICE();
|
||||
if (!agpdev || !handle)
|
||||
return EINVAL;
|
||||
|
||||
return agp_unbind_memory(agpdev, handle);
|
||||
}
|
||||
93
sys/dev/drm2/drm_atomic.h
Normal file
93
sys/dev/drm2/drm_atomic.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* \file drm_atomic.h
|
||||
* Atomic operations used in the DRM which may or may not be provided by the OS.
|
||||
*
|
||||
* \author Eric Anholt <anholt@FreeBSD.org>
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright 2004 Eric Anholt
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/* Many of these implementations are rather fake, but good enough. */
|
||||
|
||||
typedef u_int32_t atomic_t;
|
||||
|
||||
#define atomic_set(p, v) (*(p) = (v))
|
||||
#define atomic_read(p) (*(p))
|
||||
#define atomic_inc(p) atomic_add_int(p, 1)
|
||||
#define atomic_dec(p) atomic_subtract_int(p, 1)
|
||||
#define atomic_add(n, p) atomic_add_int(p, n)
|
||||
#define atomic_sub(n, p) atomic_subtract_int(p, n)
|
||||
|
||||
static __inline atomic_t
|
||||
test_and_set_bit(int b, volatile void *p)
|
||||
{
|
||||
int s = splhigh();
|
||||
unsigned int m = 1<<b;
|
||||
unsigned int r = *(volatile int *)p & m;
|
||||
*(volatile int *)p |= m;
|
||||
splx(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
clear_bit(int b, volatile void *p)
|
||||
{
|
||||
atomic_clear_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
set_bit(int b, volatile void *p)
|
||||
{
|
||||
atomic_set_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
test_bit(int b, volatile void *p)
|
||||
{
|
||||
return ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
find_first_zero_bit(volatile void *p, int max)
|
||||
{
|
||||
int b;
|
||||
volatile int *ptr = (volatile int *)p;
|
||||
|
||||
for (b = 0; b < max; b += 32) {
|
||||
if (ptr[b >> 5] != ~0) {
|
||||
for (;;) {
|
||||
if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
|
||||
return b;
|
||||
b++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
#define BITS_TO_LONGS(x) (howmany((x), NBBY * sizeof(long)))
|
||||
190
sys/dev/drm2/drm_auth.c
Normal file
190
sys/dev/drm2/drm_auth.c
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*-
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_auth.c
|
||||
* Implementation of the get/authmagic ioctls implementing the authentication
|
||||
* scheme between the master and clients.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
static int drm_hash_magic(drm_magic_t magic)
|
||||
{
|
||||
return magic & (DRM_HASH_SIZE-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file private associated with the given magic number.
|
||||
*/
|
||||
static struct drm_file *drm_find_file(struct drm_device *dev, drm_magic_t magic)
|
||||
{
|
||||
drm_magic_entry_t *pt;
|
||||
int hash = drm_hash_magic(magic);
|
||||
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
|
||||
for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
|
||||
if (pt->magic == magic) {
|
||||
return pt->priv;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the given magic number into the hash table of used magic number
|
||||
* lists.
|
||||
*/
|
||||
static int drm_add_magic(struct drm_device *dev, struct drm_file *priv,
|
||||
drm_magic_t magic)
|
||||
{
|
||||
int hash;
|
||||
drm_magic_entry_t *entry;
|
||||
|
||||
DRM_DEBUG("%d\n", magic);
|
||||
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
|
||||
hash = drm_hash_magic(magic);
|
||||
entry = malloc(sizeof(*entry), DRM_MEM_MAGIC, M_ZERO | M_NOWAIT);
|
||||
if (!entry)
|
||||
return ENOMEM;
|
||||
entry->magic = magic;
|
||||
entry->priv = priv;
|
||||
entry->next = NULL;
|
||||
|
||||
if (dev->magiclist[hash].tail) {
|
||||
dev->magiclist[hash].tail->next = entry;
|
||||
dev->magiclist[hash].tail = entry;
|
||||
} else {
|
||||
dev->magiclist[hash].head = entry;
|
||||
dev->magiclist[hash].tail = entry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given magic number from the hash table of used magic number
|
||||
* lists.
|
||||
*/
|
||||
static int drm_remove_magic(struct drm_device *dev, drm_magic_t magic)
|
||||
{
|
||||
drm_magic_entry_t *prev = NULL;
|
||||
drm_magic_entry_t *pt;
|
||||
int hash;
|
||||
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
|
||||
DRM_DEBUG("%d\n", magic);
|
||||
hash = drm_hash_magic(magic);
|
||||
|
||||
for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
|
||||
if (pt->magic == magic) {
|
||||
if (dev->magiclist[hash].head == pt) {
|
||||
dev->magiclist[hash].head = pt->next;
|
||||
}
|
||||
if (dev->magiclist[hash].tail == pt) {
|
||||
dev->magiclist[hash].tail = prev;
|
||||
}
|
||||
if (prev) {
|
||||
prev->next = pt->next;
|
||||
}
|
||||
free(pt, DRM_MEM_MAGIC);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the client, this returns a unique magic number to be authorized
|
||||
* by the master.
|
||||
*
|
||||
* The master may use its own knowledge of the client (such as the X
|
||||
* connection that the magic is passed over) to determine if the magic number
|
||||
* should be authenticated.
|
||||
*/
|
||||
int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
static drm_magic_t sequence = 0;
|
||||
struct drm_auth *auth = data;
|
||||
|
||||
/* Find unique magic */
|
||||
if (file_priv->magic) {
|
||||
auth->magic = file_priv->magic;
|
||||
} else {
|
||||
DRM_LOCK(dev);
|
||||
do {
|
||||
int old = sequence;
|
||||
|
||||
auth->magic = old+1;
|
||||
|
||||
if (!atomic_cmpset_int(&sequence, old, auth->magic))
|
||||
continue;
|
||||
} while (drm_find_file(dev, auth->magic));
|
||||
file_priv->magic = auth->magic;
|
||||
drm_add_magic(dev, file_priv, auth->magic);
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
|
||||
DRM_DEBUG("%u\n", auth->magic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the client associated with the given magic number as authenticated.
|
||||
*/
|
||||
int drm_authmagic(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_auth *auth = data;
|
||||
struct drm_file *priv;
|
||||
|
||||
DRM_DEBUG("%u\n", auth->magic);
|
||||
|
||||
DRM_LOCK(dev);
|
||||
priv = drm_find_file(dev, auth->magic);
|
||||
if (priv != NULL) {
|
||||
priv->authenticated = 1;
|
||||
drm_remove_magic(dev, auth->magic);
|
||||
DRM_UNLOCK(dev);
|
||||
return 0;
|
||||
} else {
|
||||
DRM_UNLOCK(dev);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
1130
sys/dev/drm2/drm_bufs.c
Normal file
1130
sys/dev/drm2/drm_bufs.c
Normal file
File diff suppressed because it is too large
Load diff
312
sys/dev/drm2/drm_context.c
Normal file
312
sys/dev/drm2/drm_context.c
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
/*-
|
||||
* Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_context.c
|
||||
* Implementation of the context management ioctls.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
/* ================================================================
|
||||
* Context bitmap support
|
||||
*/
|
||||
|
||||
void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle)
|
||||
{
|
||||
if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP ||
|
||||
dev->ctx_bitmap == NULL) {
|
||||
DRM_ERROR("Attempt to free invalid context handle: %d\n",
|
||||
ctx_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_LOCK(dev);
|
||||
clear_bit(ctx_handle, dev->ctx_bitmap);
|
||||
dev->context_sareas[ctx_handle] = NULL;
|
||||
DRM_UNLOCK(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
int drm_ctxbitmap_next(struct drm_device *dev)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (dev->ctx_bitmap == NULL)
|
||||
return -1;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
|
||||
if (bit >= DRM_MAX_CTXBITMAP) {
|
||||
DRM_UNLOCK(dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_bit(bit, dev->ctx_bitmap);
|
||||
DRM_DEBUG("bit : %d\n", bit);
|
||||
if ((bit+1) > dev->max_context) {
|
||||
drm_local_map_t **ctx_sareas;
|
||||
int max_ctx = (bit+1);
|
||||
|
||||
ctx_sareas = realloc(dev->context_sareas,
|
||||
max_ctx * sizeof(*dev->context_sareas),
|
||||
DRM_MEM_SAREA, M_NOWAIT);
|
||||
if (ctx_sareas == NULL) {
|
||||
clear_bit(bit, dev->ctx_bitmap);
|
||||
DRM_DEBUG("failed to allocate bit : %d\n", bit);
|
||||
DRM_UNLOCK(dev);
|
||||
return -1;
|
||||
}
|
||||
dev->max_context = max_ctx;
|
||||
dev->context_sareas = ctx_sareas;
|
||||
dev->context_sareas[bit] = NULL;
|
||||
}
|
||||
DRM_UNLOCK(dev);
|
||||
return bit;
|
||||
}
|
||||
|
||||
int drm_ctxbitmap_init(struct drm_device *dev)
|
||||
{
|
||||
int i;
|
||||
int temp;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
dev->ctx_bitmap = malloc(PAGE_SIZE, DRM_MEM_CTXBITMAP,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (dev->ctx_bitmap == NULL) {
|
||||
DRM_UNLOCK(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
dev->context_sareas = NULL;
|
||||
dev->max_context = -1;
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
|
||||
temp = drm_ctxbitmap_next(dev);
|
||||
DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drm_ctxbitmap_cleanup(struct drm_device *dev)
|
||||
{
|
||||
DRM_LOCK(dev);
|
||||
if (dev->context_sareas != NULL)
|
||||
free(dev->context_sareas, DRM_MEM_SAREA);
|
||||
free(dev->ctx_bitmap, DRM_MEM_CTXBITMAP);
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Per Context SAREA Support
|
||||
*/
|
||||
|
||||
int drm_getsareactx(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx_priv_map *request = data;
|
||||
drm_local_map_t *map;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
if (dev->max_context < 0 ||
|
||||
request->ctx_id >= (unsigned) dev->max_context) {
|
||||
DRM_UNLOCK(dev);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
map = dev->context_sareas[request->ctx_id];
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
request->handle = (void *)map->handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_setsareactx(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx_priv_map *request = data;
|
||||
drm_local_map_t *map = NULL;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
TAILQ_FOREACH(map, &dev->maplist, link) {
|
||||
if (map->handle == request->handle) {
|
||||
if (dev->max_context < 0)
|
||||
goto bad;
|
||||
if (request->ctx_id >= (unsigned) dev->max_context)
|
||||
goto bad;
|
||||
dev->context_sareas[request->ctx_id] = map;
|
||||
DRM_UNLOCK(dev);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bad:
|
||||
DRM_UNLOCK(dev);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* The actual DRM context handling routines
|
||||
*/
|
||||
|
||||
int drm_context_switch(struct drm_device *dev, int old, int new)
|
||||
{
|
||||
if (test_and_set_bit(0, &dev->context_flag)) {
|
||||
DRM_ERROR("Reentering -- FIXME\n");
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
DRM_DEBUG("Context switch from %d to %d\n", old, new);
|
||||
|
||||
if (new == dev->last_context) {
|
||||
clear_bit(0, &dev->context_flag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_context_switch_complete(struct drm_device *dev, int new)
|
||||
{
|
||||
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
|
||||
|
||||
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
|
||||
DRM_ERROR("Lock isn't held after context switch\n");
|
||||
}
|
||||
|
||||
/* If a context switch is ever initiated
|
||||
when the kernel holds the lock, release
|
||||
that lock here. */
|
||||
clear_bit(0, &dev->context_flag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx_res *res = data;
|
||||
struct drm_ctx ctx;
|
||||
int i;
|
||||
|
||||
if (res->count >= DRM_RESERVED_CONTEXTS) {
|
||||
bzero(&ctx, sizeof(ctx));
|
||||
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
|
||||
ctx.handle = i;
|
||||
if (DRM_COPY_TO_USER(&res->contexts[i],
|
||||
&ctx, sizeof(ctx)))
|
||||
return EFAULT;
|
||||
}
|
||||
}
|
||||
res->count = DRM_RESERVED_CONTEXTS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
ctx->handle = drm_ctxbitmap_next(dev);
|
||||
if (ctx->handle == DRM_KERNEL_CONTEXT) {
|
||||
/* Skip kernel's context and get a new one. */
|
||||
ctx->handle = drm_ctxbitmap_next(dev);
|
||||
}
|
||||
DRM_DEBUG("%d\n", ctx->handle);
|
||||
if (ctx->handle == -1) {
|
||||
DRM_DEBUG("Not enough free contexts.\n");
|
||||
/* Should this return -EBUSY instead? */
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
if (dev->driver->context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) {
|
||||
DRM_LOCK(dev);
|
||||
dev->driver->context_ctor(dev, ctx->handle);
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
/* This does nothing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
/* This is 0, because we don't handle any context flags */
|
||||
ctx->flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_switchctx(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx->handle);
|
||||
return drm_context_switch(dev, dev->last_context, ctx->handle);
|
||||
}
|
||||
|
||||
int drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx->handle);
|
||||
drm_context_switch_complete(dev, ctx->handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_ctx *ctx = data;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx->handle);
|
||||
if (ctx->handle != DRM_KERNEL_CONTEXT) {
|
||||
if (dev->driver->context_dtor) {
|
||||
DRM_LOCK(dev);
|
||||
dev->driver->context_dtor(dev, ctx->handle);
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
|
||||
drm_ctxbitmap_free(dev, ctx->handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
3413
sys/dev/drm2/drm_crtc.c
Normal file
3413
sys/dev/drm2/drm_crtc.c
Normal file
File diff suppressed because it is too large
Load diff
935
sys/dev/drm2/drm_crtc.h
Normal file
935
sys/dev/drm2/drm_crtc.h
Normal file
|
|
@ -0,0 +1,935 @@
|
|||
/*
|
||||
* Copyright © 2006 Keith Packard
|
||||
* Copyright © 2007-2008 Dave Airlie
|
||||
* Copyright © 2007-2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef __DRM_CRTC_H__
|
||||
#define __DRM_CRTC_H__
|
||||
|
||||
#include <dev/drm2/drm_gem_names.h>
|
||||
#include <dev/drm2/drm_fourcc.h>
|
||||
|
||||
struct drm_device;
|
||||
struct drm_mode_set;
|
||||
struct drm_framebuffer;
|
||||
struct i2c_adapter;
|
||||
|
||||
#define DRM_MODE_OBJECT_CRTC 0xcccccccc
|
||||
#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
|
||||
#define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0
|
||||
#define DRM_MODE_OBJECT_MODE 0xdededede
|
||||
#define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0
|
||||
#define DRM_MODE_OBJECT_FB 0xfbfbfbfb
|
||||
#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
|
||||
#define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
|
||||
|
||||
struct drm_mode_object {
|
||||
uint32_t id;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
/*
|
||||
* Note on terminology: here, for brevity and convenience, we refer to connector
|
||||
* control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS,
|
||||
* DVI, etc. And 'screen' refers to the whole of the visible display, which
|
||||
* may span multiple monitors (and therefore multiple CRTC and connector
|
||||
* structures).
|
||||
*/
|
||||
|
||||
enum drm_mode_status {
|
||||
MODE_OK = 0, /* Mode OK */
|
||||
MODE_HSYNC, /* hsync out of range */
|
||||
MODE_VSYNC, /* vsync out of range */
|
||||
MODE_H_ILLEGAL, /* mode has illegal horizontal timings */
|
||||
MODE_V_ILLEGAL, /* mode has illegal horizontal timings */
|
||||
MODE_BAD_WIDTH, /* requires an unsupported linepitch */
|
||||
MODE_NOMODE, /* no mode with a maching name */
|
||||
MODE_NO_INTERLACE, /* interlaced mode not supported */
|
||||
MODE_NO_DBLESCAN, /* doublescan mode not supported */
|
||||
MODE_NO_VSCAN, /* multiscan mode not supported */
|
||||
MODE_MEM, /* insufficient video memory */
|
||||
MODE_VIRTUAL_X, /* mode width too large for specified virtual size */
|
||||
MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */
|
||||
MODE_MEM_VIRT, /* insufficient video memory given virtual size */
|
||||
MODE_NOCLOCK, /* no fixed clock available */
|
||||
MODE_CLOCK_HIGH, /* clock required is too high */
|
||||
MODE_CLOCK_LOW, /* clock required is too low */
|
||||
MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */
|
||||
MODE_BAD_HVALUE, /* horizontal timing was out of range */
|
||||
MODE_BAD_VVALUE, /* vertical timing was out of range */
|
||||
MODE_BAD_VSCAN, /* VScan value out of range */
|
||||
MODE_HSYNC_NARROW, /* horizontal sync too narrow */
|
||||
MODE_HSYNC_WIDE, /* horizontal sync too wide */
|
||||
MODE_HBLANK_NARROW, /* horizontal blanking too narrow */
|
||||
MODE_HBLANK_WIDE, /* horizontal blanking too wide */
|
||||
MODE_VSYNC_NARROW, /* vertical sync too narrow */
|
||||
MODE_VSYNC_WIDE, /* vertical sync too wide */
|
||||
MODE_VBLANK_NARROW, /* vertical blanking too narrow */
|
||||
MODE_VBLANK_WIDE, /* vertical blanking too wide */
|
||||
MODE_PANEL, /* exceeds panel dimensions */
|
||||
MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */
|
||||
MODE_ONE_WIDTH, /* only one width is supported */
|
||||
MODE_ONE_HEIGHT, /* only one height is supported */
|
||||
MODE_ONE_SIZE, /* only one resolution is supported */
|
||||
MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */
|
||||
MODE_UNVERIFIED = -3, /* mode needs to reverified */
|
||||
MODE_BAD = -2, /* unspecified reason */
|
||||
MODE_ERROR = -1 /* error condition */
|
||||
};
|
||||
|
||||
#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
|
||||
DRM_MODE_TYPE_CRTC_C)
|
||||
|
||||
#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \
|
||||
.name = nm, .status = 0, .type = (t), .clock = (c), \
|
||||
.hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
|
||||
.htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \
|
||||
.vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
|
||||
.vscan = (vs), .flags = (f), .vrefresh = 0
|
||||
|
||||
#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */
|
||||
|
||||
struct drm_display_mode {
|
||||
/* Header */
|
||||
struct list_head head;
|
||||
struct drm_mode_object base;
|
||||
|
||||
char name[DRM_DISPLAY_MODE_LEN];
|
||||
|
||||
int connector_count;
|
||||
enum drm_mode_status status;
|
||||
int type;
|
||||
|
||||
/* Proposed mode values */
|
||||
int clock; /* in kHz */
|
||||
int hdisplay;
|
||||
int hsync_start;
|
||||
int hsync_end;
|
||||
int htotal;
|
||||
int hskew;
|
||||
int vdisplay;
|
||||
int vsync_start;
|
||||
int vsync_end;
|
||||
int vtotal;
|
||||
int vscan;
|
||||
unsigned int flags;
|
||||
|
||||
/* Addressable image size (may be 0 for projectors, etc.) */
|
||||
int width_mm;
|
||||
int height_mm;
|
||||
|
||||
/* Actual mode we give to hw */
|
||||
int clock_index;
|
||||
int synth_clock;
|
||||
int crtc_hdisplay;
|
||||
int crtc_hblank_start;
|
||||
int crtc_hblank_end;
|
||||
int crtc_hsync_start;
|
||||
int crtc_hsync_end;
|
||||
int crtc_htotal;
|
||||
int crtc_hskew;
|
||||
int crtc_vdisplay;
|
||||
int crtc_vblank_start;
|
||||
int crtc_vblank_end;
|
||||
int crtc_vsync_start;
|
||||
int crtc_vsync_end;
|
||||
int crtc_vtotal;
|
||||
int crtc_hadjusted;
|
||||
int crtc_vadjusted;
|
||||
|
||||
/* Driver private mode info */
|
||||
int private_size;
|
||||
int *private;
|
||||
int private_flags;
|
||||
|
||||
int vrefresh; /* in Hz */
|
||||
int hsync; /* in kHz */
|
||||
};
|
||||
|
||||
enum drm_connector_status {
|
||||
connector_status_connected = 1,
|
||||
connector_status_disconnected = 2,
|
||||
connector_status_unknown = 3,
|
||||
};
|
||||
|
||||
enum subpixel_order {
|
||||
SubPixelUnknown = 0,
|
||||
SubPixelHorizontalRGB,
|
||||
SubPixelHorizontalBGR,
|
||||
SubPixelVerticalRGB,
|
||||
SubPixelVerticalBGR,
|
||||
SubPixelNone,
|
||||
};
|
||||
|
||||
#define DRM_COLOR_FORMAT_RGB444 (1<<0)
|
||||
#define DRM_COLOR_FORMAT_YCRCB444 (1<<1)
|
||||
#define DRM_COLOR_FORMAT_YCRCB422 (1<<2)
|
||||
/*
|
||||
* Describes a given display (e.g. CRT or flat panel) and its limitations.
|
||||
*/
|
||||
struct drm_display_info {
|
||||
char name[DRM_DISPLAY_INFO_LEN];
|
||||
|
||||
/* Physical size */
|
||||
unsigned int width_mm;
|
||||
unsigned int height_mm;
|
||||
|
||||
/* Clock limits FIXME: storage format */
|
||||
unsigned int min_vfreq, max_vfreq;
|
||||
unsigned int min_hfreq, max_hfreq;
|
||||
unsigned int pixel_clock;
|
||||
unsigned int bpc;
|
||||
|
||||
enum subpixel_order subpixel_order;
|
||||
u32 color_formats;
|
||||
|
||||
u8 cea_rev;
|
||||
|
||||
char *raw_edid; /* if any */
|
||||
};
|
||||
|
||||
struct drm_framebuffer_funcs {
|
||||
void (*destroy)(struct drm_framebuffer *framebuffer);
|
||||
int (*create_handle)(struct drm_framebuffer *fb,
|
||||
struct drm_file *file_priv,
|
||||
unsigned int *handle);
|
||||
/**
|
||||
* Optinal callback for the dirty fb ioctl.
|
||||
*
|
||||
* Userspace can notify the driver via this callback
|
||||
* that a area of the framebuffer has changed and should
|
||||
* be flushed to the display hardware.
|
||||
*
|
||||
* See documentation in drm_mode.h for the struct
|
||||
* drm_mode_fb_dirty_cmd for more information as all
|
||||
* the semantics and arguments have a one to one mapping
|
||||
* on this function.
|
||||
*/
|
||||
int (*dirty)(struct drm_framebuffer *framebuffer,
|
||||
struct drm_file *file_priv, unsigned flags,
|
||||
unsigned color, struct drm_clip_rect *clips,
|
||||
unsigned num_clips);
|
||||
};
|
||||
|
||||
struct drm_framebuffer {
|
||||
struct drm_device *dev;
|
||||
struct list_head head;
|
||||
struct drm_mode_object base;
|
||||
const struct drm_framebuffer_funcs *funcs;
|
||||
unsigned int pitches[4];
|
||||
unsigned int offsets[4];
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
/* depth can be 15 or 16 */
|
||||
unsigned int depth;
|
||||
int bits_per_pixel;
|
||||
int flags;
|
||||
uint32_t pixel_format; /* fourcc format */
|
||||
struct list_head filp_head;
|
||||
/* if you are using the helper */
|
||||
void *helper_private;
|
||||
};
|
||||
|
||||
struct drm_property_blob {
|
||||
struct drm_mode_object base;
|
||||
struct list_head head;
|
||||
unsigned int length;
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
struct drm_property_enum {
|
||||
uint64_t value;
|
||||
struct list_head head;
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
};
|
||||
|
||||
struct drm_property {
|
||||
struct list_head head;
|
||||
struct drm_mode_object base;
|
||||
uint32_t flags;
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
uint32_t num_values;
|
||||
uint64_t *values;
|
||||
|
||||
struct list_head enum_blob_list;
|
||||
};
|
||||
|
||||
struct drm_crtc;
|
||||
struct drm_connector;
|
||||
struct drm_encoder;
|
||||
struct drm_pending_vblank_event;
|
||||
struct drm_plane;
|
||||
|
||||
/**
|
||||
* drm_crtc_funcs - control CRTCs for a given device
|
||||
* @reset: reset CRTC after state has been invalidate (e.g. resume)
|
||||
* @dpms: control display power levels
|
||||
* @save: save CRTC state
|
||||
* @resore: restore CRTC state
|
||||
* @lock: lock the CRTC
|
||||
* @unlock: unlock the CRTC
|
||||
* @shadow_allocate: allocate shadow pixmap
|
||||
* @shadow_create: create shadow pixmap for rotation support
|
||||
* @shadow_destroy: free shadow pixmap
|
||||
* @mode_fixup: fixup proposed mode
|
||||
* @mode_set: set the desired mode on the CRTC
|
||||
* @gamma_set: specify color ramp for CRTC
|
||||
* @destroy: deinit and free object.
|
||||
*
|
||||
* The drm_crtc_funcs structure is the central CRTC management structure
|
||||
* in the DRM. Each CRTC controls one or more connectors (note that the name
|
||||
* CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc.
|
||||
* connectors, not just CRTs).
|
||||
*
|
||||
* Each driver is responsible for filling out this structure at startup time,
|
||||
* in addition to providing other modesetting features, like i2c and DDC
|
||||
* bus accessors.
|
||||
*/
|
||||
struct drm_crtc_funcs {
|
||||
/* Save CRTC state */
|
||||
void (*save)(struct drm_crtc *crtc); /* suspend? */
|
||||
/* Restore CRTC state */
|
||||
void (*restore)(struct drm_crtc *crtc); /* resume? */
|
||||
/* Reset CRTC state */
|
||||
void (*reset)(struct drm_crtc *crtc);
|
||||
|
||||
/* cursor controls */
|
||||
int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
|
||||
uint32_t handle, uint32_t width, uint32_t height);
|
||||
int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
|
||||
|
||||
/* Set gamma on the CRTC */
|
||||
void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
|
||||
uint32_t start, uint32_t size);
|
||||
/* Object destroy routine */
|
||||
void (*destroy)(struct drm_crtc *crtc);
|
||||
|
||||
int (*set_config)(struct drm_mode_set *set);
|
||||
|
||||
/*
|
||||
* Flip to the given framebuffer. This implements the page
|
||||
* flip ioctl descibed in drm_mode.h, specifically, the
|
||||
* implementation must return immediately and block all
|
||||
* rendering to the current fb until the flip has completed.
|
||||
* If userspace set the event flag in the ioctl, the event
|
||||
* argument will point to an event to send back when the flip
|
||||
* completes, otherwise it will be NULL.
|
||||
*/
|
||||
int (*page_flip)(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event);
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_crtc - central CRTC control structure
|
||||
* @enabled: is this CRTC enabled?
|
||||
* @x: x position on screen
|
||||
* @y: y position on screen
|
||||
* @funcs: CRTC control functions
|
||||
*
|
||||
* Each CRTC may have one or more connectors associated with it. This structure
|
||||
* allows the CRTC to be controlled.
|
||||
*/
|
||||
struct drm_crtc {
|
||||
struct drm_device *dev;
|
||||
struct list_head head;
|
||||
|
||||
struct drm_mode_object base;
|
||||
|
||||
/* framebuffer the connector is currently bound to */
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
bool enabled;
|
||||
|
||||
/* Requested mode from modesetting. */
|
||||
struct drm_display_mode mode;
|
||||
|
||||
/* Programmed mode in hw, after adjustments for encoders,
|
||||
* crtc, panel scaling etc. Needed for timestamping etc.
|
||||
*/
|
||||
struct drm_display_mode hwmode;
|
||||
|
||||
int x, y;
|
||||
const struct drm_crtc_funcs *funcs;
|
||||
|
||||
/* CRTC gamma size for reporting to userspace */
|
||||
uint32_t gamma_size;
|
||||
uint16_t *gamma_store;
|
||||
|
||||
/* Constants needed for precise vblank and swap timestamping. */
|
||||
int64_t framedur_ns, linedur_ns, pixeldur_ns;
|
||||
|
||||
/* if you are using the helper */
|
||||
void *helper_private;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* drm_connector_funcs - control connectors on a given device
|
||||
* @dpms: set power state (see drm_crtc_funcs above)
|
||||
* @save: save connector state
|
||||
* @restore: restore connector state
|
||||
* @reset: reset connector after state has been invalidate (e.g. resume)
|
||||
* @mode_valid: is this mode valid on the given connector?
|
||||
* @mode_fixup: try to fixup proposed mode for this connector
|
||||
* @mode_set: set this mode
|
||||
* @detect: is this connector active?
|
||||
* @get_modes: get mode list for this connector
|
||||
* @set_property: property for this connector may need update
|
||||
* @destroy: make object go away
|
||||
* @force: notify the driver the connector is forced on
|
||||
*
|
||||
* Each CRTC may have one or more connectors attached to it. The functions
|
||||
* below allow the core DRM code to control connectors, enumerate available modes,
|
||||
* etc.
|
||||
*/
|
||||
struct drm_connector_funcs {
|
||||
void (*dpms)(struct drm_connector *connector, int mode);
|
||||
void (*save)(struct drm_connector *connector);
|
||||
void (*restore)(struct drm_connector *connector);
|
||||
void (*reset)(struct drm_connector *connector);
|
||||
|
||||
/* Check to see if anything is attached to the connector.
|
||||
* @force is set to false whilst polling, true when checking the
|
||||
* connector due to user request. @force can be used by the driver
|
||||
* to avoid expensive, destructive operations during automated
|
||||
* probing.
|
||||
*/
|
||||
enum drm_connector_status (*detect)(struct drm_connector *connector,
|
||||
bool force);
|
||||
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
|
||||
int (*set_property)(struct drm_connector *connector, struct drm_property *property,
|
||||
uint64_t val);
|
||||
void (*destroy)(struct drm_connector *connector);
|
||||
void (*force)(struct drm_connector *connector);
|
||||
};
|
||||
|
||||
struct drm_encoder_funcs {
|
||||
void (*reset)(struct drm_encoder *encoder);
|
||||
void (*destroy)(struct drm_encoder *encoder);
|
||||
};
|
||||
|
||||
#define DRM_CONNECTOR_MAX_UMODES 16
|
||||
#define DRM_CONNECTOR_MAX_PROPERTY 16
|
||||
#define DRM_CONNECTOR_LEN 32
|
||||
#define DRM_CONNECTOR_MAX_ENCODER 2
|
||||
|
||||
/**
|
||||
* drm_encoder - central DRM encoder structure
|
||||
*/
|
||||
struct drm_encoder {
|
||||
struct drm_device *dev;
|
||||
struct list_head head;
|
||||
|
||||
struct drm_mode_object base;
|
||||
int encoder_type;
|
||||
uint32_t possible_crtcs;
|
||||
uint32_t possible_clones;
|
||||
|
||||
struct drm_crtc *crtc;
|
||||
const struct drm_encoder_funcs *funcs;
|
||||
void *helper_private;
|
||||
};
|
||||
|
||||
enum drm_connector_force {
|
||||
DRM_FORCE_UNSPECIFIED,
|
||||
DRM_FORCE_OFF,
|
||||
DRM_FORCE_ON, /* force on analog part normally */
|
||||
DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
|
||||
};
|
||||
|
||||
/* should we poll this connector for connects and disconnects */
|
||||
/* hot plug detectable */
|
||||
#define DRM_CONNECTOR_POLL_HPD (1 << 0)
|
||||
/* poll for connections */
|
||||
#define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
|
||||
/* can cleanly poll for disconnections without flickering the screen */
|
||||
/* DACs should rarely do this without a lot of testing */
|
||||
#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)
|
||||
|
||||
#define MAX_ELD_BYTES 128
|
||||
|
||||
/**
|
||||
* drm_connector - central DRM connector control structure
|
||||
* @crtc: CRTC this connector is currently connected to, NULL if none
|
||||
* @interlace_allowed: can this connector handle interlaced modes?
|
||||
* @doublescan_allowed: can this connector handle doublescan?
|
||||
* @available_modes: modes available on this connector (from get_modes() + user)
|
||||
* @initial_x: initial x position for this connector
|
||||
* @initial_y: initial y position for this connector
|
||||
* @status: connector connected?
|
||||
* @funcs: connector control functions
|
||||
*
|
||||
* Each connector may be connected to one or more CRTCs, or may be clonable by
|
||||
* another connector if they can share a CRTC. Each connector also has a specific
|
||||
* position in the broader display (referred to as a 'screen' though it could
|
||||
* span multiple monitors).
|
||||
*/
|
||||
struct drm_connector {
|
||||
struct drm_device *dev;
|
||||
/* struct device kdev; XXXKIB */
|
||||
struct device_attribute *attr;
|
||||
struct list_head head;
|
||||
|
||||
struct drm_mode_object base;
|
||||
|
||||
int connector_type;
|
||||
int connector_type_id;
|
||||
bool interlace_allowed;
|
||||
bool doublescan_allowed;
|
||||
struct list_head modes; /* list of modes on this connector */
|
||||
|
||||
int initial_x, initial_y;
|
||||
enum drm_connector_status status;
|
||||
|
||||
/* these are modes added by probing with DDC or the BIOS */
|
||||
struct list_head probed_modes;
|
||||
|
||||
struct drm_display_info display_info;
|
||||
const struct drm_connector_funcs *funcs;
|
||||
|
||||
struct list_head user_modes;
|
||||
struct drm_property_blob *edid_blob_ptr;
|
||||
u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY];
|
||||
uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY];
|
||||
|
||||
uint8_t polled; /* DRM_CONNECTOR_POLL_* */
|
||||
|
||||
/* requested DPMS state */
|
||||
int dpms;
|
||||
|
||||
void *helper_private;
|
||||
|
||||
/* forced on connector */
|
||||
enum drm_connector_force force;
|
||||
uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
|
||||
uint32_t force_encoder_id;
|
||||
struct drm_encoder *encoder; /* currently active encoder */
|
||||
|
||||
/* EDID bits */
|
||||
uint8_t eld[MAX_ELD_BYTES];
|
||||
bool dvi_dual;
|
||||
int max_tmds_clock; /* in MHz */
|
||||
bool latency_present[2];
|
||||
int video_latency[2]; /* [0]: progressive, [1]: interlaced */
|
||||
int audio_latency[2];
|
||||
|
||||
int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_plane_funcs - driver plane control functions
|
||||
* @update_plane: update the plane configuration
|
||||
* @disable_plane: shut down the plane
|
||||
* @destroy: clean up plane resources
|
||||
*/
|
||||
struct drm_plane_funcs {
|
||||
int (*update_plane)(struct drm_plane *plane,
|
||||
struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||
int crtc_x, int crtc_y,
|
||||
unsigned int crtc_w, unsigned int crtc_h,
|
||||
uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h);
|
||||
int (*disable_plane)(struct drm_plane *plane);
|
||||
void (*destroy)(struct drm_plane *plane);
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_plane - central DRM plane control structure
|
||||
* @dev: DRM device this plane belongs to
|
||||
* @head: for list management
|
||||
* @base: base mode object
|
||||
* @possible_crtcs: pipes this plane can be bound to
|
||||
* @format_types: array of formats supported by this plane
|
||||
* @format_count: number of formats supported
|
||||
* @crtc: currently bound CRTC
|
||||
* @fb: currently bound fb
|
||||
* @gamma_size: size of gamma table
|
||||
* @gamma_store: gamma correction table
|
||||
* @enabled: enabled flag
|
||||
* @funcs: helper functions
|
||||
* @helper_private: storage for drver layer
|
||||
*/
|
||||
struct drm_plane {
|
||||
struct drm_device *dev;
|
||||
struct list_head head;
|
||||
|
||||
struct drm_mode_object base;
|
||||
|
||||
uint32_t possible_crtcs;
|
||||
uint32_t *format_types;
|
||||
uint32_t format_count;
|
||||
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
/* CRTC gamma size for reporting to userspace */
|
||||
uint32_t gamma_size;
|
||||
uint16_t *gamma_store;
|
||||
|
||||
bool enabled;
|
||||
|
||||
const struct drm_plane_funcs *funcs;
|
||||
void *helper_private;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_mode_set
|
||||
*
|
||||
* Represents a single crtc the connectors that it drives with what mode
|
||||
* and from which framebuffer it scans out from.
|
||||
*
|
||||
* This is used to set modes.
|
||||
*/
|
||||
struct drm_mode_set {
|
||||
struct list_head head;
|
||||
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
|
||||
struct drm_connector **connectors;
|
||||
size_t num_connectors;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_mode_config_funcs - configure CRTCs for a given screen layout
|
||||
*/
|
||||
struct drm_mode_config_funcs {
|
||||
int (*fb_create)(struct drm_device *dev,
|
||||
struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_framebuffer **res);
|
||||
void (*output_poll_changed)(struct drm_device *dev);
|
||||
};
|
||||
|
||||
struct drm_mode_group {
|
||||
uint32_t num_crtcs;
|
||||
uint32_t num_encoders;
|
||||
uint32_t num_connectors;
|
||||
|
||||
/* list of object IDs for this group */
|
||||
uint32_t *id_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_mode_config - Mode configuration control structure
|
||||
*
|
||||
*/
|
||||
struct drm_mode_config {
|
||||
struct sx mutex; /* protects configuration (mode lists etc.) */
|
||||
struct drm_gem_names crtc_names; /* use this idr for all IDs, fb, crtc, connector, modes */
|
||||
/* this is limited to one for now */
|
||||
int num_fb;
|
||||
struct list_head fb_list;
|
||||
int num_connector;
|
||||
struct list_head connector_list;
|
||||
int num_encoder;
|
||||
struct list_head encoder_list;
|
||||
int num_plane;
|
||||
struct list_head plane_list;
|
||||
|
||||
int num_crtc;
|
||||
struct list_head crtc_list;
|
||||
|
||||
struct list_head property_list;
|
||||
|
||||
int min_width, min_height;
|
||||
int max_width, max_height;
|
||||
struct drm_mode_config_funcs *funcs;
|
||||
resource_size_t fb_base;
|
||||
|
||||
/* output poll support */
|
||||
bool poll_enabled;
|
||||
struct timeout_task output_poll_task;
|
||||
|
||||
/* pointers to standard properties */
|
||||
struct list_head property_blob_list;
|
||||
struct drm_property *edid_property;
|
||||
struct drm_property *dpms_property;
|
||||
|
||||
/* DVI-I properties */
|
||||
struct drm_property *dvi_i_subconnector_property;
|
||||
struct drm_property *dvi_i_select_subconnector_property;
|
||||
|
||||
/* TV properties */
|
||||
struct drm_property *tv_subconnector_property;
|
||||
struct drm_property *tv_select_subconnector_property;
|
||||
struct drm_property *tv_mode_property;
|
||||
struct drm_property *tv_left_margin_property;
|
||||
struct drm_property *tv_right_margin_property;
|
||||
struct drm_property *tv_top_margin_property;
|
||||
struct drm_property *tv_bottom_margin_property;
|
||||
struct drm_property *tv_brightness_property;
|
||||
struct drm_property *tv_contrast_property;
|
||||
struct drm_property *tv_flicker_reduction_property;
|
||||
struct drm_property *tv_overscan_property;
|
||||
struct drm_property *tv_saturation_property;
|
||||
struct drm_property *tv_hue_property;
|
||||
|
||||
/* Optional properties */
|
||||
struct drm_property *scaling_mode_property;
|
||||
struct drm_property *dithering_mode_property;
|
||||
struct drm_property *dirty_info_property;
|
||||
|
||||
/* dumb ioctl parameters */
|
||||
uint32_t preferred_depth, prefer_shadow;
|
||||
};
|
||||
|
||||
#define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
|
||||
#define obj_to_connector(x) container_of(x, struct drm_connector, base)
|
||||
#define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
|
||||
#define obj_to_mode(x) container_of(x, struct drm_display_mode, base)
|
||||
#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base)
|
||||
#define obj_to_property(x) container_of(x, struct drm_property, base)
|
||||
#define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
|
||||
#define obj_to_plane(x) container_of(x, struct drm_plane, base)
|
||||
|
||||
struct drm_prop_enum_list {
|
||||
int type;
|
||||
char *name;
|
||||
};
|
||||
|
||||
#if defined(MODE_SETTING_LOCKING_IS_NOT_BROKEN)
|
||||
#define DRM_MODE_CONFIG_ASSERT_LOCKED(dev) \
|
||||
sx_assert(&dev->mode_config.mutex, SA_XLOCKED)
|
||||
#else
|
||||
#define DRM_MODE_CONFIG_ASSERT_LOCKED(dev)
|
||||
#endif
|
||||
|
||||
extern char *drm_get_dirty_info_name(int val);
|
||||
extern char *drm_get_connector_status_name(enum drm_connector_status status);
|
||||
|
||||
extern int drm_crtc_init(struct drm_device *dev,
|
||||
struct drm_crtc *crtc,
|
||||
const struct drm_crtc_funcs *funcs);
|
||||
extern void drm_crtc_cleanup(struct drm_crtc *crtc);
|
||||
|
||||
extern int drm_connector_init(struct drm_device *dev,
|
||||
struct drm_connector *connector,
|
||||
const struct drm_connector_funcs *funcs,
|
||||
int connector_type);
|
||||
|
||||
extern void drm_connector_cleanup(struct drm_connector *connector);
|
||||
|
||||
extern int drm_encoder_init(struct drm_device *dev,
|
||||
struct drm_encoder *encoder,
|
||||
const struct drm_encoder_funcs *funcs,
|
||||
int encoder_type);
|
||||
|
||||
extern int drm_plane_init(struct drm_device *dev,
|
||||
struct drm_plane *plane,
|
||||
unsigned long possible_crtcs,
|
||||
const struct drm_plane_funcs *funcs,
|
||||
const uint32_t *formats, uint32_t format_count,
|
||||
bool priv);
|
||||
extern void drm_plane_cleanup(struct drm_plane *plane);
|
||||
|
||||
extern void drm_encoder_cleanup(struct drm_encoder *encoder);
|
||||
|
||||
extern char *drm_get_connector_name(struct drm_connector *connector);
|
||||
extern char *drm_get_dpms_name(int val);
|
||||
extern char *drm_get_dvi_i_subconnector_name(int val);
|
||||
extern char *drm_get_dvi_i_select_name(int val);
|
||||
extern char *drm_get_tv_subconnector_name(int val);
|
||||
extern char *drm_get_tv_select_name(int val);
|
||||
extern void drm_fb_release(struct drm_file *file_priv);
|
||||
extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
|
||||
extern struct edid *drm_get_edid(struct drm_connector *connector,
|
||||
device_t adapter);
|
||||
extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
|
||||
extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
|
||||
extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);
|
||||
extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
|
||||
const struct drm_display_mode *mode);
|
||||
extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode);
|
||||
extern void drm_mode_config_init(struct drm_device *dev);
|
||||
extern void drm_mode_config_reset(struct drm_device *dev);
|
||||
extern void drm_mode_config_cleanup(struct drm_device *dev);
|
||||
extern void drm_mode_set_name(struct drm_display_mode *mode);
|
||||
extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
|
||||
extern int drm_mode_width(struct drm_display_mode *mode);
|
||||
extern int drm_mode_height(struct drm_display_mode *mode);
|
||||
|
||||
/* for us by fb module */
|
||||
extern int drm_mode_attachmode_crtc(struct drm_device *dev,
|
||||
struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode);
|
||||
extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode);
|
||||
|
||||
extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
|
||||
extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
|
||||
extern void drm_mode_list_concat(struct list_head *head,
|
||||
struct list_head *new);
|
||||
extern void drm_mode_validate_size(struct drm_device *dev,
|
||||
struct list_head *mode_list,
|
||||
int maxX, int maxY, int maxPitch);
|
||||
extern void drm_mode_validate_clocks(struct drm_device *dev,
|
||||
struct list_head *mode_list,
|
||||
int *min, int *max, int n_ranges);
|
||||
extern void drm_mode_prune_invalid(struct drm_device *dev,
|
||||
struct list_head *mode_list, bool verbose);
|
||||
extern void drm_mode_sort(struct list_head *mode_list);
|
||||
extern int drm_mode_hsync(const struct drm_display_mode *mode);
|
||||
extern int drm_mode_vrefresh(const struct drm_display_mode *mode);
|
||||
extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
|
||||
int adjust_flags);
|
||||
extern void drm_mode_connector_list_update(struct drm_connector *connector);
|
||||
extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
|
||||
struct edid *edid);
|
||||
extern int drm_connector_property_set_value(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t value);
|
||||
extern int drm_connector_property_get_value(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t *value);
|
||||
extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
|
||||
extern void drm_framebuffer_set_object(struct drm_device *dev,
|
||||
unsigned long handle);
|
||||
extern int drm_framebuffer_init(struct drm_device *dev,
|
||||
struct drm_framebuffer *fb,
|
||||
const struct drm_framebuffer_funcs *funcs);
|
||||
extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
|
||||
extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
|
||||
extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
|
||||
extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY);
|
||||
extern bool drm_crtc_in_use(struct drm_crtc *crtc);
|
||||
|
||||
extern int drm_connector_attach_property(struct drm_connector *connector,
|
||||
struct drm_property *property, uint64_t init_val);
|
||||
extern struct drm_property *drm_property_create(struct drm_device *dev, int flags,
|
||||
const char *name, int num_values);
|
||||
extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
const struct drm_prop_enum_list *props,
|
||||
int num_values);
|
||||
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
|
||||
const char *name,
|
||||
uint64_t min, uint64_t max);
|
||||
extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
|
||||
extern int drm_property_add_enum(struct drm_property *property, int index,
|
||||
uint64_t value, const char *name);
|
||||
extern int drm_mode_create_dvi_i_properties(struct drm_device *dev);
|
||||
extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats,
|
||||
char *formats[]);
|
||||
extern int drm_mode_create_scaling_mode_property(struct drm_device *dev);
|
||||
extern int drm_mode_create_dithering_property(struct drm_device *dev);
|
||||
extern int drm_mode_create_dirty_info_property(struct drm_device *dev);
|
||||
extern char *drm_get_encoder_name(struct drm_encoder *encoder);
|
||||
|
||||
extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
|
||||
struct drm_encoder *encoder);
|
||||
extern void drm_mode_connector_detach_encoder(struct drm_connector *connector,
|
||||
struct drm_encoder *encoder);
|
||||
extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
|
||||
int gamma_size);
|
||||
extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
|
||||
uint32_t id, uint32_t type);
|
||||
/* IOCTLs */
|
||||
extern int drm_mode_getresources(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_getplane_res(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
extern int drm_mode_getcrtc(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_getconnector(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_setcrtc(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_getplane(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_setplane(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_cursor_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_addfb(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_addfb2(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
|
||||
extern int drm_mode_rmfb(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_getfb(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_addmode_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_rmmode_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_attachmode_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_detachmode_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
|
||||
extern int drm_mode_getproperty_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_getblob_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_hotplug_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_replacefb(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_getencoder(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern bool drm_detect_hdmi_monitor(struct edid *edid);
|
||||
extern bool drm_detect_monitor_audio(struct edid *edid);
|
||||
extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
|
||||
int hdisplay, int vdisplay, int vrefresh,
|
||||
bool reduced, bool interlaced, bool margins);
|
||||
extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev,
|
||||
int hdisplay, int vdisplay, int vrefresh,
|
||||
bool interlaced, int margins);
|
||||
extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev,
|
||||
int hdisplay, int vdisplay, int vrefresh,
|
||||
bool interlaced, int margins, int GTF_M,
|
||||
int GTF_2C, int GTF_K, int GTF_2J);
|
||||
extern int drm_add_modes_noedid(struct drm_connector *connector,
|
||||
int hdisplay, int vdisplay);
|
||||
|
||||
extern int drm_edid_header_is_valid(const u8 *raw_edid);
|
||||
extern bool drm_edid_is_valid(struct edid *edid);
|
||||
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
||||
int hsize, int vsize, int fresh);
|
||||
|
||||
extern int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
|
||||
extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
|
||||
int *bpp);
|
||||
#endif /* __DRM_CRTC_H__ */
|
||||
1043
sys/dev/drm2/drm_crtc_helper.c
Normal file
1043
sys/dev/drm2/drm_crtc_helper.c
Normal file
File diff suppressed because it is too large
Load diff
146
sys/dev/drm2/drm_crtc_helper.h
Normal file
146
sys/dev/drm2/drm_crtc_helper.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright © 2006 Keith Packard
|
||||
* Copyright © 2007-2008 Dave Airlie
|
||||
* Copyright © 2007-2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* The DRM mode setting helper functions are common code for drivers to use if
|
||||
* they wish. Drivers are not forced to use this code in their
|
||||
* implementations but it would be useful if they code they do use at least
|
||||
* provides a consistent interface and operation to userspace
|
||||
*/
|
||||
|
||||
#ifndef __DRM_CRTC_HELPER_H__
|
||||
#define __DRM_CRTC_HELPER_H__
|
||||
|
||||
enum mode_set_atomic {
|
||||
LEAVE_ATOMIC_MODE_SET,
|
||||
ENTER_ATOMIC_MODE_SET,
|
||||
};
|
||||
|
||||
struct drm_crtc_helper_funcs {
|
||||
/*
|
||||
* Control power levels on the CRTC. If the mode passed in is
|
||||
* unsupported, the provider must use the next lowest power level.
|
||||
*/
|
||||
void (*dpms)(struct drm_crtc *crtc, int mode);
|
||||
void (*prepare)(struct drm_crtc *crtc);
|
||||
void (*commit)(struct drm_crtc *crtc);
|
||||
|
||||
/* Provider can fixup or change mode timings before modeset occurs */
|
||||
bool (*mode_fixup)(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
/* Actually set the mode */
|
||||
int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode, int x, int y,
|
||||
struct drm_framebuffer *old_fb);
|
||||
|
||||
/* Move the crtc on the current fb to the given position *optional* */
|
||||
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb);
|
||||
int (*mode_set_base_atomic)(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb, int x, int y,
|
||||
enum mode_set_atomic);
|
||||
|
||||
/* reload the current crtc LUT */
|
||||
void (*load_lut)(struct drm_crtc *crtc);
|
||||
|
||||
/* disable crtc when not in use - more explicit than dpms off */
|
||||
void (*disable)(struct drm_crtc *crtc);
|
||||
};
|
||||
|
||||
struct drm_encoder_helper_funcs {
|
||||
void (*dpms)(struct drm_encoder *encoder, int mode);
|
||||
void (*save)(struct drm_encoder *encoder);
|
||||
void (*restore)(struct drm_encoder *encoder);
|
||||
|
||||
bool (*mode_fixup)(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
void (*prepare)(struct drm_encoder *encoder);
|
||||
void (*commit)(struct drm_encoder *encoder);
|
||||
void (*mode_set)(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder);
|
||||
/* detect for DAC style encoders */
|
||||
enum drm_connector_status (*detect)(struct drm_encoder *encoder,
|
||||
struct drm_connector *connector);
|
||||
/* disable encoder when not in use - more explicit than dpms off */
|
||||
void (*disable)(struct drm_encoder *encoder);
|
||||
};
|
||||
|
||||
struct drm_connector_helper_funcs {
|
||||
int (*get_modes)(struct drm_connector *connector);
|
||||
int (*mode_valid)(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode);
|
||||
struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
|
||||
};
|
||||
|
||||
extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
|
||||
extern void drm_helper_disable_unused_functions(struct drm_device *dev);
|
||||
extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
|
||||
extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb);
|
||||
extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
|
||||
extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder);
|
||||
|
||||
extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode);
|
||||
|
||||
extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd);
|
||||
|
||||
static inline void drm_crtc_helper_add(struct drm_crtc *crtc,
|
||||
const struct drm_crtc_helper_funcs *funcs)
|
||||
{
|
||||
crtc->helper_private = __DECONST(void *, funcs);
|
||||
}
|
||||
|
||||
static inline void drm_encoder_helper_add(struct drm_encoder *encoder,
|
||||
const struct drm_encoder_helper_funcs *funcs)
|
||||
{
|
||||
encoder->helper_private = __DECONST(void *, funcs);
|
||||
}
|
||||
|
||||
static inline void drm_connector_helper_add(struct drm_connector *connector,
|
||||
const struct drm_connector_helper_funcs *funcs)
|
||||
{
|
||||
connector->helper_private = __DECONST(void *, funcs);
|
||||
}
|
||||
|
||||
extern int drm_helper_resume_force_mode(struct drm_device *dev);
|
||||
extern void drm_kms_helper_poll_init(struct drm_device *dev);
|
||||
extern void drm_kms_helper_poll_fini(struct drm_device *dev);
|
||||
extern void drm_helper_hpd_irq_event(struct drm_device *dev);
|
||||
|
||||
extern void drm_kms_helper_poll_disable(struct drm_device *dev);
|
||||
extern void drm_kms_helper_poll_enable(struct drm_device *dev);
|
||||
|
||||
extern bool drm_fetch_cmdline_mode_from_kenv(struct drm_connector *connector,
|
||||
struct drm_cmdline_mode *cmdline_mode);
|
||||
#endif
|
||||
139
sys/dev/drm2/drm_dma.c
Normal file
139
sys/dev/drm2/drm_dma.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*-
|
||||
* Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_dma.c
|
||||
* Support code for DMA buffer management.
|
||||
*
|
||||
* The implementation used to be significantly more complicated, but the
|
||||
* complexity has been moved into the drivers as different buffer management
|
||||
* schemes evolved.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
int drm_dma_setup(struct drm_device *dev)
|
||||
{
|
||||
|
||||
dev->dma = malloc(sizeof(*dev->dma), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
|
||||
if (dev->dma == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
DRM_SPININIT(&dev->dma_lock, "drmdma");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drm_dma_takedown(struct drm_device *dev)
|
||||
{
|
||||
drm_device_dma_t *dma = dev->dma;
|
||||
int i, j;
|
||||
|
||||
if (dma == NULL)
|
||||
return;
|
||||
|
||||
/* Clear dma buffers */
|
||||
for (i = 0; i <= DRM_MAX_ORDER; i++) {
|
||||
if (dma->bufs[i].seg_count) {
|
||||
DRM_DEBUG("order %d: buf_count = %d,"
|
||||
" seg_count = %d\n", i, dma->bufs[i].buf_count,
|
||||
dma->bufs[i].seg_count);
|
||||
for (j = 0; j < dma->bufs[i].seg_count; j++) {
|
||||
drm_pci_free(dev, dma->bufs[i].seglist[j]);
|
||||
}
|
||||
free(dma->bufs[i].seglist, DRM_MEM_SEGS);
|
||||
}
|
||||
|
||||
if (dma->bufs[i].buf_count) {
|
||||
for (j = 0; j < dma->bufs[i].buf_count; j++) {
|
||||
free(dma->bufs[i].buflist[j].dev_private,
|
||||
DRM_MEM_BUFS);
|
||||
}
|
||||
free(dma->bufs[i].buflist, DRM_MEM_BUFS);
|
||||
}
|
||||
}
|
||||
|
||||
free(dma->buflist, DRM_MEM_BUFS);
|
||||
free(dma->pagelist, DRM_MEM_PAGES);
|
||||
free(dev->dma, DRM_MEM_DRIVER);
|
||||
dev->dma = NULL;
|
||||
DRM_SPINUNINIT(&dev->dma_lock);
|
||||
}
|
||||
|
||||
|
||||
void drm_free_buffer(struct drm_device *dev, drm_buf_t *buf)
|
||||
{
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
buf->pending = 0;
|
||||
buf->file_priv= NULL;
|
||||
buf->used = 0;
|
||||
}
|
||||
|
||||
void drm_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
|
||||
{
|
||||
drm_device_dma_t *dma = dev->dma;
|
||||
int i;
|
||||
|
||||
if (!dma)
|
||||
return;
|
||||
|
||||
for (i = 0; i < dma->buf_count; i++) {
|
||||
if (dma->buflist[i]->file_priv == file_priv) {
|
||||
switch (dma->buflist[i]->list) {
|
||||
case DRM_LIST_NONE:
|
||||
drm_free_buffer(dev, dma->buflist[i]);
|
||||
break;
|
||||
case DRM_LIST_WAIT:
|
||||
dma->buflist[i]->list = DRM_LIST_RECLAIM;
|
||||
break;
|
||||
default:
|
||||
/* Buffer already on hardware. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Call into the driver-specific DMA handler */
|
||||
int drm_dma(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
if (dev->driver->dma_ioctl) {
|
||||
/* shared code returns -errno */
|
||||
return -dev->driver->dma_ioctl(dev, data, file_priv);
|
||||
} else {
|
||||
DRM_DEBUG("DMA ioctl on driver with no dma handler\n");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
250
sys/dev/drm2/drm_dp_helper.h
Normal file
250
sys/dev/drm2/drm_dp_helper.h
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright © 2008 Keith Packard
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DRM_DP_HELPER_H_
|
||||
#define _DRM_DP_HELPER_H_
|
||||
|
||||
/* From the VESA DisplayPort spec */
|
||||
|
||||
#define AUX_NATIVE_WRITE 0x8
|
||||
#define AUX_NATIVE_READ 0x9
|
||||
#define AUX_I2C_WRITE 0x0
|
||||
#define AUX_I2C_READ 0x1
|
||||
#define AUX_I2C_STATUS 0x2
|
||||
#define AUX_I2C_MOT 0x4
|
||||
|
||||
#define AUX_NATIVE_REPLY_ACK (0x0 << 4)
|
||||
#define AUX_NATIVE_REPLY_NACK (0x1 << 4)
|
||||
#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
|
||||
#define AUX_NATIVE_REPLY_MASK (0x3 << 4)
|
||||
|
||||
#define AUX_I2C_REPLY_ACK (0x0 << 6)
|
||||
#define AUX_I2C_REPLY_NACK (0x1 << 6)
|
||||
#define AUX_I2C_REPLY_DEFER (0x2 << 6)
|
||||
#define AUX_I2C_REPLY_MASK (0x3 << 6)
|
||||
|
||||
/* AUX CH addresses */
|
||||
/* DPCD */
|
||||
#define DP_DPCD_REV 0x000
|
||||
|
||||
#define DP_MAX_LINK_RATE 0x001
|
||||
|
||||
#define DP_MAX_LANE_COUNT 0x002
|
||||
# define DP_MAX_LANE_COUNT_MASK 0x1f
|
||||
# define DP_TPS3_SUPPORTED (1 << 6)
|
||||
# define DP_ENHANCED_FRAME_CAP (1 << 7)
|
||||
|
||||
#define DP_MAX_DOWNSPREAD 0x003
|
||||
# define DP_NO_AUX_HANDSHAKE_LINK_TRAINING (1 << 6)
|
||||
|
||||
#define DP_NORP 0x004
|
||||
|
||||
#define DP_DOWNSTREAMPORT_PRESENT 0x005
|
||||
# define DP_DWN_STRM_PORT_PRESENT (1 << 0)
|
||||
# define DP_DWN_STRM_PORT_TYPE_MASK 0x06
|
||||
/* 00b = DisplayPort */
|
||||
/* 01b = Analog */
|
||||
/* 10b = TMDS or HDMI */
|
||||
/* 11b = Other */
|
||||
# define DP_FORMAT_CONVERSION (1 << 3)
|
||||
|
||||
#define DP_MAIN_LINK_CHANNEL_CODING 0x006
|
||||
|
||||
#define DP_TRAINING_AUX_RD_INTERVAL 0x00e
|
||||
|
||||
#define DP_PSR_SUPPORT 0x070
|
||||
# define DP_PSR_IS_SUPPORTED 1
|
||||
#define DP_PSR_CAPS 0x071
|
||||
# define DP_PSR_NO_TRAIN_ON_EXIT 1
|
||||
# define DP_PSR_SETUP_TIME_330 (0 << 1)
|
||||
# define DP_PSR_SETUP_TIME_275 (1 << 1)
|
||||
# define DP_PSR_SETUP_TIME_220 (2 << 1)
|
||||
# define DP_PSR_SETUP_TIME_165 (3 << 1)
|
||||
# define DP_PSR_SETUP_TIME_110 (4 << 1)
|
||||
# define DP_PSR_SETUP_TIME_55 (5 << 1)
|
||||
# define DP_PSR_SETUP_TIME_0 (6 << 1)
|
||||
# define DP_PSR_SETUP_TIME_MASK (7 << 1)
|
||||
# define DP_PSR_SETUP_TIME_SHIFT 1
|
||||
|
||||
/* link configuration */
|
||||
#define DP_LINK_BW_SET 0x100
|
||||
# define DP_LINK_BW_1_62 0x06
|
||||
# define DP_LINK_BW_2_7 0x0a
|
||||
# define DP_LINK_BW_5_4 0x14
|
||||
|
||||
#define DP_LANE_COUNT_SET 0x101
|
||||
# define DP_LANE_COUNT_MASK 0x0f
|
||||
# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7)
|
||||
|
||||
#define DP_TRAINING_PATTERN_SET 0x102
|
||||
# define DP_TRAINING_PATTERN_DISABLE 0
|
||||
# define DP_TRAINING_PATTERN_1 1
|
||||
# define DP_TRAINING_PATTERN_2 2
|
||||
# define DP_TRAINING_PATTERN_3 3
|
||||
# define DP_TRAINING_PATTERN_MASK 0x3
|
||||
|
||||
# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2)
|
||||
# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2)
|
||||
# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2)
|
||||
# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2)
|
||||
# define DP_LINK_QUAL_PATTERN_MASK (3 << 2)
|
||||
|
||||
# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4)
|
||||
# define DP_LINK_SCRAMBLING_DISABLE (1 << 5)
|
||||
|
||||
# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6)
|
||||
# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6)
|
||||
# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6)
|
||||
# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6)
|
||||
|
||||
#define DP_TRAINING_LANE0_SET 0x103
|
||||
#define DP_TRAINING_LANE1_SET 0x104
|
||||
#define DP_TRAINING_LANE2_SET 0x105
|
||||
#define DP_TRAINING_LANE3_SET 0x106
|
||||
|
||||
# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3
|
||||
# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0
|
||||
# define DP_TRAIN_MAX_SWING_REACHED (1 << 2)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0)
|
||||
# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0)
|
||||
|
||||
# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3)
|
||||
# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3)
|
||||
# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3)
|
||||
# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3)
|
||||
# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3)
|
||||
|
||||
# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3
|
||||
# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5)
|
||||
|
||||
#define DP_DOWNSPREAD_CTRL 0x107
|
||||
# define DP_SPREAD_AMP_0_5 (1 << 4)
|
||||
|
||||
#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108
|
||||
# define DP_SET_ANSI_8B10B (1 << 0)
|
||||
|
||||
#define DP_PSR_EN_CFG 0x170
|
||||
# define DP_PSR_ENABLE (1 << 0)
|
||||
# define DP_PSR_MAIN_LINK_ACTIVE (1 << 1)
|
||||
# define DP_PSR_CRC_VERIFICATION (1 << 2)
|
||||
# define DP_PSR_FRAME_CAPTURE (1 << 3)
|
||||
|
||||
#define DP_DEVICE_SERVICE_IRQ_VECTOR 0x201
|
||||
# define DP_REMOTE_CONTROL_COMMAND_PENDING (1 << 0)
|
||||
# define DP_AUTOMATED_TEST_REQUEST (1 << 1)
|
||||
# define DP_CP_IRQ (1 << 2)
|
||||
# define DP_SINK_SPECIFIC_IRQ (1 << 6)
|
||||
|
||||
#define DP_LANE0_1_STATUS 0x202
|
||||
#define DP_LANE2_3_STATUS 0x203
|
||||
# define DP_LANE_CR_DONE (1 << 0)
|
||||
# define DP_LANE_CHANNEL_EQ_DONE (1 << 1)
|
||||
# define DP_LANE_SYMBOL_LOCKED (1 << 2)
|
||||
|
||||
#define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | \
|
||||
DP_LANE_CHANNEL_EQ_DONE | \
|
||||
DP_LANE_SYMBOL_LOCKED)
|
||||
|
||||
#define DP_LANE_ALIGN_STATUS_UPDATED 0x204
|
||||
|
||||
#define DP_INTERLANE_ALIGN_DONE (1 << 0)
|
||||
#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6)
|
||||
#define DP_LINK_STATUS_UPDATED (1 << 7)
|
||||
|
||||
#define DP_SINK_STATUS 0x205
|
||||
|
||||
#define DP_RECEIVE_PORT_0_STATUS (1 << 0)
|
||||
#define DP_RECEIVE_PORT_1_STATUS (1 << 1)
|
||||
|
||||
#define DP_ADJUST_REQUEST_LANE0_1 0x206
|
||||
#define DP_ADJUST_REQUEST_LANE2_3 0x207
|
||||
# define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03
|
||||
# define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
|
||||
# define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c
|
||||
# define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2
|
||||
# define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30
|
||||
# define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
|
||||
# define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0
|
||||
# define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6
|
||||
|
||||
#define DP_TEST_REQUEST 0x218
|
||||
# define DP_TEST_LINK_TRAINING (1 << 0)
|
||||
# define DP_TEST_LINK_PATTERN (1 << 1)
|
||||
# define DP_TEST_LINK_EDID_READ (1 << 2)
|
||||
# define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */
|
||||
|
||||
#define DP_TEST_LINK_RATE 0x219
|
||||
# define DP_LINK_RATE_162 (0x6)
|
||||
# define DP_LINK_RATE_27 (0xa)
|
||||
|
||||
#define DP_TEST_LANE_COUNT 0x220
|
||||
|
||||
#define DP_TEST_PATTERN 0x221
|
||||
|
||||
#define DP_TEST_RESPONSE 0x260
|
||||
# define DP_TEST_ACK (1 << 0)
|
||||
# define DP_TEST_NAK (1 << 1)
|
||||
# define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2)
|
||||
|
||||
#define DP_SET_POWER 0x600
|
||||
# define DP_SET_POWER_D0 0x1
|
||||
# define DP_SET_POWER_D3 0x2
|
||||
|
||||
#define DP_PSR_ERROR_STATUS 0x2006
|
||||
# define DP_PSR_LINK_CRC_ERROR (1 << 0)
|
||||
# define DP_PSR_RFB_STORAGE_ERROR (1 << 1)
|
||||
|
||||
#define DP_PSR_ESI 0x2007
|
||||
# define DP_PSR_CAPS_CHANGE (1 << 0)
|
||||
|
||||
#define DP_PSR_STATUS 0x2008
|
||||
# define DP_PSR_SINK_INACTIVE 0
|
||||
# define DP_PSR_SINK_ACTIVE_SRC_SYNCED 1
|
||||
# define DP_PSR_SINK_ACTIVE_RFB 2
|
||||
# define DP_PSR_SINK_ACTIVE_SINK_SYNCED 3
|
||||
# define DP_PSR_SINK_ACTIVE_RESYNC 4
|
||||
# define DP_PSR_SINK_INTERNAL_ERROR 7
|
||||
# define DP_PSR_SINK_STATE_MASK 0x07
|
||||
|
||||
#define MODE_I2C_START 1
|
||||
#define MODE_I2C_WRITE 2
|
||||
#define MODE_I2C_READ 4
|
||||
#define MODE_I2C_STOP 8
|
||||
|
||||
struct iic_dp_aux_data {
|
||||
bool running;
|
||||
u16 address;
|
||||
void *priv;
|
||||
int (*aux_ch)(device_t adapter, int mode, uint8_t write_byte,
|
||||
uint8_t *read_byte);
|
||||
device_t port;
|
||||
};
|
||||
|
||||
int iic_dp_aux_add_bus(device_t dev, const char *name,
|
||||
int (*ch)(device_t idev, int mode, uint8_t write_byte, uint8_t *read_byte),
|
||||
void *priv, device_t *bus, device_t *adapter);
|
||||
|
||||
#endif /* _DRM_DP_HELPER_H_ */
|
||||
292
sys/dev/drm2/drm_dp_iic_helper.c
Normal file
292
sys/dev/drm2/drm_dp_iic_helper.c
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* Copyright © 2009 Keith Packard
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/kobj.h>
|
||||
#include <sys/bus.h>
|
||||
#include <dev/iicbus/iic.h>
|
||||
#include "iicbus_if.h"
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm_dp_helper.h>
|
||||
|
||||
static int
|
||||
iic_dp_aux_transaction(device_t idev, int mode, uint8_t write_byte,
|
||||
uint8_t *read_byte)
|
||||
{
|
||||
struct iic_dp_aux_data *aux_data;
|
||||
int ret;
|
||||
|
||||
aux_data = device_get_softc(idev);
|
||||
ret = (*aux_data->aux_ch)(idev, mode, write_byte, read_byte);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C over AUX CH
|
||||
*/
|
||||
|
||||
/*
|
||||
* Send the address. If the I2C link is running, this 'restarts'
|
||||
* the connection with the new address, this is used for doing
|
||||
* a write followed by a read (as needed for DDC)
|
||||
*/
|
||||
static int
|
||||
iic_dp_aux_address(device_t idev, u16 address, bool reading)
|
||||
{
|
||||
struct iic_dp_aux_data *aux_data;
|
||||
int mode, ret;
|
||||
|
||||
aux_data = device_get_softc(idev);
|
||||
mode = MODE_I2C_START;
|
||||
if (reading)
|
||||
mode |= MODE_I2C_READ;
|
||||
else
|
||||
mode |= MODE_I2C_WRITE;
|
||||
aux_data->address = address;
|
||||
aux_data->running = true;
|
||||
ret = iic_dp_aux_transaction(idev, mode, 0, NULL);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop the I2C transaction. This closes out the link, sending
|
||||
* a bare address packet with the MOT bit turned off
|
||||
*/
|
||||
static void
|
||||
iic_dp_aux_stop(device_t idev, bool reading)
|
||||
{
|
||||
struct iic_dp_aux_data *aux_data;
|
||||
int mode;
|
||||
|
||||
aux_data = device_get_softc(idev);
|
||||
mode = MODE_I2C_STOP;
|
||||
if (reading)
|
||||
mode |= MODE_I2C_READ;
|
||||
else
|
||||
mode |= MODE_I2C_WRITE;
|
||||
if (aux_data->running) {
|
||||
(void)iic_dp_aux_transaction(idev, mode, 0, NULL);
|
||||
aux_data->running = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a single byte to the current I2C address, the
|
||||
* the I2C link must be running or this returns -EIO
|
||||
*/
|
||||
static int
|
||||
iic_dp_aux_put_byte(device_t idev, u8 byte)
|
||||
{
|
||||
struct iic_dp_aux_data *aux_data;
|
||||
int ret;
|
||||
|
||||
aux_data = device_get_softc(idev);
|
||||
|
||||
if (!aux_data->running)
|
||||
return (EIO);
|
||||
|
||||
ret = iic_dp_aux_transaction(idev, MODE_I2C_WRITE, byte, NULL);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a single byte from the current I2C address, the
|
||||
* I2C link must be running or this returns -EIO
|
||||
*/
|
||||
static int
|
||||
iic_dp_aux_get_byte(device_t idev, u8 *byte_ret)
|
||||
{
|
||||
struct iic_dp_aux_data *aux_data;
|
||||
int ret;
|
||||
|
||||
aux_data = device_get_softc(idev);
|
||||
|
||||
if (!aux_data->running)
|
||||
return (EIO);
|
||||
|
||||
ret = iic_dp_aux_transaction(idev, MODE_I2C_READ, 0, byte_ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
iic_dp_aux_xfer(device_t idev, struct iic_msg *msgs, uint32_t num)
|
||||
{
|
||||
u8 *buf;
|
||||
int b, m, ret;
|
||||
u16 len;
|
||||
bool reading;
|
||||
|
||||
ret = 0;
|
||||
reading = false;
|
||||
|
||||
for (m = 0; m < num; m++) {
|
||||
len = msgs[m].len;
|
||||
buf = msgs[m].buf;
|
||||
reading = (msgs[m].flags & IIC_M_RD) != 0;
|
||||
ret = iic_dp_aux_address(idev, msgs[m].slave, reading);
|
||||
if (ret != 0)
|
||||
break;
|
||||
if (reading) {
|
||||
for (b = 0; b < len; b++) {
|
||||
ret = iic_dp_aux_get_byte(idev, &buf[b]);
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (b = 0; b < len; b++) {
|
||||
ret = iic_dp_aux_put_byte(idev, buf[b]);
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
iic_dp_aux_stop(idev, reading);
|
||||
DRM_DEBUG_KMS("dp_aux_xfer return %d\n", ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
iic_dp_aux_reset_bus(device_t idev)
|
||||
{
|
||||
|
||||
(void)iic_dp_aux_address(idev, 0, false);
|
||||
(void)iic_dp_aux_stop(idev, false);
|
||||
}
|
||||
|
||||
static int
|
||||
iic_dp_aux_reset(device_t idev, u_char speed, u_char addr, u_char *oldaddr)
|
||||
{
|
||||
|
||||
iic_dp_aux_reset_bus(idev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
iic_dp_aux_prepare_bus(device_t idev)
|
||||
{
|
||||
|
||||
/* adapter->retries = 3; */
|
||||
iic_dp_aux_reset_bus(idev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
iic_dp_aux_probe(device_t idev)
|
||||
{
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
iic_dp_aux_attach(device_t idev)
|
||||
{
|
||||
struct iic_dp_aux_data *aux_data;
|
||||
|
||||
aux_data = device_get_softc(idev);
|
||||
aux_data->port = device_add_child(idev, "iicbus", -1);
|
||||
if (aux_data->port == NULL)
|
||||
return (ENXIO);
|
||||
device_quiet(aux_data->port);
|
||||
bus_generic_attach(idev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
iic_dp_aux_detach(device_t idev)
|
||||
{
|
||||
struct iic_dp_aux_data *aux_data;
|
||||
device_t port;
|
||||
|
||||
aux_data = device_get_softc(idev);
|
||||
|
||||
port = aux_data->port;
|
||||
bus_generic_detach(idev);
|
||||
if (port != NULL)
|
||||
device_delete_child(idev, port);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
iic_dp_aux_add_bus(device_t dev, const char *name,
|
||||
int (*ch)(device_t idev, int mode, uint8_t write_byte, uint8_t *read_byte),
|
||||
void *priv, device_t *bus, device_t *adapter)
|
||||
{
|
||||
device_t ibus;
|
||||
struct iic_dp_aux_data *data;
|
||||
int idx, error;
|
||||
static int dp_bus_counter;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
|
||||
idx = atomic_fetchadd_int(&dp_bus_counter, 1);
|
||||
ibus = device_add_child(dev, "drm_iic_dp_aux", idx);
|
||||
if (ibus == NULL) {
|
||||
mtx_unlock(&Giant);
|
||||
DRM_ERROR("drm_iic_dp_aux bus %d creation error\n", idx);
|
||||
return (-ENXIO);
|
||||
}
|
||||
device_quiet(ibus);
|
||||
error = device_probe_and_attach(ibus);
|
||||
if (error != 0) {
|
||||
device_delete_child(dev, ibus);
|
||||
mtx_unlock(&Giant);
|
||||
DRM_ERROR("drm_iic_dp_aux bus %d attach failed, %d\n",
|
||||
idx, error);
|
||||
return (-error);
|
||||
}
|
||||
data = device_get_softc(ibus);
|
||||
data->running = false;
|
||||
data->address = 0;
|
||||
data->aux_ch = ch;
|
||||
data->priv = priv;
|
||||
error = iic_dp_aux_prepare_bus(ibus);
|
||||
if (error == 0) {
|
||||
*bus = ibus;
|
||||
*adapter = data->port;
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static device_method_t drm_iic_dp_aux_methods[] = {
|
||||
DEVMETHOD(device_probe, iic_dp_aux_probe),
|
||||
DEVMETHOD(device_attach, iic_dp_aux_attach),
|
||||
DEVMETHOD(device_detach, iic_dp_aux_detach),
|
||||
DEVMETHOD(iicbus_reset, iic_dp_aux_reset),
|
||||
DEVMETHOD(iicbus_transfer, iic_dp_aux_xfer),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
static driver_t drm_iic_dp_aux_driver = {
|
||||
"drm_iic_dp_aux",
|
||||
drm_iic_dp_aux_methods,
|
||||
sizeof(struct iic_dp_aux_data)
|
||||
};
|
||||
static devclass_t drm_iic_dp_aux_devclass;
|
||||
DRIVER_MODULE_ORDERED(drm_iic_dp_aux, drmn, drm_iic_dp_aux_driver,
|
||||
drm_iic_dp_aux_devclass, 0, 0, SI_ORDER_SECOND);
|
||||
173
sys/dev/drm2/drm_drawable.c
Normal file
173
sys/dev/drm2/drm_drawable.c
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*-
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_drawable.c
|
||||
* This file implements ioctls to store information along with DRM drawables,
|
||||
* such as the current set of cliprects for vblank-synced buffer swaps.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
struct bsd_drm_drawable_info {
|
||||
struct drm_drawable_info info;
|
||||
int handle;
|
||||
RB_ENTRY(bsd_drm_drawable_info) tree;
|
||||
};
|
||||
|
||||
static int
|
||||
drm_drawable_compare(struct bsd_drm_drawable_info *a,
|
||||
struct bsd_drm_drawable_info *b)
|
||||
{
|
||||
if (a->handle > b->handle)
|
||||
return 1;
|
||||
if (a->handle < b->handle)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
RB_GENERATE_STATIC(drawable_tree, bsd_drm_drawable_info, tree,
|
||||
drm_drawable_compare);
|
||||
|
||||
struct drm_drawable_info *
|
||||
drm_get_drawable_info(struct drm_device *dev, int handle)
|
||||
{
|
||||
struct bsd_drm_drawable_info find, *result;
|
||||
|
||||
find.handle = handle;
|
||||
result = RB_FIND(drawable_tree, &dev->drw_head, &find);
|
||||
|
||||
return &result->info;
|
||||
}
|
||||
|
||||
int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_draw *draw = data;
|
||||
struct bsd_drm_drawable_info *info;
|
||||
|
||||
info = malloc(sizeof(struct bsd_drm_drawable_info), DRM_MEM_DRAWABLE,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (info == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
info->handle = alloc_unr(dev->drw_unrhdr);
|
||||
DRM_SPINLOCK(&dev->drw_lock);
|
||||
RB_INSERT(drawable_tree, &dev->drw_head, info);
|
||||
draw->handle = info->handle;
|
||||
DRM_SPINUNLOCK(&dev->drw_lock);
|
||||
|
||||
DRM_DEBUG("%d\n", draw->handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_draw *draw = (struct drm_draw *)data;
|
||||
struct drm_drawable_info *info;
|
||||
|
||||
DRM_SPINLOCK(&dev->drw_lock);
|
||||
info = drm_get_drawable_info(dev, draw->handle);
|
||||
if (info != NULL) {
|
||||
RB_REMOVE(drawable_tree, &dev->drw_head,
|
||||
(struct bsd_drm_drawable_info *)info);
|
||||
DRM_SPINUNLOCK(&dev->drw_lock);
|
||||
free_unr(dev->drw_unrhdr, draw->handle);
|
||||
free(info->rects, DRM_MEM_DRAWABLE);
|
||||
free(info, DRM_MEM_DRAWABLE);
|
||||
return 0;
|
||||
} else {
|
||||
DRM_SPINUNLOCK(&dev->drw_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int drm_update_draw(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_drawable_info *info;
|
||||
struct drm_update_draw *update = (struct drm_update_draw *)data;
|
||||
int ret;
|
||||
|
||||
info = drm_get_drawable_info(dev, update->handle);
|
||||
if (info == NULL)
|
||||
return EINVAL;
|
||||
|
||||
switch (update->type) {
|
||||
case DRM_DRAWABLE_CLIPRECTS:
|
||||
DRM_SPINLOCK(&dev->drw_lock);
|
||||
if (update->num != info->num_rects) {
|
||||
free(info->rects, DRM_MEM_DRAWABLE);
|
||||
info->rects = NULL;
|
||||
info->num_rects = 0;
|
||||
}
|
||||
if (update->num == 0) {
|
||||
DRM_SPINUNLOCK(&dev->drw_lock);
|
||||
return 0;
|
||||
}
|
||||
if (info->rects == NULL) {
|
||||
info->rects = malloc(sizeof(*info->rects) *
|
||||
update->num, DRM_MEM_DRAWABLE, M_NOWAIT);
|
||||
if (info->rects == NULL) {
|
||||
DRM_SPINUNLOCK(&dev->drw_lock);
|
||||
return ENOMEM;
|
||||
}
|
||||
info->num_rects = update->num;
|
||||
}
|
||||
/* For some reason the pointer arg is unsigned long long. */
|
||||
ret = copyin((void *)(intptr_t)update->data, info->rects,
|
||||
sizeof(*info->rects) * info->num_rects);
|
||||
DRM_SPINUNLOCK(&dev->drw_lock);
|
||||
return ret;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
void drm_drawable_free_all(struct drm_device *dev)
|
||||
{
|
||||
struct bsd_drm_drawable_info *info, *next;
|
||||
|
||||
DRM_SPINLOCK(&dev->drw_lock);
|
||||
for (info = RB_MIN(drawable_tree, &dev->drw_head);
|
||||
info != NULL ; info = next) {
|
||||
next = RB_NEXT(drawable_tree, &dev->drw_head, info);
|
||||
RB_REMOVE(drawable_tree, &dev->drw_head,
|
||||
(struct bsd_drm_drawable_info *)info);
|
||||
DRM_SPINUNLOCK(&dev->drw_lock);
|
||||
free_unr(dev->drw_unrhdr, info->handle);
|
||||
free(info->info.rects, DRM_MEM_DRAWABLE);
|
||||
free(info, DRM_MEM_DRAWABLE);
|
||||
DRM_SPINLOCK(&dev->drw_lock);
|
||||
}
|
||||
DRM_SPINUNLOCK(&dev->drw_lock);
|
||||
}
|
||||
980
sys/dev/drm2/drm_drv.c
Normal file
980
sys/dev/drm2/drm_drv.c
Normal file
|
|
@ -0,0 +1,980 @@
|
|||
/*-
|
||||
* Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_drv.c
|
||||
* The catch-all file for DRM device support, including module setup/teardown,
|
||||
* open/close, and ioctl dispatch.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/limits.h>
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_sarea.h>
|
||||
#include <dev/drm2/drm_mode.h>
|
||||
|
||||
#ifdef DRM_DEBUG_DEFAULT_ON
|
||||
int drm_debug_flag = 1;
|
||||
#else
|
||||
int drm_debug_flag = 2;
|
||||
#endif
|
||||
int drm_notyet_flag = 0;
|
||||
|
||||
unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
|
||||
unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
|
||||
|
||||
static int drm_load(struct drm_device *dev);
|
||||
static void drm_unload(struct drm_device *dev);
|
||||
static drm_pci_id_list_t *drm_find_description(int vendor, int device,
|
||||
drm_pci_id_list_t *idlist);
|
||||
|
||||
static int
|
||||
drm_modevent(module_t mod, int type, void *data)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
TUNABLE_INT_FETCH("drm.debug", &drm_debug_flag);
|
||||
TUNABLE_INT_FETCH("drm.notyet", &drm_notyet_flag);
|
||||
break;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static moduledata_t drm_mod = {
|
||||
"drmn",
|
||||
drm_modevent,
|
||||
0
|
||||
};
|
||||
DECLARE_MODULE(drmn, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
|
||||
MODULE_VERSION(drmn, 1);
|
||||
MODULE_DEPEND(drmn, agp, 1, 1, 1);
|
||||
MODULE_DEPEND(drmn, pci, 1, 1, 1);
|
||||
MODULE_DEPEND(drmn, mem, 1, 1, 1);
|
||||
MODULE_DEPEND(drmn, iicbus, 1, 1, 1);
|
||||
|
||||
static drm_ioctl_desc_t drm_ioctls[256] = {
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma, DRM_AUTH),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
|
||||
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
};
|
||||
|
||||
static struct cdevsw drm_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = drm_open,
|
||||
.d_read = drm_read,
|
||||
.d_ioctl = drm_ioctl,
|
||||
.d_poll = drm_poll,
|
||||
.d_mmap = drm_mmap,
|
||||
.d_mmap_single = drm_gem_mmap_single,
|
||||
.d_name = "drm",
|
||||
.d_flags = D_TRACKCLOSE
|
||||
};
|
||||
|
||||
static int drm_msi = 1; /* Enable by default. */
|
||||
TUNABLE_INT("hw.drm.msi", &drm_msi);
|
||||
SYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW, NULL, "DRM device");
|
||||
SYSCTL_INT(_hw_drm, OID_AUTO, msi, CTLFLAG_RDTUN, &drm_msi, 1,
|
||||
"Enable MSI interrupts for drm devices");
|
||||
|
||||
static struct drm_msi_blacklist_entry drm_msi_blacklist[] = {
|
||||
{0x8086, 0x2772}, /* Intel i945G */ \
|
||||
{0x8086, 0x27A2}, /* Intel i945GM */ \
|
||||
{0x8086, 0x27AE}, /* Intel i945GME */ \
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static int drm_msi_is_blacklisted(int vendor, int device)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; drm_msi_blacklist[i].vendor != 0; i++) {
|
||||
if ((drm_msi_blacklist[i].vendor == vendor) &&
|
||||
(drm_msi_blacklist[i].device == device)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_probe(device_t kdev, drm_pci_id_list_t *idlist)
|
||||
{
|
||||
drm_pci_id_list_t *id_entry;
|
||||
int vendor, device;
|
||||
|
||||
vendor = pci_get_vendor(kdev);
|
||||
device = pci_get_device(kdev);
|
||||
|
||||
if (pci_get_class(kdev) != PCIC_DISPLAY
|
||||
|| pci_get_subclass(kdev) != PCIS_DISPLAY_VGA)
|
||||
return ENXIO;
|
||||
|
||||
id_entry = drm_find_description(vendor, device, idlist);
|
||||
if (id_entry != NULL) {
|
||||
if (!device_get_desc(kdev)) {
|
||||
DRM_DEBUG("desc : %s\n", device_get_desc(kdev));
|
||||
device_set_desc(kdev, id_entry->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
int drm_attach(device_t kdev, drm_pci_id_list_t *idlist)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
drm_pci_id_list_t *id_entry;
|
||||
int error, msicount;
|
||||
|
||||
dev = device_get_softc(kdev);
|
||||
|
||||
dev->device = kdev;
|
||||
|
||||
dev->pci_domain = pci_get_domain(dev->device);
|
||||
dev->pci_bus = pci_get_bus(dev->device);
|
||||
dev->pci_slot = pci_get_slot(dev->device);
|
||||
dev->pci_func = pci_get_function(dev->device);
|
||||
|
||||
dev->pci_vendor = pci_get_vendor(dev->device);
|
||||
dev->pci_device = pci_get_device(dev->device);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) {
|
||||
if (drm_msi &&
|
||||
!drm_msi_is_blacklisted(dev->pci_vendor, dev->pci_device)) {
|
||||
msicount = pci_msi_count(dev->device);
|
||||
DRM_DEBUG("MSI count = %d\n", msicount);
|
||||
if (msicount > 1)
|
||||
msicount = 1;
|
||||
|
||||
if (pci_alloc_msi(dev->device, &msicount) == 0) {
|
||||
DRM_INFO("MSI enabled %d message(s)\n",
|
||||
msicount);
|
||||
dev->msi_enabled = 1;
|
||||
dev->irqrid = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ,
|
||||
&dev->irqrid, RF_SHAREABLE);
|
||||
if (!dev->irqr) {
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
dev->irq = (int) rman_get_start(dev->irqr);
|
||||
}
|
||||
|
||||
mtx_init(&dev->dev_lock, "drmdev", NULL, MTX_DEF);
|
||||
mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF);
|
||||
mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF);
|
||||
mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF);
|
||||
mtx_init(&dev->event_lock, "drmev", NULL, MTX_DEF);
|
||||
sx_init(&dev->dev_struct_lock, "drmslk");
|
||||
|
||||
id_entry = drm_find_description(dev->pci_vendor,
|
||||
dev->pci_device, idlist);
|
||||
dev->id_entry = id_entry;
|
||||
|
||||
error = drm_load(dev);
|
||||
if (error == 0)
|
||||
error = drm_create_cdevs(kdev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
drm_create_cdevs(device_t kdev)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
int error, unit;
|
||||
|
||||
unit = device_get_unit(kdev);
|
||||
dev = device_get_softc(kdev);
|
||||
|
||||
error = make_dev_p(MAKEDEV_WAITOK | MAKEDEV_CHECKNAME, &dev->devnode,
|
||||
&drm_cdevsw, 0, DRM_DEV_UID, DRM_DEV_GID,
|
||||
DRM_DEV_MODE, "dri/card%d", unit);
|
||||
if (error == 0)
|
||||
dev->devnode->si_drv1 = dev;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int drm_detach(device_t kdev)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
|
||||
dev = device_get_softc(kdev);
|
||||
drm_unload(dev);
|
||||
if (dev->irqr) {
|
||||
bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
|
||||
dev->irqr);
|
||||
if (dev->msi_enabled) {
|
||||
pci_release_msi(dev->device);
|
||||
DRM_INFO("MSI released\n");
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifndef DRM_DEV_NAME
|
||||
#define DRM_DEV_NAME "drm"
|
||||
#endif
|
||||
|
||||
devclass_t drm_devclass;
|
||||
|
||||
drm_pci_id_list_t *drm_find_description(int vendor, int device,
|
||||
drm_pci_id_list_t *idlist)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; idlist[i].vendor != 0; i++) {
|
||||
if ((idlist[i].vendor == vendor) &&
|
||||
((idlist[i].device == device) ||
|
||||
(idlist[i].device == 0))) {
|
||||
return &idlist[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int drm_firstopen(struct drm_device *dev)
|
||||
{
|
||||
drm_local_map_t *map;
|
||||
int i;
|
||||
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
|
||||
/* prebuild the SAREA */
|
||||
i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
|
||||
_DRM_CONTAINS_LOCK, &map);
|
||||
if (i != 0)
|
||||
return i;
|
||||
|
||||
if (dev->driver->firstopen)
|
||||
dev->driver->firstopen(dev);
|
||||
|
||||
dev->buf_use = 0;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) {
|
||||
i = drm_dma_setup(dev);
|
||||
if (i != 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
for (i = 0; i < DRM_HASH_SIZE; i++) {
|
||||
dev->magiclist[i].head = NULL;
|
||||
dev->magiclist[i].tail = NULL;
|
||||
}
|
||||
|
||||
dev->lock.lock_queue = 0;
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
dev->irq_enabled = 0;
|
||||
dev->context_flag = 0;
|
||||
dev->last_context = 0;
|
||||
dev->if_version = 0;
|
||||
|
||||
dev->buf_sigio = NULL;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_lastclose(struct drm_device *dev)
|
||||
{
|
||||
drm_magic_entry_t *pt, *next;
|
||||
drm_local_map_t *map, *mapsave;
|
||||
int i;
|
||||
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
if (dev->driver->lastclose != NULL)
|
||||
dev->driver->lastclose(dev);
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET) && dev->irq_enabled)
|
||||
drm_irq_uninstall(dev);
|
||||
|
||||
if (dev->unique) {
|
||||
free(dev->unique, DRM_MEM_DRIVER);
|
||||
dev->unique = NULL;
|
||||
dev->unique_len = 0;
|
||||
}
|
||||
/* Clear pid list */
|
||||
for (i = 0; i < DRM_HASH_SIZE; i++) {
|
||||
for (pt = dev->magiclist[i].head; pt; pt = next) {
|
||||
next = pt->next;
|
||||
free(pt, DRM_MEM_MAGIC);
|
||||
}
|
||||
dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
|
||||
}
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
drm_drawable_free_all(dev);
|
||||
DRM_LOCK(dev);
|
||||
|
||||
/* Clear AGP information */
|
||||
if (dev->agp) {
|
||||
drm_agp_mem_t *entry;
|
||||
drm_agp_mem_t *nexte;
|
||||
|
||||
/* Remove AGP resources, but leave dev->agp intact until
|
||||
* drm_unload is called.
|
||||
*/
|
||||
for (entry = dev->agp->memory; entry; entry = nexte) {
|
||||
nexte = entry->next;
|
||||
if (entry->bound)
|
||||
drm_agp_unbind_memory(entry->handle);
|
||||
drm_agp_free_memory(entry->handle);
|
||||
free(entry, DRM_MEM_AGPLISTS);
|
||||
}
|
||||
dev->agp->memory = NULL;
|
||||
|
||||
if (dev->agp->acquired)
|
||||
drm_agp_release(dev);
|
||||
|
||||
dev->agp->acquired = 0;
|
||||
dev->agp->enabled = 0;
|
||||
}
|
||||
if (dev->sg != NULL) {
|
||||
drm_sg_cleanup(dev->sg);
|
||||
dev->sg = NULL;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(map, &dev->maplist, link, mapsave) {
|
||||
if (!(map->flags & _DRM_DRIVER))
|
||||
drm_rmmap(dev, map);
|
||||
}
|
||||
|
||||
drm_dma_takedown(dev);
|
||||
if (dev->lock.hw_lock) {
|
||||
dev->lock.hw_lock = NULL; /* SHM removed */
|
||||
dev->lock.file_priv = NULL;
|
||||
DRM_WAKEUP_INT((void *)&dev->lock.lock_queue);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_load(struct drm_device *dev)
|
||||
{
|
||||
int i, retcode;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
TAILQ_INIT(&dev->maplist);
|
||||
dev->map_unrhdr = new_unrhdr(1, ((1 << DRM_MAP_HANDLE_BITS) - 1), NULL);
|
||||
if (dev->map_unrhdr == NULL) {
|
||||
DRM_ERROR("Couldn't allocate map number allocator\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
|
||||
drm_mem_init();
|
||||
drm_sysctl_init(dev);
|
||||
TAILQ_INIT(&dev->files);
|
||||
|
||||
dev->counters = 6;
|
||||
dev->types[0] = _DRM_STAT_LOCK;
|
||||
dev->types[1] = _DRM_STAT_OPENS;
|
||||
dev->types[2] = _DRM_STAT_CLOSES;
|
||||
dev->types[3] = _DRM_STAT_IOCTLS;
|
||||
dev->types[4] = _DRM_STAT_LOCKS;
|
||||
dev->types[5] = _DRM_STAT_UNLOCKS;
|
||||
|
||||
for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++)
|
||||
atomic_set(&dev->counts[i], 0);
|
||||
|
||||
INIT_LIST_HEAD(&dev->vblank_event_list);
|
||||
|
||||
if (drm_core_has_AGP(dev)) {
|
||||
if (drm_device_is_agp(dev))
|
||||
dev->agp = drm_agp_init();
|
||||
if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) &&
|
||||
dev->agp == NULL) {
|
||||
DRM_ERROR("Card isn't AGP, or couldn't initialize "
|
||||
"AGP.\n");
|
||||
retcode = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
if (dev->agp != NULL && dev->agp->info.ai_aperture_base != 0) {
|
||||
if (drm_mtrr_add(dev->agp->info.ai_aperture_base,
|
||||
dev->agp->info.ai_aperture_size, DRM_MTRR_WC) == 0)
|
||||
dev->agp->mtrr = 1;
|
||||
}
|
||||
}
|
||||
|
||||
retcode = drm_ctxbitmap_init(dev);
|
||||
if (retcode != 0) {
|
||||
DRM_ERROR("Cannot allocate memory for context bitmap.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->drw_unrhdr = new_unrhdr(1, INT_MAX, NULL);
|
||||
if (dev->drw_unrhdr == NULL) {
|
||||
DRM_ERROR("Couldn't allocate drawable number allocator\n");
|
||||
retcode = ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (dev->driver->driver_features & DRIVER_GEM) {
|
||||
retcode = drm_gem_init(dev);
|
||||
if (retcode != 0) {
|
||||
DRM_ERROR("Cannot initialize graphics execution "
|
||||
"manager (GEM)\n");
|
||||
goto error1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->driver->load != NULL) {
|
||||
DRM_LOCK(dev);
|
||||
/* Shared code returns -errno. */
|
||||
retcode = -dev->driver->load(dev,
|
||||
dev->id_entry->driver_private);
|
||||
if (pci_enable_busmaster(dev->device))
|
||||
DRM_ERROR("Request to enable bus-master failed.\n");
|
||||
DRM_UNLOCK(dev);
|
||||
if (retcode != 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
DRM_INFO("Initialized %s %d.%d.%d %s\n",
|
||||
dev->driver->name,
|
||||
dev->driver->major,
|
||||
dev->driver->minor,
|
||||
dev->driver->patchlevel,
|
||||
dev->driver->date);
|
||||
|
||||
return 0;
|
||||
|
||||
error1:
|
||||
delete_unrhdr(dev->drw_unrhdr);
|
||||
error:
|
||||
drm_sysctl_cleanup(dev);
|
||||
DRM_LOCK(dev);
|
||||
drm_lastclose(dev);
|
||||
DRM_UNLOCK(dev);
|
||||
if (dev->devnode != NULL)
|
||||
destroy_dev(dev->devnode);
|
||||
|
||||
mtx_destroy(&dev->drw_lock);
|
||||
mtx_destroy(&dev->vbl_lock);
|
||||
mtx_destroy(&dev->irq_lock);
|
||||
mtx_destroy(&dev->dev_lock);
|
||||
mtx_destroy(&dev->event_lock);
|
||||
sx_destroy(&dev->dev_struct_lock);
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static void drm_unload(struct drm_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
drm_sysctl_cleanup(dev);
|
||||
if (dev->devnode != NULL)
|
||||
destroy_dev(dev->devnode);
|
||||
|
||||
drm_ctxbitmap_cleanup(dev);
|
||||
|
||||
if (dev->driver->driver_features & DRIVER_GEM)
|
||||
drm_gem_destroy(dev);
|
||||
|
||||
if (dev->agp && dev->agp->mtrr) {
|
||||
int __unused retcode;
|
||||
|
||||
retcode = drm_mtrr_del(0, dev->agp->info.ai_aperture_base,
|
||||
dev->agp->info.ai_aperture_size, DRM_MTRR_WC);
|
||||
DRM_DEBUG("mtrr_del = %d", retcode);
|
||||
}
|
||||
|
||||
drm_vblank_cleanup(dev);
|
||||
|
||||
DRM_LOCK(dev);
|
||||
drm_lastclose(dev);
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
/* Clean up PCI resources allocated by drm_bufs.c. We're not really
|
||||
* worried about resource consumption while the DRM is inactive (between
|
||||
* lastclose and firstopen or unload) because these aren't actually
|
||||
* taking up KVA, just keeping the PCI resource allocated.
|
||||
*/
|
||||
for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) {
|
||||
if (dev->pcir[i] == NULL)
|
||||
continue;
|
||||
bus_release_resource(dev->device, SYS_RES_MEMORY,
|
||||
dev->pcirid[i], dev->pcir[i]);
|
||||
dev->pcir[i] = NULL;
|
||||
}
|
||||
|
||||
if (dev->agp) {
|
||||
free(dev->agp, DRM_MEM_AGPLISTS);
|
||||
dev->agp = NULL;
|
||||
}
|
||||
|
||||
if (dev->driver->unload != NULL) {
|
||||
DRM_LOCK(dev);
|
||||
dev->driver->unload(dev);
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
|
||||
delete_unrhdr(dev->drw_unrhdr);
|
||||
delete_unrhdr(dev->map_unrhdr);
|
||||
|
||||
drm_mem_uninit();
|
||||
|
||||
if (pci_disable_busmaster(dev->device))
|
||||
DRM_ERROR("Request to disable bus-master failed.\n");
|
||||
|
||||
mtx_destroy(&dev->drw_lock);
|
||||
mtx_destroy(&dev->vbl_lock);
|
||||
mtx_destroy(&dev->irq_lock);
|
||||
mtx_destroy(&dev->dev_lock);
|
||||
mtx_destroy(&dev->event_lock);
|
||||
sx_destroy(&dev->dev_struct_lock);
|
||||
}
|
||||
|
||||
int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_version *version = data;
|
||||
int len;
|
||||
|
||||
#define DRM_COPY( name, value ) \
|
||||
len = strlen( value ); \
|
||||
if ( len > name##_len ) len = name##_len; \
|
||||
name##_len = strlen( value ); \
|
||||
if ( len && name ) { \
|
||||
if ( DRM_COPY_TO_USER( name, value, len ) ) \
|
||||
return EFAULT; \
|
||||
}
|
||||
|
||||
version->version_major = dev->driver->major;
|
||||
version->version_minor = dev->driver->minor;
|
||||
version->version_patchlevel = dev->driver->patchlevel;
|
||||
|
||||
DRM_COPY(version->name, dev->driver->name);
|
||||
DRM_COPY(version->date, dev->driver->date);
|
||||
DRM_COPY(version->desc, dev->driver->desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
int retcode;
|
||||
|
||||
dev = kdev->si_drv1;
|
||||
if (dev == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
DRM_DEBUG("open_count = %d\n", dev->open_count);
|
||||
|
||||
retcode = drm_open_helper(kdev, flags, fmt, p, dev);
|
||||
|
||||
if (retcode == 0) {
|
||||
atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
|
||||
DRM_LOCK(dev);
|
||||
mtx_lock(&Giant);
|
||||
device_busy(dev->device);
|
||||
mtx_unlock(&Giant);
|
||||
if (!dev->open_count++)
|
||||
retcode = drm_firstopen(dev);
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
|
||||
return (retcode);
|
||||
}
|
||||
|
||||
void drm_close(void *data)
|
||||
{
|
||||
struct drm_file *file_priv = data;
|
||||
struct drm_device *dev = file_priv->dev;
|
||||
int retcode = 0;
|
||||
|
||||
DRM_DEBUG("open_count = %d\n", dev->open_count);
|
||||
|
||||
DRM_LOCK(dev);
|
||||
|
||||
if (dev->driver->preclose != NULL)
|
||||
dev->driver->preclose(dev, file_priv);
|
||||
|
||||
/* ========================================================
|
||||
* Begin inline drm_release
|
||||
*/
|
||||
|
||||
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
|
||||
DRM_CURRENTPID, (long)dev->device, dev->open_count);
|
||||
|
||||
if (dev->driver->driver_features & DRIVER_GEM)
|
||||
drm_gem_release(dev, file_priv);
|
||||
|
||||
if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
|
||||
&& dev->lock.file_priv == file_priv) {
|
||||
DRM_DEBUG("Process %d dead, freeing lock for context %d\n",
|
||||
DRM_CURRENTPID,
|
||||
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
|
||||
if (dev->driver->reclaim_buffers_locked != NULL)
|
||||
dev->driver->reclaim_buffers_locked(dev, file_priv);
|
||||
|
||||
drm_lock_free(&dev->lock,
|
||||
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
|
||||
|
||||
/* FIXME: may require heavy-handed reset of
|
||||
hardware at this point, possibly
|
||||
processed via a callback to the X
|
||||
server. */
|
||||
} else if (dev->driver->reclaim_buffers_locked != NULL &&
|
||||
dev->lock.hw_lock != NULL) {
|
||||
/* The lock is required to reclaim buffers */
|
||||
for (;;) {
|
||||
if (!dev->lock.hw_lock) {
|
||||
/* Device has been unregistered */
|
||||
retcode = EINTR;
|
||||
break;
|
||||
}
|
||||
if (drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT)) {
|
||||
dev->lock.file_priv = file_priv;
|
||||
dev->lock.lock_time = jiffies;
|
||||
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
|
||||
break; /* Got lock */
|
||||
}
|
||||
/* Contention */
|
||||
retcode = DRM_LOCK_SLEEP(dev, &dev->lock.lock_queue,
|
||||
PCATCH, "drmlk2", 0);
|
||||
if (retcode)
|
||||
break;
|
||||
}
|
||||
if (retcode == 0) {
|
||||
dev->driver->reclaim_buffers_locked(dev, file_priv);
|
||||
drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT);
|
||||
}
|
||||
}
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
|
||||
!dev->driver->reclaim_buffers_locked)
|
||||
drm_reclaim_buffers(dev, file_priv);
|
||||
|
||||
funsetown(&dev->buf_sigio);
|
||||
seldrain(&file_priv->event_poll);
|
||||
|
||||
if (dev->driver->postclose != NULL)
|
||||
dev->driver->postclose(dev, file_priv);
|
||||
TAILQ_REMOVE(&dev->files, file_priv, link);
|
||||
free(file_priv, DRM_MEM_FILES);
|
||||
|
||||
/* ========================================================
|
||||
* End inline drm_release
|
||||
*/
|
||||
|
||||
atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
|
||||
mtx_lock(&Giant);
|
||||
device_unbusy(dev->device);
|
||||
mtx_unlock(&Giant);
|
||||
if (--dev->open_count == 0) {
|
||||
retcode = drm_lastclose(dev);
|
||||
}
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
|
||||
/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm.
|
||||
*/
|
||||
int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags,
|
||||
DRM_STRUCTPROC *p)
|
||||
{
|
||||
struct drm_device *dev = drm_get_device_from_kdev(kdev);
|
||||
int retcode = 0;
|
||||
drm_ioctl_desc_t *ioctl;
|
||||
int (*func)(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
int nr = DRM_IOCTL_NR(cmd);
|
||||
int is_driver_ioctl = 0;
|
||||
struct drm_file *file_priv;
|
||||
|
||||
retcode = devfs_get_cdevpriv((void **)&file_priv);
|
||||
if (retcode != 0) {
|
||||
DRM_ERROR("can't find authenticator\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
|
||||
++file_priv->ioctl_count;
|
||||
|
||||
DRM_DEBUG("pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n",
|
||||
DRM_CURRENTPID, cmd, nr, (long)dev->device,
|
||||
file_priv->authenticated);
|
||||
|
||||
switch (cmd) {
|
||||
case FIONBIO:
|
||||
case FIOASYNC:
|
||||
return 0;
|
||||
|
||||
case FIOSETOWN:
|
||||
return fsetown(*(int *)data, &dev->buf_sigio);
|
||||
|
||||
case FIOGETOWN:
|
||||
*(int *) data = fgetown(&dev->buf_sigio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IOCGROUP(cmd) != DRM_IOCTL_BASE) {
|
||||
DRM_DEBUG("Bad ioctl group 0x%x\n", (int)IOCGROUP(cmd));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ioctl = &drm_ioctls[nr];
|
||||
/* It's not a core DRM ioctl, try driver-specific. */
|
||||
if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) {
|
||||
/* The array entries begin at DRM_COMMAND_BASE ioctl nr */
|
||||
nr -= DRM_COMMAND_BASE;
|
||||
if (nr > dev->driver->max_ioctl) {
|
||||
DRM_DEBUG("Bad driver ioctl number, 0x%x (of 0x%x)\n",
|
||||
nr, dev->driver->max_ioctl);
|
||||
return EINVAL;
|
||||
}
|
||||
ioctl = &dev->driver->ioctls[nr];
|
||||
is_driver_ioctl = 1;
|
||||
}
|
||||
func = ioctl->func;
|
||||
|
||||
if (func == NULL) {
|
||||
DRM_DEBUG("no function\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(p)) ||
|
||||
((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
|
||||
((ioctl->flags & DRM_MASTER) && !file_priv->master))
|
||||
return EACCES;
|
||||
|
||||
if (is_driver_ioctl) {
|
||||
if ((ioctl->flags & DRM_UNLOCKED) == 0)
|
||||
DRM_LOCK(dev);
|
||||
/* shared code returns -errno */
|
||||
retcode = -func(dev, data, file_priv);
|
||||
if ((ioctl->flags & DRM_UNLOCKED) == 0)
|
||||
DRM_UNLOCK(dev);
|
||||
} else {
|
||||
retcode = func(dev, data, file_priv);
|
||||
}
|
||||
|
||||
if (retcode != 0)
|
||||
DRM_DEBUG(" returning %d\n", retcode);
|
||||
if (retcode != 0 &&
|
||||
(drm_debug_flag & DRM_DEBUGBITS_FAILED_IOCTL) != 0) {
|
||||
printf(
|
||||
"pid %d, cmd 0x%02lx, nr 0x%02x/%1d, dev 0x%lx, auth %d, res %d\n",
|
||||
DRM_CURRENTPID, cmd, nr, is_driver_ioctl, (long)dev->device,
|
||||
file_priv->authenticated, retcode);
|
||||
}
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
drm_local_map_t *drm_getsarea(struct drm_device *dev)
|
||||
{
|
||||
drm_local_map_t *map;
|
||||
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
TAILQ_FOREACH(map, &dev->maplist, link) {
|
||||
if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK))
|
||||
return map;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
drm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx,
|
||||
struct sysctl_oid *top)
|
||||
{
|
||||
struct sysctl_oid *oid;
|
||||
|
||||
snprintf(dev->busid_str, sizeof(dev->busid_str),
|
||||
"pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus,
|
||||
dev->pci_slot, dev->pci_func);
|
||||
oid = SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "busid",
|
||||
CTLFLAG_RD, dev->busid_str, 0, NULL);
|
||||
if (oid == NULL)
|
||||
return (ENOMEM);
|
||||
dev->modesetting = (dev->driver->driver_features & DRIVER_MODESET) != 0;
|
||||
oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO,
|
||||
"modesetting", CTLFLAG_RD, &dev->modesetting, 0, NULL);
|
||||
if (oid == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if DRM_LINUX
|
||||
|
||||
#include <sys/sysproto.h>
|
||||
|
||||
MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1);
|
||||
|
||||
#define LINUX_IOCTL_DRM_MIN 0x6400
|
||||
#define LINUX_IOCTL_DRM_MAX 0x64ff
|
||||
|
||||
static linux_ioctl_function_t drm_linux_ioctl;
|
||||
static struct linux_ioctl_handler drm_handler = {drm_linux_ioctl,
|
||||
LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX};
|
||||
|
||||
SYSINIT(drm_register, SI_SUB_KLD, SI_ORDER_MIDDLE,
|
||||
linux_ioctl_register_handler, &drm_handler);
|
||||
SYSUNINIT(drm_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
|
||||
linux_ioctl_unregister_handler, &drm_handler);
|
||||
|
||||
/* The bits for in/out are switched on Linux */
|
||||
#define LINUX_IOC_IN IOC_OUT
|
||||
#define LINUX_IOC_OUT IOC_IN
|
||||
|
||||
static int
|
||||
drm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args)
|
||||
{
|
||||
int error;
|
||||
int cmd = args->cmd;
|
||||
|
||||
args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT);
|
||||
if (cmd & LINUX_IOC_IN)
|
||||
args->cmd |= IOC_IN;
|
||||
if (cmd & LINUX_IOC_OUT)
|
||||
args->cmd |= IOC_OUT;
|
||||
|
||||
error = ioctl(p, (struct ioctl_args *)args);
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif /* DRM_LINUX */
|
||||
|
||||
bool
|
||||
dmi_check_system(const struct dmi_system_id *sysid)
|
||||
{
|
||||
|
||||
/* XXXKIB */
|
||||
return (false);
|
||||
}
|
||||
|
||||
1781
sys/dev/drm2/drm_edid.c
Normal file
1781
sys/dev/drm2/drm_edid.c
Normal file
File diff suppressed because it is too large
Load diff
244
sys/dev/drm2/drm_edid.h
Normal file
244
sys/dev/drm2/drm_edid.h
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Copyright © 2007-2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef __DRM_EDID_H__
|
||||
#define __DRM_EDID_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
#define EDID_LENGTH 128
|
||||
#define DDC_ADDR 0x50
|
||||
|
||||
#define CEA_EXT 0x02
|
||||
#define VTB_EXT 0x10
|
||||
#define DI_EXT 0x40
|
||||
#define LS_EXT 0x50
|
||||
#define MI_EXT 0x60
|
||||
|
||||
struct est_timings {
|
||||
u8 t1;
|
||||
u8 t2;
|
||||
u8 mfg_rsvd;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
|
||||
#define EDID_TIMING_ASPECT_SHIFT 6
|
||||
#define EDID_TIMING_ASPECT_MASK (0x3 << EDID_TIMING_ASPECT_SHIFT)
|
||||
|
||||
/* need to add 60 */
|
||||
#define EDID_TIMING_VFREQ_SHIFT 0
|
||||
#define EDID_TIMING_VFREQ_MASK (0x3f << EDID_TIMING_VFREQ_SHIFT)
|
||||
|
||||
struct std_timing {
|
||||
u8 hsize; /* need to multiply by 8 then add 248 */
|
||||
u8 vfreq_aspect;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1)
|
||||
#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2)
|
||||
#define DRM_EDID_PT_SEPARATE_SYNC (3 << 3)
|
||||
#define DRM_EDID_PT_STEREO (1 << 5)
|
||||
#define DRM_EDID_PT_INTERLACED (1 << 7)
|
||||
|
||||
/* If detailed data is pixel timing */
|
||||
struct detailed_pixel_timing {
|
||||
u8 hactive_lo;
|
||||
u8 hblank_lo;
|
||||
u8 hactive_hblank_hi;
|
||||
u8 vactive_lo;
|
||||
u8 vblank_lo;
|
||||
u8 vactive_vblank_hi;
|
||||
u8 hsync_offset_lo;
|
||||
u8 hsync_pulse_width_lo;
|
||||
u8 vsync_offset_pulse_width_lo;
|
||||
u8 hsync_vsync_offset_pulse_width_hi;
|
||||
u8 width_mm_lo;
|
||||
u8 height_mm_lo;
|
||||
u8 width_height_mm_hi;
|
||||
u8 hborder;
|
||||
u8 vborder;
|
||||
u8 misc;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* If it's not pixel timing, it'll be one of the below */
|
||||
struct detailed_data_string {
|
||||
u8 str[13];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct detailed_data_monitor_range {
|
||||
u8 min_vfreq;
|
||||
u8 max_vfreq;
|
||||
u8 min_hfreq_khz;
|
||||
u8 max_hfreq_khz;
|
||||
u8 pixel_clock_mhz; /* need to multiply by 10 */
|
||||
u16 sec_gtf_toggle; /* A000=use above, 20=use below */
|
||||
u8 hfreq_start_khz; /* need to multiply by 2 */
|
||||
u8 c; /* need to divide by 2 */
|
||||
u16 m;
|
||||
u8 k;
|
||||
u8 j; /* need to divide by 2 */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct detailed_data_wpindex {
|
||||
u8 white_yx_lo; /* Lower 2 bits each */
|
||||
u8 white_x_hi;
|
||||
u8 white_y_hi;
|
||||
u8 gamma; /* need to divide by 100 then add 1 */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct detailed_data_color_point {
|
||||
u8 windex1;
|
||||
u8 wpindex1[3];
|
||||
u8 windex2;
|
||||
u8 wpindex2[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cvt_timing {
|
||||
u8 code[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct detailed_non_pixel {
|
||||
u8 pad1;
|
||||
u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name
|
||||
fb=color point data, fa=standard timing data,
|
||||
f9=undefined, f8=mfg. reserved */
|
||||
u8 pad2;
|
||||
union {
|
||||
struct detailed_data_string str;
|
||||
struct detailed_data_monitor_range range;
|
||||
struct detailed_data_wpindex color;
|
||||
struct std_timing timings[6];
|
||||
struct cvt_timing cvt[4];
|
||||
} data;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define EDID_DETAIL_EST_TIMINGS 0xf7
|
||||
#define EDID_DETAIL_CVT_3BYTE 0xf8
|
||||
#define EDID_DETAIL_COLOR_MGMT_DATA 0xf9
|
||||
#define EDID_DETAIL_STD_MODES 0xfa
|
||||
#define EDID_DETAIL_MONITOR_CPDATA 0xfb
|
||||
#define EDID_DETAIL_MONITOR_NAME 0xfc
|
||||
#define EDID_DETAIL_MONITOR_RANGE 0xfd
|
||||
#define EDID_DETAIL_MONITOR_STRING 0xfe
|
||||
#define EDID_DETAIL_MONITOR_SERIAL 0xff
|
||||
|
||||
struct detailed_timing {
|
||||
u16 pixel_clock; /* need to multiply by 10 KHz */
|
||||
union {
|
||||
struct detailed_pixel_timing pixel_data;
|
||||
struct detailed_non_pixel other_data;
|
||||
} data;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 0)
|
||||
#define DRM_EDID_INPUT_SYNC_ON_GREEN (1 << 1)
|
||||
#define DRM_EDID_INPUT_COMPOSITE_SYNC (1 << 2)
|
||||
#define DRM_EDID_INPUT_SEPARATE_SYNCS (1 << 3)
|
||||
#define DRM_EDID_INPUT_BLANK_TO_BLACK (1 << 4)
|
||||
#define DRM_EDID_INPUT_VIDEO_LEVEL (3 << 5)
|
||||
#define DRM_EDID_INPUT_DIGITAL (1 << 7)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_MASK (7 << 4)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_UNDEF (0 << 4)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_6 (1 << 4)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_8 (2 << 4)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_10 (3 << 4)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_12 (4 << 4)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_14 (5 << 4)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_16 (6 << 4)
|
||||
#define DRM_EDID_DIGITAL_DEPTH_RSVD (7 << 4)
|
||||
#define DRM_EDID_DIGITAL_TYPE_UNDEF (0)
|
||||
#define DRM_EDID_DIGITAL_TYPE_DVI (1)
|
||||
#define DRM_EDID_DIGITAL_TYPE_HDMI_A (2)
|
||||
#define DRM_EDID_DIGITAL_TYPE_HDMI_B (3)
|
||||
#define DRM_EDID_DIGITAL_TYPE_MDDI (4)
|
||||
#define DRM_EDID_DIGITAL_TYPE_DP (5)
|
||||
|
||||
#define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0)
|
||||
#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1)
|
||||
#define DRM_EDID_FEATURE_STANDARD_COLOR (1 << 2)
|
||||
#define DRM_EDID_FEATURE_DISPLAY_TYPE (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
|
||||
/* If digital */
|
||||
#define DRM_EDID_FEATURE_COLOR_MASK (3 << 3)
|
||||
#define DRM_EDID_FEATURE_RGB (0 << 3)
|
||||
#define DRM_EDID_FEATURE_RGB_YCRCB444 (1 << 3)
|
||||
#define DRM_EDID_FEATURE_RGB_YCRCB422 (2 << 3)
|
||||
#define DRM_EDID_FEATURE_RGB_YCRCB (3 << 3) /* both 4:4:4 and 4:2:2 */
|
||||
|
||||
#define DRM_EDID_FEATURE_PM_ACTIVE_OFF (1 << 5)
|
||||
#define DRM_EDID_FEATURE_PM_SUSPEND (1 << 6)
|
||||
#define DRM_EDID_FEATURE_PM_STANDBY (1 << 7)
|
||||
|
||||
struct edid {
|
||||
u8 header[8];
|
||||
/* Vendor & product info */
|
||||
u8 mfg_id[2];
|
||||
u8 prod_code[2];
|
||||
u32 serial; /* FIXME: byte order */
|
||||
u8 mfg_week;
|
||||
u8 mfg_year;
|
||||
/* EDID version */
|
||||
u8 version;
|
||||
u8 revision;
|
||||
/* Display info: */
|
||||
u8 input;
|
||||
u8 width_cm;
|
||||
u8 height_cm;
|
||||
u8 gamma;
|
||||
u8 features;
|
||||
/* Color characteristics */
|
||||
u8 red_green_lo;
|
||||
u8 black_white_lo;
|
||||
u8 red_x;
|
||||
u8 red_y;
|
||||
u8 green_x;
|
||||
u8 green_y;
|
||||
u8 blue_x;
|
||||
u8 blue_y;
|
||||
u8 white_x;
|
||||
u8 white_y;
|
||||
/* Est. timings and mfg rsvd timings*/
|
||||
struct est_timings established_timings;
|
||||
/* Standard timings 1-8*/
|
||||
struct std_timing standard_timings[8];
|
||||
/* Detailing timings 1-4 */
|
||||
struct detailed_timing detailed_timings[4];
|
||||
/* Number of 128 byte ext. blocks */
|
||||
u8 extensions;
|
||||
/* Checksum */
|
||||
u8 checksum;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
|
||||
|
||||
struct drm_encoder;
|
||||
struct drm_connector;
|
||||
struct drm_display_mode;
|
||||
void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid);
|
||||
int drm_av_sync_delay(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode);
|
||||
struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode);
|
||||
|
||||
#endif /* __DRM_EDID_H__ */
|
||||
381
sys/dev/drm2/drm_edid_modes.h
Normal file
381
sys/dev/drm2/drm_edid_modes.h
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Copyright (c) 2007-2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
* Copyright 2010 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
|
||||
/*
|
||||
* Autogenerated from the DMT spec.
|
||||
* This table is copied from xfree86/modes/xf86EdidModes.c.
|
||||
* But the mode with Reduced blank feature is deleted.
|
||||
*/
|
||||
static struct drm_display_mode drm_dmt_modes[] = {
|
||||
/* 640x350@85Hz */
|
||||
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
|
||||
736, 832, 0, 350, 382, 385, 445, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x400@85Hz */
|
||||
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
|
||||
736, 832, 0, 400, 401, 404, 445, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 720x400@85Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
|
||||
828, 936, 0, 400, 401, 404, 446, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 640x480@60Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
752, 800, 0, 480, 489, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@72Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
|
||||
704, 832, 0, 480, 489, 492, 520, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@75Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
|
||||
720, 840, 0, 480, 481, 484, 500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 640x480@85Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
|
||||
752, 832, 0, 480, 481, 484, 509, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 800x600@56Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
|
||||
896, 1024, 0, 600, 601, 603, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@60Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@72Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
|
||||
976, 1040, 0, 600, 637, 643, 666, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
|
||||
896, 1056, 0, 600, 601, 604, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 800x600@85Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
|
||||
896, 1048, 0, 600, 601, 604, 631, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 848x480@60Hz */
|
||||
{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
|
||||
976, 1088, 0, 480, 486, 494, 517, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@43Hz, interlace */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
|
||||
1208, 1264, 0, 768, 768, 772, 817, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
|
||||
DRM_MODE_FLAG_INTERLACE) },
|
||||
/* 1024x768@60Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
|
||||
1184, 1344, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1024x768@70Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
|
||||
1184, 1328, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1024x768@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
|
||||
1136, 1312, 0, 768, 769, 772, 800, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1024x768@85Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
|
||||
1168, 1376, 0, 768, 769, 772, 808, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1152x864@75Hz */
|
||||
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
|
||||
1344, 1600, 0, 864, 865, 868, 900, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@60Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
|
||||
1472, 1664, 0, 768, 771, 778, 798, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x768@75Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
|
||||
1488, 1696, 0, 768, 771, 778, 805, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x768@85Hz */
|
||||
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
|
||||
1496, 1712, 0, 768, 771, 778, 809, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x800@60Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
|
||||
1480, 1680, 0, 800, 803, 809, 831, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
/* 1280x800@75Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
|
||||
1488, 1696, 0, 800, 803, 809, 838, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x800@85Hz */
|
||||
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
|
||||
1496, 1712, 0, 800, 803, 809, 843, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x960@60Hz */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
|
||||
1488, 1800, 0, 960, 961, 964, 1000, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x960@85Hz */
|
||||
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
|
||||
1504, 1728, 0, 960, 961, 964, 1011, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@60Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@75Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1280x1024@85Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
|
||||
1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1360x768@60Hz */
|
||||
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
|
||||
1536, 1792, 0, 768, 771, 777, 795, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x1050@60Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
|
||||
1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x1050@75Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
|
||||
1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x1050@85Hz */
|
||||
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
|
||||
1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@60Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
|
||||
1672, 1904, 0, 900, 903, 909, 934, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@75Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
|
||||
1688, 1936, 0, 900, 903, 909, 942, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1440x900@85Hz */
|
||||
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
|
||||
1696, 1952, 0, 900, 903, 909, 948, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@60Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@65Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@70Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@75Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1600x1200@85Hz */
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
|
||||
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@60Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
|
||||
1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@75Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
|
||||
1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1680x1050@85Hz */
|
||||
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
|
||||
1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1792x1344@60Hz */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
|
||||
2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1729x1344@75Hz */
|
||||
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
|
||||
2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1853x1392@60Hz */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
|
||||
2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1856x1392@75Hz */
|
||||
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
|
||||
2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@60Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
|
||||
2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@75Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
|
||||
2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1200@85Hz */
|
||||
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
|
||||
2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1440@60Hz */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
|
||||
2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 1920x1440@75Hz */
|
||||
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
|
||||
2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@60Hz */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
|
||||
3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@75HZ */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
|
||||
3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
/* 2560x1600@85HZ */
|
||||
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
|
||||
3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
};
|
||||
static const int drm_num_dmt_modes =
|
||||
sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
|
||||
|
||||
static struct drm_display_mode edid_est_modes[] = {
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
|
||||
896, 1024, 0, 600, 601, 603, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
|
||||
720, 840, 0, 480, 481, 484, 500, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
|
||||
704, 832, 0, 480, 489, 491, 520, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
|
||||
768, 864, 0, 480, 483, 486, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
|
||||
752, 800, 0, 480, 490, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
|
||||
846, 900, 0, 400, 421, 423, 449, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
|
||||
846, 900, 0, 400, 412, 414, 449, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
|
||||
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
|
||||
1136, 1312, 0, 768, 769, 772, 800, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
|
||||
1184, 1328, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
|
||||
1184, 1344, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
|
||||
1208, 1264, 0, 768, 768, 776, 817, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
|
||||
{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
|
||||
928, 1152, 0, 624, 625, 628, 667, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
|
||||
896, 1056, 0, 600, 601, 604, 625, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
|
||||
976, 1040, 0, 600, 637, 643, 666, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
|
||||
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
|
||||
1344, 1600, 0, 864, 865, 868, 900, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
|
||||
};
|
||||
|
||||
static const struct {
|
||||
short w;
|
||||
short h;
|
||||
short r;
|
||||
short rb;
|
||||
} est3_modes[] = {
|
||||
/* byte 6 */
|
||||
{ 640, 350, 85, 0 },
|
||||
{ 640, 400, 85, 0 },
|
||||
{ 720, 400, 85, 0 },
|
||||
{ 640, 480, 85, 0 },
|
||||
{ 848, 480, 60, 0 },
|
||||
{ 800, 600, 85, 0 },
|
||||
{ 1024, 768, 85, 0 },
|
||||
{ 1152, 864, 75, 0 },
|
||||
/* byte 7 */
|
||||
{ 1280, 768, 60, 1 },
|
||||
{ 1280, 768, 60, 0 },
|
||||
{ 1280, 768, 75, 0 },
|
||||
{ 1280, 768, 85, 0 },
|
||||
{ 1280, 960, 60, 0 },
|
||||
{ 1280, 960, 85, 0 },
|
||||
{ 1280, 1024, 60, 0 },
|
||||
{ 1280, 1024, 85, 0 },
|
||||
/* byte 8 */
|
||||
{ 1360, 768, 60, 0 },
|
||||
{ 1440, 900, 60, 1 },
|
||||
{ 1440, 900, 60, 0 },
|
||||
{ 1440, 900, 75, 0 },
|
||||
{ 1440, 900, 85, 0 },
|
||||
{ 1400, 1050, 60, 1 },
|
||||
{ 1400, 1050, 60, 0 },
|
||||
{ 1400, 1050, 75, 0 },
|
||||
/* byte 9 */
|
||||
{ 1400, 1050, 85, 0 },
|
||||
{ 1680, 1050, 60, 1 },
|
||||
{ 1680, 1050, 60, 0 },
|
||||
{ 1680, 1050, 75, 0 },
|
||||
{ 1680, 1050, 85, 0 },
|
||||
{ 1600, 1200, 60, 0 },
|
||||
{ 1600, 1200, 65, 0 },
|
||||
{ 1600, 1200, 70, 0 },
|
||||
/* byte 10 */
|
||||
{ 1600, 1200, 75, 0 },
|
||||
{ 1600, 1200, 85, 0 },
|
||||
{ 1792, 1344, 60, 0 },
|
||||
{ 1792, 1344, 85, 0 },
|
||||
{ 1856, 1392, 60, 0 },
|
||||
{ 1856, 1392, 75, 0 },
|
||||
{ 1920, 1200, 60, 1 },
|
||||
{ 1920, 1200, 60, 0 },
|
||||
/* byte 11 */
|
||||
{ 1920, 1200, 75, 0 },
|
||||
{ 1920, 1200, 85, 0 },
|
||||
{ 1920, 1440, 60, 0 },
|
||||
{ 1920, 1440, 75, 0 },
|
||||
};
|
||||
static const int num_est3_modes = sizeof(est3_modes) / sizeof(est3_modes[0]);
|
||||
1568
sys/dev/drm2/drm_fb_helper.c
Normal file
1568
sys/dev/drm2/drm_fb_helper.c
Normal file
File diff suppressed because it is too large
Load diff
141
sys/dev/drm2/drm_fb_helper.h
Normal file
141
sys/dev/drm2/drm_fb_helper.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2009 Red Hat Inc.
|
||||
* Copyright (c) 2006-2008 Intel Corporation
|
||||
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
||||
*
|
||||
* DRM framebuffer helper functions
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Dave Airlie <airlied@linux.ie>
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef DRM_FB_HELPER_H
|
||||
#define DRM_FB_HELPER_H
|
||||
|
||||
struct drm_fb_helper;
|
||||
|
||||
struct drm_fb_helper_crtc {
|
||||
uint32_t crtc_id;
|
||||
struct drm_mode_set mode_set;
|
||||
struct drm_display_mode *desired_mode;
|
||||
};
|
||||
|
||||
/* mode specified on the command line */
|
||||
struct drm_fb_helper_cmdline_mode {
|
||||
bool specified;
|
||||
bool refresh_specified;
|
||||
bool bpp_specified;
|
||||
int xres, yres;
|
||||
int bpp;
|
||||
int refresh;
|
||||
bool rb;
|
||||
bool interlace;
|
||||
bool cvt;
|
||||
bool margins;
|
||||
};
|
||||
|
||||
struct drm_fb_helper_surface_size {
|
||||
u32 fb_width;
|
||||
u32 fb_height;
|
||||
u32 surface_width;
|
||||
u32 surface_height;
|
||||
u32 surface_bpp;
|
||||
u32 surface_depth;
|
||||
};
|
||||
|
||||
struct drm_fb_helper_funcs {
|
||||
void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
|
||||
u16 blue, int regno);
|
||||
void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
|
||||
u16 *blue, int regno);
|
||||
|
||||
int (*fb_probe)(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes);
|
||||
};
|
||||
|
||||
struct drm_fb_helper_connector {
|
||||
struct drm_fb_helper_cmdline_mode cmdline_mode;
|
||||
struct drm_cmdline_mode cmdline_mode1;
|
||||
struct drm_connector *connector;
|
||||
};
|
||||
|
||||
struct drm_fb_helper {
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_framebuffer *saved_fb;
|
||||
struct drm_device *dev;
|
||||
struct drm_display_mode *mode;
|
||||
int crtc_count;
|
||||
struct drm_fb_helper_crtc *crtc_info;
|
||||
int connector_count;
|
||||
struct drm_fb_helper_connector **connector_info;
|
||||
struct drm_fb_helper_funcs *funcs;
|
||||
int conn_limit;
|
||||
struct fb_info *fbdev;
|
||||
u32 pseudo_palette[17];
|
||||
struct list_head kernel_fb_list;
|
||||
|
||||
/* we got a hotplug but fbdev wasn't running the console
|
||||
delay until next set_par */
|
||||
bool delayed_hotplug;
|
||||
};
|
||||
|
||||
struct fb_var_screeninfo;
|
||||
struct fb_cmap;
|
||||
|
||||
int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
|
||||
int preferred_bpp);
|
||||
|
||||
int drm_fb_helper_init(struct drm_device *dev,
|
||||
struct drm_fb_helper *helper, int crtc_count,
|
||||
int max_conn);
|
||||
void drm_fb_helper_fini(struct drm_fb_helper *helper);
|
||||
int drm_fb_helper_blank(int blank, struct fb_info *info);
|
||||
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info);
|
||||
int drm_fb_helper_set_par(struct fb_info *info);
|
||||
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info);
|
||||
int drm_fb_helper_setcolreg(unsigned regno,
|
||||
unsigned red,
|
||||
unsigned green,
|
||||
unsigned blue,
|
||||
unsigned transp,
|
||||
struct fb_info *info);
|
||||
|
||||
bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper);
|
||||
void drm_fb_helper_restore(void);
|
||||
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
|
||||
uint32_t fb_width, uint32_t fb_height);
|
||||
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
|
||||
uint32_t depth);
|
||||
|
||||
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
|
||||
|
||||
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
|
||||
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
|
||||
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
|
||||
int drm_fb_helper_debug_enter(struct fb_info *info);
|
||||
int drm_fb_helper_debug_leave(struct fb_info *info);
|
||||
bool drm_fb_helper_force_kernel_mode(void);
|
||||
|
||||
#endif
|
||||
202
sys/dev/drm2/drm_fops.c
Normal file
202
sys/dev/drm2/drm_fops.c
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*-
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Daryll Strauss <daryll@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_fops.c
|
||||
* Support code for dealing with the file privates associated with each
|
||||
* open of the DRM device.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
/* drm_open_helper is called whenever a process opens /dev/drm. */
|
||||
int drm_open_helper(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p,
|
||||
struct drm_device *dev)
|
||||
{
|
||||
struct drm_file *priv;
|
||||
int retcode;
|
||||
|
||||
if (flags & O_EXCL)
|
||||
return EBUSY; /* No exclusive opens */
|
||||
dev->flags = flags;
|
||||
|
||||
DRM_DEBUG("pid = %d, device = %s\n", DRM_CURRENTPID, devtoname(kdev));
|
||||
|
||||
priv = malloc(sizeof(*priv), DRM_MEM_FILES, M_NOWAIT | M_ZERO);
|
||||
if (priv == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
retcode = devfs_set_cdevpriv(priv, drm_close);
|
||||
if (retcode != 0) {
|
||||
free(priv, DRM_MEM_FILES);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
DRM_LOCK(dev);
|
||||
priv->dev = dev;
|
||||
priv->uid = p->td_ucred->cr_svuid;
|
||||
priv->pid = p->td_proc->p_pid;
|
||||
priv->ioctl_count = 0;
|
||||
|
||||
/* for compatibility root is always authenticated */
|
||||
priv->authenticated = DRM_SUSER(p);
|
||||
|
||||
INIT_LIST_HEAD(&priv->fbs);
|
||||
INIT_LIST_HEAD(&priv->event_list);
|
||||
priv->event_space = 4096; /* set aside 4k for event buffer */
|
||||
|
||||
if (dev->driver->driver_features & DRIVER_GEM)
|
||||
drm_gem_open(dev, priv);
|
||||
|
||||
if (dev->driver->open) {
|
||||
/* shared code returns -errno */
|
||||
retcode = -dev->driver->open(dev, priv);
|
||||
if (retcode != 0) {
|
||||
devfs_clear_cdevpriv();
|
||||
free(priv, DRM_MEM_FILES);
|
||||
DRM_UNLOCK(dev);
|
||||
return retcode;
|
||||
}
|
||||
}
|
||||
|
||||
/* first opener automatically becomes master */
|
||||
priv->master = TAILQ_EMPTY(&dev->files);
|
||||
|
||||
TAILQ_INSERT_TAIL(&dev->files, priv, link);
|
||||
DRM_UNLOCK(dev);
|
||||
kdev->si_drv1 = dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
drm_dequeue_event(struct drm_device *dev, struct drm_file *file_priv,
|
||||
struct uio *uio, struct drm_pending_event **out)
|
||||
{
|
||||
struct drm_pending_event *e;
|
||||
|
||||
if (list_empty(&file_priv->event_list))
|
||||
return (false);
|
||||
e = list_first_entry(&file_priv->event_list,
|
||||
struct drm_pending_event, link);
|
||||
if (e->event->length > uio->uio_resid)
|
||||
return (false);
|
||||
|
||||
file_priv->event_space += e->event->length;
|
||||
list_del(&e->link);
|
||||
*out = e;
|
||||
return (true);
|
||||
}
|
||||
|
||||
int
|
||||
drm_read(struct cdev *kdev, struct uio *uio, int ioflag)
|
||||
{
|
||||
struct drm_file *file_priv;
|
||||
struct drm_device *dev;
|
||||
struct drm_pending_event *e;
|
||||
int error;
|
||||
|
||||
error = devfs_get_cdevpriv((void **)&file_priv);
|
||||
if (error != 0) {
|
||||
DRM_ERROR("can't find authenticator\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
dev = drm_get_device_from_kdev(kdev);
|
||||
mtx_lock(&dev->event_lock);
|
||||
while (list_empty(&file_priv->event_list)) {
|
||||
if ((ioflag & O_NONBLOCK) != 0) {
|
||||
error = EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
error = msleep(&file_priv->event_space, &dev->event_lock,
|
||||
PCATCH, "drmrea", 0);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
}
|
||||
while (drm_dequeue_event(dev, file_priv, uio, &e)) {
|
||||
mtx_unlock(&dev->event_lock);
|
||||
error = uiomove(e->event, e->event->length, uio);
|
||||
CTR3(KTR_DRM, "drm_event_dequeued %d %d %d", curproc->p_pid,
|
||||
e->event->type, e->event->length);
|
||||
e->destroy(e);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
mtx_lock(&dev->event_lock);
|
||||
}
|
||||
out:
|
||||
mtx_unlock(&dev->event_lock);
|
||||
return (error);
|
||||
}
|
||||
|
||||
void
|
||||
drm_event_wakeup(struct drm_pending_event *e)
|
||||
{
|
||||
struct drm_file *file_priv;
|
||||
struct drm_device *dev;
|
||||
|
||||
file_priv = e->file_priv;
|
||||
dev = file_priv->dev;
|
||||
mtx_assert(&dev->event_lock, MA_OWNED);
|
||||
|
||||
wakeup(&file_priv->event_space);
|
||||
selwakeup(&file_priv->event_poll);
|
||||
}
|
||||
|
||||
int
|
||||
drm_poll(struct cdev *kdev, int events, struct thread *td)
|
||||
{
|
||||
struct drm_file *file_priv;
|
||||
struct drm_device *dev;
|
||||
int error, revents;
|
||||
|
||||
error = devfs_get_cdevpriv((void **)&file_priv);
|
||||
if (error != 0) {
|
||||
DRM_ERROR("can't find authenticator\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
dev = drm_get_device_from_kdev(kdev);
|
||||
|
||||
revents = 0;
|
||||
mtx_lock(&dev->event_lock);
|
||||
if ((events & (POLLIN | POLLRDNORM)) != 0) {
|
||||
if (list_empty(&file_priv->event_list)) {
|
||||
CTR0(KTR_DRM, "drm_poll empty list");
|
||||
selrecord(td, &file_priv->event_poll);
|
||||
} else {
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
CTR1(KTR_DRM, "drm_poll revents %x", revents);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&dev->event_lock);
|
||||
return (revents);
|
||||
}
|
||||
139
sys/dev/drm2/drm_fourcc.h
Normal file
139
sys/dev/drm2/drm_fourcc.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright 2011 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef DRM_FOURCC_H
|
||||
#define DRM_FOURCC_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
|
||||
((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
|
||||
|
||||
#define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */
|
||||
|
||||
/* color index */
|
||||
#define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */
|
||||
|
||||
/* 8 bpp RGB */
|
||||
#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
|
||||
#define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */
|
||||
|
||||
/* 16 bpp RGB */
|
||||
#define DRM_FORMAT_XRGB4444 fourcc_code('X', 'R', '1', '2') /* [15:0] x:R:G:B 4:4:4:4 little endian */
|
||||
#define DRM_FORMAT_XBGR4444 fourcc_code('X', 'B', '1', '2') /* [15:0] x:B:G:R 4:4:4:4 little endian */
|
||||
#define DRM_FORMAT_RGBX4444 fourcc_code('R', 'X', '1', '2') /* [15:0] R:G:B:x 4:4:4:4 little endian */
|
||||
#define DRM_FORMAT_BGRX4444 fourcc_code('B', 'X', '1', '2') /* [15:0] B:G:R:x 4:4:4:4 little endian */
|
||||
|
||||
#define DRM_FORMAT_ARGB4444 fourcc_code('A', 'R', '1', '2') /* [15:0] A:R:G:B 4:4:4:4 little endian */
|
||||
#define DRM_FORMAT_ABGR4444 fourcc_code('A', 'B', '1', '2') /* [15:0] A:B:G:R 4:4:4:4 little endian */
|
||||
#define DRM_FORMAT_RGBA4444 fourcc_code('R', 'A', '1', '2') /* [15:0] R:G:B:A 4:4:4:4 little endian */
|
||||
#define DRM_FORMAT_BGRA4444 fourcc_code('B', 'A', '1', '2') /* [15:0] B:G:R:A 4:4:4:4 little endian */
|
||||
|
||||
#define DRM_FORMAT_XRGB1555 fourcc_code('X', 'R', '1', '5') /* [15:0] x:R:G:B 1:5:5:5 little endian */
|
||||
#define DRM_FORMAT_XBGR1555 fourcc_code('X', 'B', '1', '5') /* [15:0] x:B:G:R 1:5:5:5 little endian */
|
||||
#define DRM_FORMAT_RGBX5551 fourcc_code('R', 'X', '1', '5') /* [15:0] R:G:B:x 5:5:5:1 little endian */
|
||||
#define DRM_FORMAT_BGRX5551 fourcc_code('B', 'X', '1', '5') /* [15:0] B:G:R:x 5:5:5:1 little endian */
|
||||
|
||||
#define DRM_FORMAT_ARGB1555 fourcc_code('A', 'R', '1', '5') /* [15:0] A:R:G:B 1:5:5:5 little endian */
|
||||
#define DRM_FORMAT_ABGR1555 fourcc_code('A', 'B', '1', '5') /* [15:0] A:B:G:R 1:5:5:5 little endian */
|
||||
#define DRM_FORMAT_RGBA5551 fourcc_code('R', 'A', '1', '5') /* [15:0] R:G:B:A 5:5:5:1 little endian */
|
||||
#define DRM_FORMAT_BGRA5551 fourcc_code('B', 'A', '1', '5') /* [15:0] B:G:R:A 5:5:5:1 little endian */
|
||||
|
||||
#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */
|
||||
#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') /* [15:0] B:G:R 5:6:5 little endian */
|
||||
|
||||
/* 24 bpp RGB */
|
||||
#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */
|
||||
#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */
|
||||
|
||||
/* 32 bpp RGB */
|
||||
#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_RGBX8888 fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_BGRX8888 fourcc_code('B', 'X', '2', '4') /* [31:0] B:G:R:x 8:8:8:8 little endian */
|
||||
|
||||
#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */
|
||||
|
||||
#define DRM_FORMAT_XRGB2101010 fourcc_code('X', 'R', '3', '0') /* [31:0] x:R:G:B 2:10:10:10 little endian */
|
||||
#define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0') /* [31:0] x:B:G:R 2:10:10:10 little endian */
|
||||
#define DRM_FORMAT_RGBX1010102 fourcc_code('R', 'X', '3', '0') /* [31:0] R:G:B:x 10:10:10:2 little endian */
|
||||
#define DRM_FORMAT_BGRX1010102 fourcc_code('B', 'X', '3', '0') /* [31:0] B:G:R:x 10:10:10:2 little endian */
|
||||
|
||||
#define DRM_FORMAT_ARGB2101010 fourcc_code('A', 'R', '3', '0') /* [31:0] A:R:G:B 2:10:10:10 little endian */
|
||||
#define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0') /* [31:0] A:B:G:R 2:10:10:10 little endian */
|
||||
#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */
|
||||
#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */
|
||||
|
||||
/* packed YCbCr */
|
||||
#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */
|
||||
#define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */
|
||||
|
||||
#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
|
||||
|
||||
/*
|
||||
* 2 plane YCbCr
|
||||
* index 0 = Y plane, [7:0] Y
|
||||
* index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
|
||||
* or
|
||||
* index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian
|
||||
*/
|
||||
#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */
|
||||
#define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */
|
||||
#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */
|
||||
#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
|
||||
|
||||
/* 2 non contiguous plane YCbCr */
|
||||
#define DRM_FORMAT_NV12M fourcc_code('N', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane */
|
||||
#define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */
|
||||
|
||||
/*
|
||||
* 3 plane YCbCr
|
||||
* index 0: Y plane, [7:0] Y
|
||||
* index 1: Cb plane, [7:0] Cb
|
||||
* index 2: Cr plane, [7:0] Cr
|
||||
* or
|
||||
* index 1: Cr plane, [7:0] Cr
|
||||
* index 2: Cb plane, [7:0] Cb
|
||||
*/
|
||||
#define DRM_FORMAT_YUV410 fourcc_code('Y', 'U', 'V', '9') /* 4x4 subsampled Cb (1) and Cr (2) planes */
|
||||
#define DRM_FORMAT_YVU410 fourcc_code('Y', 'V', 'U', '9') /* 4x4 subsampled Cr (1) and Cb (2) planes */
|
||||
#define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */
|
||||
#define DRM_FORMAT_YVU411 fourcc_code('Y', 'V', '1', '1') /* 4x1 subsampled Cr (1) and Cb (2) planes */
|
||||
#define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */
|
||||
#define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */
|
||||
#define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */
|
||||
#define DRM_FORMAT_YVU422 fourcc_code('Y', 'V', '1', '6') /* 2x1 subsampled Cr (1) and Cb (2) planes */
|
||||
#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
|
||||
#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
|
||||
|
||||
/* 3 non contiguous plane YCbCr */
|
||||
#define DRM_FORMAT_YUV420M fourcc_code('Y', 'M', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */
|
||||
|
||||
#endif /* DRM_FOURCC_H */
|
||||
487
sys/dev/drm2/drm_gem.c
Normal file
487
sys/dev/drm2/drm_gem.c
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
/*-
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Konstantin Belousov under sponsorship from
|
||||
* the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_vm.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_sarea.h>
|
||||
|
||||
/*
|
||||
* We make up offsets for buffer objects so we can recognize them at
|
||||
* mmap time.
|
||||
*/
|
||||
|
||||
/* pgoff in mmap is an unsigned long, so we need to make sure that
|
||||
* the faked up offset will fit
|
||||
*/
|
||||
|
||||
#if ULONG_MAX == UINT64_MAX
|
||||
#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
|
||||
#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
|
||||
#else
|
||||
#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1)
|
||||
#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16)
|
||||
#endif
|
||||
|
||||
int
|
||||
drm_gem_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_gem_mm *mm;
|
||||
|
||||
drm_gem_names_init(&dev->object_names);
|
||||
mm = malloc(sizeof(*mm), DRM_MEM_DRIVER, M_WAITOK);
|
||||
dev->mm_private = mm;
|
||||
if (drm_ht_create(&mm->offset_hash, 19) != 0) {
|
||||
free(mm, DRM_MEM_DRIVER);
|
||||
return (ENOMEM);
|
||||
}
|
||||
mm->idxunr = new_unrhdr(0, DRM_GEM_MAX_IDX, NULL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_destroy(struct drm_device *dev)
|
||||
{
|
||||
struct drm_gem_mm *mm;
|
||||
|
||||
mm = dev->mm_private;
|
||||
dev->mm_private = NULL;
|
||||
drm_ht_remove(&mm->offset_hash);
|
||||
delete_unrhdr(mm->idxunr);
|
||||
free(mm, DRM_MEM_DRIVER);
|
||||
drm_gem_names_fini(&dev->object_names);
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
|
||||
size_t size)
|
||||
{
|
||||
|
||||
KASSERT((size & (PAGE_SIZE - 1)) == 0,
|
||||
("Bad size %ju", (uintmax_t)size));
|
||||
|
||||
obj->dev = dev;
|
||||
obj->vm_obj = vm_pager_allocate(OBJT_DEFAULT, NULL, size,
|
||||
VM_PROT_READ | VM_PROT_WRITE, 0, curthread->td_ucred);
|
||||
|
||||
obj->refcount = 1;
|
||||
obj->handle_count = 0;
|
||||
obj->size = size;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_private_object_init(struct drm_device *dev, struct drm_gem_object *obj,
|
||||
size_t size)
|
||||
{
|
||||
|
||||
MPASS((size & (PAGE_SIZE - 1)) == 0);
|
||||
|
||||
obj->dev = dev;
|
||||
obj->vm_obj = NULL;
|
||||
|
||||
obj->refcount = 1;
|
||||
atomic_set(&obj->handle_count, 0);
|
||||
obj->size = size;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
struct drm_gem_object *
|
||||
drm_gem_object_alloc(struct drm_device *dev, size_t size)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = malloc(sizeof(*obj), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
|
||||
if (drm_gem_object_init(dev, obj, size) != 0)
|
||||
goto free;
|
||||
|
||||
if (dev->driver->gem_init_object != NULL &&
|
||||
dev->driver->gem_init_object(obj) != 0)
|
||||
goto dealloc;
|
||||
return (obj);
|
||||
dealloc:
|
||||
vm_object_deallocate(obj->vm_obj);
|
||||
free:
|
||||
free(obj, DRM_MEM_DRIVER);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_free(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
|
||||
dev = obj->dev;
|
||||
DRM_LOCK_ASSERT(dev);
|
||||
if (dev->driver->gem_free_object != NULL)
|
||||
dev->driver->gem_free_object(obj);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_reference(struct drm_gem_object *obj)
|
||||
{
|
||||
|
||||
KASSERT(obj->refcount > 0, ("Dandling obj %p", obj));
|
||||
refcount_acquire(&obj->refcount);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_unreference(struct drm_gem_object *obj)
|
||||
{
|
||||
|
||||
if (obj == NULL)
|
||||
return;
|
||||
if (refcount_release(&obj->refcount))
|
||||
drm_gem_object_free(obj);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
|
||||
if (obj == NULL)
|
||||
return;
|
||||
dev = obj->dev;
|
||||
DRM_LOCK(dev);
|
||||
drm_gem_object_unreference(obj);
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_handle_reference(struct drm_gem_object *obj)
|
||||
{
|
||||
|
||||
drm_gem_object_reference(obj);
|
||||
atomic_add_rel_int(&obj->handle_count, 1);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_handle_free(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_gem_object *obj1;
|
||||
|
||||
dev = obj->dev;
|
||||
if (obj->name != 0) {
|
||||
obj1 = drm_gem_names_remove(&dev->object_names, obj->name);
|
||||
obj->name = 0;
|
||||
drm_gem_object_unreference(obj1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_handle_unreference(struct drm_gem_object *obj)
|
||||
{
|
||||
|
||||
if (obj == NULL ||
|
||||
atomic_load_acq_int(&obj->handle_count) == 0)
|
||||
return;
|
||||
|
||||
if (atomic_fetchadd_int(&obj->handle_count, -1) == 1)
|
||||
drm_gem_object_handle_free(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
|
||||
{
|
||||
|
||||
if (obj == NULL ||
|
||||
atomic_load_acq_int(&obj->handle_count) == 0)
|
||||
return;
|
||||
|
||||
if (atomic_fetchadd_int(&obj->handle_count, -1) == 1)
|
||||
drm_gem_object_handle_free(obj);
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_handle_create(struct drm_file *file_priv, struct drm_gem_object *obj,
|
||||
uint32_t *handle)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = drm_gem_name_create(&file_priv->object_names, obj, handle);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
drm_gem_object_handle_reference(obj);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_handle_delete(struct drm_file *file_priv, uint32_t handle)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = drm_gem_names_remove(&file_priv->object_names, handle);
|
||||
if (obj == NULL)
|
||||
return (EINVAL);
|
||||
drm_gem_object_handle_unreference_unlocked(obj);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_object_release(struct drm_gem_object *obj)
|
||||
{
|
||||
|
||||
/*
|
||||
* obj->vm_obj can be NULL for private gem objects.
|
||||
*/
|
||||
vm_object_deallocate(obj->vm_obj);
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_open_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_gem_open *args;
|
||||
struct drm_gem_object *obj;
|
||||
int ret;
|
||||
uint32_t handle;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_GEM))
|
||||
return (ENODEV);
|
||||
args = data;
|
||||
|
||||
obj = drm_gem_name_ref(&dev->object_names, args->name,
|
||||
(void (*)(void *))drm_gem_object_reference);
|
||||
if (obj == NULL)
|
||||
return (ENOENT);
|
||||
handle = 0;
|
||||
ret = drm_gem_handle_create(file_priv, obj, &handle);
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
args->handle = handle;
|
||||
args->size = obj->size;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_open(struct drm_device *dev, struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
drm_gem_names_init(&file_priv->object_names);
|
||||
}
|
||||
|
||||
static int
|
||||
drm_gem_object_release_handle(uint32_t name, void *ptr, void *arg)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = ptr;
|
||||
drm_gem_object_handle_unreference(obj);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_release(struct drm_device *dev, struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
drm_gem_names_foreach(&file_priv->object_names,
|
||||
drm_gem_object_release_handle, NULL);
|
||||
drm_gem_names_fini(&file_priv->object_names);
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_close_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_gem_close *args;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_GEM))
|
||||
return (ENODEV);
|
||||
args = data;
|
||||
|
||||
return (drm_gem_handle_delete(file_priv, args->handle));
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_flink_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_gem_flink *args;
|
||||
struct drm_gem_object *obj;
|
||||
int error;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_GEM))
|
||||
return (ENODEV);
|
||||
args = data;
|
||||
|
||||
obj = drm_gem_name_ref(&file_priv->object_names, args->handle,
|
||||
(void (*)(void *))drm_gem_object_reference);
|
||||
if (obj == NULL)
|
||||
return (ENOENT);
|
||||
error = drm_gem_name_create(&dev->object_names, obj, &obj->name);
|
||||
if (error != 0) {
|
||||
if (error == EALREADY)
|
||||
error = 0;
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
}
|
||||
if (error == 0)
|
||||
args->name = obj->name;
|
||||
return (error);
|
||||
}
|
||||
|
||||
struct drm_gem_object *
|
||||
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *file_priv,
|
||||
uint32_t handle)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
|
||||
obj = drm_gem_name_ref(&file_priv->object_names, handle,
|
||||
(void (*)(void *))drm_gem_object_reference);
|
||||
return (obj);
|
||||
}
|
||||
|
||||
static struct drm_gem_object *
|
||||
drm_gem_object_from_offset(struct drm_device *dev, vm_ooffset_t offset)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_gem_mm *mm;
|
||||
struct drm_hash_item *map_list;
|
||||
|
||||
if ((offset & DRM_GEM_MAPPING_MASK) != DRM_GEM_MAPPING_KEY)
|
||||
return (NULL);
|
||||
offset &= ~DRM_GEM_MAPPING_KEY;
|
||||
mm = dev->mm_private;
|
||||
if (drm_ht_find_item(&mm->offset_hash, DRM_GEM_MAPPING_IDX(offset),
|
||||
&map_list) != 0) {
|
||||
DRM_DEBUG("drm_gem_object_from_offset: offset 0x%jx obj not found\n",
|
||||
(uintmax_t)offset);
|
||||
return (NULL);
|
||||
}
|
||||
obj = member2struct(drm_gem_object, map_list, map_list);
|
||||
return (obj);
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_create_mmap_offset(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_gem_mm *mm;
|
||||
int ret;
|
||||
|
||||
if (obj->on_map)
|
||||
return (0);
|
||||
dev = obj->dev;
|
||||
mm = dev->mm_private;
|
||||
ret = 0;
|
||||
|
||||
obj->map_list.key = alloc_unr(mm->idxunr);
|
||||
ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list);
|
||||
if (ret != 0) {
|
||||
DRM_ERROR("failed to add to map hash\n");
|
||||
free_unr(mm->idxunr, obj->map_list.key);
|
||||
return (ret);
|
||||
}
|
||||
obj->on_map = true;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_free_mmap_offset(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_hash_item *list;
|
||||
struct drm_gem_mm *mm;
|
||||
|
||||
if (!obj->on_map)
|
||||
return;
|
||||
mm = obj->dev->mm_private;
|
||||
list = &obj->map_list;
|
||||
|
||||
drm_ht_remove_item(&mm->offset_hash, list);
|
||||
free_unr(mm->idxunr, list->key);
|
||||
obj->on_map = false;
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, vm_size_t size,
|
||||
struct vm_object **obj_res, int nprot)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_gem_object *gem_obj;
|
||||
struct vm_object *vm_obj;
|
||||
|
||||
dev = drm_get_device_from_kdev(kdev);
|
||||
if ((dev->driver->driver_features & DRIVER_GEM) == 0)
|
||||
return (ENODEV);
|
||||
DRM_LOCK(dev);
|
||||
gem_obj = drm_gem_object_from_offset(dev, *offset);
|
||||
if (gem_obj == NULL) {
|
||||
DRM_UNLOCK(dev);
|
||||
return (ENODEV);
|
||||
}
|
||||
drm_gem_object_reference(gem_obj);
|
||||
DRM_UNLOCK(dev);
|
||||
vm_obj = cdev_pager_allocate(gem_obj, OBJT_MGTDEVICE,
|
||||
dev->driver->gem_pager_ops, size, nprot,
|
||||
DRM_GEM_MAPPING_MAPOFF(*offset), curthread->td_ucred);
|
||||
if (vm_obj == NULL) {
|
||||
drm_gem_object_unreference_unlocked(gem_obj);
|
||||
return (EINVAL);
|
||||
}
|
||||
*offset = DRM_GEM_MAPPING_MAPOFF(*offset);
|
||||
*obj_res = vm_obj;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_pager_dtr(void *handle)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_device *dev;
|
||||
|
||||
obj = handle;
|
||||
dev = obj->dev;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
drm_gem_free_mmap_offset(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
DRM_UNLOCK(dev);
|
||||
}
|
||||
211
sys/dev/drm2/drm_gem_names.c
Normal file
211
sys/dev/drm2/drm_gem_names.c
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*-
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Konstantin Belousov under sponsorship from
|
||||
* the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <dev/drm2/drm_gem_names.h>
|
||||
|
||||
MALLOC_DEFINE(M_GEM_NAMES, "gem_name", "Hash headers for the gem names");
|
||||
|
||||
static void drm_gem_names_delete_name(struct drm_gem_names *names,
|
||||
struct drm_gem_name *np);
|
||||
|
||||
void
|
||||
drm_gem_names_init(struct drm_gem_names *names)
|
||||
{
|
||||
|
||||
names->unr = new_unrhdr(1, INT_MAX, NULL); /* XXXKIB */
|
||||
names->names_hash = hashinit(1000 /* XXXKIB */, M_GEM_NAMES,
|
||||
&names->hash_mask);
|
||||
mtx_init(&names->lock, "drmnames", NULL, MTX_DEF);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_names_fini(struct drm_gem_names *names)
|
||||
{
|
||||
struct drm_gem_name *np;
|
||||
int i;
|
||||
|
||||
mtx_lock(&names->lock);
|
||||
for (i = 0; i <= names->hash_mask; i++) {
|
||||
while ((np = LIST_FIRST(&names->names_hash[i])) != NULL) {
|
||||
drm_gem_names_delete_name(names, np);
|
||||
mtx_lock(&names->lock);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&names->lock);
|
||||
mtx_destroy(&names->lock);
|
||||
hashdestroy(names->names_hash, M_GEM_NAMES, names->hash_mask);
|
||||
delete_unrhdr(names->unr);
|
||||
}
|
||||
|
||||
static struct drm_gem_names_head *
|
||||
gem_name_hash_index(struct drm_gem_names *names, int name)
|
||||
{
|
||||
|
||||
return (&names->names_hash[name & names->hash_mask]);
|
||||
}
|
||||
|
||||
void *
|
||||
drm_gem_name_ref(struct drm_gem_names *names, uint32_t name,
|
||||
void (*ref)(void *))
|
||||
{
|
||||
struct drm_gem_name *n;
|
||||
|
||||
mtx_lock(&names->lock);
|
||||
LIST_FOREACH(n, gem_name_hash_index(names, name), link) {
|
||||
if (n->name == name) {
|
||||
if (ref != NULL)
|
||||
ref(n->ptr);
|
||||
mtx_unlock(&names->lock);
|
||||
return (n->ptr);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&names->lock);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct drm_gem_ptr_match_arg {
|
||||
uint32_t res;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
static int
|
||||
drm_gem_ptr_match(uint32_t name, void *ptr, void *arg)
|
||||
{
|
||||
struct drm_gem_ptr_match_arg *a;
|
||||
|
||||
a = arg;
|
||||
if (ptr == a->ptr) {
|
||||
a->res = name;
|
||||
return (1);
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
drm_gem_find_name(struct drm_gem_names *names, void *ptr)
|
||||
{
|
||||
struct drm_gem_ptr_match_arg arg;
|
||||
|
||||
arg.res = 0;
|
||||
arg.ptr = ptr;
|
||||
drm_gem_names_foreach(names, drm_gem_ptr_match, &arg);
|
||||
return (arg.res);
|
||||
}
|
||||
|
||||
int
|
||||
drm_gem_name_create(struct drm_gem_names *names, void *p, uint32_t *name)
|
||||
{
|
||||
struct drm_gem_name *np;
|
||||
|
||||
np = malloc(sizeof(struct drm_gem_name), M_GEM_NAMES, M_WAITOK);
|
||||
mtx_lock(&names->lock);
|
||||
if (*name != 0) {
|
||||
mtx_unlock(&names->lock);
|
||||
return (EALREADY);
|
||||
}
|
||||
np->name = alloc_unr(names->unr);
|
||||
if (np->name == -1) {
|
||||
mtx_unlock(&names->lock);
|
||||
free(np, M_GEM_NAMES);
|
||||
return (ENOMEM);
|
||||
}
|
||||
*name = np->name;
|
||||
np->ptr = p;
|
||||
LIST_INSERT_HEAD(gem_name_hash_index(names, np->name), np, link);
|
||||
mtx_unlock(&names->lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
drm_gem_names_delete_name(struct drm_gem_names *names, struct drm_gem_name *np)
|
||||
{
|
||||
|
||||
mtx_assert(&names->lock, MA_OWNED);
|
||||
LIST_REMOVE(np, link);
|
||||
mtx_unlock(&names->lock);
|
||||
free_unr(names->unr, np->name);
|
||||
free(np, M_GEM_NAMES);
|
||||
}
|
||||
|
||||
void *
|
||||
drm_gem_names_remove(struct drm_gem_names *names, uint32_t name)
|
||||
{
|
||||
struct drm_gem_name *n;
|
||||
void *res;
|
||||
|
||||
mtx_lock(&names->lock);
|
||||
LIST_FOREACH(n, gem_name_hash_index(names, name), link) {
|
||||
if (n->name == name) {
|
||||
res = n->ptr;
|
||||
drm_gem_names_delete_name(names, n);
|
||||
return (res);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&names->lock);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
drm_gem_names_foreach(struct drm_gem_names *names,
|
||||
int (*f)(uint32_t, void *, void *), void *arg)
|
||||
{
|
||||
struct drm_gem_name *np;
|
||||
struct drm_gem_name marker;
|
||||
int i, fres;
|
||||
|
||||
bzero(&marker, sizeof(marker));
|
||||
marker.name = -1;
|
||||
mtx_lock(&names->lock);
|
||||
for (i = 0; i <= names->hash_mask; i++) {
|
||||
for (np = LIST_FIRST(&names->names_hash[i]); np != NULL; ) {
|
||||
if (np->name == -1) {
|
||||
np = LIST_NEXT(np, link);
|
||||
continue;
|
||||
}
|
||||
LIST_INSERT_AFTER(np, &marker, link);
|
||||
mtx_unlock(&names->lock);
|
||||
fres = f(np->name, np->ptr, arg);
|
||||
mtx_lock(&names->lock);
|
||||
np = LIST_NEXT(&marker, link);
|
||||
LIST_REMOVE(&marker, link);
|
||||
if (fres)
|
||||
break;
|
||||
}
|
||||
}
|
||||
mtx_unlock(&names->lock);
|
||||
}
|
||||
64
sys/dev/drm2/drm_gem_names.h
Normal file
64
sys/dev/drm2/drm_gem_names.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*-
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Konstantin Belousov under sponsorship from
|
||||
* the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DRM_GEM_NAMES_H
|
||||
#define DRM_GEM_NAMES_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
struct drm_gem_name {
|
||||
uint32_t name;
|
||||
void *ptr;
|
||||
LIST_ENTRY(drm_gem_name) link;
|
||||
};
|
||||
|
||||
struct drm_gem_names {
|
||||
struct mtx lock;
|
||||
LIST_HEAD(drm_gem_names_head, drm_gem_name) *names_hash;
|
||||
u_long hash_mask;
|
||||
struct unrhdr *unr;
|
||||
};
|
||||
|
||||
void drm_gem_names_init(struct drm_gem_names *names);
|
||||
void drm_gem_names_fini(struct drm_gem_names *names);
|
||||
uint32_t drm_gem_find_name(struct drm_gem_names *names, void *ptr);
|
||||
void *drm_gem_name_ref(struct drm_gem_names *names, uint32_t name,
|
||||
void (*ref)(void *));
|
||||
int drm_gem_name_create(struct drm_gem_names *names, void *obj, uint32_t *name);
|
||||
void drm_gem_names_foreach(struct drm_gem_names *names,
|
||||
int (*f)(uint32_t, void *, void *), void *arg);
|
||||
void *drm_gem_names_remove(struct drm_gem_names *names, uint32_t name);
|
||||
|
||||
#endif
|
||||
181
sys/dev/drm2/drm_hashtab.c
Normal file
181
sys/dev/drm2/drm_hashtab.c
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Simple open hash tab implementation.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm_hashtab.h>
|
||||
|
||||
#include <sys/hash.h>
|
||||
|
||||
int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
|
||||
{
|
||||
ht->size = 1 << order;
|
||||
ht->order = order;
|
||||
ht->table = NULL;
|
||||
ht->table = hashinit_flags(ht->size, DRM_MEM_HASHTAB, &ht->mask,
|
||||
HASH_NOWAIT);
|
||||
if (!ht->table) {
|
||||
DRM_ERROR("Out of memory for hash table\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
|
||||
{
|
||||
struct drm_hash_item *entry;
|
||||
struct drm_hash_item_list *h_list;
|
||||
unsigned int hashed_key;
|
||||
int count = 0;
|
||||
|
||||
hashed_key = hash32_buf(&key, sizeof(key), ht->order);
|
||||
DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
|
||||
h_list = &ht->table[hashed_key & ht->mask];
|
||||
LIST_FOREACH(entry, h_list, head)
|
||||
DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
|
||||
}
|
||||
|
||||
static struct drm_hash_item *
|
||||
drm_ht_find_key(struct drm_open_hash *ht, unsigned long key)
|
||||
{
|
||||
struct drm_hash_item *entry;
|
||||
struct drm_hash_item_list *h_list;
|
||||
unsigned int hashed_key;
|
||||
|
||||
hashed_key = hash32_buf(&key, sizeof(key), ht->order);
|
||||
h_list = &ht->table[hashed_key & ht->mask];
|
||||
LIST_FOREACH(entry, h_list, head) {
|
||||
if (entry->key == key)
|
||||
return entry;
|
||||
if (entry->key > key)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
|
||||
{
|
||||
struct drm_hash_item *entry, *parent;
|
||||
struct drm_hash_item_list *h_list;
|
||||
unsigned int hashed_key;
|
||||
unsigned long key = item->key;
|
||||
|
||||
hashed_key = hash32_buf(&key, sizeof(key), ht->order);
|
||||
h_list = &ht->table[hashed_key & ht->mask];
|
||||
parent = NULL;
|
||||
LIST_FOREACH(entry, h_list, head) {
|
||||
if (entry->key == key)
|
||||
return -EINVAL;
|
||||
if (entry->key > key)
|
||||
break;
|
||||
parent = entry;
|
||||
}
|
||||
if (parent) {
|
||||
LIST_INSERT_AFTER(parent, item, head);
|
||||
} else {
|
||||
LIST_INSERT_HEAD(h_list, item, head);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just insert an item and return any "bits" bit key that hasn't been
|
||||
* used before.
|
||||
*/
|
||||
int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
|
||||
unsigned long seed, int bits, int shift,
|
||||
unsigned long add)
|
||||
{
|
||||
int ret;
|
||||
unsigned long mask = (1 << bits) - 1;
|
||||
unsigned long first, unshifted_key = 0;
|
||||
|
||||
unshifted_key = hash32_buf(&seed, sizeof(seed), unshifted_key);
|
||||
first = unshifted_key;
|
||||
do {
|
||||
item->key = (unshifted_key << shift) + add;
|
||||
ret = drm_ht_insert_item(ht, item);
|
||||
if (ret)
|
||||
unshifted_key = (unshifted_key + 1) & mask;
|
||||
} while(ret && (unshifted_key != first));
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("Available key bit space exhausted\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
|
||||
struct drm_hash_item **item)
|
||||
{
|
||||
struct drm_hash_item *entry;
|
||||
|
||||
entry = drm_ht_find_key(ht, key);
|
||||
if (!entry)
|
||||
return -EINVAL;
|
||||
|
||||
*item = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
|
||||
{
|
||||
struct drm_hash_item *entry;
|
||||
|
||||
entry = drm_ht_find_key(ht, key);
|
||||
if (entry) {
|
||||
LIST_REMOVE(entry, head);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
|
||||
{
|
||||
LIST_REMOVE(item, head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drm_ht_remove(struct drm_open_hash *ht)
|
||||
{
|
||||
if (ht->table) {
|
||||
hashdestroy(ht->table, DRM_MEM_HASHTAB, ht->mask);
|
||||
ht->table = NULL;
|
||||
}
|
||||
}
|
||||
68
sys/dev/drm2/drm_hashtab.h
Normal file
68
sys/dev/drm2/drm_hashtab.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Simple open hash tab implementation.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#ifndef DRM_HASHTAB_H
|
||||
#define DRM_HASHTAB_H
|
||||
|
||||
#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
|
||||
|
||||
struct drm_hash_item {
|
||||
LIST_ENTRY(drm_hash_item) head;
|
||||
unsigned long key;
|
||||
};
|
||||
|
||||
struct drm_open_hash {
|
||||
LIST_HEAD(drm_hash_item_list, drm_hash_item) *table;
|
||||
unsigned int size;
|
||||
unsigned int order;
|
||||
unsigned long mask;
|
||||
};
|
||||
|
||||
extern int drm_ht_create(struct drm_open_hash *ht, unsigned int order);
|
||||
extern int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item);
|
||||
extern int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
|
||||
unsigned long seed, int bits, int shift,
|
||||
unsigned long add);
|
||||
extern int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item);
|
||||
|
||||
extern void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key);
|
||||
extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key);
|
||||
extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item);
|
||||
extern void drm_ht_remove(struct drm_open_hash *ht);
|
||||
|
||||
#endif
|
||||
43
sys/dev/drm2/drm_internal.h
Normal file
43
sys/dev/drm2/drm_internal.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*-
|
||||
* Copyright 2007 Red Hat, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/* This header file holds function prototypes and data types that are
|
||||
* internal to the drm (not exported to user space) but shared across
|
||||
* drivers and platforms */
|
||||
|
||||
#ifndef __DRM_INTERNAL_H__
|
||||
#define __DRM_INTERNAL_H__
|
||||
|
||||
/**
|
||||
* Drawable information.
|
||||
*/
|
||||
struct drm_drawable_info {
|
||||
unsigned int num_rects;
|
||||
struct drm_clip_rect *rects;
|
||||
};
|
||||
|
||||
#endif
|
||||
320
sys/dev/drm2/drm_ioctl.c
Normal file
320
sys/dev/drm2/drm_ioctl.c
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
/*-
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_ioctl.c
|
||||
* Varios minor DRM ioctls not applicable to other files, such as versioning
|
||||
* information and reporting DRM information to userland.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
/*
|
||||
* Beginning in revision 1.1 of the DRM interface, getunique will return
|
||||
* a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function)
|
||||
* before setunique has been called. The format for the bus-specific part of
|
||||
* the unique is not defined for any other bus.
|
||||
*/
|
||||
int drm_getunique(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_unique *u = data;
|
||||
|
||||
if (u->unique_len >= dev->unique_len) {
|
||||
if (DRM_COPY_TO_USER(u->unique, dev->unique, dev->unique_len))
|
||||
return EFAULT;
|
||||
}
|
||||
u->unique_len = dev->unique_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Deprecated in DRM version 1.1, and will return EBUSY when setversion has
|
||||
* requested version 1.1 or greater.
|
||||
*/
|
||||
int drm_setunique(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_unique *u = data;
|
||||
int domain, bus, slot, func, ret;
|
||||
char *busid;
|
||||
|
||||
/* Check and copy in the submitted Bus ID */
|
||||
if (!u->unique_len || u->unique_len > 1024)
|
||||
return EINVAL;
|
||||
|
||||
busid = malloc(u->unique_len + 1, DRM_MEM_DRIVER, M_WAITOK);
|
||||
if (busid == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
if (DRM_COPY_FROM_USER(busid, u->unique, u->unique_len)) {
|
||||
free(busid, DRM_MEM_DRIVER);
|
||||
return EFAULT;
|
||||
}
|
||||
busid[u->unique_len] = '\0';
|
||||
|
||||
/* Return error if the busid submitted doesn't match the device's actual
|
||||
* busid.
|
||||
*/
|
||||
ret = sscanf(busid, "PCI:%d:%d:%d", &bus, &slot, &func);
|
||||
if (ret != 3) {
|
||||
free(busid, DRM_MEM_DRIVER);
|
||||
return EINVAL;
|
||||
}
|
||||
domain = bus >> 8;
|
||||
bus &= 0xff;
|
||||
|
||||
if ((domain != dev->pci_domain) ||
|
||||
(bus != dev->pci_bus) ||
|
||||
(slot != dev->pci_slot) ||
|
||||
(func != dev->pci_func)) {
|
||||
free(busid, DRM_MEM_DRIVER);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Actually set the device's busid now. */
|
||||
DRM_LOCK(dev);
|
||||
if (dev->unique_len || dev->unique) {
|
||||
DRM_UNLOCK(dev);
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
dev->unique_len = u->unique_len;
|
||||
dev->unique = busid;
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
drm_set_busid(struct drm_device *dev)
|
||||
{
|
||||
|
||||
DRM_LOCK(dev);
|
||||
|
||||
if (dev->unique != NULL) {
|
||||
DRM_UNLOCK(dev);
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
dev->unique_len = 20;
|
||||
dev->unique = malloc(dev->unique_len + 1, DRM_MEM_DRIVER, M_NOWAIT);
|
||||
if (dev->unique == NULL) {
|
||||
DRM_UNLOCK(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
|
||||
dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_getmap(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_map *map = data;
|
||||
drm_local_map_t *mapinlist;
|
||||
int idx;
|
||||
int i = 0;
|
||||
|
||||
idx = map->offset;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
if (idx < 0) {
|
||||
DRM_UNLOCK(dev);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(mapinlist, &dev->maplist, link) {
|
||||
if (i == idx) {
|
||||
map->offset = mapinlist->offset;
|
||||
map->size = mapinlist->size;
|
||||
map->type = mapinlist->type;
|
||||
map->flags = mapinlist->flags;
|
||||
map->handle = mapinlist->handle;
|
||||
map->mtrr = mapinlist->mtrr;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
if (mapinlist == NULL)
|
||||
return EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_getclient(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_client *client = data;
|
||||
struct drm_file *pt;
|
||||
int idx;
|
||||
int i = 0;
|
||||
|
||||
idx = client->idx;
|
||||
DRM_LOCK(dev);
|
||||
TAILQ_FOREACH(pt, &dev->files, link) {
|
||||
if (i == idx) {
|
||||
client->auth = pt->authenticated;
|
||||
client->pid = pt->pid;
|
||||
client->uid = pt->uid;
|
||||
client->magic = pt->magic;
|
||||
client->iocs = pt->ioctl_count;
|
||||
DRM_UNLOCK(dev);
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
int drm_getstats(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_stats *stats = data;
|
||||
int i;
|
||||
|
||||
memset(stats, 0, sizeof(struct drm_stats));
|
||||
|
||||
DRM_LOCK(dev);
|
||||
|
||||
for (i = 0; i < dev->counters; i++) {
|
||||
if (dev->types[i] == _DRM_STAT_LOCK)
|
||||
stats->data[i].value =
|
||||
(dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
|
||||
else
|
||||
stats->data[i].value = atomic_read(&dev->counts[i]);
|
||||
stats->data[i].type = dev->types[i];
|
||||
}
|
||||
|
||||
stats->count = dev->counters;
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_get_cap *req = data;
|
||||
|
||||
req->value = 0;
|
||||
switch (req->capability) {
|
||||
case DRM_CAP_DUMB_BUFFER:
|
||||
if (dev->driver->dumb_create)
|
||||
req->value = 1;
|
||||
break;
|
||||
case DRM_CAP_VBLANK_HIGH_CRTC:
|
||||
req->value = 1;
|
||||
break;
|
||||
case DRM_CAP_DUMB_PREFERRED_DEPTH:
|
||||
req->value = dev->mode_config.preferred_depth;
|
||||
break;
|
||||
case DRM_CAP_DUMB_PREFER_SHADOW:
|
||||
req->value = dev->mode_config.prefer_shadow;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define DRM_IF_MAJOR 1
|
||||
#define DRM_IF_MINOR 2
|
||||
|
||||
int drm_setversion(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_set_version *sv = data;
|
||||
struct drm_set_version ver;
|
||||
int if_version;
|
||||
|
||||
/* Save the incoming data, and set the response before continuing
|
||||
* any further.
|
||||
*/
|
||||
ver = *sv;
|
||||
sv->drm_di_major = DRM_IF_MAJOR;
|
||||
sv->drm_di_minor = DRM_IF_MINOR;
|
||||
sv->drm_dd_major = dev->driver->major;
|
||||
sv->drm_dd_minor = dev->driver->minor;
|
||||
|
||||
DRM_DEBUG("ver.drm_di_major %d ver.drm_di_minor %d "
|
||||
"ver.drm_dd_major %d ver.drm_dd_minor %d\n",
|
||||
ver.drm_di_major, ver.drm_di_minor, ver.drm_dd_major,
|
||||
ver.drm_dd_minor);
|
||||
DRM_DEBUG("sv->drm_di_major %d sv->drm_di_minor %d "
|
||||
"sv->drm_dd_major %d sv->drm_dd_minor %d\n",
|
||||
sv->drm_di_major, sv->drm_di_minor, sv->drm_dd_major,
|
||||
sv->drm_dd_minor);
|
||||
|
||||
if (ver.drm_di_major != -1) {
|
||||
if (ver.drm_di_major != DRM_IF_MAJOR ||
|
||||
ver.drm_di_minor < 0 || ver.drm_di_minor > DRM_IF_MINOR) {
|
||||
return EINVAL;
|
||||
}
|
||||
if_version = DRM_IF_VERSION(ver.drm_di_major,
|
||||
ver.drm_dd_minor);
|
||||
dev->if_version = DRM_MAX(if_version, dev->if_version);
|
||||
if (ver.drm_di_minor >= 1) {
|
||||
/*
|
||||
* Version 1.1 includes tying of DRM to specific device
|
||||
*/
|
||||
drm_set_busid(dev);
|
||||
}
|
||||
}
|
||||
|
||||
if (ver.drm_dd_major != -1) {
|
||||
if (ver.drm_dd_major != dev->driver->major ||
|
||||
ver.drm_dd_minor < 0 ||
|
||||
ver.drm_dd_minor > dev->driver->minor)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int drm_noop(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
DRM_DEBUG("\n");
|
||||
return 0;
|
||||
}
|
||||
1253
sys/dev/drm2/drm_irq.c
Normal file
1253
sys/dev/drm2/drm_irq.c
Normal file
File diff suppressed because it is too large
Load diff
177
sys/dev/drm2/drm_linux_list.h
Normal file
177
sys/dev/drm2/drm_linux_list.h
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/* drm_linux_list.h -- linux list functions for the BSDs.
|
||||
* Created: Mon Apr 7 14:30:16 1999 by anholt@FreeBSD.org
|
||||
*/
|
||||
/*-
|
||||
* Copyright 2003 Eric Anholt
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <anholt@FreeBSD.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifndef _DRM_LINUX_LIST_H_
|
||||
#define _DRM_LINUX_LIST_H_
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define list_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
|
||||
static __inline__ void
|
||||
INIT_LIST_HEAD(struct list_head *head) {
|
||||
(head)->next = head;
|
||||
(head)->prev = head;
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define DRM_LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
static __inline__ int
|
||||
list_empty(const struct list_head *head) {
|
||||
return (head)->next == head;
|
||||
}
|
||||
|
||||
static __inline__ void
|
||||
list_add(struct list_head *new, struct list_head *head) {
|
||||
(head)->next->prev = new;
|
||||
(new)->next = (head)->next;
|
||||
(new)->prev = head;
|
||||
(head)->next = new;
|
||||
}
|
||||
|
||||
static __inline__ void
|
||||
list_add_tail(struct list_head *entry, struct list_head *head) {
|
||||
(entry)->prev = (head)->prev;
|
||||
(entry)->next = head;
|
||||
(head)->prev->next = entry;
|
||||
(head)->prev = entry;
|
||||
}
|
||||
|
||||
static __inline__ void
|
||||
list_del(struct list_head *entry) {
|
||||
(entry)->next->prev = (entry)->prev;
|
||||
(entry)->prev->next = (entry)->next;
|
||||
}
|
||||
|
||||
static inline void list_replace(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
new->next = old->next;
|
||||
new->next->prev = new;
|
||||
new->prev = old->prev;
|
||||
new->prev->next = new;
|
||||
}
|
||||
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
list_del(list);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
list_del(list);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
static __inline__ void
|
||||
list_del_init(struct list_head *entry) {
|
||||
(entry)->next->prev = (entry)->prev;
|
||||
(entry)->prev->next = (entry)->next;
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
#define list_for_each(entry, head) \
|
||||
for (entry = (head)->next; entry != head; entry = (entry)->next)
|
||||
|
||||
#define list_for_each_prev(entry, head) \
|
||||
for (entry = (head)->prev; entry != (head); \
|
||||
entry = entry->prev)
|
||||
|
||||
#define list_for_each_safe(entry, temp, head) \
|
||||
for (entry = (head)->next, temp = (entry)->next; \
|
||||
entry != head; \
|
||||
entry = temp, temp = entry->next)
|
||||
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_entry((head)->next, __typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, __typeof(*pos), member))
|
||||
|
||||
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
||||
for (pos = list_entry(pos->member.prev, __typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.prev, __typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->next, __typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, __typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, __typeof(*n), member))
|
||||
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
|
||||
static inline void
|
||||
__list_splice(const struct list_head *list, struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
|
||||
first->prev = prev;
|
||||
prev->next = first;
|
||||
|
||||
last->next = next;
|
||||
next->prev = last;
|
||||
}
|
||||
|
||||
static inline void
|
||||
list_splice(const struct list_head *list, struct list_head *head)
|
||||
{
|
||||
if (list_empty(list))
|
||||
return;
|
||||
|
||||
__list_splice(list, head, head->next);
|
||||
}
|
||||
|
||||
void drm_list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
|
||||
struct list_head *a, struct list_head *b));
|
||||
|
||||
#endif /* _DRM_LINUX_LIST_H_ */
|
||||
75
sys/dev/drm2/drm_linux_list_sort.c
Normal file
75
sys/dev/drm2/drm_linux_list_sort.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Konstantin Belousov under sponsorship from
|
||||
* the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
struct drm_list_sort_thunk {
|
||||
int (*cmp)(void *, struct list_head *, struct list_head *);
|
||||
void *priv;
|
||||
};
|
||||
|
||||
static int
|
||||
drm_le_cmp(void *priv, const void *d1, const void *d2)
|
||||
{
|
||||
struct list_head *le1, *le2;
|
||||
struct drm_list_sort_thunk *thunk;
|
||||
|
||||
thunk = priv;
|
||||
le1 = __DECONST(struct list_head *, d1);
|
||||
le2 = __DECONST(struct list_head *, d2);
|
||||
return ((thunk->cmp)(thunk->priv, le1, le2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Punt and use array sort.
|
||||
*/
|
||||
void
|
||||
drm_list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
|
||||
struct list_head *a, struct list_head *b))
|
||||
{
|
||||
struct drm_list_sort_thunk thunk;
|
||||
struct list_head **ar, *le;
|
||||
int count, i;
|
||||
|
||||
count = 0;
|
||||
list_for_each(le, head)
|
||||
count++;
|
||||
ar = malloc(sizeof(struct list_head *) * count, M_TEMP, M_WAITOK);
|
||||
i = 0;
|
||||
list_for_each(le, head)
|
||||
ar[i++] = le;
|
||||
thunk.cmp = cmp;
|
||||
thunk.priv = priv;
|
||||
qsort_r(ar, count, sizeof(struct list_head *), &thunk, drm_le_cmp);
|
||||
INIT_LIST_HEAD(head);
|
||||
for (i = 0; i < count; i++)
|
||||
list_add_tail(ar[i], head);
|
||||
free(ar, M_TEMP);
|
||||
}
|
||||
199
sys/dev/drm2/drm_lock.c
Normal file
199
sys/dev/drm2/drm_lock.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*-
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_lock.c
|
||||
* Implementation of the ioctls and other support code for dealing with the
|
||||
* hardware lock.
|
||||
*
|
||||
* The DRM hardware lock is a shared structure between the kernel and userland.
|
||||
*
|
||||
* On uncontended access where the new context was the last context, the
|
||||
* client may take the lock without dropping down into the kernel, using atomic
|
||||
* compare-and-set.
|
||||
*
|
||||
* If the client finds during compare-and-set that it was not the last owner
|
||||
* of the lock, it calls the DRM lock ioctl, which may sleep waiting for the
|
||||
* lock, and may have side-effects of kernel-managed context switching.
|
||||
*
|
||||
* When the client releases the lock, if the lock is marked as being contended
|
||||
* by another client, then the DRM unlock ioctl is called so that the
|
||||
* contending client may be woken up.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_lock *lock = data;
|
||||
int ret = 0;
|
||||
|
||||
if (lock->context == DRM_KERNEL_CONTEXT) {
|
||||
DRM_ERROR("Process %d using kernel context %d\n",
|
||||
DRM_CURRENTPID, lock->context);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
|
||||
lock->context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
|
||||
lock->flags);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) &&
|
||||
lock->context < 0)
|
||||
return EINVAL;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
for (;;) {
|
||||
if (drm_lock_take(&dev->lock, lock->context)) {
|
||||
dev->lock.file_priv = file_priv;
|
||||
dev->lock.lock_time = jiffies;
|
||||
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
|
||||
break; /* Got lock */
|
||||
}
|
||||
|
||||
/* Contention */
|
||||
ret = DRM_LOCK_SLEEP(dev, &dev->lock.lock_queue,
|
||||
PCATCH, "drmlk2", 0);
|
||||
if (ret != 0)
|
||||
break;
|
||||
}
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
if (ret == ERESTART)
|
||||
DRM_DEBUG("restarting syscall\n");
|
||||
else
|
||||
DRM_DEBUG("%d %s\n", lock->context,
|
||||
ret ? "interrupted" : "has lock");
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* XXX: Add signal blocking here */
|
||||
|
||||
if (dev->driver->dma_quiescent != NULL &&
|
||||
(lock->flags & _DRM_LOCK_QUIESCENT))
|
||||
dev->driver->dma_quiescent(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_lock *lock = data;
|
||||
|
||||
DRM_DEBUG("%d (pid %d) requests unlock (0x%08x), flags = 0x%08x\n",
|
||||
lock->context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
|
||||
lock->flags);
|
||||
|
||||
if (lock->context == DRM_KERNEL_CONTEXT) {
|
||||
DRM_ERROR("Process %d using kernel context %d\n",
|
||||
DRM_CURRENTPID, lock->context);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
|
||||
|
||||
DRM_LOCK(dev);
|
||||
drm_lock_transfer(&dev->lock, DRM_KERNEL_CONTEXT);
|
||||
|
||||
if (drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT)) {
|
||||
DRM_ERROR("\n");
|
||||
}
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context)
|
||||
{
|
||||
volatile unsigned int *lock = &lock_data->hw_lock->lock;
|
||||
unsigned int old, new;
|
||||
|
||||
do {
|
||||
old = *lock;
|
||||
if (old & _DRM_LOCK_HELD)
|
||||
new = old | _DRM_LOCK_CONT;
|
||||
else
|
||||
new = context | _DRM_LOCK_HELD;
|
||||
} while (!atomic_cmpset_int(lock, old, new));
|
||||
|
||||
if (_DRM_LOCKING_CONTEXT(old) == context) {
|
||||
if (old & _DRM_LOCK_HELD) {
|
||||
if (context != DRM_KERNEL_CONTEXT) {
|
||||
DRM_ERROR("%d holds heavyweight lock\n",
|
||||
context);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (new == (context | _DRM_LOCK_HELD)) {
|
||||
/* Have lock */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This takes a lock forcibly and hands it to context. Should ONLY be used
|
||||
inside *_unlock to give lock to kernel before calling *_dma_schedule. */
|
||||
int drm_lock_transfer(struct drm_lock_data *lock_data, unsigned int context)
|
||||
{
|
||||
volatile unsigned int *lock = &lock_data->hw_lock->lock;
|
||||
unsigned int old, new;
|
||||
|
||||
lock_data->file_priv = NULL;
|
||||
do {
|
||||
old = *lock;
|
||||
new = context | _DRM_LOCK_HELD;
|
||||
} while (!atomic_cmpset_int(lock, old, new));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
|
||||
{
|
||||
volatile unsigned int *lock = &lock_data->hw_lock->lock;
|
||||
unsigned int old, new;
|
||||
|
||||
lock_data->file_priv = NULL;
|
||||
do {
|
||||
old = *lock;
|
||||
new = 0;
|
||||
} while (!atomic_cmpset_int(lock, old, new));
|
||||
|
||||
if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
|
||||
DRM_ERROR("%d freed heavyweight lock held by %d\n",
|
||||
context, _DRM_LOCKING_CONTEXT(old));
|
||||
return 1;
|
||||
}
|
||||
DRM_WAKEUP_INT((void *)&lock_data->lock_queue);
|
||||
return 0;
|
||||
}
|
||||
127
sys/dev/drm2/drm_memory.c
Normal file
127
sys/dev/drm2/drm_memory.c
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*-
|
||||
*Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed by Konstantin Belousov
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_memory.c
|
||||
* Wrappers for kernel memory allocation routines, and MTRR management support.
|
||||
*
|
||||
* This file previously implemented a memory consumption tracking system using
|
||||
* the "area" argument for various different types of allocations, but that
|
||||
* has been stripped out for now.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
MALLOC_DEFINE(DRM_MEM_DMA, "drm_dma", "DRM DMA Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_SAREA, "drm_sarea", "DRM SAREA Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_DRIVER, "drm_driver", "DRM DRIVER Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_MAGIC, "drm_magic", "DRM MAGIC Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_IOCTLS, "drm_ioctls", "DRM IOCTL Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_MAPS, "drm_maps", "DRM MAP Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_BUFS, "drm_bufs", "DRM BUFFER Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_SEGS, "drm_segs", "DRM SEGMENTS Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_PAGES, "drm_pages", "DRM PAGES Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_FILES, "drm_files", "DRM FILE Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_QUEUES, "drm_queues", "DRM QUEUE Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_CMDS, "drm_cmds", "DRM COMMAND Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_MAPPINGS, "drm_mapping", "DRM MAPPING Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_BUFLISTS, "drm_buflists", "DRM BUFLISTS Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_AGPLISTS, "drm_agplists", "DRM AGPLISTS Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_CTXBITMAP, "drm_ctxbitmap",
|
||||
"DRM CTXBITMAP Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_SGLISTS, "drm_sglists", "DRM SGLISTS Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_DRAWABLE, "drm_drawable", "DRM DRAWABLE Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_MM, "drm_sman", "DRM MEMORY MANAGER Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_HASHTAB, "drm_hashtab", "DRM HASHTABLE Data Structures");
|
||||
MALLOC_DEFINE(DRM_MEM_KMS, "drm_kms", "DRM KMS Data Structures");
|
||||
|
||||
void drm_mem_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
void drm_mem_uninit(void)
|
||||
{
|
||||
}
|
||||
|
||||
void *drm_ioremap_wc(struct drm_device *dev, drm_local_map_t *map)
|
||||
{
|
||||
return pmap_mapdev_attr(map->offset, map->size, VM_MEMATTR_WRITE_COMBINING);
|
||||
}
|
||||
|
||||
void *drm_ioremap(struct drm_device *dev, drm_local_map_t *map)
|
||||
{
|
||||
return pmap_mapdev(map->offset, map->size);
|
||||
}
|
||||
|
||||
void drm_ioremapfree(drm_local_map_t *map)
|
||||
{
|
||||
pmap_unmapdev((vm_offset_t) map->virtual, map->size);
|
||||
}
|
||||
|
||||
int
|
||||
drm_mtrr_add(unsigned long offset, size_t size, int flags)
|
||||
{
|
||||
int act;
|
||||
struct mem_range_desc mrdesc;
|
||||
|
||||
mrdesc.mr_base = offset;
|
||||
mrdesc.mr_len = size;
|
||||
mrdesc.mr_flags = flags;
|
||||
act = MEMRANGE_SET_UPDATE;
|
||||
strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
|
||||
return mem_range_attr_set(&mrdesc, &act);
|
||||
}
|
||||
|
||||
int
|
||||
drm_mtrr_del(int __unused handle, unsigned long offset, size_t size, int flags)
|
||||
{
|
||||
int act;
|
||||
struct mem_range_desc mrdesc;
|
||||
|
||||
mrdesc.mr_base = offset;
|
||||
mrdesc.mr_len = size;
|
||||
mrdesc.mr_flags = flags;
|
||||
act = MEMRANGE_SET_REMOVE;
|
||||
strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
|
||||
return mem_range_attr_set(&mrdesc, &act);
|
||||
}
|
||||
|
||||
void
|
||||
drm_clflush_pages(vm_page_t *pages, unsigned long num_pages)
|
||||
{
|
||||
|
||||
pmap_invalidate_cache_pages(pages, num_pages);
|
||||
}
|
||||
563
sys/dev/drm2/drm_mm.c
Normal file
563
sys/dev/drm2/drm_mm.c
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Generic simple memory manager implementation. Intended to be used as a base
|
||||
* class implementation for more advanced memory managers.
|
||||
*
|
||||
* Note that the algorithm used is quite simple and there might be substantial
|
||||
* performance gains if a smarter free list is implemented. Currently it is just an
|
||||
* unordered stack of free regions. This could easily be improved if an RB-tree
|
||||
* is used instead. At least if we expect heavy fragmentation.
|
||||
*
|
||||
* Aligned allocations can also see improvement.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm_mm.h>
|
||||
|
||||
#define MM_UNUSED_TARGET 4
|
||||
|
||||
static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
|
||||
{
|
||||
struct drm_mm_node *child;
|
||||
|
||||
child = malloc(sizeof(*child), DRM_MEM_MM, M_ZERO |
|
||||
(atomic ? M_NOWAIT : M_WAITOK));
|
||||
|
||||
if (unlikely(child == NULL)) {
|
||||
mtx_lock(&mm->unused_lock);
|
||||
if (list_empty(&mm->unused_nodes))
|
||||
child = NULL;
|
||||
else {
|
||||
child =
|
||||
list_entry(mm->unused_nodes.next,
|
||||
struct drm_mm_node, node_list);
|
||||
list_del(&child->node_list);
|
||||
--mm->num_unused;
|
||||
}
|
||||
mtx_unlock(&mm->unused_lock);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
int drm_mm_pre_get(struct drm_mm *mm)
|
||||
{
|
||||
struct drm_mm_node *node;
|
||||
|
||||
mtx_lock(&mm->unused_lock);
|
||||
while (mm->num_unused < MM_UNUSED_TARGET) {
|
||||
mtx_unlock(&mm->unused_lock);
|
||||
node = malloc(sizeof(*node), DRM_MEM_MM, M_WAITOK);
|
||||
mtx_lock(&mm->unused_lock);
|
||||
|
||||
if (unlikely(node == NULL)) {
|
||||
int ret = (mm->num_unused < 2) ? -ENOMEM : 0;
|
||||
mtx_unlock(&mm->unused_lock);
|
||||
return ret;
|
||||
}
|
||||
++mm->num_unused;
|
||||
list_add_tail(&node->node_list, &mm->unused_nodes);
|
||||
}
|
||||
mtx_unlock(&mm->unused_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
|
||||
{
|
||||
return hole_node->start + hole_node->size;
|
||||
}
|
||||
|
||||
static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
|
||||
{
|
||||
struct drm_mm_node *next_node =
|
||||
list_entry(hole_node->node_list.next, struct drm_mm_node,
|
||||
node_list);
|
||||
|
||||
return next_node->start;
|
||||
}
|
||||
|
||||
static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
|
||||
struct drm_mm_node *node,
|
||||
unsigned long size, unsigned alignment)
|
||||
{
|
||||
struct drm_mm *mm = hole_node->mm;
|
||||
unsigned long tmp = 0, wasted = 0;
|
||||
unsigned long hole_start = drm_mm_hole_node_start(hole_node);
|
||||
unsigned long hole_end = drm_mm_hole_node_end(hole_node);
|
||||
|
||||
KASSERT(hole_node->hole_follows && !node->allocated, ("hole_node"));
|
||||
|
||||
if (alignment)
|
||||
tmp = hole_start % alignment;
|
||||
|
||||
if (!tmp) {
|
||||
hole_node->hole_follows = 0;
|
||||
list_del_init(&hole_node->hole_stack);
|
||||
} else
|
||||
wasted = alignment - tmp;
|
||||
|
||||
node->start = hole_start + wasted;
|
||||
node->size = size;
|
||||
node->mm = mm;
|
||||
node->allocated = 1;
|
||||
|
||||
INIT_LIST_HEAD(&node->hole_stack);
|
||||
list_add(&node->node_list, &hole_node->node_list);
|
||||
|
||||
KASSERT(node->start + node->size <= hole_end, ("hole pos"));
|
||||
|
||||
if (node->start + node->size < hole_end) {
|
||||
list_add(&node->hole_stack, &mm->hole_stack);
|
||||
node->hole_follows = 1;
|
||||
} else {
|
||||
node->hole_follows = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
int atomic)
|
||||
{
|
||||
struct drm_mm_node *node;
|
||||
|
||||
node = drm_mm_kmalloc(hole_node->mm, atomic);
|
||||
if (unlikely(node == NULL))
|
||||
return NULL;
|
||||
|
||||
drm_mm_insert_helper(hole_node, node, size, alignment);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
|
||||
unsigned long size, unsigned alignment)
|
||||
{
|
||||
struct drm_mm_node *hole_node;
|
||||
|
||||
hole_node = drm_mm_search_free(mm, size, alignment, 0);
|
||||
if (!hole_node)
|
||||
return -ENOSPC;
|
||||
|
||||
drm_mm_insert_helper(hole_node, node, size, alignment);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
|
||||
struct drm_mm_node *node,
|
||||
unsigned long size, unsigned alignment,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
struct drm_mm *mm = hole_node->mm;
|
||||
unsigned long tmp = 0, wasted = 0;
|
||||
unsigned long hole_start = drm_mm_hole_node_start(hole_node);
|
||||
unsigned long hole_end = drm_mm_hole_node_end(hole_node);
|
||||
|
||||
KASSERT(hole_node->hole_follows && !node->allocated, ("hole_node"));
|
||||
|
||||
if (hole_start < start)
|
||||
wasted += start - hole_start;
|
||||
if (alignment)
|
||||
tmp = (hole_start + wasted) % alignment;
|
||||
|
||||
if (tmp)
|
||||
wasted += alignment - tmp;
|
||||
|
||||
if (!wasted) {
|
||||
hole_node->hole_follows = 0;
|
||||
list_del_init(&hole_node->hole_stack);
|
||||
}
|
||||
|
||||
node->start = hole_start + wasted;
|
||||
node->size = size;
|
||||
node->mm = mm;
|
||||
node->allocated = 1;
|
||||
|
||||
INIT_LIST_HEAD(&node->hole_stack);
|
||||
list_add(&node->node_list, &hole_node->node_list);
|
||||
|
||||
KASSERT(node->start + node->size <= hole_end, ("hole_end"));
|
||||
KASSERT(node->start + node->size <= end, ("end"));
|
||||
|
||||
if (node->start + node->size < hole_end) {
|
||||
list_add(&node->hole_stack, &mm->hole_stack);
|
||||
node->hole_follows = 1;
|
||||
} else {
|
||||
node->hole_follows = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *hole_node,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long start,
|
||||
unsigned long end,
|
||||
int atomic)
|
||||
{
|
||||
struct drm_mm_node *node;
|
||||
|
||||
node = drm_mm_kmalloc(hole_node->mm, atomic);
|
||||
if (unlikely(node == NULL))
|
||||
return NULL;
|
||||
|
||||
drm_mm_insert_helper_range(hole_node, node, size, alignment,
|
||||
start, end);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node,
|
||||
unsigned long size, unsigned alignment,
|
||||
unsigned long start, unsigned long end)
|
||||
{
|
||||
struct drm_mm_node *hole_node;
|
||||
|
||||
hole_node = drm_mm_search_free_in_range(mm, size, alignment,
|
||||
start, end, 0);
|
||||
if (!hole_node)
|
||||
return -ENOSPC;
|
||||
|
||||
drm_mm_insert_helper_range(hole_node, node, size, alignment,
|
||||
start, end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drm_mm_remove_node(struct drm_mm_node *node)
|
||||
{
|
||||
struct drm_mm *mm = node->mm;
|
||||
struct drm_mm_node *prev_node;
|
||||
|
||||
KASSERT(!node->scanned_block && !node->scanned_prev_free
|
||||
&& !node->scanned_next_free, ("node"));
|
||||
|
||||
prev_node =
|
||||
list_entry(node->node_list.prev, struct drm_mm_node, node_list);
|
||||
|
||||
if (node->hole_follows) {
|
||||
KASSERT(drm_mm_hole_node_start(node)
|
||||
!= drm_mm_hole_node_end(node), ("hole_follows"));
|
||||
list_del(&node->hole_stack);
|
||||
} else
|
||||
KASSERT(drm_mm_hole_node_start(node)
|
||||
== drm_mm_hole_node_end(node), ("!hole_follows"));
|
||||
|
||||
if (!prev_node->hole_follows) {
|
||||
prev_node->hole_follows = 1;
|
||||
list_add(&prev_node->hole_stack, &mm->hole_stack);
|
||||
} else
|
||||
list_move(&prev_node->hole_stack, &mm->hole_stack);
|
||||
|
||||
list_del(&node->node_list);
|
||||
node->allocated = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a block. Merge with the previous and / or next block if they are free.
|
||||
* Otherwise add to the free stack.
|
||||
*/
|
||||
|
||||
void drm_mm_put_block(struct drm_mm_node *node)
|
||||
{
|
||||
struct drm_mm *mm = node->mm;
|
||||
|
||||
drm_mm_remove_node(node);
|
||||
|
||||
mtx_lock(&mm->unused_lock);
|
||||
if (mm->num_unused < MM_UNUSED_TARGET) {
|
||||
list_add(&node->node_list, &mm->unused_nodes);
|
||||
++mm->num_unused;
|
||||
} else
|
||||
free(node, DRM_MEM_MM);
|
||||
mtx_unlock(&mm->unused_lock);
|
||||
}
|
||||
|
||||
static int check_free_hole(unsigned long start, unsigned long end,
|
||||
unsigned long size, unsigned alignment)
|
||||
{
|
||||
unsigned wasted = 0;
|
||||
|
||||
if (end - start < size)
|
||||
return 0;
|
||||
|
||||
if (alignment) {
|
||||
unsigned tmp = start % alignment;
|
||||
if (tmp)
|
||||
wasted = alignment - tmp;
|
||||
}
|
||||
|
||||
if (end >= start + size + wasted) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
|
||||
unsigned long size,
|
||||
unsigned alignment, int best_match)
|
||||
{
|
||||
struct drm_mm_node *entry;
|
||||
struct drm_mm_node *best;
|
||||
unsigned long best_size;
|
||||
|
||||
best = NULL;
|
||||
best_size = ~0UL;
|
||||
|
||||
list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
|
||||
KASSERT(entry->hole_follows, ("hole_follows"));
|
||||
if (!check_free_hole(drm_mm_hole_node_start(entry),
|
||||
drm_mm_hole_node_end(entry),
|
||||
size, alignment))
|
||||
continue;
|
||||
|
||||
if (!best_match)
|
||||
return entry;
|
||||
|
||||
if (entry->size < best_size) {
|
||||
best = entry;
|
||||
best_size = entry->size;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long start,
|
||||
unsigned long end,
|
||||
int best_match)
|
||||
{
|
||||
struct drm_mm_node *entry;
|
||||
struct drm_mm_node *best;
|
||||
unsigned long best_size;
|
||||
|
||||
KASSERT(!mm->scanned_blocks, ("scanned"));
|
||||
|
||||
best = NULL;
|
||||
best_size = ~0UL;
|
||||
|
||||
list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
|
||||
unsigned long adj_start = drm_mm_hole_node_start(entry) < start ?
|
||||
start : drm_mm_hole_node_start(entry);
|
||||
unsigned long adj_end = drm_mm_hole_node_end(entry) > end ?
|
||||
end : drm_mm_hole_node_end(entry);
|
||||
|
||||
KASSERT(entry->hole_follows, ("hole_follows"));
|
||||
if (!check_free_hole(adj_start, adj_end, size, alignment))
|
||||
continue;
|
||||
|
||||
if (!best_match)
|
||||
return entry;
|
||||
|
||||
if (entry->size < best_size) {
|
||||
best = entry;
|
||||
best_size = entry->size;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
|
||||
{
|
||||
list_replace(&old->node_list, &new->node_list);
|
||||
list_replace(&old->hole_stack, &new->hole_stack);
|
||||
new->hole_follows = old->hole_follows;
|
||||
new->mm = old->mm;
|
||||
new->start = old->start;
|
||||
new->size = old->size;
|
||||
|
||||
old->allocated = 0;
|
||||
new->allocated = 1;
|
||||
}
|
||||
|
||||
void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
|
||||
unsigned alignment)
|
||||
{
|
||||
mm->scan_alignment = alignment;
|
||||
mm->scan_size = size;
|
||||
mm->scanned_blocks = 0;
|
||||
mm->scan_hit_start = 0;
|
||||
mm->scan_hit_size = 0;
|
||||
mm->scan_check_range = 0;
|
||||
mm->prev_scanned_node = NULL;
|
||||
}
|
||||
|
||||
void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long start,
|
||||
unsigned long end)
|
||||
{
|
||||
mm->scan_alignment = alignment;
|
||||
mm->scan_size = size;
|
||||
mm->scanned_blocks = 0;
|
||||
mm->scan_hit_start = 0;
|
||||
mm->scan_hit_size = 0;
|
||||
mm->scan_start = start;
|
||||
mm->scan_end = end;
|
||||
mm->scan_check_range = 1;
|
||||
mm->prev_scanned_node = NULL;
|
||||
}
|
||||
|
||||
int drm_mm_scan_add_block(struct drm_mm_node *node)
|
||||
{
|
||||
struct drm_mm *mm = node->mm;
|
||||
struct drm_mm_node *prev_node;
|
||||
unsigned long hole_start, hole_end;
|
||||
unsigned long adj_start;
|
||||
unsigned long adj_end;
|
||||
|
||||
mm->scanned_blocks++;
|
||||
|
||||
KASSERT(!node->scanned_block, ("node->scanned_block"));
|
||||
node->scanned_block = 1;
|
||||
|
||||
prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
|
||||
node_list);
|
||||
|
||||
node->scanned_preceeds_hole = prev_node->hole_follows;
|
||||
prev_node->hole_follows = 1;
|
||||
list_del(&node->node_list);
|
||||
node->node_list.prev = &prev_node->node_list;
|
||||
node->node_list.next = &mm->prev_scanned_node->node_list;
|
||||
mm->prev_scanned_node = node;
|
||||
|
||||
hole_start = drm_mm_hole_node_start(prev_node);
|
||||
hole_end = drm_mm_hole_node_end(prev_node);
|
||||
if (mm->scan_check_range) {
|
||||
adj_start = hole_start < mm->scan_start ?
|
||||
mm->scan_start : hole_start;
|
||||
adj_end = hole_end > mm->scan_end ?
|
||||
mm->scan_end : hole_end;
|
||||
} else {
|
||||
adj_start = hole_start;
|
||||
adj_end = hole_end;
|
||||
}
|
||||
|
||||
if (check_free_hole(adj_start , adj_end,
|
||||
mm->scan_size, mm->scan_alignment)) {
|
||||
mm->scan_hit_start = hole_start;
|
||||
mm->scan_hit_size = hole_end;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_mm_scan_remove_block(struct drm_mm_node *node)
|
||||
{
|
||||
struct drm_mm *mm = node->mm;
|
||||
struct drm_mm_node *prev_node;
|
||||
|
||||
mm->scanned_blocks--;
|
||||
|
||||
KASSERT(node->scanned_block, ("scanned_block"));
|
||||
node->scanned_block = 0;
|
||||
|
||||
prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
|
||||
node_list);
|
||||
|
||||
prev_node->hole_follows = node->scanned_preceeds_hole;
|
||||
INIT_LIST_HEAD(&node->node_list);
|
||||
list_add(&node->node_list, &prev_node->node_list);
|
||||
|
||||
/* Only need to check for containement because start&size for the
|
||||
* complete resulting free block (not just the desired part) is
|
||||
* stored. */
|
||||
if (node->start >= mm->scan_hit_start &&
|
||||
node->start + node->size
|
||||
<= mm->scan_hit_start + mm->scan_hit_size) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_mm_clean(struct drm_mm * mm)
|
||||
{
|
||||
struct list_head *head = &mm->head_node.node_list;
|
||||
|
||||
return (head->next->next == head);
|
||||
}
|
||||
|
||||
int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
|
||||
{
|
||||
INIT_LIST_HEAD(&mm->hole_stack);
|
||||
INIT_LIST_HEAD(&mm->unused_nodes);
|
||||
mm->num_unused = 0;
|
||||
mm->scanned_blocks = 0;
|
||||
mtx_init(&mm->unused_lock, "drm_unused", NULL, MTX_DEF);
|
||||
|
||||
INIT_LIST_HEAD(&mm->head_node.node_list);
|
||||
INIT_LIST_HEAD(&mm->head_node.hole_stack);
|
||||
mm->head_node.hole_follows = 1;
|
||||
mm->head_node.scanned_block = 0;
|
||||
mm->head_node.scanned_prev_free = 0;
|
||||
mm->head_node.scanned_next_free = 0;
|
||||
mm->head_node.mm = mm;
|
||||
mm->head_node.start = start + size;
|
||||
mm->head_node.size = start - mm->head_node.start;
|
||||
list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drm_mm_takedown(struct drm_mm * mm)
|
||||
{
|
||||
struct drm_mm_node *entry, *next;
|
||||
|
||||
if (!list_empty(&mm->head_node.node_list)) {
|
||||
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mtx_lock(&mm->unused_lock);
|
||||
list_for_each_entry_safe(entry, next, &mm->unused_nodes, node_list) {
|
||||
list_del(&entry->node_list);
|
||||
free(entry, DRM_MEM_MM);
|
||||
--mm->num_unused;
|
||||
}
|
||||
mtx_unlock(&mm->unused_lock);
|
||||
|
||||
mtx_destroy(&mm->unused_lock);
|
||||
|
||||
KASSERT(mm->num_unused == 0, ("num_unused != 0"));
|
||||
}
|
||||
185
sys/dev/drm2/drm_mm.h
Normal file
185
sys/dev/drm2/drm_mm.h
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Authors:
|
||||
* Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#ifndef _DRM_MM_H_
|
||||
#define _DRM_MM_H_
|
||||
|
||||
#include <dev/drm2/drm_linux_list.h>
|
||||
|
||||
struct drm_mm_node {
|
||||
struct list_head node_list;
|
||||
struct list_head hole_stack;
|
||||
unsigned hole_follows : 1;
|
||||
unsigned scanned_block : 1;
|
||||
unsigned scanned_prev_free : 1;
|
||||
unsigned scanned_next_free : 1;
|
||||
unsigned scanned_preceeds_hole : 1;
|
||||
unsigned allocated : 1;
|
||||
unsigned long start;
|
||||
unsigned long size;
|
||||
struct drm_mm *mm;
|
||||
void *private;
|
||||
};
|
||||
|
||||
struct drm_mm {
|
||||
struct list_head hole_stack;
|
||||
struct drm_mm_node head_node;
|
||||
struct list_head unused_nodes;
|
||||
int num_unused;
|
||||
struct mtx unused_lock;
|
||||
unsigned int scan_check_range : 1;
|
||||
unsigned scan_alignment;
|
||||
unsigned long scan_size;
|
||||
unsigned long scan_hit_start;
|
||||
unsigned scan_hit_size;
|
||||
unsigned scanned_blocks;
|
||||
unsigned long scan_start;
|
||||
unsigned long scan_end;
|
||||
struct drm_mm_node *prev_scanned_node;
|
||||
};
|
||||
|
||||
static inline bool drm_mm_node_allocated(struct drm_mm_node *node)
|
||||
{
|
||||
return node->allocated;
|
||||
}
|
||||
|
||||
static inline bool drm_mm_initialized(struct drm_mm *mm)
|
||||
{
|
||||
return (mm->hole_stack.next != NULL);
|
||||
}
|
||||
#define drm_mm_for_each_node(entry, mm) list_for_each_entry(entry, \
|
||||
&(mm)->head_node.node_list, \
|
||||
node_list)
|
||||
#define drm_mm_for_each_scanned_node_reverse(entry, n, mm) \
|
||||
for (entry = (mm)->prev_scanned_node, \
|
||||
next = entry ? list_entry(entry->node_list.next, \
|
||||
struct drm_mm_node, node_list) : NULL; \
|
||||
entry != NULL; entry = next, \
|
||||
next = entry ? list_entry(entry->node_list.next, \
|
||||
struct drm_mm_node, node_list) : NULL)
|
||||
|
||||
/*
|
||||
* Basic range manager support (drm_mm.c)
|
||||
*/
|
||||
extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
int atomic);
|
||||
extern struct drm_mm_node *drm_mm_get_block_range_generic(
|
||||
struct drm_mm_node *node,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long start,
|
||||
unsigned long end,
|
||||
int atomic);
|
||||
static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
|
||||
unsigned long size,
|
||||
unsigned alignment)
|
||||
{
|
||||
return drm_mm_get_block_generic(parent, size, alignment, 0);
|
||||
}
|
||||
static inline struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
|
||||
unsigned long size,
|
||||
unsigned alignment)
|
||||
{
|
||||
return drm_mm_get_block_generic(parent, size, alignment, 1);
|
||||
}
|
||||
static inline struct drm_mm_node *drm_mm_get_block_range(
|
||||
struct drm_mm_node *parent,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long start,
|
||||
unsigned long end)
|
||||
{
|
||||
return drm_mm_get_block_range_generic(parent, size, alignment,
|
||||
start, end, 0);
|
||||
}
|
||||
static inline struct drm_mm_node *drm_mm_get_block_atomic_range(
|
||||
struct drm_mm_node *parent,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long start,
|
||||
unsigned long end)
|
||||
{
|
||||
return drm_mm_get_block_range_generic(parent, size, alignment,
|
||||
start, end, 1);
|
||||
}
|
||||
extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
|
||||
unsigned long size, unsigned alignment);
|
||||
extern int drm_mm_insert_node_in_range(struct drm_mm *mm,
|
||||
struct drm_mm_node *node,
|
||||
unsigned long size, unsigned alignment,
|
||||
unsigned long start, unsigned long end);
|
||||
extern void drm_mm_put_block(struct drm_mm_node *cur);
|
||||
extern void drm_mm_remove_node(struct drm_mm_node *node);
|
||||
extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
|
||||
extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
int best_match);
|
||||
extern struct drm_mm_node *drm_mm_search_free_in_range(
|
||||
const struct drm_mm *mm,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long start,
|
||||
unsigned long end,
|
||||
int best_match);
|
||||
extern int drm_mm_init(struct drm_mm *mm, unsigned long start,
|
||||
unsigned long size);
|
||||
extern void drm_mm_takedown(struct drm_mm *mm);
|
||||
extern int drm_mm_clean(struct drm_mm *mm);
|
||||
extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
|
||||
extern int drm_mm_remove_space_from_tail(struct drm_mm *mm,
|
||||
unsigned long size);
|
||||
extern int drm_mm_add_space_to_tail(struct drm_mm *mm,
|
||||
unsigned long size, int atomic);
|
||||
extern int drm_mm_pre_get(struct drm_mm *mm);
|
||||
|
||||
static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
|
||||
{
|
||||
return block->mm;
|
||||
}
|
||||
|
||||
void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
|
||||
unsigned alignment);
|
||||
void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long start,
|
||||
unsigned long end);
|
||||
int drm_mm_scan_add_block(struct drm_mm_node *node);
|
||||
int drm_mm_scan_remove_block(struct drm_mm_node *node);
|
||||
|
||||
#endif
|
||||
444
sys/dev/drm2/drm_mode.h
Normal file
444
sys/dev/drm2/drm_mode.h
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
||||
* Copyright (c) 2007 Jakob Bornecrantz <wallbraker@gmail.com>
|
||||
* Copyright (c) 2008 Red Hat Inc.
|
||||
* Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA
|
||||
* Copyright (c) 2007-2008 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _DRM_MODE_H
|
||||
#define _DRM_MODE_H
|
||||
|
||||
#define DRM_DISPLAY_INFO_LEN 32
|
||||
#define DRM_CONNECTOR_NAME_LEN 32
|
||||
#define DRM_DISPLAY_MODE_LEN 32
|
||||
#define DRM_PROP_NAME_LEN 32
|
||||
|
||||
#define DRM_MODE_TYPE_BUILTIN (1<<0)
|
||||
#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN)
|
||||
#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN)
|
||||
#define DRM_MODE_TYPE_PREFERRED (1<<3)
|
||||
#define DRM_MODE_TYPE_DEFAULT (1<<4)
|
||||
#define DRM_MODE_TYPE_USERDEF (1<<5)
|
||||
#define DRM_MODE_TYPE_DRIVER (1<<6)
|
||||
|
||||
/* Video mode flags */
|
||||
/* bit compatible with the xorg definitions. */
|
||||
#define DRM_MODE_FLAG_PHSYNC (1<<0)
|
||||
#define DRM_MODE_FLAG_NHSYNC (1<<1)
|
||||
#define DRM_MODE_FLAG_PVSYNC (1<<2)
|
||||
#define DRM_MODE_FLAG_NVSYNC (1<<3)
|
||||
#define DRM_MODE_FLAG_INTERLACE (1<<4)
|
||||
#define DRM_MODE_FLAG_DBLSCAN (1<<5)
|
||||
#define DRM_MODE_FLAG_CSYNC (1<<6)
|
||||
#define DRM_MODE_FLAG_PCSYNC (1<<7)
|
||||
#define DRM_MODE_FLAG_NCSYNC (1<<8)
|
||||
#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */
|
||||
#define DRM_MODE_FLAG_BCAST (1<<10)
|
||||
#define DRM_MODE_FLAG_PIXMUX (1<<11)
|
||||
#define DRM_MODE_FLAG_DBLCLK (1<<12)
|
||||
#define DRM_MODE_FLAG_CLKDIV2 (1<<13)
|
||||
|
||||
/* DPMS flags */
|
||||
/* bit compatible with the xorg definitions. */
|
||||
#define DRM_MODE_DPMS_ON 0
|
||||
#define DRM_MODE_DPMS_STANDBY 1
|
||||
#define DRM_MODE_DPMS_SUSPEND 2
|
||||
#define DRM_MODE_DPMS_OFF 3
|
||||
|
||||
/* Scaling mode options */
|
||||
#define DRM_MODE_SCALE_NONE 0 /* Unmodified timing (display or
|
||||
software can still scale) */
|
||||
#define DRM_MODE_SCALE_FULLSCREEN 1 /* Full screen, ignore aspect */
|
||||
#define DRM_MODE_SCALE_CENTER 2 /* Centered, no scaling */
|
||||
#define DRM_MODE_SCALE_ASPECT 3 /* Full screen, preserve aspect */
|
||||
|
||||
/* Dithering mode options */
|
||||
#define DRM_MODE_DITHERING_OFF 0
|
||||
#define DRM_MODE_DITHERING_ON 1
|
||||
#define DRM_MODE_DITHERING_AUTO 2
|
||||
|
||||
/* Dirty info options */
|
||||
#define DRM_MODE_DIRTY_OFF 0
|
||||
#define DRM_MODE_DIRTY_ON 1
|
||||
#define DRM_MODE_DIRTY_ANNOTATE 2
|
||||
|
||||
struct drm_mode_modeinfo {
|
||||
uint32_t clock;
|
||||
uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
|
||||
uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
|
||||
|
||||
uint32_t vrefresh;
|
||||
|
||||
uint32_t flags;
|
||||
uint32_t type;
|
||||
char name[DRM_DISPLAY_MODE_LEN];
|
||||
};
|
||||
|
||||
struct drm_mode_card_res {
|
||||
uint64_t fb_id_ptr;
|
||||
uint64_t crtc_id_ptr;
|
||||
uint64_t connector_id_ptr;
|
||||
uint64_t encoder_id_ptr;
|
||||
uint32_t count_fbs;
|
||||
uint32_t count_crtcs;
|
||||
uint32_t count_connectors;
|
||||
uint32_t count_encoders;
|
||||
uint32_t min_width, max_width;
|
||||
uint32_t min_height, max_height;
|
||||
};
|
||||
|
||||
struct drm_mode_crtc {
|
||||
uint64_t set_connectors_ptr;
|
||||
uint32_t count_connectors;
|
||||
|
||||
uint32_t crtc_id; /**< Id */
|
||||
uint32_t fb_id; /**< Id of framebuffer */
|
||||
|
||||
uint32_t x, y; /**< Position on the frameuffer */
|
||||
|
||||
uint32_t gamma_size;
|
||||
uint32_t mode_valid;
|
||||
struct drm_mode_modeinfo mode;
|
||||
};
|
||||
|
||||
#define DRM_MODE_PRESENT_TOP_FIELD (1<<0)
|
||||
#define DRM_MODE_PRESENT_BOTTOM_FIELD (1<<1)
|
||||
|
||||
/* Planes blend with or override other bits on the CRTC */
|
||||
struct drm_mode_set_plane {
|
||||
uint32_t plane_id;
|
||||
uint32_t crtc_id;
|
||||
uint32_t fb_id; /* fb object contains surface format type */
|
||||
uint32_t flags; /* see above flags */
|
||||
|
||||
/* Signed dest location allows it to be partially off screen */
|
||||
int32_t crtc_x, crtc_y;
|
||||
uint32_t crtc_w, crtc_h;
|
||||
|
||||
/* Source values are 16.16 fixed point */
|
||||
uint32_t src_x, src_y;
|
||||
uint32_t src_h, src_w;
|
||||
};
|
||||
|
||||
struct drm_mode_get_plane {
|
||||
uint32_t plane_id;
|
||||
|
||||
uint32_t crtc_id;
|
||||
uint32_t fb_id;
|
||||
|
||||
uint32_t possible_crtcs;
|
||||
uint32_t gamma_size;
|
||||
|
||||
uint32_t count_format_types;
|
||||
uint64_t format_type_ptr;
|
||||
};
|
||||
|
||||
struct drm_mode_get_plane_res {
|
||||
uint64_t plane_id_ptr;
|
||||
uint32_t count_planes;
|
||||
};
|
||||
|
||||
#define DRM_MODE_ENCODER_NONE 0
|
||||
#define DRM_MODE_ENCODER_DAC 1
|
||||
#define DRM_MODE_ENCODER_TMDS 2
|
||||
#define DRM_MODE_ENCODER_LVDS 3
|
||||
#define DRM_MODE_ENCODER_TVDAC 4
|
||||
|
||||
struct drm_mode_get_encoder {
|
||||
uint32_t encoder_id;
|
||||
uint32_t encoder_type;
|
||||
|
||||
uint32_t crtc_id; /**< Id of crtc */
|
||||
|
||||
uint32_t possible_crtcs;
|
||||
uint32_t possible_clones;
|
||||
};
|
||||
|
||||
/* This is for connectors with multiple signal types. */
|
||||
/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
|
||||
#define DRM_MODE_SUBCONNECTOR_Automatic 0
|
||||
#define DRM_MODE_SUBCONNECTOR_Unknown 0
|
||||
#define DRM_MODE_SUBCONNECTOR_DVID 3
|
||||
#define DRM_MODE_SUBCONNECTOR_DVIA 4
|
||||
#define DRM_MODE_SUBCONNECTOR_Composite 5
|
||||
#define DRM_MODE_SUBCONNECTOR_SVIDEO 6
|
||||
#define DRM_MODE_SUBCONNECTOR_Component 8
|
||||
#define DRM_MODE_SUBCONNECTOR_SCART 9
|
||||
|
||||
#define DRM_MODE_CONNECTOR_Unknown 0
|
||||
#define DRM_MODE_CONNECTOR_VGA 1
|
||||
#define DRM_MODE_CONNECTOR_DVII 2
|
||||
#define DRM_MODE_CONNECTOR_DVID 3
|
||||
#define DRM_MODE_CONNECTOR_DVIA 4
|
||||
#define DRM_MODE_CONNECTOR_Composite 5
|
||||
#define DRM_MODE_CONNECTOR_SVIDEO 6
|
||||
#define DRM_MODE_CONNECTOR_LVDS 7
|
||||
#define DRM_MODE_CONNECTOR_Component 8
|
||||
#define DRM_MODE_CONNECTOR_9PinDIN 9
|
||||
#define DRM_MODE_CONNECTOR_DisplayPort 10
|
||||
#define DRM_MODE_CONNECTOR_HDMIA 11
|
||||
#define DRM_MODE_CONNECTOR_HDMIB 12
|
||||
#define DRM_MODE_CONNECTOR_TV 13
|
||||
#define DRM_MODE_CONNECTOR_eDP 14
|
||||
|
||||
struct drm_mode_get_connector {
|
||||
|
||||
uint64_t encoders_ptr;
|
||||
uint64_t modes_ptr;
|
||||
uint64_t props_ptr;
|
||||
uint64_t prop_values_ptr;
|
||||
|
||||
uint32_t count_modes;
|
||||
uint32_t count_props;
|
||||
uint32_t count_encoders;
|
||||
|
||||
uint32_t encoder_id; /**< Current Encoder */
|
||||
uint32_t connector_id; /**< Id */
|
||||
uint32_t connector_type;
|
||||
uint32_t connector_type_id;
|
||||
|
||||
uint32_t connection;
|
||||
uint32_t mm_width, mm_height; /**< HxW in millimeters */
|
||||
uint32_t subpixel;
|
||||
};
|
||||
|
||||
#define DRM_MODE_PROP_PENDING (1<<0)
|
||||
#define DRM_MODE_PROP_RANGE (1<<1)
|
||||
#define DRM_MODE_PROP_IMMUTABLE (1<<2)
|
||||
#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */
|
||||
#define DRM_MODE_PROP_BLOB (1<<4)
|
||||
|
||||
struct drm_mode_property_enum {
|
||||
uint64_t value;
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
};
|
||||
|
||||
struct drm_mode_get_property {
|
||||
uint64_t values_ptr; /* values and blob lengths */
|
||||
uint64_t enum_blob_ptr; /* enum and blob id ptrs */
|
||||
|
||||
uint32_t prop_id;
|
||||
uint32_t flags;
|
||||
char name[DRM_PROP_NAME_LEN];
|
||||
|
||||
uint32_t count_values;
|
||||
uint32_t count_enum_blobs;
|
||||
};
|
||||
|
||||
struct drm_mode_connector_set_property {
|
||||
uint64_t value;
|
||||
uint32_t prop_id;
|
||||
uint32_t connector_id;
|
||||
};
|
||||
|
||||
struct drm_mode_get_blob {
|
||||
uint32_t blob_id;
|
||||
uint32_t length;
|
||||
uint64_t data;
|
||||
};
|
||||
|
||||
struct drm_mode_fb_cmd {
|
||||
uint32_t fb_id;
|
||||
uint32_t width, height;
|
||||
uint32_t pitch;
|
||||
uint32_t bpp;
|
||||
uint32_t depth;
|
||||
/* driver specific handle */
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
#define DRM_MODE_FB_INTERLACED (1<<0 /* for interlaced framebuffers */
|
||||
|
||||
struct drm_mode_fb_cmd2 {
|
||||
uint32_t fb_id;
|
||||
uint32_t width, height;
|
||||
uint32_t pixel_format; /* fourcc code from drm_fourcc.h */
|
||||
uint32_t flags; /* see above flags */
|
||||
|
||||
/*
|
||||
* In case of planar formats, this ioctl allows up to 4
|
||||
* buffer objects with offets and pitches per plane.
|
||||
* The pitch and offset order is dictated by the fourcc,
|
||||
* e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as:
|
||||
*
|
||||
* YUV 4:2:0 image with a plane of 8 bit Y samples
|
||||
* followed by an interleaved U/V plane containing
|
||||
* 8 bit 2x2 subsampled colour difference samples.
|
||||
*
|
||||
* So it would consist of Y as offset[0] and UV as
|
||||
* offeset[1]. Note that offset[0] will generally
|
||||
* be 0.
|
||||
*/
|
||||
uint32_t handles[4];
|
||||
uint32_t pitches[4]; /* pitch for each plane */
|
||||
uint32_t offsets[4]; /* offset of each plane */
|
||||
};
|
||||
|
||||
#define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01
|
||||
#define DRM_MODE_FB_DIRTY_ANNOTATE_FILL 0x02
|
||||
#define DRM_MODE_FB_DIRTY_FLAGS 0x03
|
||||
|
||||
#define DRM_MODE_FB_DIRTY_MAX_CLIPS 256
|
||||
|
||||
/*
|
||||
* Mark a region of a framebuffer as dirty.
|
||||
*
|
||||
* Some hardware does not automatically update display contents
|
||||
* as a hardware or software draw to a framebuffer. This ioctl
|
||||
* allows userspace to tell the kernel and the hardware what
|
||||
* regions of the framebuffer have changed.
|
||||
*
|
||||
* The kernel or hardware is free to update more then just the
|
||||
* region specified by the clip rects. The kernel or hardware
|
||||
* may also delay and/or coalesce several calls to dirty into a
|
||||
* single update.
|
||||
*
|
||||
* Userspace may annotate the updates, the annotates are a
|
||||
* promise made by the caller that the change is either a copy
|
||||
* of pixels or a fill of a single color in the region specified.
|
||||
*
|
||||
* If the DRM_MODE_FB_DIRTY_ANNOTATE_COPY flag is given then
|
||||
* the number of updated regions are half of num_clips given,
|
||||
* where the clip rects are paired in src and dst. The width and
|
||||
* height of each one of the pairs must match.
|
||||
*
|
||||
* If the DRM_MODE_FB_DIRTY_ANNOTATE_FILL flag is given the caller
|
||||
* promises that the region specified of the clip rects is filled
|
||||
* completely with a single color as given in the color argument.
|
||||
*/
|
||||
|
||||
struct drm_mode_fb_dirty_cmd {
|
||||
uint32_t fb_id;
|
||||
uint32_t flags;
|
||||
uint32_t color;
|
||||
uint32_t num_clips;
|
||||
uint64_t clips_ptr;
|
||||
};
|
||||
|
||||
struct drm_mode_mode_cmd {
|
||||
uint32_t connector_id;
|
||||
struct drm_mode_modeinfo mode;
|
||||
};
|
||||
|
||||
#define DRM_MODE_CURSOR_BO (1<<0)
|
||||
#define DRM_MODE_CURSOR_MOVE (1<<1)
|
||||
|
||||
/*
|
||||
* depending on the value in flags diffrent members are used.
|
||||
*
|
||||
* CURSOR_BO uses
|
||||
* crtc
|
||||
* width
|
||||
* height
|
||||
* handle - if 0 turns the cursor of
|
||||
*
|
||||
* CURSOR_MOVE uses
|
||||
* crtc
|
||||
* x
|
||||
* y
|
||||
*/
|
||||
struct drm_mode_cursor {
|
||||
uint32_t flags;
|
||||
uint32_t crtc_id;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
/* driver specific handle */
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
struct drm_mode_crtc_lut {
|
||||
uint32_t crtc_id;
|
||||
uint32_t gamma_size;
|
||||
|
||||
/* pointers to arrays */
|
||||
uint64_t red;
|
||||
uint64_t green;
|
||||
uint64_t blue;
|
||||
};
|
||||
|
||||
#define DRM_MODE_PAGE_FLIP_EVENT 0x01
|
||||
#define DRM_MODE_PAGE_FLIP_FLAGS DRM_MODE_PAGE_FLIP_EVENT
|
||||
|
||||
/*
|
||||
* Request a page flip on the specified crtc.
|
||||
*
|
||||
* This ioctl will ask KMS to schedule a page flip for the specified
|
||||
* crtc. Once any pending rendering targeting the specified fb (as of
|
||||
* ioctl time) has completed, the crtc will be reprogrammed to display
|
||||
* that fb after the next vertical refresh. The ioctl returns
|
||||
* immediately, but subsequent rendering to the current fb will block
|
||||
* in the execbuffer ioctl until the page flip happens. If a page
|
||||
* flip is already pending as the ioctl is called, EBUSY will be
|
||||
* returned.
|
||||
*
|
||||
* The ioctl supports one flag, DRM_MODE_PAGE_FLIP_EVENT, which will
|
||||
* request that drm sends back a vblank event (see drm.h: struct
|
||||
* drm_event_vblank) when the page flip is done. The user_data field
|
||||
* passed in with this ioctl will be returned as the user_data field
|
||||
* in the vblank event struct.
|
||||
*
|
||||
* The reserved field must be zero until we figure out something
|
||||
* clever to use it for.
|
||||
*/
|
||||
|
||||
struct drm_mode_crtc_page_flip {
|
||||
uint32_t crtc_id;
|
||||
uint32_t fb_id;
|
||||
uint32_t flags;
|
||||
uint32_t reserved;
|
||||
uint64_t user_data;
|
||||
};
|
||||
|
||||
/* create a dumb scanout buffer */
|
||||
struct drm_mode_create_dumb {
|
||||
uint32_t height;
|
||||
uint32_t width;
|
||||
uint32_t bpp;
|
||||
uint32_t flags;
|
||||
/* handle, pitch, size will be returned */
|
||||
uint32_t handle;
|
||||
uint32_t pitch;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
/* set up for mmap of a dumb scanout buffer */
|
||||
struct drm_mode_map_dumb {
|
||||
/** Handle for the object being mapped. */
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
/**
|
||||
* Fake offset to use for subsequent mmap call
|
||||
*
|
||||
* This is a fixed-size type for 32/64 compatibility.
|
||||
*/
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct drm_mode_destroy_dumb {
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
#endif
|
||||
1147
sys/dev/drm2/drm_modes.c
Normal file
1147
sys/dev/drm2/drm_modes.c
Normal file
File diff suppressed because it is too large
Load diff
125
sys/dev/drm2/drm_pci.c
Normal file
125
sys/dev/drm2/drm_pci.c
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*-
|
||||
* Copyright 2003 Eric Anholt.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/**
|
||||
* \file drm_pci.h
|
||||
* \brief PCI consistent, DMA-accessible memory allocation.
|
||||
*
|
||||
* \author Eric Anholt <anholt@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
/**********************************************************************/
|
||||
/** \name PCI memory */
|
||||
/*@{*/
|
||||
|
||||
static void
|
||||
drm_pci_busdma_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
|
||||
{
|
||||
drm_dma_handle_t *dmah = arg;
|
||||
|
||||
if (error != 0)
|
||||
return;
|
||||
|
||||
KASSERT(nsegs == 1, ("drm_pci_busdma_callback: bad dma segment count"));
|
||||
dmah->busaddr = segs[0].ds_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate a physically contiguous DMA-accessible consistent
|
||||
* memory block.
|
||||
*/
|
||||
drm_dma_handle_t *
|
||||
drm_pci_alloc(struct drm_device *dev, size_t size,
|
||||
size_t align, dma_addr_t maxaddr)
|
||||
{
|
||||
drm_dma_handle_t *dmah;
|
||||
int ret;
|
||||
|
||||
/* Need power-of-two alignment, so fail the allocation if it isn't. */
|
||||
if ((align & (align - 1)) != 0) {
|
||||
DRM_ERROR("drm_pci_alloc with non-power-of-two alignment %d\n",
|
||||
(int)align);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dmah = malloc(sizeof(drm_dma_handle_t), DRM_MEM_DMA, M_ZERO | M_NOWAIT);
|
||||
if (dmah == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Make sure we aren't holding mutexes here */
|
||||
mtx_assert(&dev->dma_lock, MA_NOTOWNED);
|
||||
if (mtx_owned(&dev->dma_lock))
|
||||
DRM_ERROR("called while holding dma_lock\n");
|
||||
|
||||
ret = bus_dma_tag_create(NULL, align, 0, /* tag, align, boundary */
|
||||
maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
|
||||
NULL, NULL, /* filtfunc, filtfuncargs */
|
||||
size, 1, size, /* maxsize, nsegs, maxsegsize */
|
||||
0, NULL, NULL, /* flags, lockfunc, lockfuncargs */
|
||||
&dmah->tag);
|
||||
if (ret != 0) {
|
||||
free(dmah, DRM_MEM_DMA);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr,
|
||||
BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map);
|
||||
if (ret != 0) {
|
||||
bus_dma_tag_destroy(dmah->tag);
|
||||
free(dmah, DRM_MEM_DMA);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size,
|
||||
drm_pci_busdma_callback, dmah, BUS_DMA_NOWAIT);
|
||||
if (ret != 0) {
|
||||
bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
|
||||
bus_dma_tag_destroy(dmah->tag);
|
||||
free(dmah, DRM_MEM_DMA);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dmah;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Free a DMA-accessible consistent memory block.
|
||||
*/
|
||||
void
|
||||
drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah)
|
||||
{
|
||||
if (dmah == NULL)
|
||||
return;
|
||||
|
||||
bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
|
||||
bus_dma_tag_destroy(dmah->tag);
|
||||
|
||||
free(dmah, DRM_MEM_DMA);
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
764
sys/dev/drm2/drm_pciids.h
Normal file
764
sys/dev/drm2/drm_pciids.h
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
/*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
/*
|
||||
This file is auto-generated from the drm_pciids.txt in the DRM CVS
|
||||
Please contact dri-devel@lists.sf.net to add new cards to this list
|
||||
*/
|
||||
#define radeon_PCI_IDS \
|
||||
{0x1002, 0x3150, CHIP_RV380|RADEON_IS_MOBILITY, "ATI Radeon Mobility X600 M24"}, \
|
||||
{0x1002, 0x3152, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Radeon Mobility X300 M24"}, \
|
||||
{0x1002, 0x3154, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI FireGL M24 GL"}, \
|
||||
{0x1002, 0x3E50, CHIP_RV380|RADEON_NEW_MEMMAP, "ATI Radeon RV380 X600"}, \
|
||||
{0x1002, 0x3E54, CHIP_RV380|RADEON_NEW_MEMMAP, "ATI FireGL V3200 RV380"}, \
|
||||
{0x1002, 0x4136, CHIP_RS100|RADEON_IS_IGP, "ATI Radeon RS100 IGP 320"}, \
|
||||
{0x1002, 0x4137, CHIP_RS200|RADEON_IS_IGP, "ATI Radeon RS200 IGP 340"}, \
|
||||
{0x1002, 0x4144, CHIP_R300, "ATI Radeon AD 9500"}, \
|
||||
{0x1002, 0x4145, CHIP_R300, "ATI Radeon AE 9700 Pro"}, \
|
||||
{0x1002, 0x4146, CHIP_R300, "ATI Radeon AF R300 9600TX"}, \
|
||||
{0x1002, 0x4147, CHIP_R300, "ATI FireGL AG Z1"}, \
|
||||
{0x1002, 0x4148, CHIP_R350, "ATI Radeon AH 9800 SE"}, \
|
||||
{0x1002, 0x4149, CHIP_R350, "ATI Radeon AI 9800"}, \
|
||||
{0x1002, 0x414A, CHIP_R350, "ATI Radeon AJ 9800"}, \
|
||||
{0x1002, 0x414B, CHIP_R350, "ATI FireGL AK X2"}, \
|
||||
{0x1002, 0x4150, CHIP_RV350, "ATI Radeon AP 9600"}, \
|
||||
{0x1002, 0x4151, CHIP_RV350, "ATI Radeon AQ 9600 SE"}, \
|
||||
{0x1002, 0x4152, CHIP_RV350, "ATI Radeon AR 9600 XT"}, \
|
||||
{0x1002, 0x4153, CHIP_RV350, "ATI Radeon AS 9550"}, \
|
||||
{0x1002, 0x4154, CHIP_RV350, "ATI FireGL AT T2"}, \
|
||||
{0x1002, 0x4155, CHIP_RV350, "ATI Radeon 9650"}, \
|
||||
{0x1002, 0x4156, CHIP_RV350, "ATI FireGL AV RV360 T2"}, \
|
||||
{0x1002, 0x4237, CHIP_RS200|RADEON_IS_IGP, "ATI Radeon RS250 IGP"}, \
|
||||
{0x1002, 0x4242, CHIP_R200, "ATI Radeon BB R200 AIW 8500DV"}, \
|
||||
{0x1002, 0x4243, CHIP_R200, "ATI Radeon BC R200"}, \
|
||||
{0x1002, 0x4336, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY, "ATI Radeon RS100 Mobility U1"}, \
|
||||
{0x1002, 0x4337, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY, "ATI Radeon RS200 Mobility IGP 340M"}, \
|
||||
{0x1002, 0x4437, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY, "ATI Radeon RS250 Mobility IGP"}, \
|
||||
{0x1002, 0x4966, CHIP_RV250, "ATI Radeon If RV250 9000"}, \
|
||||
{0x1002, 0x4967, CHIP_RV250, "ATI Radeon Ig RV250 9000"}, \
|
||||
{0x1002, 0x4A48, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon JH R420 X800"}, \
|
||||
{0x1002, 0x4A49, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon JI R420 X800 Pro"}, \
|
||||
{0x1002, 0x4A4A, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon JJ R420 X800 SE"}, \
|
||||
{0x1002, 0x4A4B, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon JK R420 X800 XT"}, \
|
||||
{0x1002, 0x4A4C, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon JL R420 X800"}, \
|
||||
{0x1002, 0x4A4D, CHIP_R420|RADEON_NEW_MEMMAP, "ATI FireGL JM X3-256"}, \
|
||||
{0x1002, 0x4A4E, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Radeon JN R420 Mobility M18"}, \
|
||||
{0x1002, 0x4A4F, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon JO R420 X800 SE"}, \
|
||||
{0x1002, 0x4A50, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon JP R420 X800 XT PE"}, \
|
||||
{0x1002, 0x4A54, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon JT R420 AIW X800 VE"}, \
|
||||
{0x1002, 0x4B49, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon R481 X850 XT"}, \
|
||||
{0x1002, 0x4B4A, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon R481 X850 SE"}, \
|
||||
{0x1002, 0x4B4B, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon R481 X850 Pro"}, \
|
||||
{0x1002, 0x4B4C, CHIP_R420|RADEON_NEW_MEMMAP, "ATI Radeon R481 X850 XT PE"}, \
|
||||
{0x1002, 0x4C57, CHIP_RV200|RADEON_IS_MOBILITY, "ATI Radeon LW RV200 Mobility 7500 M7"}, \
|
||||
{0x1002, 0x4C58, CHIP_RV200|RADEON_IS_MOBILITY, "ATI Radeon LX RV200 Mobility FireGL 7800 M7"}, \
|
||||
{0x1002, 0x4C59, CHIP_RV100|RADEON_IS_MOBILITY, "ATI Radeon LY RV100 Mobility M6"}, \
|
||||
{0x1002, 0x4C5A, CHIP_RV100|RADEON_IS_MOBILITY, "ATI Radeon LZ RV100 Mobility M6"}, \
|
||||
{0x1002, 0x4C64, CHIP_RV250|RADEON_IS_MOBILITY, "ATI Radeon Ld RV250 Mobility 9000 M9"}, \
|
||||
{0x1002, 0x4C66, CHIP_RV250, "ATI Radeon Lf RV250 Mobility 9000 M9 / FireMV 2400 PCI"}, \
|
||||
{0x1002, 0x4C67, CHIP_RV250|RADEON_IS_MOBILITY, "ATI Radeon Lg RV250 Mobility 9000 M9"}, \
|
||||
{0x1002, 0x4E44, CHIP_R300, "ATI Radeon ND R300 9700 Pro"}, \
|
||||
{0x1002, 0x4E45, CHIP_R300, "ATI Radeon NE R300 9500 Pro / 9700"}, \
|
||||
{0x1002, 0x4E46, CHIP_R300, "ATI Radeon NF R300 9600TX"}, \
|
||||
{0x1002, 0x4E47, CHIP_R300, "ATI Radeon NG R300 FireGL X1"}, \
|
||||
{0x1002, 0x4E48, CHIP_R350, "ATI Radeon NH R350 9800 Pro"}, \
|
||||
{0x1002, 0x4E49, CHIP_R350, "ATI Radeon NI R350 9800"}, \
|
||||
{0x1002, 0x4E4A, CHIP_R350, "ATI Radeon NJ R360 9800 XT"}, \
|
||||
{0x1002, 0x4E4B, CHIP_R350, "ATI FireGL NK X2"}, \
|
||||
{0x1002, 0x4E50, CHIP_RV350|RADEON_IS_MOBILITY, "ATI Radeon RV350 Mobility 9600 M10 NP"}, \
|
||||
{0x1002, 0x4E51, CHIP_RV350|RADEON_IS_MOBILITY, "ATI Radeon RV350 Mobility 9600 M10 NQ"}, \
|
||||
{0x1002, 0x4E52, CHIP_RV350|RADEON_IS_MOBILITY, "ATI Radeon RV350 Mobility 9600 M11 NR"}, \
|
||||
{0x1002, 0x4E53, CHIP_RV350|RADEON_IS_MOBILITY, "ATI Radeon RV350 Mobility 9600 M10 NS"}, \
|
||||
{0x1002, 0x4E54, CHIP_RV350|RADEON_IS_MOBILITY, "ATI FireGL T2/T2e"}, \
|
||||
{0x1002, 0x4E56, CHIP_RV350|RADEON_IS_MOBILITY, "ATI Radeon Mobility 9550"}, \
|
||||
{0x1002, 0x5144, CHIP_R100|RADEON_SINGLE_CRTC, "ATI Radeon QD R100"}, \
|
||||
{0x1002, 0x5145, CHIP_R100|RADEON_SINGLE_CRTC, "ATI Radeon QE R100"}, \
|
||||
{0x1002, 0x5146, CHIP_R100|RADEON_SINGLE_CRTC, "ATI Radeon QF R100"}, \
|
||||
{0x1002, 0x5147, CHIP_R100|RADEON_SINGLE_CRTC, "ATI Radeon QG R100"}, \
|
||||
{0x1002, 0x5148, CHIP_R200, "ATI Radeon QH R200 8500"}, \
|
||||
{0x1002, 0x514C, CHIP_R200, "ATI Radeon QL R200 8500 LE"}, \
|
||||
{0x1002, 0x514D, CHIP_R200, "ATI Radeon QM R200 9100"}, \
|
||||
{0x1002, 0x5157, CHIP_RV200, "ATI Radeon QW RV200 7500"}, \
|
||||
{0x1002, 0x5158, CHIP_RV200, "ATI Radeon QX RV200 7500"}, \
|
||||
{0x1002, 0x5159, CHIP_RV100, "ATI Radeon QY RV100 7000/VE"}, \
|
||||
{0x1002, 0x515A, CHIP_RV100, "ATI Radeon QZ RV100 7000/VE"}, \
|
||||
{0x1002, 0x515E, CHIP_RV100, "ATI ES1000 RN50"}, \
|
||||
{0x1002, 0x5460, CHIP_RV380|RADEON_IS_MOBILITY, "ATI Radeon Mobility X300 M22"}, \
|
||||
{0x1002, 0x5462, CHIP_RV380|RADEON_IS_MOBILITY, "ATI Radeon Mobility X600 SE M24C"}, \
|
||||
{0x1002, 0x5464, CHIP_RV380|RADEON_IS_MOBILITY, "ATI FireGL M22 GL 5464"}, \
|
||||
{0x1002, 0x5548, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R423 X800"}, \
|
||||
{0x1002, 0x5549, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R423 X800 Pro"}, \
|
||||
{0x1002, 0x554A, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R423 X800 XT PE"}, \
|
||||
{0x1002, 0x554B, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R423 X800 SE"}, \
|
||||
{0x1002, 0x554C, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R430 X800 XTP"}, \
|
||||
{0x1002, 0x554D, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R430 X800 XL"}, \
|
||||
{0x1002, 0x554E, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R430 X800 SE"}, \
|
||||
{0x1002, 0x554F, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R430 X800"}, \
|
||||
{0x1002, 0x5550, CHIP_R423|RADEON_NEW_MEMMAP, "ATI FireGL V7100 R423"}, \
|
||||
{0x1002, 0x5551, CHIP_R423|RADEON_NEW_MEMMAP, "ATI FireGL V5100 R423 UQ"}, \
|
||||
{0x1002, 0x5552, CHIP_R423|RADEON_NEW_MEMMAP, "ATI FireGL unknown R423 UR"}, \
|
||||
{0x1002, 0x5554, CHIP_R423|RADEON_NEW_MEMMAP, "ATI FireGL unknown R423 UT"}, \
|
||||
{0x1002, 0x564A, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V5000 M26"}, \
|
||||
{0x1002, 0x564B, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V5000 M26"}, \
|
||||
{0x1002, 0x564F, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Radeon Mobility X700 XL M26"}, \
|
||||
{0x1002, 0x5652, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Radeon Mobility X700 M26"}, \
|
||||
{0x1002, 0x5653, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Radeon Mobility X700 M26"}, \
|
||||
{0x1002, 0x5657, CHIP_RV410|RADEON_NEW_MEMMAP, "ATI Radeon X550XTX"}, \
|
||||
{0x1002, 0x5834, CHIP_RS300|RADEON_IS_IGP, "ATI Radeon RS300 9100 IGP"}, \
|
||||
{0x1002, 0x5835, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY, "ATI Radeon RS300 Mobility IGP"}, \
|
||||
{0x1002, 0x5954, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_IGPGART, "ATI RS480 XPRESS 200G"}, \
|
||||
{0x1002, 0x5955, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART, "ATI Radeon XPRESS 200M 5955"}, \
|
||||
{0x1002, 0x5974, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART, "ATI Radeon RS482 XPRESS 200"}, \
|
||||
{0x1002, 0x5975, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART, "ATI Radeon RS485 XPRESS 1100 IGP"}, \
|
||||
{0x1002, 0x5960, CHIP_RV280, "ATI Radeon RV280 9250"}, \
|
||||
{0x1002, 0x5961, CHIP_RV280, "ATI Radeon RV280 9200"}, \
|
||||
{0x1002, 0x5962, CHIP_RV280, "ATI Radeon RV280 9200"}, \
|
||||
{0x1002, 0x5964, CHIP_RV280, "ATI Radeon RV280 9200 SE"}, \
|
||||
{0x1002, 0x5965, CHIP_RV280, "ATI FireMV 2200 PCI"}, \
|
||||
{0x1002, 0x5969, CHIP_RV100, "ATI ES1000 RN50"}, \
|
||||
{0x1002, 0x5a41, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART, "ATI Radeon XPRESS 200 5A41 (PCIE)"}, \
|
||||
{0x1002, 0x5a42, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART, "ATI Radeon XPRESS 200M 5A42 (PCIE)"}, \
|
||||
{0x1002, 0x5a61, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART, "ATI Radeon RC410 XPRESS 200"}, \
|
||||
{0x1002, 0x5a62, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART, "ATI Radeon RC410 XPRESS 200M"}, \
|
||||
{0x1002, 0x5b60, CHIP_RV380|RADEON_NEW_MEMMAP, "ATI Radeon RV370 X300 SE"}, \
|
||||
{0x1002, 0x5b62, CHIP_RV380|RADEON_NEW_MEMMAP, "ATI Radeon RV370 X600 Pro"}, \
|
||||
{0x1002, 0x5b63, CHIP_RV380|RADEON_NEW_MEMMAP, "ATI Radeon RV370 X550"}, \
|
||||
{0x1002, 0x5b64, CHIP_RV380|RADEON_NEW_MEMMAP, "ATI FireGL V3100 (RV370) 5B64"}, \
|
||||
{0x1002, 0x5b65, CHIP_RV380|RADEON_NEW_MEMMAP, "ATI FireMV 2200 PCIE (RV370) 5B65"}, \
|
||||
{0x1002, 0x5c61, CHIP_RV280|RADEON_IS_MOBILITY, "ATI Radeon RV280 Mobility"}, \
|
||||
{0x1002, 0x5c63, CHIP_RV280|RADEON_IS_MOBILITY, "ATI Radeon RV280 Mobility"}, \
|
||||
{0x1002, 0x5d48, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X800 XT M28"}, \
|
||||
{0x1002, 0x5d49, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V5100 M28"}, \
|
||||
{0x1002, 0x5d4a, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X800 M28"}, \
|
||||
{0x1002, 0x5d4c, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R480 X850"}, \
|
||||
{0x1002, 0x5d4d, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R480 X850 XT PE"}, \
|
||||
{0x1002, 0x5d4e, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R480 X850 SE"}, \
|
||||
{0x1002, 0x5d4f, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R480 X850 Pro"}, \
|
||||
{0x1002, 0x5d50, CHIP_R423|RADEON_NEW_MEMMAP, "ATI unknown Radeon / FireGL R480"}, \
|
||||
{0x1002, 0x5d52, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R480 X850 XT"}, \
|
||||
{0x1002, 0x5d57, CHIP_R423|RADEON_NEW_MEMMAP, "ATI Radeon R423 X800 XT"}, \
|
||||
{0x1002, 0x5e48, CHIP_RV410|RADEON_NEW_MEMMAP, "ATI FireGL V5000 RV410"}, \
|
||||
{0x1002, 0x5e4a, CHIP_RV410|RADEON_NEW_MEMMAP, "ATI Radeon RV410 X700 XT"}, \
|
||||
{0x1002, 0x5e4b, CHIP_RV410|RADEON_NEW_MEMMAP, "ATI Radeon RV410 X700 Pro"}, \
|
||||
{0x1002, 0x5e4c, CHIP_RV410|RADEON_NEW_MEMMAP, "ATI Radeon RV410 X700 SE"}, \
|
||||
{0x1002, 0x5e4d, CHIP_RV410|RADEON_NEW_MEMMAP, "ATI Radeon RV410 X700"}, \
|
||||
{0x1002, 0x5e4f, CHIP_RV410|RADEON_NEW_MEMMAP, "ATI Radeon RV410 X700 SE"}, \
|
||||
{0x1002, 0x7100, CHIP_R520|RADEON_NEW_MEMMAP, "ATI Radeon X1800"}, \
|
||||
{0x1002, 0x7101, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1800 XT"}, \
|
||||
{0x1002, 0x7102, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1800"}, \
|
||||
{0x1002, 0x7103, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V7200"}, \
|
||||
{0x1002, 0x7104, CHIP_R520|RADEON_NEW_MEMMAP, "ATI FireGL V7200"}, \
|
||||
{0x1002, 0x7105, CHIP_R520|RADEON_NEW_MEMMAP, "ATI FireGL V5300"}, \
|
||||
{0x1002, 0x7106, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V7100"}, \
|
||||
{0x1002, 0x7108, CHIP_R520|RADEON_NEW_MEMMAP, "ATI Radeon X1800"}, \
|
||||
{0x1002, 0x7109, CHIP_R520|RADEON_NEW_MEMMAP, "ATI Radeon X1800"}, \
|
||||
{0x1002, 0x710A, CHIP_R520|RADEON_NEW_MEMMAP, "ATI Radeon X1800"}, \
|
||||
{0x1002, 0x710B, CHIP_R520|RADEON_NEW_MEMMAP, "ATI Radeon X1800"}, \
|
||||
{0x1002, 0x710C, CHIP_R520|RADEON_NEW_MEMMAP, "ATI Radeon X1800"}, \
|
||||
{0x1002, 0x710E, CHIP_R520|RADEON_NEW_MEMMAP, "ATI FireGL V7300"}, \
|
||||
{0x1002, 0x710F, CHIP_R520|RADEON_NEW_MEMMAP, "ATI FireGL V7350"}, \
|
||||
{0x1002, 0x7140, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1600"}, \
|
||||
{0x1002, 0x7141, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI RV505"}, \
|
||||
{0x1002, 0x7142, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300/X1550"}, \
|
||||
{0x1002, 0x7143, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1550"}, \
|
||||
{0x1002, 0x7144, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI M54-GL"}, \
|
||||
{0x1002, 0x7145, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1400"}, \
|
||||
{0x1002, 0x7146, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300/X1550"}, \
|
||||
{0x1002, 0x7147, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1550 64-bit"}, \
|
||||
{0x1002, 0x7149, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1300"}, \
|
||||
{0x1002, 0x714A, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1300"}, \
|
||||
{0x1002, 0x714B, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1300"}, \
|
||||
{0x1002, 0x714C, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1300"}, \
|
||||
{0x1002, 0x714D, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300"}, \
|
||||
{0x1002, 0x714E, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300"}, \
|
||||
{0x1002, 0x714F, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI RV505"}, \
|
||||
{0x1002, 0x7151, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI RV505"}, \
|
||||
{0x1002, 0x7152, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI FireGL V3300"}, \
|
||||
{0x1002, 0x7153, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI FireGL V3350"}, \
|
||||
{0x1002, 0x715E, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300"}, \
|
||||
{0x1002, 0x715F, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1550 64-bit"}, \
|
||||
{0x1002, 0x7180, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300/X1550"}, \
|
||||
{0x1002, 0x7181, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1600"}, \
|
||||
{0x1002, 0x7183, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300/X1550"}, \
|
||||
{0x1002, 0x7186, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1450"}, \
|
||||
{0x1002, 0x7187, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300/X1550"}, \
|
||||
{0x1002, 0x7188, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X2300"}, \
|
||||
{0x1002, 0x718A, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X2300"}, \
|
||||
{0x1002, 0x718B, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1350"}, \
|
||||
{0x1002, 0x718C, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1350"}, \
|
||||
{0x1002, 0x718D, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1450"}, \
|
||||
{0x1002, 0x718F, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1300"}, \
|
||||
{0x1002, 0x7193, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1550"}, \
|
||||
{0x1002, 0x7196, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1350"}, \
|
||||
{0x1002, 0x719B, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI FireMV 2250"}, \
|
||||
{0x1002, 0x719F, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X1550 64-bit"}, \
|
||||
{0x1002, 0x71C0, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI Radeon X1600"}, \
|
||||
{0x1002, 0x71C1, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI Radeon X1650"}, \
|
||||
{0x1002, 0x71C2, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI Radeon X1600"}, \
|
||||
{0x1002, 0x71C3, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI Radeon X1600"}, \
|
||||
{0x1002, 0x71C4, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V5200"}, \
|
||||
{0x1002, 0x71C5, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1600"}, \
|
||||
{0x1002, 0x71C6, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI Radeon X1650"}, \
|
||||
{0x1002, 0x71C7, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI Radeon X1650"}, \
|
||||
{0x1002, 0x71CD, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI Radeon X1600"}, \
|
||||
{0x1002, 0x71CE, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI Radeon X1300 XT/X1600 Pro"}, \
|
||||
{0x1002, 0x71D2, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI FireGL V3400"}, \
|
||||
{0x1002, 0x71D4, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V5250"}, \
|
||||
{0x1002, 0x71D5, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1700"}, \
|
||||
{0x1002, 0x71D6, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1700 XT"}, \
|
||||
{0x1002, 0x71DA, CHIP_RV530|RADEON_NEW_MEMMAP, "ATI FireGL V5200"}, \
|
||||
{0x1002, 0x71DE, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1700"}, \
|
||||
{0x1002, 0x7200, CHIP_RV515|RADEON_NEW_MEMMAP, "ATI Radeon X2300HD"}, \
|
||||
{0x1002, 0x7210, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 2300"}, \
|
||||
{0x1002, 0x7211, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 2300"}, \
|
||||
{0x1002, 0x7240, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1950"}, \
|
||||
{0x1002, 0x7243, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x7244, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1950"}, \
|
||||
{0x1002, 0x7245, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x7246, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x7247, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x7248, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x7249, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x724A, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x724B, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x724C, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x724D, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x724E, CHIP_R580|RADEON_NEW_MEMMAP, "ATI AMD Stream Processor"}, \
|
||||
{0x1002, 0x724F, CHIP_R580|RADEON_NEW_MEMMAP, "ATI Radeon X1900"}, \
|
||||
{0x1002, 0x7280, CHIP_RV570|RADEON_NEW_MEMMAP, "ATI Radeon X1950"}, \
|
||||
{0x1002, 0x7281, CHIP_RV560|RADEON_NEW_MEMMAP, "ATI RV560"}, \
|
||||
{0x1002, 0x7283, CHIP_RV560|RADEON_NEW_MEMMAP, "ATI RV560"}, \
|
||||
{0x1002, 0x7284, CHIP_R580|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon X1900"}, \
|
||||
{0x1002, 0x7287, CHIP_RV560|RADEON_NEW_MEMMAP, "ATI RV560"}, \
|
||||
{0x1002, 0x7288, CHIP_RV570|RADEON_NEW_MEMMAP, "ATI Radeon X1950 GT"}, \
|
||||
{0x1002, 0x7289, CHIP_RV570|RADEON_NEW_MEMMAP, "ATI RV570"}, \
|
||||
{0x1002, 0x728B, CHIP_RV570|RADEON_NEW_MEMMAP, "ATI RV570"}, \
|
||||
{0x1002, 0x728C, CHIP_RV570|RADEON_NEW_MEMMAP, "ATI ATI FireGL V7400"}, \
|
||||
{0x1002, 0x7290, CHIP_RV560|RADEON_NEW_MEMMAP, "ATI RV560"}, \
|
||||
{0x1002, 0x7291, CHIP_RV560|RADEON_NEW_MEMMAP, "ATI Radeon X1650"}, \
|
||||
{0x1002, 0x7293, CHIP_RV560|RADEON_NEW_MEMMAP, "ATI Radeon X1650"}, \
|
||||
{0x1002, 0x7297, CHIP_RV560|RADEON_NEW_MEMMAP, "ATI RV560"}, \
|
||||
{0x1002, 0x7834, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP, "ATI Radeon RS350 9000/9100 IGP"}, \
|
||||
{0x1002, 0x7835, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Radeon RS350 Mobility IGP"}, \
|
||||
{0x1002, 0x793f, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP, "ATI Radeon X1200"}, \
|
||||
{0x1002, 0x7941, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP, "ATI Radeon X1200"}, \
|
||||
{0x1002, 0x7942, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP, "ATI Radeon X1200"}, \
|
||||
{0x1002, 0x791e, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART, "ATI Radeon RS690 X1250 IGP"}, \
|
||||
{0x1002, 0x791f, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART, "ATI Radeon RS690 X1270 IGP"}, \
|
||||
{0x1002, 0x796c, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART, "ATI Radeon RS740 HD2100 IGP"}, \
|
||||
{0x1002, 0x796d, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART, "ATI Radeon RS740 HD2100 IGP"}, \
|
||||
{0x1002, 0x796e, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART, "ATI Radeon RS740 HD2100 IGP"}, \
|
||||
{0x1002, 0x796f, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART, "ATI Radeon RS740 HD2100 IGP"}, \
|
||||
{0x1002, 0x9400, CHIP_R600|RADEON_NEW_MEMMAP, "ATI Radeon HD 2900 XT"}, \
|
||||
{0x1002, 0x9401, CHIP_R600|RADEON_NEW_MEMMAP, "ATI Radeon HD 2900 XT"}, \
|
||||
{0x1002, 0x9402, CHIP_R600|RADEON_NEW_MEMMAP, "ATI Radeon HD 2900 XT"}, \
|
||||
{0x1002, 0x9403, CHIP_R600|RADEON_NEW_MEMMAP, "ATI Radeon HD 2900 Pro"}, \
|
||||
{0x1002, 0x9405, CHIP_R600|RADEON_NEW_MEMMAP, "ATI Radeon HD 2900 GT"}, \
|
||||
{0x1002, 0x940A, CHIP_R600|RADEON_NEW_MEMMAP, "ATI FireGL V8650"}, \
|
||||
{0x1002, 0x940B, CHIP_R600|RADEON_NEW_MEMMAP, "ATI FireGL V8600"}, \
|
||||
{0x1002, 0x940F, CHIP_R600|RADEON_NEW_MEMMAP, "ATI FireGL V7600"}, \
|
||||
{0x1002, 0x94A0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 4830"}, \
|
||||
{0x1002, 0x94A1, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 4850"}, \
|
||||
{0x1002, 0x94A3, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI FirePro M7740"}, \
|
||||
{0x1002, 0x94B1, CHIP_RV740|RADEON_NEW_MEMMAP, "ATI RV740"}, \
|
||||
{0x1002, 0x94B3, CHIP_RV740|RADEON_NEW_MEMMAP, "ATI Radeon HD 4770"}, \
|
||||
{0x1002, 0x94B4, CHIP_RV740|RADEON_NEW_MEMMAP, "ATI Radeon HD 4700 Series"}, \
|
||||
{0x1002, 0x94B5, CHIP_RV740|RADEON_NEW_MEMMAP, "ATI Radeon HD 4770"}, \
|
||||
{0x1002, 0x94B9, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI FirePro M5750"}, \
|
||||
{0x1002, 0x94C0, CHIP_RV610|RADEON_NEW_MEMMAP, "RV610"}, \
|
||||
{0x1002, 0x94C1, CHIP_RV610|RADEON_NEW_MEMMAP, "Radeon HD 2400 XT"}, \
|
||||
{0x1002, 0x94C3, CHIP_RV610|RADEON_NEW_MEMMAP, "Radeon HD 2400 Pro"}, \
|
||||
{0x1002, 0x94C4, CHIP_RV610|RADEON_NEW_MEMMAP, "Radeon HD 2400 PRO AGP"}, \
|
||||
{0x1002, 0x94C5, CHIP_RV610|RADEON_NEW_MEMMAP, "FireGL V4000"}, \
|
||||
{0x1002, 0x94C6, CHIP_RV610|RADEON_NEW_MEMMAP, "RV610"}, \
|
||||
{0x1002, 0x94C7, CHIP_RV610|RADEON_NEW_MEMMAP, "ATI Radeon HD 2350"}, \
|
||||
{0x1002, 0x94C8, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 2400 XT"}, \
|
||||
{0x1002, 0x94C9, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 2400"}, \
|
||||
{0x1002, 0x94CB, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI RADEON E2400"}, \
|
||||
{0x1002, 0x94CC, CHIP_RV610|RADEON_NEW_MEMMAP, "ATI RV610"}, \
|
||||
{0x1002, 0x94CD, CHIP_RV610|RADEON_NEW_MEMMAP, "ATI FireMV 2260"}, \
|
||||
{0x1002, 0x9500, CHIP_RV670|RADEON_NEW_MEMMAP, "ATI RV670"}, \
|
||||
{0x1002, 0x9501, CHIP_RV670|RADEON_NEW_MEMMAP, "ATI Radeon HD3870"}, \
|
||||
{0x1002, 0x9504, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 3850"}, \
|
||||
{0x1002, 0x9505, CHIP_RV670|RADEON_NEW_MEMMAP, "ATI Radeon HD3850"}, \
|
||||
{0x1002, 0x9506, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 3850 X2"}, \
|
||||
{0x1002, 0x9507, CHIP_RV670|RADEON_NEW_MEMMAP, "ATI RV670"}, \
|
||||
{0x1002, 0x9508, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 3870"}, \
|
||||
{0x1002, 0x9509, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 3870 X2"}, \
|
||||
{0x1002, 0x950F, CHIP_RV670|RADEON_NEW_MEMMAP, "ATI Radeon HD3870 X2"}, \
|
||||
{0x1002, 0x9511, CHIP_RV670|RADEON_NEW_MEMMAP, "ATI FireGL V7700"}, \
|
||||
{0x1002, 0x9515, CHIP_RV670|RADEON_NEW_MEMMAP, "ATI Radeon HD3850"}, \
|
||||
{0x1002, 0x9517, CHIP_RV670|RADEON_NEW_MEMMAP, "ATI Radeon HD3690"}, \
|
||||
{0x1002, 0x9519, CHIP_RV670|RADEON_NEW_MEMMAP, "AMD Firestream 9170"}, \
|
||||
{0x1002, 0x9580, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI RV630"}, \
|
||||
{0x1002, 0x9581, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 2600"}, \
|
||||
{0x1002, 0x9583, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 2600 XT"}, \
|
||||
{0x1002, 0x9586, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI Radeon HD 2600 XT AGP"}, \
|
||||
{0x1002, 0x9587, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI Radeon HD 2600 Pro AGP"}, \
|
||||
{0x1002, 0x9588, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI Radeon HD 2600 XT"}, \
|
||||
{0x1002, 0x9589, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI Radeon HD 2600 Pro"}, \
|
||||
{0x1002, 0x958A, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI Gemini RV630"}, \
|
||||
{0x1002, 0x958B, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Gemini Mobility Radeon HD 2600 XT"}, \
|
||||
{0x1002, 0x958C, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI FireGL V5600"}, \
|
||||
{0x1002, 0x958D, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI FireGL V3600"}, \
|
||||
{0x1002, 0x958E, CHIP_RV630|RADEON_NEW_MEMMAP, "ATI Radeon HD 2600 LE"}, \
|
||||
{0x1002, 0x958F, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL Graphics Processor"}, \
|
||||
{0x1002, 0x95C0, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI Radeon HD 3470"}, \
|
||||
{0x1002, 0x95C5, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI Radeon HD 3450"}, \
|
||||
{0x1002, 0x95C6, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI Radeon HD 3450"}, \
|
||||
{0x1002, 0x95C7, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI Radeon HD 3430"}, \
|
||||
{0x1002, 0x95C9, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI Radeon HD 3450"}, \
|
||||
{0x1002, 0x95C2, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 3430"}, \
|
||||
{0x1002, 0x95C4, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 3400 Series"}, \
|
||||
{0x1002, 0x95CC, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI FirePro V3700"}, \
|
||||
{0x1002, 0x95CD, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI FireMV 2450"}, \
|
||||
{0x1002, 0x95CE, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI FireMV 2260"}, \
|
||||
{0x1002, 0x95CF, CHIP_RV620|RADEON_NEW_MEMMAP, "ATI FireMV 2260"}, \
|
||||
{0x1002, 0x9590, CHIP_RV635|RADEON_NEW_MEMMAP, "ATI ATI Radeon HD 3600 Series"}, \
|
||||
{0x1002, 0x9596, CHIP_RV635|RADEON_NEW_MEMMAP, "ATI ATI Radeon HD 3650 AGP"}, \
|
||||
{0x1002, 0x9597, CHIP_RV635|RADEON_NEW_MEMMAP, "ATI ATI Radeon HD 3600 PRO"}, \
|
||||
{0x1002, 0x9598, CHIP_RV635|RADEON_NEW_MEMMAP, "ATI ATI Radeon HD 3600 XT"}, \
|
||||
{0x1002, 0x9599, CHIP_RV635|RADEON_NEW_MEMMAP, "ATI ATI Radeon HD 3600 PRO"}, \
|
||||
{0x1002, 0x9591, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 3650"}, \
|
||||
{0x1002, 0x9593, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 3670"}, \
|
||||
{0x1002, 0x9595, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V5700"}, \
|
||||
{0x1002, 0x959B, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility FireGL V5725"}, \
|
||||
{0x1002, 0x9610, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon HD 3200 Graphics"}, \
|
||||
{0x1002, 0x9611, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon 3100 Graphics"}, \
|
||||
{0x1002, 0x9612, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon HD 3200 Graphics"}, \
|
||||
{0x1002, 0x9613, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon 3100 Graphics"}, \
|
||||
{0x1002, 0x9614, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon 3300 Graphics"}, \
|
||||
{0x1002, 0x9615, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon 3200 Graphics"}, \
|
||||
{0x1002, 0x9616, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon 3000 Graphics"}, \
|
||||
{0x1002, 0x9710, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon HD 4200"}, \
|
||||
{0x1002, 0x9711, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon 4100"}, \
|
||||
{0x1002, 0x9712, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Mobility Radeon HD 4200"}, \
|
||||
{0x1002, 0x9713, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Mobility Radeon 4100"}, \
|
||||
{0x1002, 0x9714, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI RS880"}, \
|
||||
{0x1002, 0x9715, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "ATI Radeon HD 4250"}, \
|
||||
{0x1002, 0x9440, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4800 Series"}, \
|
||||
{0x1002, 0x9441, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4870 X2"}, \
|
||||
{0x1002, 0x9442, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4800 Series"}, \
|
||||
{0x1002, 0x9443, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4850 X2"}, \
|
||||
{0x1002, 0x944C, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4800 Series"}, \
|
||||
{0x1002, 0x9450, CHIP_RV770|RADEON_NEW_MEMMAP, "AMD FireStream 9270"}, \
|
||||
{0x1002, 0x9452, CHIP_RV770|RADEON_NEW_MEMMAP, "AMD FireStream 9250"}, \
|
||||
{0x1002, 0x9444, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI FirePro V8750 (FireGL)"}, \
|
||||
{0x1002, 0x9446, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI FirePro V7760 (FireGL)"}, \
|
||||
{0x1002, 0x9456, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI FirePro V8700 (FireGL)"}, \
|
||||
{0x1002, 0x944E, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI FirePro RV770"}, \
|
||||
{0x1002, 0x944A, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 4850"}, \
|
||||
{0x1002, 0x944B, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 4850 X2"}, \
|
||||
{0x1002, 0x945A, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 4870"}, \
|
||||
{0x1002, 0x945B, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon M98"}, \
|
||||
{0x1002, 0x9460, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4800 Series"}, \
|
||||
{0x1002, 0x9462, CHIP_RV770|RADEON_NEW_MEMMAP, "ATI Radeon 4800 Series"}, \
|
||||
{0x1002, 0x946A, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI FirePro M7750"}, \
|
||||
{0x1002, 0x946B, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI M98"}, \
|
||||
{0x1002, 0x947A, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI M98"}, \
|
||||
{0x1002, 0x947B, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI M98"}, \
|
||||
{0x1002, 0x9487, CHIP_RV730|RADEON_NEW_MEMMAP, "ATI Radeon RV730 (AGP)"}, \
|
||||
{0x1002, 0x948F, CHIP_RV730|RADEON_NEW_MEMMAP, "ATI Radeon RV730 (AGP)"}, \
|
||||
{0x1002, 0x9490, CHIP_RV730|RADEON_NEW_MEMMAP, "ATI Radeon HD 4670"}, \
|
||||
{0x1002, 0x9495, CHIP_RV730|RADEON_NEW_MEMMAP, "ATI Radeon HD 4600 Series"}, \
|
||||
{0x1002, 0x9498, CHIP_RV730|RADEON_NEW_MEMMAP, "ATI Radeon HD 4650"}, \
|
||||
{0x1002, 0x9480, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 4650"}, \
|
||||
{0x1002, 0x9488, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon HD 4670"}, \
|
||||
{0x1002, 0x9489, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI FirePro M5750"}, \
|
||||
{0x1002, 0x9491, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI RADEON E4600"}, \
|
||||
{0x1002, 0x949C, CHIP_RV730|RADEON_NEW_MEMMAP, "ATI FirePro V7750 (FireGL)"}, \
|
||||
{0x1002, 0x949E, CHIP_RV730|RADEON_NEW_MEMMAP, "ATI FirePro V5700 (FireGL)"}, \
|
||||
{0x1002, 0x949F, CHIP_RV730|RADEON_NEW_MEMMAP, "ATI FirePro V3750 (FireGL)"}, \
|
||||
{0x1002, 0x9540, CHIP_RV710|RADEON_NEW_MEMMAP, "ATI Radeon HD 4550"}, \
|
||||
{0x1002, 0x9541, CHIP_RV710|RADEON_NEW_MEMMAP, "ATI Radeon RV710"}, \
|
||||
{0x1002, 0x9542, CHIP_RV710|RADEON_NEW_MEMMAP, "ATI Radeon RV710"}, \
|
||||
{0x1002, 0x954E, CHIP_RV710|RADEON_NEW_MEMMAP, "ATI Radeon RV710"}, \
|
||||
{0x1002, 0x954F, CHIP_RV710|RADEON_NEW_MEMMAP, "ATI Radeon HD 4350"}, \
|
||||
{0x1002, 0x9552, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon 4300 Series"}, \
|
||||
{0x1002, 0x9553, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon 4500 Series"}, \
|
||||
{0x1002, 0x9555, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI Mobility Radeon 4500 Series"}, \
|
||||
{0x1002, 0x9557, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "ATI FirePro RG220"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define r128_PCI_IDS \
|
||||
{0x1002, 0x4c45, 0, "ATI Rage 128 Mobility LE (PCI)"}, \
|
||||
{0x1002, 0x4c46, 0, "ATI Rage 128 Mobility LF (AGP)"}, \
|
||||
{0x1002, 0x4d46, 0, "ATI Rage 128 Mobility MF (AGP)"}, \
|
||||
{0x1002, 0x4d4c, 0, "ATI Rage 128 Mobility ML (AGP)"}, \
|
||||
{0x1002, 0x5041, 0, "ATI Rage 128 Pro PA (PCI)"}, \
|
||||
{0x1002, 0x5042, 0, "ATI Rage 128 Pro PB (AGP)"}, \
|
||||
{0x1002, 0x5043, 0, "ATI Rage 128 Pro PC (AGP)"}, \
|
||||
{0x1002, 0x5044, 0, "ATI Rage 128 Pro PD (PCI)"}, \
|
||||
{0x1002, 0x5045, 0, "ATI Rage 128 Pro PE (AGP)"}, \
|
||||
{0x1002, 0x5046, 0, "ATI Rage 128 Pro PF (AGP)"}, \
|
||||
{0x1002, 0x5047, 0, "ATI Rage 128 Pro PG (PCI)"}, \
|
||||
{0x1002, 0x5048, 0, "ATI Rage 128 Pro PH (AGP)"}, \
|
||||
{0x1002, 0x5049, 0, "ATI Rage 128 Pro PI (AGP)"}, \
|
||||
{0x1002, 0x504A, 0, "ATI Rage 128 Pro PJ (PCI)"}, \
|
||||
{0x1002, 0x504B, 0, "ATI Rage 128 Pro PK (AGP)"}, \
|
||||
{0x1002, 0x504C, 0, "ATI Rage 128 Pro PL (AGP)"}, \
|
||||
{0x1002, 0x504D, 0, "ATI Rage 128 Pro PM (PCI)"}, \
|
||||
{0x1002, 0x504E, 0, "ATI Rage 128 Pro PN (AGP)"}, \
|
||||
{0x1002, 0x504F, 0, "ATI Rage 128 Pro PO (AGP)"}, \
|
||||
{0x1002, 0x5050, 0, "ATI Rage 128 Pro PP (PCI)"}, \
|
||||
{0x1002, 0x5051, 0, "ATI Rage 128 Pro PQ (AGP)"}, \
|
||||
{0x1002, 0x5052, 0, "ATI Rage 128 Pro PR (PCI)"}, \
|
||||
{0x1002, 0x5053, 0, "ATI Rage 128 Pro PS (PCI)"}, \
|
||||
{0x1002, 0x5054, 0, "ATI Rage 128 Pro PT (AGP)"}, \
|
||||
{0x1002, 0x5055, 0, "ATI Rage 128 Pro PU (AGP)"}, \
|
||||
{0x1002, 0x5056, 0, "ATI Rage 128 Pro PV (PCI)"}, \
|
||||
{0x1002, 0x5057, 0, "ATI Rage 128 Pro PW (AGP)"}, \
|
||||
{0x1002, 0x5058, 0, "ATI Rage 128 Pro PX (AGP)"}, \
|
||||
{0x1002, 0x5245, 0, "ATI Rage 128 RE (PCI)"}, \
|
||||
{0x1002, 0x5246, 0, "ATI Rage 128 RF (AGP)"}, \
|
||||
{0x1002, 0x5247, 0, "ATI Rage 128 RG (AGP)"}, \
|
||||
{0x1002, 0x524b, 0, "ATI Rage 128 RK (PCI)"}, \
|
||||
{0x1002, 0x524c, 0, "ATI Rage 128 RL (AGP)"}, \
|
||||
{0x1002, 0x534d, 0, "ATI Rage 128 SM (AGP)"}, \
|
||||
{0x1002, 0x5446, 0, "ATI Rage 128 Pro Ultra TF (AGP)"}, \
|
||||
{0x1002, 0x544C, 0, "ATI Rage 128 Pro Ultra TL (AGP)"}, \
|
||||
{0x1002, 0x5452, 0, "ATI Rage 128 Pro Ultra TR (AGP)"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define mga_PCI_IDS \
|
||||
{0x102b, 0x0520, MGA_CARD_TYPE_G200, "Matrox G200 (PCI)"}, \
|
||||
{0x102b, 0x0521, MGA_CARD_TYPE_G200, "Matrox G200 (AGP)"}, \
|
||||
{0x102b, 0x0525, MGA_CARD_TYPE_G400, "Matrox G400/G450 (AGP)"}, \
|
||||
{0x102b, 0x2527, MGA_CARD_TYPE_G550, "Matrox G550 (AGP)"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define mach64_PCI_IDS \
|
||||
{0x1002, 0x4749, 0, "3D Rage Pro"}, \
|
||||
{0x1002, 0x4750, 0, "3D Rage Pro 215GP"}, \
|
||||
{0x1002, 0x4751, 0, "3D Rage Pro 215GQ"}, \
|
||||
{0x1002, 0x4742, 0, "3D Rage Pro AGP 1X/2X"}, \
|
||||
{0x1002, 0x4744, 0, "3D Rage Pro AGP 1X"}, \
|
||||
{0x1002, 0x4c49, 0, "3D Rage LT Pro"}, \
|
||||
{0x1002, 0x4c50, 0, "3D Rage LT Pro"}, \
|
||||
{0x1002, 0x4c51, 0, "3D Rage LT Pro"}, \
|
||||
{0x1002, 0x4c42, 0, "3D Rage LT Pro AGP-133"}, \
|
||||
{0x1002, 0x4c44, 0, "3D Rage LT Pro AGP-66"}, \
|
||||
{0x1002, 0x474c, 0, "Rage XC"}, \
|
||||
{0x1002, 0x474f, 0, "Rage XL"}, \
|
||||
{0x1002, 0x4752, 0, "Rage XL"}, \
|
||||
{0x1002, 0x4753, 0, "Rage XC"}, \
|
||||
{0x1002, 0x474d, 0, "Rage XL AGP 2X"}, \
|
||||
{0x1002, 0x474e, 0, "Rage XC AGP"}, \
|
||||
{0x1002, 0x4c52, 0, "Rage Mobility P/M"}, \
|
||||
{0x1002, 0x4c53, 0, "Rage Mobility L"}, \
|
||||
{0x1002, 0x4c4d, 0, "Rage Mobility P/M AGP 2X"}, \
|
||||
{0x1002, 0x4c4e, 0, "Rage Mobility L AGP 2X"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define sis_PCI_IDS \
|
||||
{0x1039, 0x0300, 0, "SiS 300/305"}, \
|
||||
{0x1039, 0x5300, 0, "SiS 540"}, \
|
||||
{0x1039, 0x6300, 0, "SiS 630"}, \
|
||||
{0x1039, 0x6330, SIS_CHIP_315, "SiS 661"}, \
|
||||
{0x1039, 0x7300, 0, "SiS 730"}, \
|
||||
{0x18CA, 0x0040, SIS_CHIP_315, "Volari V3XT/V5/V8"}, \
|
||||
{0x18CA, 0x0042, SIS_CHIP_315, "Volari Unknown"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define tdfx_PCI_IDS \
|
||||
{0x121a, 0x0003, 0, "3dfx Voodoo Banshee"}, \
|
||||
{0x121a, 0x0004, 0, "3dfx Voodoo3 2000"}, \
|
||||
{0x121a, 0x0005, 0, "3dfx Voodoo3 3000"}, \
|
||||
{0x121a, 0x0007, 0, "3dfx Voodoo4 4500"}, \
|
||||
{0x121a, 0x0009, 0, "3dfx Voodoo5 5500"}, \
|
||||
{0x121a, 0x000b, 0, "3dfx Voodoo4 4200"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define viadrv_PCI_IDS \
|
||||
{0x1106, 0x3022, 0, "VIA CLE266 3022"}, \
|
||||
{0x1106, 0x3118, VIA_PRO_GROUP_A, "VIA CN400 / PM8X0"}, \
|
||||
{0x1106, 0x3122, 0, "VIA CLE266"}, \
|
||||
{0x1106, 0x7205, 0, "VIA KM400"}, \
|
||||
{0x1106, 0x3108, 0, "VIA K8M800"}, \
|
||||
{0x1106, 0x3344, 0, "VIA CN700 / VM800 / P4M800Pro"}, \
|
||||
{0x1106, 0x3343, 0, "VIA P4M890"}, \
|
||||
{0x1106, 0x3230, VIA_DX9_0, "VIA K8M890"}, \
|
||||
{0x1106, 0x3157, VIA_PRO_GROUP_A, "VIA CX700"}, \
|
||||
{0x1106, 0x3371, VIA_DX9_0, "VIA P4M900 / VN896"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define i810_PCI_IDS \
|
||||
{0x8086, 0x7121, 0, "Intel i810 GMCH"}, \
|
||||
{0x8086, 0x7123, 0, "Intel i810-DC100 GMCH"}, \
|
||||
{0x8086, 0x7125, 0, "Intel i810E GMCH"}, \
|
||||
{0x8086, 0x1132, 0, "Intel i815 GMCH"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define i830_PCI_IDS \
|
||||
{0x8086, 0x3577, 0, "Intel i830M GMCH"}, \
|
||||
{0x8086, 0x2562, 0, "Intel i845G GMCH"}, \
|
||||
{0x8086, 0x3582, 0, "Intel i852GM/i855GM GMCH"}, \
|
||||
{0x8086, 0x2572, 0, "Intel i865G GMCH"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define gamma_PCI_IDS \
|
||||
{0x3d3d, 0x0008, 0, "3DLabs GLINT Gamma G1"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define savage_PCI_IDS \
|
||||
{0x5333, 0x8a20, S3_SAVAGE3D, "Savage 3D"}, \
|
||||
{0x5333, 0x8a21, S3_SAVAGE3D, "Savage 3D/MV"}, \
|
||||
{0x5333, 0x8a22, S3_SAVAGE4, "Savage4"}, \
|
||||
{0x5333, 0x8a23, S3_SAVAGE4, "Savage4"}, \
|
||||
{0x5333, 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV"}, \
|
||||
{0x5333, 0x8c11, S3_SAVAGE_MX, "Savage/MX"}, \
|
||||
{0x5333, 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV"}, \
|
||||
{0x5333, 0x8c13, S3_SAVAGE_MX, "Savage/IX"}, \
|
||||
{0x5333, 0x8c22, S3_SUPERSAVAGE, "SuperSavage MX/128"}, \
|
||||
{0x5333, 0x8c24, S3_SUPERSAVAGE, "SuperSavage MX/64"}, \
|
||||
{0x5333, 0x8c26, S3_SUPERSAVAGE, "SuperSavage MX/64C"}, \
|
||||
{0x5333, 0x8c2a, S3_SUPERSAVAGE, "SuperSavage IX/128 SDR"}, \
|
||||
{0x5333, 0x8c2b, S3_SUPERSAVAGE, "SuperSavage IX/128 DDR"}, \
|
||||
{0x5333, 0x8c2c, S3_SUPERSAVAGE, "SuperSavage IX/64 SDR"}, \
|
||||
{0x5333, 0x8c2d, S3_SUPERSAVAGE, "SuperSavage IX/64 DDR"}, \
|
||||
{0x5333, 0x8c2e, S3_SUPERSAVAGE, "SuperSavage IX/C SDR"}, \
|
||||
{0x5333, 0x8c2f, S3_SUPERSAVAGE, "SuperSavage IX/C DDR"}, \
|
||||
{0x5333, 0x8a25, S3_PROSAVAGE, "ProSavage PM133"}, \
|
||||
{0x5333, 0x8a26, S3_PROSAVAGE, "ProSavage KM133"}, \
|
||||
{0x5333, 0x8d01, S3_TWISTER, "ProSavage Twister PN133"}, \
|
||||
{0x5333, 0x8d02, S3_TWISTER, "ProSavage Twister KN133"}, \
|
||||
{0x5333, 0x8d03, S3_PROSAVAGEDDR, "ProSavage DDR"}, \
|
||||
{0x5333, 0x8d04, S3_PROSAVAGEDDR, "ProSavage DDR-K"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define ffb_PCI_IDS \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define i915_PCI_IDS \
|
||||
{0x8086, 0x3577, CHIP_I8XX, "Intel i830M GMCH"}, \
|
||||
{0x8086, 0x2562, CHIP_I8XX, "Intel i845G GMCH"}, \
|
||||
{0x8086, 0x3582, CHIP_I8XX, "Intel i852GM/i855GM GMCH"}, \
|
||||
{0x8086, 0x358e, CHIP_I8XX, "Intel i852GM/i855GM GMCH"}, \
|
||||
{0x8086, 0x2572, CHIP_I8XX, "Intel i865G GMCH"}, \
|
||||
{0x8086, 0x2582, CHIP_I9XX|CHIP_I915, "Intel i915G"}, \
|
||||
{0x8086, 0x258a, CHIP_I9XX|CHIP_I915, "Intel E7221 (i915)"}, \
|
||||
{0x8086, 0x2592, CHIP_I9XX|CHIP_I915, "Intel i915GM"}, \
|
||||
{0x8086, 0x2772, CHIP_I9XX|CHIP_I915, "Intel i945G"}, \
|
||||
{0x8086, 0x27A2, CHIP_I9XX|CHIP_I915, "Intel i945GM"}, \
|
||||
{0x8086, 0x27AE, CHIP_I9XX|CHIP_I915, "Intel i945GME"}, \
|
||||
{0x8086, 0x2972, CHIP_I9XX|CHIP_I965, "Intel i946GZ"}, \
|
||||
{0x8086, 0x2982, CHIP_I9XX|CHIP_I965, "Intel i965G"}, \
|
||||
{0x8086, 0x2992, CHIP_I9XX|CHIP_I965, "Intel i965Q"}, \
|
||||
{0x8086, 0x29A2, CHIP_I9XX|CHIP_I965, "Intel i965G"}, \
|
||||
{0x8086, 0x29B2, CHIP_I9XX|CHIP_I915, "Intel Q35"}, \
|
||||
{0x8086, 0x29C2, CHIP_I9XX|CHIP_I915, "Intel G33"}, \
|
||||
{0x8086, 0x29D2, CHIP_I9XX|CHIP_I915, "Intel Q33"}, \
|
||||
{0x8086, 0x2A02, CHIP_I9XX|CHIP_I965, "Intel i965GM"}, \
|
||||
{0x8086, 0x2A12, CHIP_I9XX|CHIP_I965, "Intel i965GME/GLE"}, \
|
||||
{0x8086, 0x2A42, CHIP_I9XX|CHIP_I965, "Mobile Intel® GM45 Express Chipset"}, \
|
||||
{0x8086, 0x2E02, CHIP_I9XX|CHIP_I965, "Intel Eaglelake"}, \
|
||||
{0x8086, 0x2E12, CHIP_I9XX|CHIP_I965, "Intel Q45/Q43"}, \
|
||||
{0x8086, 0x2E22, CHIP_I9XX|CHIP_I965, "Intel G45/G43"}, \
|
||||
{0x8086, 0x2E32, CHIP_I9XX|CHIP_I965, "Intel G41"}, \
|
||||
{0x8086, 0x2e42, CHIP_I9XX|CHIP_I915, "Intel G43 ?"}, \
|
||||
{0x8086, 0x2e92, CHIP_I9XX|CHIP_I915, "Intel G43 ?"}, \
|
||||
{0x8086, 0x0042, CHIP_I9XX|CHIP_I915, "Intel IronLake"}, \
|
||||
{0x8086, 0x0046, CHIP_I9XX|CHIP_I915, "Intel IronLake"}, \
|
||||
{0x8086, 0x0102, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0112, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0122, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
|
||||
{0x8086, 0x0106, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x0116, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x0126, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0x010A, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
|
||||
{0x8086, 0xA001, CHIP_I9XX|CHIP_I965, "Intel Pineview"}, \
|
||||
{0x8086, 0xA011, CHIP_I9XX|CHIP_I965, "Intel Pineview (M)"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define imagine_PCI_IDS \
|
||||
{0x105d, 0x2309, IMAGINE_128, "Imagine 128"}, \
|
||||
{0x105d, 0x2339, IMAGINE_128_2, "Imagine 128-II"}, \
|
||||
{0x105d, 0x493d, IMAGINE_T2R, "Ticket to Ride"}, \
|
||||
{0x105d, 0x5348, IMAGINE_REV4, "Revolution IV"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define nv_PCI_IDS \
|
||||
{0x10DE, 0x0020, NV04, "NVidia RIVA TNT"}, \
|
||||
{0x10DE, 0x0028, NV04, "NVidia RIVA TNT2"}, \
|
||||
{0x10DE, 0x002A, NV04, "NVidia Unknown TNT2"}, \
|
||||
{0x10DE, 0x002C, NV04, "NVidia Vanta"}, \
|
||||
{0x10DE, 0x0029, NV04, "NVidia RIVA TNT2 Ultra"}, \
|
||||
{0x10DE, 0x002D, NV04, "NVidia RIVA TNT2 Model 64"}, \
|
||||
{0x10DE, 0x00A0, NV04, "NVidia Aladdin TNT2"}, \
|
||||
{0x10DE, 0x0100, NV10, "NVidia GeForce 256"}, \
|
||||
{0x10DE, 0x0101, NV10, "NVidia GeForce DDR"}, \
|
||||
{0x10DE, 0x0103, NV10, "NVidia Quadro"}, \
|
||||
{0x10DE, 0x0110, NV10, "NVidia GeForce2 MX/MX 400"}, \
|
||||
{0x10DE, 0x0111, NV10, "NVidia GeForce2 MX 100/200"}, \
|
||||
{0x10DE, 0x0112, NV10, "NVidia GeForce2 Go"}, \
|
||||
{0x10DE, 0x0113, NV10, "NVidia Quadro2 MXR/EX/Go"}, \
|
||||
{0x10DE, 0x0150, NV10, "NVidia GeForce2 GTS"}, \
|
||||
{0x10DE, 0x0151, NV10, "NVidia GeForce2 Ti"}, \
|
||||
{0x10DE, 0x0152, NV10, "NVidia GeForce2 Ultra"}, \
|
||||
{0x10DE, 0x0153, NV10, "NVidia Quadro2 Pro"}, \
|
||||
{0x10DE, 0x0170, NV10, "NVidia GeForce4 MX 460"}, \
|
||||
{0x10DE, 0x0171, NV10, "NVidia GeForce4 MX 440"}, \
|
||||
{0x10DE, 0x0172, NV10, "NVidia GeForce4 MX 420"}, \
|
||||
{0x10DE, 0x0173, NV10, "NVidia GeForce4 MX 440-SE"}, \
|
||||
{0x10DE, 0x0174, NV10, "NVidia GeForce4 440 Go"}, \
|
||||
{0x10DE, 0x0175, NV10, "NVidia GeForce4 420 Go"}, \
|
||||
{0x10DE, 0x0176, NV10, "NVidia GeForce4 420 Go 32M"}, \
|
||||
{0x10DE, 0x0177, NV10, "NVidia GeForce4 460 Go"}, \
|
||||
{0x10DE, 0x0178, NV10, "NVidia Quadro4 550 XGL"}, \
|
||||
{0x10DE, 0x0179, NV10, "NVidia GeForce4"}, \
|
||||
{0x10DE, 0x017A, NV10, "NVidia Quadro4 NVS"}, \
|
||||
{0x10DE, 0x017C, NV10, "NVidia Quadro4 500 GoGL"}, \
|
||||
{0x10DE, 0x017D, NV10, "NVidia GeForce4 410 Go 16M"}, \
|
||||
{0x10DE, 0x0181, NV10, "NVidia GeForce4 MX 440 with AGP8X"}, \
|
||||
{0x10DE, 0x0182, NV10, "NVidia GeForce4 MX 440SE with AGP8X"}, \
|
||||
{0x10DE, 0x0183, NV10, "NVidia GeForce4 MX 420 with AGP8X"}, \
|
||||
{0x10DE, 0x0185, NV10, "NVidia GeForce4 MX 4000"}, \
|
||||
{0x10DE, 0x0186, NV10, "NVidia GeForce4 448 Go"}, \
|
||||
{0x10DE, 0x0187, NV10, "NVidia GeForce4 488 Go"}, \
|
||||
{0x10DE, 0x0188, NV10, "NVidia Quadro4 580 XGL"}, \
|
||||
{0x10DE, 0x0189, NV10, "NVidia GeForce4 MX with AGP8X (Mac)"}, \
|
||||
{0x10DE, 0x018A, NV10, "NVidia Quadro4 280 NVS"}, \
|
||||
{0x10DE, 0x018B, NV10, "NVidia Quadro4 380 XGL"}, \
|
||||
{0x10DE, 0x018C, NV10, "NVidia Quadro NVS 50 PCI"}, \
|
||||
{0x10DE, 0x018D, NV10, "NVidia GeForce4 448 Go"}, \
|
||||
{0x10DE, 0x01A0, NV10, "NVidia GeForce2 Integrated GPU"}, \
|
||||
{0x10DE, 0x01F0, NV10, "NVidia GeForce4 MX Integrated GPU"}, \
|
||||
{0x10DE, 0x0200, NV20, "NVidia GeForce3"}, \
|
||||
{0x10DE, 0x0201, NV20, "NVidia GeForce3 Ti 200"}, \
|
||||
{0x10DE, 0x0202, NV20, "NVidia GeForce3 Ti 500"}, \
|
||||
{0x10DE, 0x0203, NV20, "NVidia Quadro DCC"}, \
|
||||
{0x10DE, 0x0250, NV20, "NVidia GeForce4 Ti 4600"}, \
|
||||
{0x10DE, 0x0251, NV20, "NVidia GeForce4 Ti 4400"}, \
|
||||
{0x10DE, 0x0252, NV20, "NVidia 0x0252"}, \
|
||||
{0x10DE, 0x0253, NV20, "NVidia GeForce4 Ti 4200"}, \
|
||||
{0x10DE, 0x0258, NV20, "NVidia Quadro4 900 XGL"}, \
|
||||
{0x10DE, 0x0259, NV20, "NVidia Quadro4 750 XGL"}, \
|
||||
{0x10DE, 0x025B, NV20, "NVidia Quadro4 700 XGL"}, \
|
||||
{0x10DE, 0x0280, NV20, "NVidia GeForce4 Ti 4800"}, \
|
||||
{0x10DE, 0x0281, NV20, "NVidia GeForce4 Ti 4200 with AGP8X"}, \
|
||||
{0x10DE, 0x0282, NV20, "NVidia GeForce4 Ti 4800 SE"}, \
|
||||
{0x10DE, 0x0286, NV20, "NVidia GeForce4 4200 Go"}, \
|
||||
{0x10DE, 0x028C, NV20, "NVidia Quadro4 700 GoGL"}, \
|
||||
{0x10DE, 0x0288, NV20, "NVidia Quadro4 980 XGL"}, \
|
||||
{0x10DE, 0x0289, NV20, "NVidia Quadro4 780 XGL"}, \
|
||||
{0x10DE, 0x0301, NV30, "NVidia GeForce FX 5800 Ultra"}, \
|
||||
{0x10DE, 0x0302, NV30, "NVidia GeForce FX 5800"}, \
|
||||
{0x10DE, 0x0308, NV30, "NVidia Quadro FX 2000"}, \
|
||||
{0x10DE, 0x0309, NV30, "NVidia Quadro FX 1000"}, \
|
||||
{0x10DE, 0x0311, NV30, "NVidia GeForce FX 5600 Ultra"}, \
|
||||
{0x10DE, 0x0312, NV30, "NVidia GeForce FX 5600"}, \
|
||||
{0x10DE, 0x0313, NV30, "NVidia 0x0313"}, \
|
||||
{0x10DE, 0x0314, NV30, "NVidia GeForce FX 5600SE"}, \
|
||||
{0x10DE, 0x0316, NV30, "NVidia 0x0316"}, \
|
||||
{0x10DE, 0x0317, NV30, "NVidia 0x0317"}, \
|
||||
{0x10DE, 0x031A, NV30, "NVidia GeForce FX Go5600"}, \
|
||||
{0x10DE, 0x031B, NV30, "NVidia GeForce FX Go5650"}, \
|
||||
{0x10DE, 0x031C, NV30, "NVidia Quadro FX Go700"}, \
|
||||
{0x10DE, 0x031D, NV30, "NVidia 0x031D"}, \
|
||||
{0x10DE, 0x031E, NV30, "NVidia 0x031E"}, \
|
||||
{0x10DE, 0x031F, NV30, "NVidia 0x031F"}, \
|
||||
{0x10DE, 0x0320, NV30, "NVidia GeForce FX 5200"}, \
|
||||
{0x10DE, 0x0321, NV30, "NVidia GeForce FX 5200 Ultra"}, \
|
||||
{0x10DE, 0x0322, NV30, "NVidia GeForce FX 5200"}, \
|
||||
{0x10DE, 0x0323, NV30, "NVidia GeForce FX 5200SE"}, \
|
||||
{0x10DE, 0x0324, NV30, "NVidia GeForce FX Go5200"}, \
|
||||
{0x10DE, 0x0325, NV30, "NVidia GeForce FX Go5250"}, \
|
||||
{0x10DE, 0x0326, NV30, "NVidia GeForce FX 5500"}, \
|
||||
{0x10DE, 0x0327, NV30, "NVidia GeForce FX 5100"}, \
|
||||
{0x10DE, 0x0328, NV30, "NVidia GeForce FX Go5200 32M/64M"}, \
|
||||
{0x10DE, 0x0329, NV30, "NVidia GeForce FX 5200 (Mac)"}, \
|
||||
{0x10DE, 0x032A, NV30, "NVidia Quadro NVS 280 PCI"}, \
|
||||
{0x10DE, 0x032B, NV30, "NVidia Quadro FX 500/600 PCI"}, \
|
||||
{0x10DE, 0x032C, NV30, "NVidia GeForce FX Go53xx Series"}, \
|
||||
{0x10DE, 0x032D, NV30, "NVidia GeForce FX Go5100"}, \
|
||||
{0x10DE, 0x032F, NV30, "NVidia 0x032F"}, \
|
||||
{0x10DE, 0x0330, NV30, "NVidia GeForce FX 5900 Ultra"}, \
|
||||
{0x10DE, 0x0331, NV30, "NVidia GeForce FX 5900"}, \
|
||||
{0x10DE, 0x0332, NV30, "NVidia GeForce FX 5900XT"}, \
|
||||
{0x10DE, 0x0333, NV30, "NVidia GeForce FX 5950 Ultra"}, \
|
||||
{0x10DE, 0x033F, NV30, "NVidia Quadro FX 700"}, \
|
||||
{0x10DE, 0x0334, NV30, "NVidia GeForce FX 5900ZT"}, \
|
||||
{0x10DE, 0x0338, NV30, "NVidia Quadro FX 3000"}, \
|
||||
{0x10DE, 0x0341, NV30, "NVidia GeForce FX 5700 Ultra"}, \
|
||||
{0x10DE, 0x0342, NV30, "NVidia GeForce FX 5700"}, \
|
||||
{0x10DE, 0x0343, NV30, "NVidia GeForce FX 5700LE"}, \
|
||||
{0x10DE, 0x0344, NV30, "NVidia GeForce FX 5700VE"}, \
|
||||
{0x10DE, 0x0345, NV30, "NVidia 0x0345"}, \
|
||||
{0x10DE, 0x0347, NV30, "NVidia GeForce FX Go5700"}, \
|
||||
{0x10DE, 0x0348, NV30, "NVidia GeForce FX Go5700"}, \
|
||||
{0x10DE, 0x0349, NV30, "NVidia 0x0349"}, \
|
||||
{0x10DE, 0x034B, NV30, "NVidia 0x034B"}, \
|
||||
{0x10DE, 0x034C, NV30, "NVidia Quadro FX Go1000"}, \
|
||||
{0x10DE, 0x034E, NV30, "NVidia Quadro FX 1100"}, \
|
||||
{0x10DE, 0x034F, NV30, "NVidia 0x034F"}, \
|
||||
{0x10DE, 0x0040, NV40, "NVidia GeForce 6800 Ultra"}, \
|
||||
{0x10DE, 0x0041, NV40, "NVidia GeForce 6800"}, \
|
||||
{0x10DE, 0x0042, NV40, "NVidia GeForce 6800 LE"}, \
|
||||
{0x10DE, 0x0043, NV40, "NVidia 0x0043"}, \
|
||||
{0x10DE, 0x0045, NV40, "NVidia GeForce 6800 GT"}, \
|
||||
{0x10DE, 0x0046, NV40, "NVidia GeForce 6800 GT"}, \
|
||||
{0x10DE, 0x0049, NV40, "NVidia 0x0049"}, \
|
||||
{0x10DE, 0x004E, NV40, "NVidia Quadro FX 4000"}, \
|
||||
{0x10DE, 0x00C0, NV40, "NVidia 0x00C0"}, \
|
||||
{0x10DE, 0x00C1, NV40, "NVidia GeForce 6800"}, \
|
||||
{0x10DE, 0x00C2, NV40, "NVidia GeForce 6800 LE"}, \
|
||||
{0x10DE, 0x00C8, NV40, "NVidia GeForce Go 6800"}, \
|
||||
{0x10DE, 0x00C9, NV40, "NVidia GeForce Go 6800 Ultra"}, \
|
||||
{0x10DE, 0x00CC, NV40, "NVidia Quadro FX Go1400"}, \
|
||||
{0x10DE, 0x00CD, NV40, "NVidia Quadro FX 3450/4000 SDI"}, \
|
||||
{0x10DE, 0x00CE, NV40, "NVidia Quadro FX 1400"}, \
|
||||
{0x10de, 0x00f0, NV40, "Nvidia GeForce 6600 GT"}, \
|
||||
{0x10de, 0x00f1, NV40, "Nvidia GeForce 6600 GT"}, \
|
||||
{0x10DE, 0x0140, NV40, "NVidia GeForce 6600 GT"}, \
|
||||
{0x10DE, 0x0141, NV40, "NVidia GeForce 6600"}, \
|
||||
{0x10DE, 0x0142, NV40, "NVidia GeForce 6600 LE"}, \
|
||||
{0x10DE, 0x0143, NV40, "NVidia 0x0143"}, \
|
||||
{0x10DE, 0x0144, NV40, "NVidia GeForce Go 6600"}, \
|
||||
{0x10DE, 0x0145, NV40, "NVidia GeForce 6610 XL"}, \
|
||||
{0x10DE, 0x0146, NV40, "NVidia GeForce Go 6600 TE/6200 TE"}, \
|
||||
{0x10DE, 0x0147, NV40, "NVidia GeForce 6700 XL"}, \
|
||||
{0x10DE, 0x0148, NV40, "NVidia GeForce Go 6600"}, \
|
||||
{0x10DE, 0x0149, NV40, "NVidia GeForce Go 6600 GT"}, \
|
||||
{0x10DE, 0x014B, NV40, "NVidia 0x014B"}, \
|
||||
{0x10DE, 0x014C, NV40, "NVidia 0x014C"}, \
|
||||
{0x10DE, 0x014D, NV40, "NVidia 0x014D"}, \
|
||||
{0x10DE, 0x014E, NV40, "NVidia Quadro FX 540"}, \
|
||||
{0x10DE, 0x014F, NV40, "NVidia GeForce 6200"}, \
|
||||
{0x10DE, 0x0160, NV40, "NVidia 0x0160"}, \
|
||||
{0x10DE, 0x0161, NV40, "NVidia GeForce 6200 TurboCache(TM)"}, \
|
||||
{0x10DE, 0x0162, NV40, "NVidia GeForce 6200SE TurboCache(TM)"}, \
|
||||
{0x10DE, 0x0163, NV40, "NVidia 0x0163"}, \
|
||||
{0x10DE, 0x0164, NV40, "NVidia GeForce Go 6200"}, \
|
||||
{0x10DE, 0x0165, NV40, "NVidia Quadro NVS 285"}, \
|
||||
{0x10DE, 0x0166, NV40, "NVidia GeForce Go 6400"}, \
|
||||
{0x10DE, 0x0167, NV40, "NVidia GeForce Go 6200"}, \
|
||||
{0x10DE, 0x0168, NV40, "NVidia GeForce Go 6400"}, \
|
||||
{0x10DE, 0x0169, NV40, "NVidia 0x0169"}, \
|
||||
{0x10DE, 0x016B, NV40, "NVidia 0x016B"}, \
|
||||
{0x10DE, 0x016C, NV40, "NVidia 0x016C"}, \
|
||||
{0x10DE, 0x016D, NV40, "NVidia 0x016D"}, \
|
||||
{0x10DE, 0x016E, NV40, "NVidia 0x016E"}, \
|
||||
{0x10DE, 0x0210, NV40, "NVidia 0x0210"}, \
|
||||
{0x10DE, 0x0211, NV40, "NVidia GeForce 6800"}, \
|
||||
{0x10DE, 0x0212, NV40, "NVidia GeForce 6800 LE"}, \
|
||||
{0x10DE, 0x0215, NV40, "NVidia GeForce 6800 GT"}, \
|
||||
{0x10DE, 0x0220, NV40, "NVidia 0x0220"}, \
|
||||
{0x10DE, 0x0221, NV40, "NVidia GeForce 6200"}, \
|
||||
{0x10DE, 0x0222, NV40, "NVidia 0x0222"}, \
|
||||
{0x10DE, 0x0228, NV40, "NVidia 0x0228"}, \
|
||||
{0x10DE, 0x0090, NV40, "NVidia 0x0090"}, \
|
||||
{0x10DE, 0x0091, NV40, "NVidia GeForce 7800 GTX"}, \
|
||||
{0x10DE, 0x0092, NV40, "NVidia 0x0092"}, \
|
||||
{0x10DE, 0x0093, NV40, "NVidia 0x0093"}, \
|
||||
{0x10DE, 0x0094, NV40, "NVidia 0x0094"}, \
|
||||
{0x10DE, 0x0098, NV40, "NVidia 0x0098"}, \
|
||||
{0x10DE, 0x0099, NV40, "NVidia GeForce Go 7800 GTX"}, \
|
||||
{0x10DE, 0x009C, NV40, "NVidia 0x009C"}, \
|
||||
{0x10DE, 0x009D, NV40, "NVidia Quadro FX 4500"}, \
|
||||
{0x10DE, 0x009E, NV40, "NVidia 0x009E"}, \
|
||||
{0, 0, 0, NULL}
|
||||
|
||||
#define xgi_PCI_IDS \
|
||||
{0x18ca, 0x2200, 0, "XP5"}, \
|
||||
{0x18ca, 0x0047, 0, "XP10 / XG47"}, \
|
||||
{0, 0, 0, NULL}
|
||||
87
sys/dev/drm2/drm_sarea.h
Normal file
87
sys/dev/drm2/drm_sarea.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* \file drm_sarea.h
|
||||
* \brief SAREA definitions
|
||||
*
|
||||
* \author Michel D<EFBFBD>zer <michel@daenzer.net>
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifndef _DRM_SAREA_H_
|
||||
#define _DRM_SAREA_H_
|
||||
|
||||
#include <dev/drm2/drm.h>
|
||||
|
||||
/* SAREA area needs to be at least a page */
|
||||
#if defined(__alpha__)
|
||||
#define SAREA_MAX 0x2000
|
||||
#elif defined(__ia64__)
|
||||
#define SAREA_MAX 0x10000 /* 64kB */
|
||||
#else
|
||||
/* Intel 830M driver needs at least 8k SAREA */
|
||||
#define SAREA_MAX 0x2000UL
|
||||
#endif
|
||||
|
||||
/** Maximum number of drawables in the SAREA */
|
||||
#define SAREA_MAX_DRAWABLES 256
|
||||
|
||||
#define SAREA_DRAWABLE_CLAIMED_ENTRY 0x80000000
|
||||
|
||||
/** SAREA drawable */
|
||||
struct drm_sarea_drawable {
|
||||
unsigned int stamp;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/** SAREA frame */
|
||||
struct drm_sarea_frame {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int fullscreen;
|
||||
};
|
||||
|
||||
/** SAREA */
|
||||
struct drm_sarea {
|
||||
/** first thing is always the DRM locking structure */
|
||||
struct drm_hw_lock lock;
|
||||
/** \todo Use readers/writer lock for drm_sarea::drawable_lock */
|
||||
struct drm_hw_lock drawable_lock;
|
||||
struct drm_sarea_drawable drawableTable[SAREA_MAX_DRAWABLES]; /**< drawables */
|
||||
struct drm_sarea_frame frame; /**< frame */
|
||||
drm_context_t dummy_context;
|
||||
};
|
||||
|
||||
#ifndef __KERNEL__
|
||||
typedef struct drm_sarea_drawable drm_sarea_drawable_t;
|
||||
typedef struct drm_sarea_frame drm_sarea_frame_t;
|
||||
typedef struct drm_sarea drm_sarea_t;
|
||||
#endif
|
||||
|
||||
#endif /* _DRM_SAREA_H_ */
|
||||
129
sys/dev/drm2/drm_scatter.c
Normal file
129
sys/dev/drm2/drm_scatter.c
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*-
|
||||
* Copyright (c) 2009 Robert C. Noland III <rnoland@FreeBSD.org>
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_scatter.c
|
||||
* Allocation of memory for scatter-gather mappings by the graphics chip.
|
||||
* The memory allocated here is then made into an aperture in the card
|
||||
* by mapping the pages into the GART.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
int
|
||||
drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request)
|
||||
{
|
||||
struct drm_sg_mem *entry;
|
||||
vm_size_t size;
|
||||
vm_pindex_t pindex;
|
||||
|
||||
if (dev->sg)
|
||||
return EINVAL;
|
||||
|
||||
DRM_DEBUG("request size=%ld\n", request->size);
|
||||
|
||||
entry = malloc(sizeof(*entry), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
|
||||
|
||||
size = round_page(request->size);
|
||||
entry->pages = OFF_TO_IDX(size);
|
||||
entry->busaddr = malloc(entry->pages * sizeof(*entry->busaddr),
|
||||
DRM_MEM_SGLISTS, M_WAITOK | M_ZERO);
|
||||
|
||||
entry->vaddr = kmem_alloc_attr(kernel_map, size, M_WAITOK | M_ZERO,
|
||||
0, BUS_SPACE_MAXADDR_32BIT, VM_MEMATTR_WRITE_COMBINING);
|
||||
if (entry->vaddr == 0) {
|
||||
drm_sg_cleanup(entry);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
for(pindex = 0; pindex < entry->pages; pindex++) {
|
||||
entry->busaddr[pindex] =
|
||||
vtophys(entry->vaddr + IDX_TO_OFF(pindex));
|
||||
}
|
||||
|
||||
DRM_LOCK(dev);
|
||||
if (dev->sg) {
|
||||
DRM_UNLOCK(dev);
|
||||
drm_sg_cleanup(entry);
|
||||
return (EINVAL);
|
||||
}
|
||||
dev->sg = entry;
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
request->handle = entry->vaddr;
|
||||
|
||||
DRM_DEBUG("allocated %ju pages @ 0x%08zx, contents=%08lx\n",
|
||||
entry->pages, entry->vaddr, *(unsigned long *)entry->vaddr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_scatter_gather *request = data;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
return (drm_sg_alloc(dev, request));
|
||||
}
|
||||
|
||||
void
|
||||
drm_sg_cleanup(struct drm_sg_mem *entry)
|
||||
{
|
||||
if (entry == NULL)
|
||||
return;
|
||||
|
||||
if (entry->vaddr != 0)
|
||||
kmem_free(kernel_map, entry->vaddr, IDX_TO_OFF(entry->pages));
|
||||
|
||||
free(entry->busaddr, DRM_MEM_SGLISTS);
|
||||
free(entry, DRM_MEM_DRIVER);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_scatter_gather *request = data;
|
||||
struct drm_sg_mem *entry;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
entry = dev->sg;
|
||||
dev->sg = NULL;
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
if (!entry || entry->vaddr != request->handle)
|
||||
return (EINVAL);
|
||||
|
||||
DRM_DEBUG("free 0x%zx\n", entry->vaddr);
|
||||
|
||||
drm_sg_cleanup(entry);
|
||||
|
||||
return (0);
|
||||
}
|
||||
352
sys/dev/drm2/drm_sman.c
Normal file
352
sys/dev/drm2/drm_sman.c
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Simple memory manager interface that keeps track on allocate regions on a
|
||||
* per "owner" basis. All regions associated with an "owner" can be released
|
||||
* with a simple call. Typically if the "owner" exists. The owner is any
|
||||
* "unsigned long" identifier. Can typically be a pointer to a file private
|
||||
* struct or a context identifier.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm_sman.h>
|
||||
|
||||
struct drm_owner_item {
|
||||
struct drm_hash_item owner_hash;
|
||||
struct list_head sman_list;
|
||||
struct list_head mem_blocks;
|
||||
};
|
||||
|
||||
void drm_sman_takedown(struct drm_sman * sman)
|
||||
{
|
||||
drm_ht_remove(&sman->user_hash_tab);
|
||||
drm_ht_remove(&sman->owner_hash_tab);
|
||||
if (sman->mm)
|
||||
drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm),
|
||||
DRM_MEM_MM);
|
||||
}
|
||||
|
||||
int
|
||||
drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
|
||||
unsigned int user_order, unsigned int owner_order)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sman->mm = (struct drm_sman_mm *) drm_calloc(num_managers,
|
||||
sizeof(*sman->mm), DRM_MEM_MM);
|
||||
if (!sman->mm) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
sman->num_managers = num_managers;
|
||||
INIT_LIST_HEAD(&sman->owner_items);
|
||||
ret = drm_ht_create(&sman->owner_hash_tab, owner_order);
|
||||
if (ret)
|
||||
goto out1;
|
||||
ret = drm_ht_create(&sman->user_hash_tab, user_order);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
drm_ht_remove(&sman->owner_hash_tab);
|
||||
out1:
|
||||
drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *drm_sman_mm_allocate(void *private, unsigned long size,
|
||||
unsigned alignment)
|
||||
{
|
||||
struct drm_mm *mm = (struct drm_mm *) private;
|
||||
struct drm_mm_node *tmp;
|
||||
|
||||
tmp = drm_mm_search_free(mm, size, alignment, 1);
|
||||
if (!tmp) {
|
||||
return NULL;
|
||||
}
|
||||
/* This could be non-atomic, but we are called from a locked path */
|
||||
tmp = drm_mm_get_block_atomic(tmp, size, alignment);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static void drm_sman_mm_free(void *private, void *ref)
|
||||
{
|
||||
struct drm_mm_node *node = (struct drm_mm_node *) ref;
|
||||
|
||||
drm_mm_put_block(node);
|
||||
}
|
||||
|
||||
static void drm_sman_mm_destroy(void *private)
|
||||
{
|
||||
struct drm_mm *mm = (struct drm_mm *) private;
|
||||
drm_mm_takedown(mm);
|
||||
drm_free(mm, sizeof(*mm), DRM_MEM_MM);
|
||||
}
|
||||
|
||||
static unsigned long drm_sman_mm_offset(void *private, void *ref)
|
||||
{
|
||||
struct drm_mm_node *node = (struct drm_mm_node *) ref;
|
||||
return node->start;
|
||||
}
|
||||
|
||||
int
|
||||
drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
|
||||
unsigned long start, unsigned long size)
|
||||
{
|
||||
struct drm_sman_mm *sman_mm;
|
||||
struct drm_mm *mm;
|
||||
int ret;
|
||||
|
||||
KASSERT(manager < sman->num_managers, ("Invalid manager"));
|
||||
|
||||
sman_mm = &sman->mm[manager];
|
||||
mm = malloc(sizeof(*mm), DRM_MEM_MM, M_NOWAIT | M_ZERO);
|
||||
if (!mm) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
sman_mm->private = mm;
|
||||
ret = drm_mm_init(mm, start, size);
|
||||
|
||||
if (ret) {
|
||||
drm_free(mm, sizeof(*mm), DRM_MEM_MM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sman_mm->allocate = drm_sman_mm_allocate;
|
||||
sman_mm->free = drm_sman_mm_free;
|
||||
sman_mm->destroy = drm_sman_mm_destroy;
|
||||
sman_mm->offset = drm_sman_mm_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
drm_sman_set_manager(struct drm_sman * sman, unsigned int manager,
|
||||
struct drm_sman_mm * allocator)
|
||||
{
|
||||
KASSERT(manager < sman->num_managers, ("Invalid manager"));
|
||||
sman->mm[manager] = *allocator;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman,
|
||||
unsigned long owner)
|
||||
{
|
||||
int ret;
|
||||
struct drm_hash_item *owner_hash_item;
|
||||
struct drm_owner_item *owner_item;
|
||||
|
||||
ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
|
||||
if (!ret) {
|
||||
return drm_hash_entry(owner_hash_item, struct drm_owner_item,
|
||||
owner_hash);
|
||||
}
|
||||
|
||||
owner_item = malloc(sizeof(*owner_item), DRM_MEM_MM, M_NOWAIT | M_ZERO);
|
||||
if (!owner_item)
|
||||
goto out;
|
||||
|
||||
INIT_LIST_HEAD(&owner_item->mem_blocks);
|
||||
owner_item->owner_hash.key = owner;
|
||||
DRM_DEBUG("owner_item = %p, mem_blocks = %p\n", owner_item, &owner_item->mem_blocks);
|
||||
if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash))
|
||||
goto out1;
|
||||
|
||||
list_add_tail(&owner_item->sman_list, &sman->owner_items);
|
||||
return owner_item;
|
||||
|
||||
out1:
|
||||
drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int manager,
|
||||
unsigned long size, unsigned alignment,
|
||||
unsigned long owner)
|
||||
{
|
||||
void *tmp;
|
||||
struct drm_sman_mm *sman_mm;
|
||||
struct drm_owner_item *owner_item;
|
||||
struct drm_memblock_item *memblock;
|
||||
|
||||
KASSERT(manager < sman->num_managers, ("Invalid manager"));
|
||||
|
||||
sman_mm = &sman->mm[manager];
|
||||
tmp = sman_mm->allocate(sman_mm->private, size, alignment);
|
||||
if (!tmp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memblock = malloc(sizeof(*memblock), DRM_MEM_MM, M_NOWAIT | M_ZERO);
|
||||
DRM_DEBUG("allocated mem_block %p\n", memblock);
|
||||
if (!memblock)
|
||||
goto out;
|
||||
|
||||
memblock->mm_info = tmp;
|
||||
memblock->mm = sman_mm;
|
||||
memblock->sman = sman;
|
||||
INIT_LIST_HEAD(&memblock->owner_list);
|
||||
|
||||
if (drm_ht_just_insert_please
|
||||
(&sman->user_hash_tab, &memblock->user_hash,
|
||||
(unsigned long)memblock, 32, 0, 0))
|
||||
goto out1;
|
||||
|
||||
owner_item = drm_sman_get_owner_item(sman, owner);
|
||||
if (!owner_item)
|
||||
goto out2;
|
||||
|
||||
DRM_DEBUG("owner_item = %p, mem_blocks = %p\n", owner_item, &owner_item->mem_blocks);
|
||||
DRM_DEBUG("owner_list.prev = %p, mem_blocks.prev = %p\n", memblock->owner_list.prev, owner_item->mem_blocks.prev);
|
||||
DRM_DEBUG("owner_list.next = %p, mem_blocks.next = %p\n", memblock->owner_list.next, owner_item->mem_blocks.next);
|
||||
list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
|
||||
|
||||
DRM_DEBUG("Complete\n");
|
||||
return memblock;
|
||||
|
||||
out2:
|
||||
drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
|
||||
out1:
|
||||
drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
|
||||
out:
|
||||
sman_mm->free(sman_mm->private, tmp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void drm_sman_free(struct drm_memblock_item *item)
|
||||
{
|
||||
struct drm_sman *sman = item->sman;
|
||||
|
||||
list_del(&item->owner_list);
|
||||
drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
|
||||
item->mm->free(item->mm->private, item->mm_info);
|
||||
drm_free(item, sizeof(*item), DRM_MEM_MM);
|
||||
}
|
||||
|
||||
int drm_sman_free_key(struct drm_sman *sman, unsigned int key)
|
||||
{
|
||||
struct drm_hash_item *hash_item;
|
||||
struct drm_memblock_item *memblock_item;
|
||||
|
||||
if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
|
||||
return -EINVAL;
|
||||
|
||||
memblock_item = drm_hash_entry(hash_item, struct drm_memblock_item,
|
||||
user_hash);
|
||||
drm_sman_free(memblock_item);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drm_sman_remove_owner(struct drm_sman *sman,
|
||||
struct drm_owner_item *owner_item)
|
||||
{
|
||||
list_del(&owner_item->sman_list);
|
||||
drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
|
||||
drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
|
||||
}
|
||||
|
||||
int drm_sman_owner_clean(struct drm_sman *sman, unsigned long owner)
|
||||
{
|
||||
|
||||
struct drm_hash_item *hash_item;
|
||||
struct drm_owner_item *owner_item;
|
||||
|
||||
if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
|
||||
DRM_DEBUG("cleaning owner_item %p\n", owner_item);
|
||||
if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
|
||||
drm_sman_remove_owner(sman, owner_item);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void drm_sman_do_owner_cleanup(struct drm_sman *sman,
|
||||
struct drm_owner_item *owner_item)
|
||||
{
|
||||
struct drm_memblock_item *entry, *next;
|
||||
|
||||
list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
|
||||
owner_list) {
|
||||
DRM_DEBUG("freeing mem_block %p\n", entry);
|
||||
drm_sman_free(entry);
|
||||
}
|
||||
drm_sman_remove_owner(sman, owner_item);
|
||||
}
|
||||
|
||||
void drm_sman_owner_cleanup(struct drm_sman *sman, unsigned long owner)
|
||||
{
|
||||
|
||||
struct drm_hash_item *hash_item;
|
||||
struct drm_owner_item *owner_item;
|
||||
|
||||
if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
|
||||
drm_sman_do_owner_cleanup(sman, owner_item);
|
||||
}
|
||||
|
||||
void drm_sman_cleanup(struct drm_sman *sman)
|
||||
{
|
||||
struct drm_owner_item *entry, *next;
|
||||
unsigned int i;
|
||||
struct drm_sman_mm *sman_mm;
|
||||
|
||||
DRM_DEBUG("sman = %p, owner_items = %p\n",
|
||||
sman, &sman->owner_items);
|
||||
list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
|
||||
DRM_DEBUG("cleaning owner_item = %p\n", entry);
|
||||
drm_sman_do_owner_cleanup(sman, entry);
|
||||
}
|
||||
if (sman->mm) {
|
||||
for (i = 0; i < sman->num_managers; ++i) {
|
||||
sman_mm = &sman->mm[i];
|
||||
if (sman_mm->private) {
|
||||
sman_mm->destroy(sman_mm->private);
|
||||
sman_mm->private = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
sys/dev/drm2/drm_sman.h
Normal file
181
sys/dev/drm2/drm_sman.h
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Simple memory MANager interface that keeps track on allocate regions on a
|
||||
* per "owner" basis. All regions associated with an "owner" can be released
|
||||
* with a simple call. Typically if the "owner" exists. The owner is any
|
||||
* "unsigned long" identifier. Can typically be a pointer to a file private
|
||||
* struct or a context identifier.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#ifndef DRM_SMAN_H
|
||||
#define DRM_SMAN_H
|
||||
|
||||
#include <dev/drm2/drm_hashtab.h>
|
||||
#include <dev/drm2/drm_linux_list.h>
|
||||
#include <dev/drm2/drm_mm.h>
|
||||
|
||||
/*
|
||||
* A class that is an abstration of a simple memory allocator.
|
||||
* The sman implementation provides a default such allocator
|
||||
* using the drm_mm.c implementation. But the user can replace it.
|
||||
* See the SiS implementation, which may use the SiS FB kernel module
|
||||
* for memory management.
|
||||
*/
|
||||
|
||||
struct drm_sman_mm {
|
||||
/* private info. If allocated, needs to be destroyed by the destroy
|
||||
function */
|
||||
void *private;
|
||||
|
||||
/* Allocate a memory block with given size and alignment.
|
||||
Return an opaque reference to the memory block */
|
||||
|
||||
void *(*allocate) (void *private, unsigned long size,
|
||||
unsigned alignment);
|
||||
|
||||
/* Free a memory block. "ref" is the opaque reference that we got from
|
||||
the "alloc" function */
|
||||
|
||||
void (*free) (void *private, void *ref);
|
||||
|
||||
/* Free all resources associated with this allocator */
|
||||
|
||||
void (*destroy) (void *private);
|
||||
|
||||
/* Return a memory offset from the opaque reference returned from the
|
||||
"alloc" function */
|
||||
|
||||
unsigned long (*offset) (void *private, void *ref);
|
||||
};
|
||||
|
||||
struct drm_memblock_item {
|
||||
struct list_head owner_list;
|
||||
struct drm_hash_item user_hash;
|
||||
void *mm_info;
|
||||
struct drm_sman_mm *mm;
|
||||
struct drm_sman *sman;
|
||||
};
|
||||
|
||||
struct drm_sman {
|
||||
struct drm_sman_mm *mm;
|
||||
int num_managers;
|
||||
struct drm_open_hash owner_hash_tab;
|
||||
struct drm_open_hash user_hash_tab;
|
||||
struct list_head owner_items;
|
||||
};
|
||||
|
||||
/*
|
||||
* Take down a memory manager. This function should only be called after a
|
||||
* successful init and after a call to drm_sman_cleanup.
|
||||
*/
|
||||
|
||||
extern void drm_sman_takedown(struct drm_sman * sman);
|
||||
|
||||
/*
|
||||
* Allocate structures for a manager.
|
||||
* num_managers are the number of memory pools to manage. (VRAM, AGP, ....)
|
||||
* user_order is the log2 of the number of buckets in the user hash table.
|
||||
* set this to approximately log2 of the max number of memory regions
|
||||
* that will be allocated for _all_ pools together.
|
||||
* owner_order is the log2 of the number of buckets in the owner hash table.
|
||||
* set this to approximately log2 of
|
||||
* the number of client file connections that will
|
||||
* be using the manager.
|
||||
*
|
||||
*/
|
||||
|
||||
extern int drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
|
||||
unsigned int user_order, unsigned int owner_order);
|
||||
|
||||
/*
|
||||
* Initialize a drm_mm.c allocator. Should be called only once for each
|
||||
* manager unless a customized allogator is used.
|
||||
*/
|
||||
|
||||
extern int drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
|
||||
unsigned long start, unsigned long size);
|
||||
|
||||
/*
|
||||
* Initialize a customized allocator for one of the managers.
|
||||
* (See the SiS module). The object pointed to by "allocator" is copied,
|
||||
* so it can be destroyed after this call.
|
||||
*/
|
||||
|
||||
extern int drm_sman_set_manager(struct drm_sman * sman, unsigned int mananger,
|
||||
struct drm_sman_mm * allocator);
|
||||
|
||||
/*
|
||||
* Allocate a memory block. Aligment is not implemented yet.
|
||||
*/
|
||||
|
||||
extern struct drm_memblock_item *drm_sman_alloc(struct drm_sman * sman,
|
||||
unsigned int manager,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long owner);
|
||||
/*
|
||||
* Free a memory block identified by its user hash key.
|
||||
*/
|
||||
|
||||
extern int drm_sman_free_key(struct drm_sman * sman, unsigned int key);
|
||||
|
||||
/*
|
||||
* returns 1 iff there are no stale memory blocks associated with this owner.
|
||||
* Typically called to determine if we need to idle the hardware and call
|
||||
* drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all
|
||||
* resources associated with owner.
|
||||
*/
|
||||
|
||||
extern int drm_sman_owner_clean(struct drm_sman * sman, unsigned long owner);
|
||||
|
||||
/*
|
||||
* Frees all stale memory blocks associated with this owner. Note that this
|
||||
* requires that the hardware is finished with all blocks, so the graphics engine
|
||||
* should be idled before this call is made. This function also frees
|
||||
* any resources associated with "owner" and should be called when owner
|
||||
* is not going to be referenced anymore.
|
||||
*/
|
||||
|
||||
extern void drm_sman_owner_cleanup(struct drm_sman * sman, unsigned long owner);
|
||||
|
||||
/*
|
||||
* Frees all stale memory blocks associated with the memory manager.
|
||||
* See idling above.
|
||||
*/
|
||||
|
||||
extern void drm_sman_cleanup(struct drm_sman * sman);
|
||||
|
||||
#endif
|
||||
60
sys/dev/drm2/drm_stub.c
Normal file
60
sys/dev/drm2/drm_stub.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* \file drm_stub.h
|
||||
* Stub support
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
|
||||
*
|
||||
* Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
int
|
||||
drm_setmaster_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
DRM_DEBUG("setmaster\n");
|
||||
|
||||
if (file_priv->master != 0)
|
||||
return (0);
|
||||
return (-EPERM);
|
||||
}
|
||||
|
||||
int
|
||||
drm_dropmaster_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
DRM_DEBUG("dropmaster\n");
|
||||
if (file_priv->master != 0)
|
||||
return (-EINVAL);
|
||||
return (0);
|
||||
}
|
||||
364
sys/dev/drm2/drm_sysctl.c
Normal file
364
sys/dev/drm2/drm_sysctl.c
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
/*-
|
||||
* Copyright 2003 Eric Anholt
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_sysctl.c
|
||||
* Implementation of various sysctls for controlling DRM behavior and reporting
|
||||
* debug information.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
static int drm_name_info DRM_SYSCTL_HANDLER_ARGS;
|
||||
static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS;
|
||||
static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS;
|
||||
static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS;
|
||||
static int drm_vblank_info DRM_SYSCTL_HANDLER_ARGS;
|
||||
|
||||
struct drm_sysctl_list {
|
||||
const char *name;
|
||||
int (*f) DRM_SYSCTL_HANDLER_ARGS;
|
||||
} drm_sysctl_list[] = {
|
||||
{"name", drm_name_info},
|
||||
{"vm", drm_vm_info},
|
||||
{"clients", drm_clients_info},
|
||||
{"bufs", drm_bufs_info},
|
||||
{"vblank", drm_vblank_info},
|
||||
};
|
||||
#define DRM_SYSCTL_ENTRIES (sizeof(drm_sysctl_list)/sizeof(drm_sysctl_list[0]))
|
||||
|
||||
struct drm_sysctl_info {
|
||||
struct sysctl_ctx_list ctx;
|
||||
char name[2];
|
||||
};
|
||||
|
||||
int drm_sysctl_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_sysctl_info *info;
|
||||
struct sysctl_oid *oid;
|
||||
struct sysctl_oid *top, *drioid;
|
||||
int i;
|
||||
|
||||
info = malloc(sizeof *info, DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
|
||||
dev->sysctl = info;
|
||||
|
||||
/* Add the sysctl node for DRI if it doesn't already exist */
|
||||
drioid = SYSCTL_ADD_NODE(&info->ctx, &sysctl__hw_children, OID_AUTO,
|
||||
"dri", CTLFLAG_RW, NULL, "DRI Graphics");
|
||||
if (!drioid)
|
||||
return 1;
|
||||
|
||||
/* Find the next free slot under hw.dri */
|
||||
i = 0;
|
||||
SLIST_FOREACH(oid, SYSCTL_CHILDREN(drioid), oid_link) {
|
||||
if (i <= oid->oid_arg2)
|
||||
i = oid->oid_arg2 + 1;
|
||||
}
|
||||
if (i > 9)
|
||||
return (1);
|
||||
|
||||
dev->sysctl_node_idx = i;
|
||||
/* Add the hw.dri.x for our device */
|
||||
info->name[0] = '0' + i;
|
||||
info->name[1] = 0;
|
||||
top = SYSCTL_ADD_NODE(&info->ctx, SYSCTL_CHILDREN(drioid),
|
||||
OID_AUTO, info->name, CTLFLAG_RW, NULL, NULL);
|
||||
if (!top)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < DRM_SYSCTL_ENTRIES; i++) {
|
||||
oid = SYSCTL_ADD_OID(&info->ctx,
|
||||
SYSCTL_CHILDREN(top),
|
||||
OID_AUTO,
|
||||
drm_sysctl_list[i].name,
|
||||
CTLTYPE_STRING | CTLFLAG_RD,
|
||||
dev,
|
||||
0,
|
||||
drm_sysctl_list[i].f,
|
||||
"A",
|
||||
NULL);
|
||||
if (!oid)
|
||||
return 1;
|
||||
}
|
||||
SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "debug",
|
||||
CTLFLAG_RW, &drm_debug_flag, sizeof(drm_debug_flag),
|
||||
"Enable debugging output");
|
||||
SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "notyet",
|
||||
CTLFLAG_RW, &drm_notyet_flag, sizeof(drm_debug_flag),
|
||||
"Enable notyet reminders");
|
||||
|
||||
if (dev->driver->sysctl_init != NULL)
|
||||
dev->driver->sysctl_init(dev, &info->ctx, top);
|
||||
|
||||
SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO,
|
||||
"vblank_offdelay", CTLFLAG_RW, &drm_vblank_offdelay,
|
||||
sizeof(drm_vblank_offdelay),
|
||||
"");
|
||||
SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO,
|
||||
"timestamp_precision", CTLFLAG_RW, &drm_timestamp_precision,
|
||||
sizeof(drm_timestamp_precision),
|
||||
"");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int drm_sysctl_cleanup(struct drm_device *dev)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = sysctl_ctx_free(&dev->sysctl->ctx);
|
||||
free(dev->sysctl, DRM_MEM_DRIVER);
|
||||
dev->sysctl = NULL;
|
||||
if (dev->driver->sysctl_cleanup != NULL)
|
||||
dev->driver->sysctl_cleanup(dev);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#define DRM_SYSCTL_PRINT(fmt, arg...) \
|
||||
do { \
|
||||
snprintf(buf, sizeof(buf), fmt, ##arg); \
|
||||
retcode = SYSCTL_OUT(req, buf, strlen(buf)); \
|
||||
if (retcode) \
|
||||
goto done; \
|
||||
} while (0)
|
||||
|
||||
static int drm_name_info DRM_SYSCTL_HANDLER_ARGS
|
||||
{
|
||||
struct drm_device *dev = arg1;
|
||||
char buf[128];
|
||||
int retcode;
|
||||
int hasunique = 0;
|
||||
|
||||
DRM_SYSCTL_PRINT("%s 0x%x", dev->driver->name, dev2udev(dev->devnode));
|
||||
|
||||
DRM_LOCK(dev);
|
||||
if (dev->unique) {
|
||||
snprintf(buf, sizeof(buf), " %s", dev->unique);
|
||||
hasunique = 1;
|
||||
}
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
if (hasunique)
|
||||
SYSCTL_OUT(req, buf, strlen(buf));
|
||||
|
||||
SYSCTL_OUT(req, "", 1);
|
||||
|
||||
done:
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS
|
||||
{
|
||||
struct drm_device *dev = arg1;
|
||||
drm_local_map_t *map, *tempmaps;
|
||||
const char *types[] = { "FB", "REG", "SHM", "AGP", "SG" };
|
||||
const char *type, *yesno;
|
||||
int i, mapcount;
|
||||
char buf[128];
|
||||
int retcode;
|
||||
|
||||
/* We can't hold the lock while doing SYSCTL_OUTs, so allocate a
|
||||
* temporary copy of all the map entries and then SYSCTL_OUT that.
|
||||
*/
|
||||
DRM_LOCK(dev);
|
||||
|
||||
mapcount = 0;
|
||||
TAILQ_FOREACH(map, &dev->maplist, link)
|
||||
mapcount++;
|
||||
|
||||
tempmaps = malloc(sizeof(drm_local_map_t) * mapcount, DRM_MEM_DRIVER,
|
||||
M_NOWAIT);
|
||||
if (tempmaps == NULL) {
|
||||
DRM_UNLOCK(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
TAILQ_FOREACH(map, &dev->maplist, link)
|
||||
tempmaps[i++] = *map;
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
DRM_SYSCTL_PRINT("\nslot offset size "
|
||||
"type flags address handle mtrr\n");
|
||||
|
||||
for (i = 0; i < mapcount; i++) {
|
||||
map = &tempmaps[i];
|
||||
|
||||
if (map->type < 0 || map->type > 4)
|
||||
type = "??";
|
||||
else
|
||||
type = types[map->type];
|
||||
|
||||
if (!map->mtrr)
|
||||
yesno = "no";
|
||||
else
|
||||
yesno = "yes";
|
||||
|
||||
DRM_SYSCTL_PRINT(
|
||||
"%4d 0x%016lx 0x%08lx %4.4s 0x%02x 0x%016lx %6d %s\n",
|
||||
i, map->offset, map->size, type, map->flags,
|
||||
(unsigned long)map->virtual,
|
||||
(unsigned int)((unsigned long)map->handle >>
|
||||
DRM_MAP_HANDLE_SHIFT), yesno);
|
||||
}
|
||||
SYSCTL_OUT(req, "", 1);
|
||||
|
||||
done:
|
||||
free(tempmaps, DRM_MEM_DRIVER);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS
|
||||
{
|
||||
struct drm_device *dev = arg1;
|
||||
drm_device_dma_t *dma = dev->dma;
|
||||
drm_device_dma_t tempdma;
|
||||
int *templists;
|
||||
int i;
|
||||
char buf[128];
|
||||
int retcode;
|
||||
|
||||
/* We can't hold the locks around DRM_SYSCTL_PRINT, so make a temporary
|
||||
* copy of the whole structure and the relevant data from buflist.
|
||||
*/
|
||||
DRM_LOCK(dev);
|
||||
if (dma == NULL) {
|
||||
DRM_UNLOCK(dev);
|
||||
return 0;
|
||||
}
|
||||
DRM_SPINLOCK(&dev->dma_lock);
|
||||
tempdma = *dma;
|
||||
templists = malloc(sizeof(int) * dma->buf_count, DRM_MEM_DRIVER,
|
||||
M_NOWAIT);
|
||||
for (i = 0; i < dma->buf_count; i++)
|
||||
templists[i] = dma->buflist[i]->list;
|
||||
dma = &tempdma;
|
||||
DRM_SPINUNLOCK(&dev->dma_lock);
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
DRM_SYSCTL_PRINT("\n o size count free segs pages kB\n");
|
||||
for (i = 0; i <= DRM_MAX_ORDER; i++) {
|
||||
if (dma->bufs[i].buf_count)
|
||||
DRM_SYSCTL_PRINT("%2d %8d %5d %5d %5d %5d %5d\n",
|
||||
i,
|
||||
dma->bufs[i].buf_size,
|
||||
dma->bufs[i].buf_count,
|
||||
atomic_read(&dma->bufs[i]
|
||||
.freelist.count),
|
||||
dma->bufs[i].seg_count,
|
||||
dma->bufs[i].seg_count
|
||||
*(1 << dma->bufs[i].page_order),
|
||||
(dma->bufs[i].seg_count
|
||||
* (1 << dma->bufs[i].page_order))
|
||||
* (int)PAGE_SIZE / 1024);
|
||||
}
|
||||
DRM_SYSCTL_PRINT("\n");
|
||||
for (i = 0; i < dma->buf_count; i++) {
|
||||
if (i && !(i%32)) DRM_SYSCTL_PRINT("\n");
|
||||
DRM_SYSCTL_PRINT(" %d", templists[i]);
|
||||
}
|
||||
DRM_SYSCTL_PRINT("\n");
|
||||
|
||||
SYSCTL_OUT(req, "", 1);
|
||||
done:
|
||||
free(templists, DRM_MEM_DRIVER);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS
|
||||
{
|
||||
struct drm_device *dev = arg1;
|
||||
struct drm_file *priv, *tempprivs;
|
||||
char buf[128];
|
||||
int retcode;
|
||||
int privcount, i;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
|
||||
privcount = 0;
|
||||
TAILQ_FOREACH(priv, &dev->files, link)
|
||||
privcount++;
|
||||
|
||||
tempprivs = malloc(sizeof(struct drm_file) * privcount, DRM_MEM_DRIVER,
|
||||
M_NOWAIT);
|
||||
if (tempprivs == NULL) {
|
||||
DRM_UNLOCK(dev);
|
||||
return ENOMEM;
|
||||
}
|
||||
i = 0;
|
||||
TAILQ_FOREACH(priv, &dev->files, link)
|
||||
tempprivs[i++] = *priv;
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
DRM_SYSCTL_PRINT(
|
||||
"\na dev pid uid magic ioctls\n");
|
||||
for (i = 0; i < privcount; i++) {
|
||||
priv = &tempprivs[i];
|
||||
DRM_SYSCTL_PRINT("%c %-12s %5d %5d %10u %10lu\n",
|
||||
priv->authenticated ? 'y' : 'n',
|
||||
devtoname(priv->dev->devnode),
|
||||
priv->pid,
|
||||
priv->uid,
|
||||
priv->magic,
|
||||
priv->ioctl_count);
|
||||
}
|
||||
|
||||
SYSCTL_OUT(req, "", 1);
|
||||
done:
|
||||
free(tempprivs, DRM_MEM_DRIVER);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static int drm_vblank_info DRM_SYSCTL_HANDLER_ARGS
|
||||
{
|
||||
struct drm_device *dev = arg1;
|
||||
char buf[128];
|
||||
int retcode;
|
||||
int i;
|
||||
|
||||
DRM_SYSCTL_PRINT("\ncrtc ref count last enabled inmodeset\n");
|
||||
DRM_LOCK(dev);
|
||||
if (dev->_vblank_count == NULL)
|
||||
goto done;
|
||||
for (i = 0 ; i < dev->num_crtcs ; i++) {
|
||||
DRM_SYSCTL_PRINT(" %02d %02d %08d %08d %02d %02d\n",
|
||||
i, dev->vblank_refcount[i],
|
||||
dev->_vblank_count[i],
|
||||
dev->last_vblank[i],
|
||||
dev->vblank_enabled[i],
|
||||
dev->vblank_inmodeset[i]);
|
||||
}
|
||||
done:
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
SYSCTL_OUT(req, "", -1);
|
||||
return retcode;
|
||||
}
|
||||
134
sys/dev/drm2/drm_vm.c
Normal file
134
sys/dev/drm2/drm_vm.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*-
|
||||
* Copyright 2003 Eric Anholt
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/** @file drm_vm.c
|
||||
* Support code for mmaping of DRM maps.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
|
||||
int
|
||||
drm_mmap(struct cdev *kdev, vm_ooffset_t offset, vm_paddr_t *paddr,
|
||||
int prot, vm_memattr_t *memattr)
|
||||
{
|
||||
struct drm_device *dev = drm_get_device_from_kdev(kdev);
|
||||
struct drm_file *file_priv = NULL;
|
||||
drm_local_map_t *map;
|
||||
enum drm_map_type type;
|
||||
vm_paddr_t phys;
|
||||
int error;
|
||||
|
||||
/* d_mmap gets called twice, we can only reference file_priv during
|
||||
* the first call. We need to assume that if error is EBADF the
|
||||
* call was succesful and the client is authenticated.
|
||||
*/
|
||||
error = devfs_get_cdevpriv((void **)&file_priv);
|
||||
if (error == ENOENT) {
|
||||
DRM_ERROR("Could not find authenticator!\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (file_priv && !file_priv->authenticated)
|
||||
return EACCES;
|
||||
|
||||
DRM_DEBUG("called with offset %016jx\n", offset);
|
||||
if (dev->dma && offset < ptoa(dev->dma->page_count)) {
|
||||
drm_device_dma_t *dma = dev->dma;
|
||||
|
||||
DRM_SPINLOCK(&dev->dma_lock);
|
||||
|
||||
if (dma->pagelist != NULL) {
|
||||
unsigned long page = offset >> PAGE_SHIFT;
|
||||
unsigned long phys = dma->pagelist[page];
|
||||
|
||||
DRM_SPINUNLOCK(&dev->dma_lock);
|
||||
*paddr = phys;
|
||||
return 0;
|
||||
} else {
|
||||
DRM_SPINUNLOCK(&dev->dma_lock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* A sequential search of a linked list is
|
||||
fine here because: 1) there will only be
|
||||
about 5-10 entries in the list and, 2) a
|
||||
DRI client only has to do this mapping
|
||||
once, so it doesn't have to be optimized
|
||||
for performance, even if the list was a
|
||||
bit longer.
|
||||
*/
|
||||
DRM_LOCK(dev);
|
||||
TAILQ_FOREACH(map, &dev->maplist, link) {
|
||||
if (offset >> DRM_MAP_HANDLE_SHIFT ==
|
||||
(unsigned long)map->handle >> DRM_MAP_HANDLE_SHIFT)
|
||||
break;
|
||||
}
|
||||
|
||||
if (map == NULL) {
|
||||
DRM_DEBUG("Can't find map, request offset = %016jx\n", offset);
|
||||
TAILQ_FOREACH(map, &dev->maplist, link) {
|
||||
DRM_DEBUG("map offset = %016lx, handle = %016lx\n",
|
||||
map->offset, (unsigned long)map->handle);
|
||||
}
|
||||
DRM_UNLOCK(dev);
|
||||
return -1;
|
||||
}
|
||||
if (((map->flags & _DRM_RESTRICTED) && !DRM_SUSER(DRM_CURPROC))) {
|
||||
DRM_UNLOCK(dev);
|
||||
DRM_DEBUG("restricted map\n");
|
||||
return -1;
|
||||
}
|
||||
type = map->type;
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
offset = offset & ((1ULL << DRM_MAP_HANDLE_SHIFT) - 1);
|
||||
|
||||
switch (type) {
|
||||
case _DRM_FRAME_BUFFER:
|
||||
case _DRM_AGP:
|
||||
*memattr = VM_MEMATTR_WRITE_COMBINING;
|
||||
/* FALLTHROUGH */
|
||||
case _DRM_REGISTERS:
|
||||
phys = map->offset + offset;
|
||||
break;
|
||||
case _DRM_SCATTER_GATHER:
|
||||
*memattr = VM_MEMATTR_WRITE_COMBINING;
|
||||
/* FALLTHROUGH */
|
||||
case _DRM_CONSISTENT:
|
||||
case _DRM_SHM:
|
||||
phys = vtophys((char *)map->virtual + offset);
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("bad map type %d\n", type);
|
||||
return -1; /* This should never happen. */
|
||||
}
|
||||
|
||||
*paddr = phys;
|
||||
return 0;
|
||||
}
|
||||
|
||||
1683
sys/dev/drm2/i915/i915_debug.c
Normal file
1683
sys/dev/drm2/i915/i915_debug.c
Normal file
File diff suppressed because it is too large
Load diff
2075
sys/dev/drm2/i915/i915_dma.c
Normal file
2075
sys/dev/drm2/i915/i915_dma.c
Normal file
File diff suppressed because it is too large
Load diff
971
sys/dev/drm2/i915/i915_drm.h
Normal file
971
sys/dev/drm2/i915/i915_drm.h
Normal file
|
|
@ -0,0 +1,971 @@
|
|||
/*-
|
||||
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifndef _I915_DRM_H_
|
||||
#define _I915_DRM_H_
|
||||
|
||||
/* Please note that modifications to all structs defined here are
|
||||
* subject to backwards-compatibility constraints.
|
||||
*/
|
||||
|
||||
#include <dev/drm2/drm.h>
|
||||
|
||||
/* Each region is a minimum of 16k, and there are at most 255 of them.
|
||||
*/
|
||||
#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use
|
||||
* of chars for next/prev indices */
|
||||
#define I915_LOG_MIN_TEX_REGION_SIZE 14
|
||||
|
||||
typedef struct _drm_i915_init {
|
||||
enum {
|
||||
I915_INIT_DMA = 0x01,
|
||||
I915_CLEANUP_DMA = 0x02,
|
||||
I915_RESUME_DMA = 0x03,
|
||||
|
||||
/* Since this struct isn't versioned, just used a new
|
||||
* 'func' code to indicate the presence of dri2 sarea
|
||||
* info. */
|
||||
I915_INIT_DMA2 = 0x04
|
||||
} func;
|
||||
unsigned int mmio_offset;
|
||||
int sarea_priv_offset;
|
||||
unsigned int ring_start;
|
||||
unsigned int ring_end;
|
||||
unsigned int ring_size;
|
||||
unsigned int front_offset;
|
||||
unsigned int back_offset;
|
||||
unsigned int depth_offset;
|
||||
unsigned int w;
|
||||
unsigned int h;
|
||||
unsigned int pitch;
|
||||
unsigned int pitch_bits;
|
||||
unsigned int back_pitch;
|
||||
unsigned int depth_pitch;
|
||||
unsigned int cpp;
|
||||
unsigned int chipset;
|
||||
unsigned int sarea_handle;
|
||||
} drm_i915_init_t;
|
||||
|
||||
typedef struct drm_i915_sarea {
|
||||
struct drm_tex_region texList[I915_NR_TEX_REGIONS + 1];
|
||||
int last_upload; /* last time texture was uploaded */
|
||||
int last_enqueue; /* last time a buffer was enqueued */
|
||||
int last_dispatch; /* age of the most recently dispatched buffer */
|
||||
int ctxOwner; /* last context to upload state */
|
||||
int texAge;
|
||||
int pf_enabled; /* is pageflipping allowed? */
|
||||
int pf_active;
|
||||
int pf_current_page; /* which buffer is being displayed? */
|
||||
int perf_boxes; /* performance boxes to be displayed */
|
||||
int width, height; /* screen size in pixels */
|
||||
|
||||
drm_handle_t front_handle;
|
||||
int front_offset;
|
||||
int front_size;
|
||||
|
||||
drm_handle_t back_handle;
|
||||
int back_offset;
|
||||
int back_size;
|
||||
|
||||
drm_handle_t depth_handle;
|
||||
int depth_offset;
|
||||
int depth_size;
|
||||
|
||||
drm_handle_t tex_handle;
|
||||
int tex_offset;
|
||||
int tex_size;
|
||||
int log_tex_granularity;
|
||||
int pitch;
|
||||
int rotation; /* 0, 90, 180 or 270 */
|
||||
int rotated_offset;
|
||||
int rotated_size;
|
||||
int rotated_pitch;
|
||||
int virtualX, virtualY;
|
||||
|
||||
unsigned int front_tiled;
|
||||
unsigned int back_tiled;
|
||||
unsigned int depth_tiled;
|
||||
unsigned int rotated_tiled;
|
||||
unsigned int rotated2_tiled;
|
||||
|
||||
int planeA_x;
|
||||
int planeA_y;
|
||||
int planeA_w;
|
||||
int planeA_h;
|
||||
int planeB_x;
|
||||
int planeB_y;
|
||||
int planeB_w;
|
||||
int planeB_h;
|
||||
|
||||
/* Triple buffering */
|
||||
drm_handle_t third_handle;
|
||||
int third_offset;
|
||||
int third_size;
|
||||
unsigned int third_tiled;
|
||||
|
||||
/* buffer object handles for the static buffers. May change
|
||||
* over the lifetime of the client, though it doesn't in our current
|
||||
* implementation.
|
||||
*/
|
||||
unsigned int front_bo_handle;
|
||||
unsigned int back_bo_handle;
|
||||
unsigned int third_bo_handle;
|
||||
unsigned int depth_bo_handle;
|
||||
} drm_i915_sarea_t;
|
||||
|
||||
/* Driver specific fence types and classes.
|
||||
*/
|
||||
|
||||
/* The only fence class we support */
|
||||
#define DRM_I915_FENCE_CLASS_ACCEL 0
|
||||
/* Fence type that guarantees read-write flush */
|
||||
#define DRM_I915_FENCE_TYPE_RW 2
|
||||
/* MI_FLUSH programmed just before the fence */
|
||||
#define DRM_I915_FENCE_FLAG_FLUSHED 0x01000000
|
||||
|
||||
/* Flags for perf_boxes
|
||||
*/
|
||||
#define I915_BOX_RING_EMPTY 0x1
|
||||
#define I915_BOX_FLIP 0x2
|
||||
#define I915_BOX_WAIT 0x4
|
||||
#define I915_BOX_TEXTURE_LOAD 0x8
|
||||
#define I915_BOX_LOST_CONTEXT 0x10
|
||||
|
||||
/* I915 specific ioctls
|
||||
* The device specific ioctl range is 0x40 to 0x79.
|
||||
*/
|
||||
#define DRM_I915_INIT 0x00
|
||||
#define DRM_I915_FLUSH 0x01
|
||||
#define DRM_I915_FLIP 0x02
|
||||
#define DRM_I915_BATCHBUFFER 0x03
|
||||
#define DRM_I915_IRQ_EMIT 0x04
|
||||
#define DRM_I915_IRQ_WAIT 0x05
|
||||
#define DRM_I915_GETPARAM 0x06
|
||||
#define DRM_I915_SETPARAM 0x07
|
||||
#define DRM_I915_ALLOC 0x08
|
||||
#define DRM_I915_FREE 0x09
|
||||
#define DRM_I915_INIT_HEAP 0x0a
|
||||
#define DRM_I915_CMDBUFFER 0x0b
|
||||
#define DRM_I915_DESTROY_HEAP 0x0c
|
||||
#define DRM_I915_SET_VBLANK_PIPE 0x0d
|
||||
#define DRM_I915_GET_VBLANK_PIPE 0x0e
|
||||
#define DRM_I915_VBLANK_SWAP 0x0f
|
||||
#define DRM_I915_MMIO 0x10
|
||||
#define DRM_I915_HWS_ADDR 0x11
|
||||
#define DRM_I915_EXECBUFFER 0x12
|
||||
#define DRM_I915_GEM_INIT 0x13
|
||||
#define DRM_I915_GEM_EXECBUFFER 0x14
|
||||
#define DRM_I915_GEM_PIN 0x15
|
||||
#define DRM_I915_GEM_UNPIN 0x16
|
||||
#define DRM_I915_GEM_BUSY 0x17
|
||||
#define DRM_I915_GEM_THROTTLE 0x18
|
||||
#define DRM_I915_GEM_ENTERVT 0x19
|
||||
#define DRM_I915_GEM_LEAVEVT 0x1a
|
||||
#define DRM_I915_GEM_CREATE 0x1b
|
||||
#define DRM_I915_GEM_PREAD 0x1c
|
||||
#define DRM_I915_GEM_PWRITE 0x1d
|
||||
#define DRM_I915_GEM_MMAP 0x1e
|
||||
#define DRM_I915_GEM_SET_DOMAIN 0x1f
|
||||
#define DRM_I915_GEM_SW_FINISH 0x20
|
||||
#define DRM_I915_GEM_SET_TILING 0x21
|
||||
#define DRM_I915_GEM_GET_TILING 0x22
|
||||
#define DRM_I915_GEM_GET_APERTURE 0x23
|
||||
#define DRM_I915_GEM_MMAP_GTT 0x24
|
||||
#define DRM_I915_GET_PIPE_FROM_CRTC_ID 0x25
|
||||
#define DRM_I915_GEM_MADVISE 0x26
|
||||
#define DRM_I915_OVERLAY_PUT_IMAGE 0x27
|
||||
#define DRM_I915_OVERLAY_ATTRS 0x28
|
||||
#define DRM_I915_GEM_EXECBUFFER2 0x29
|
||||
#define DRM_I915_GET_SPRITE_COLORKEY 0x2a
|
||||
#define DRM_I915_SET_SPRITE_COLORKEY 0x2b
|
||||
|
||||
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
|
||||
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
|
||||
#define DRM_IOCTL_I915_FLIP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FLIP, drm_i915_flip_t)
|
||||
#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t)
|
||||
#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t)
|
||||
#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t)
|
||||
#define DRM_IOCTL_I915_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GETPARAM, drm_i915_getparam_t)
|
||||
#define DRM_IOCTL_I915_SETPARAM DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SETPARAM, drm_i915_setparam_t)
|
||||
#define DRM_IOCTL_I915_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_ALLOC, drm_i915_mem_alloc_t)
|
||||
#define DRM_IOCTL_I915_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FREE, drm_i915_mem_free_t)
|
||||
#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
|
||||
#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
|
||||
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
|
||||
#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
|
||||
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
|
||||
#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
|
||||
#define DRM_IOCTL_I915_MMIO DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_MMIO, drm_i915_mmio)
|
||||
#define DRM_IOCTL_I915_EXECBUFFER DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_EXECBUFFER, struct drm_i915_execbuffer)
|
||||
#define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init)
|
||||
#define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
|
||||
#define DRM_IOCTL_I915_GEM_EXECBUFFER2 DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2)
|
||||
#define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin)
|
||||
#define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin)
|
||||
#define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
|
||||
#define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
|
||||
#define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT)
|
||||
#define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT)
|
||||
#define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
|
||||
#define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
|
||||
#define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
|
||||
#define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
|
||||
#define DRM_IOCTL_I915_GEM_MMAP_GTT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt)
|
||||
#define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain)
|
||||
#define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish)
|
||||
#define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling)
|
||||
#define DRM_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling)
|
||||
#define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
|
||||
#define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id)
|
||||
#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
|
||||
#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_IOCTL_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image)
|
||||
#define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
|
||||
#define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
|
||||
#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
|
||||
|
||||
/* Asynchronous page flipping:
|
||||
*/
|
||||
typedef struct drm_i915_flip {
|
||||
/*
|
||||
* This is really talking about planes, and we could rename it
|
||||
* except for the fact that some of the duplicated i915_drm.h files
|
||||
* out there check for HAVE_I915_FLIP and so might pick up this
|
||||
* version.
|
||||
*/
|
||||
int pipes;
|
||||
} drm_i915_flip_t;
|
||||
|
||||
/* Allow drivers to submit batchbuffers directly to hardware, relying
|
||||
* on the security mechanisms provided by hardware.
|
||||
*/
|
||||
typedef struct drm_i915_batchbuffer {
|
||||
int start; /* agp offset */
|
||||
int used; /* nr bytes in use */
|
||||
int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */
|
||||
int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */
|
||||
int num_cliprects; /* mulitpass with multiple cliprects? */
|
||||
struct drm_clip_rect __user *cliprects; /* pointer to userspace cliprects */
|
||||
} drm_i915_batchbuffer_t;
|
||||
|
||||
/* As above, but pass a pointer to userspace buffer which can be
|
||||
* validated by the kernel prior to sending to hardware.
|
||||
*/
|
||||
typedef struct _drm_i915_cmdbuffer {
|
||||
char __user *buf; /* pointer to userspace command buffer */
|
||||
int sz; /* nr bytes in buf */
|
||||
int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */
|
||||
int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */
|
||||
int num_cliprects; /* mulitpass with multiple cliprects? */
|
||||
struct drm_clip_rect __user *cliprects; /* pointer to userspace cliprects */
|
||||
} drm_i915_cmdbuffer_t;
|
||||
|
||||
/* Userspace can request & wait on irq's:
|
||||
*/
|
||||
typedef struct drm_i915_irq_emit {
|
||||
int __user *irq_seq;
|
||||
} drm_i915_irq_emit_t;
|
||||
|
||||
typedef struct drm_i915_irq_wait {
|
||||
int irq_seq;
|
||||
} drm_i915_irq_wait_t;
|
||||
|
||||
/* Ioctl to query kernel params:
|
||||
*/
|
||||
#define I915_PARAM_IRQ_ACTIVE 1
|
||||
#define I915_PARAM_ALLOW_BATCHBUFFER 2
|
||||
#define I915_PARAM_LAST_DISPATCH 3
|
||||
#define I915_PARAM_CHIPSET_ID 4
|
||||
#define I915_PARAM_HAS_GEM 5
|
||||
#define I915_PARAM_NUM_FENCES_AVAIL 6
|
||||
#define I915_PARAM_HAS_OVERLAY 7
|
||||
#define I915_PARAM_HAS_PAGEFLIPPING 8
|
||||
#define I915_PARAM_HAS_EXECBUF2 9
|
||||
#define I915_PARAM_HAS_BSD 10
|
||||
#define I915_PARAM_HAS_BLT 11
|
||||
#define I915_PARAM_HAS_RELAXED_FENCING 12
|
||||
#define I915_PARAM_HAS_COHERENT_RINGS 13
|
||||
#define I915_PARAM_HAS_EXEC_CONSTANTS 14
|
||||
#define I915_PARAM_HAS_RELAXED_DELTA 15
|
||||
#define I915_PARAM_HAS_GEN7_SOL_RESET 16
|
||||
#define I915_PARAM_HAS_LLC 17
|
||||
|
||||
typedef struct drm_i915_getparam {
|
||||
int param;
|
||||
int __user *value;
|
||||
} drm_i915_getparam_t;
|
||||
|
||||
/* Ioctl to set kernel params:
|
||||
*/
|
||||
#define I915_SETPARAM_USE_MI_BATCHBUFFER_START 1
|
||||
#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2
|
||||
#define I915_SETPARAM_ALLOW_BATCHBUFFER 3
|
||||
#define I915_SETPARAM_NUM_USED_FENCES 4
|
||||
|
||||
typedef struct drm_i915_setparam {
|
||||
int param;
|
||||
int value;
|
||||
} drm_i915_setparam_t;
|
||||
|
||||
/* A memory manager for regions of shared memory:
|
||||
*/
|
||||
#define I915_MEM_REGION_AGP 1
|
||||
|
||||
typedef struct drm_i915_mem_alloc {
|
||||
int region;
|
||||
int alignment;
|
||||
int size;
|
||||
int __user *region_offset; /* offset from start of fb or agp */
|
||||
} drm_i915_mem_alloc_t;
|
||||
|
||||
typedef struct drm_i915_mem_free {
|
||||
int region;
|
||||
int region_offset;
|
||||
} drm_i915_mem_free_t;
|
||||
|
||||
typedef struct drm_i915_mem_init_heap {
|
||||
int region;
|
||||
int size;
|
||||
int start;
|
||||
} drm_i915_mem_init_heap_t;
|
||||
|
||||
/* Allow memory manager to be torn down and re-initialized (eg on
|
||||
* rotate):
|
||||
*/
|
||||
typedef struct drm_i915_mem_destroy_heap {
|
||||
int region;
|
||||
} drm_i915_mem_destroy_heap_t;
|
||||
|
||||
/* Allow X server to configure which pipes to monitor for vblank signals
|
||||
*/
|
||||
#define DRM_I915_VBLANK_PIPE_A 1
|
||||
#define DRM_I915_VBLANK_PIPE_B 2
|
||||
|
||||
typedef struct drm_i915_vblank_pipe {
|
||||
int pipe;
|
||||
} drm_i915_vblank_pipe_t;
|
||||
|
||||
/* Schedule buffer swap at given vertical blank:
|
||||
*/
|
||||
typedef struct drm_i915_vblank_swap {
|
||||
drm_drawable_t drawable;
|
||||
enum drm_vblank_seq_type seqtype;
|
||||
unsigned int sequence;
|
||||
} drm_i915_vblank_swap_t;
|
||||
|
||||
#define I915_MMIO_READ 0
|
||||
#define I915_MMIO_WRITE 1
|
||||
|
||||
#define I915_MMIO_MAY_READ 0x1
|
||||
#define I915_MMIO_MAY_WRITE 0x2
|
||||
|
||||
#define MMIO_REGS_IA_PRIMATIVES_COUNT 0
|
||||
#define MMIO_REGS_IA_VERTICES_COUNT 1
|
||||
#define MMIO_REGS_VS_INVOCATION_COUNT 2
|
||||
#define MMIO_REGS_GS_PRIMITIVES_COUNT 3
|
||||
#define MMIO_REGS_GS_INVOCATION_COUNT 4
|
||||
#define MMIO_REGS_CL_PRIMITIVES_COUNT 5
|
||||
#define MMIO_REGS_CL_INVOCATION_COUNT 6
|
||||
#define MMIO_REGS_PS_INVOCATION_COUNT 7
|
||||
#define MMIO_REGS_PS_DEPTH_COUNT 8
|
||||
|
||||
typedef struct drm_i915_mmio_entry {
|
||||
unsigned int flag;
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
} drm_i915_mmio_entry_t;
|
||||
|
||||
typedef struct drm_i915_mmio {
|
||||
unsigned int read_write:1;
|
||||
unsigned int reg:31;
|
||||
void __user *data;
|
||||
} drm_i915_mmio_t;
|
||||
|
||||
typedef struct drm_i915_hws_addr {
|
||||
uint64_t addr;
|
||||
} drm_i915_hws_addr_t;
|
||||
|
||||
/*
|
||||
* Relocation header is 4 uint32_ts
|
||||
* 0 - 32 bit reloc count
|
||||
* 1 - 32-bit relocation type
|
||||
* 2-3 - 64-bit user buffer handle ptr for another list of relocs.
|
||||
*/
|
||||
#define I915_RELOC_HEADER 4
|
||||
|
||||
/*
|
||||
* type 0 relocation has 4-uint32_t stride
|
||||
* 0 - offset into buffer
|
||||
* 1 - delta to add in
|
||||
* 2 - buffer handle
|
||||
* 3 - reserved (for optimisations later).
|
||||
*/
|
||||
/*
|
||||
* type 1 relocation has 4-uint32_t stride.
|
||||
* Hangs off the first item in the op list.
|
||||
* Performed after all valiations are done.
|
||||
* Try to group relocs into the same relocatee together for
|
||||
* performance reasons.
|
||||
* 0 - offset into buffer
|
||||
* 1 - delta to add in
|
||||
* 2 - buffer index in op list.
|
||||
* 3 - relocatee index in op list.
|
||||
*/
|
||||
#define I915_RELOC_TYPE_0 0
|
||||
#define I915_RELOC0_STRIDE 4
|
||||
#define I915_RELOC_TYPE_1 1
|
||||
#define I915_RELOC1_STRIDE 4
|
||||
|
||||
|
||||
struct drm_i915_op_arg {
|
||||
uint64_t next;
|
||||
uint64_t reloc_ptr;
|
||||
int handled;
|
||||
unsigned int pad64;
|
||||
union {
|
||||
struct drm_bo_op_req req;
|
||||
struct drm_bo_arg_rep rep;
|
||||
} d;
|
||||
|
||||
};
|
||||
|
||||
struct drm_i915_execbuffer {
|
||||
uint64_t ops_list;
|
||||
uint32_t num_buffers;
|
||||
struct drm_i915_batchbuffer batch;
|
||||
drm_context_t context; /* for lockless use in the future */
|
||||
struct drm_fence_arg fence_arg;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_init {
|
||||
/**
|
||||
* Beginning offset in the GTT to be managed by the DRM memory
|
||||
* manager.
|
||||
*/
|
||||
uint64_t gtt_start;
|
||||
/**
|
||||
* Ending offset in the GTT to be managed by the DRM memory
|
||||
* manager.
|
||||
*/
|
||||
uint64_t gtt_end;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_create {
|
||||
/**
|
||||
* Requested size for the object.
|
||||
*
|
||||
* The (page-aligned) allocated size for the object will be returned.
|
||||
*/
|
||||
uint64_t size;
|
||||
/**
|
||||
* Returned handle for the object.
|
||||
*
|
||||
* Object handles are nonzero.
|
||||
*/
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_pread {
|
||||
/** Handle for the object being read. */
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
/** Offset into the object to read from */
|
||||
uint64_t offset;
|
||||
/** Length of data to read */
|
||||
uint64_t size;
|
||||
/** Pointer to write the data into. */
|
||||
uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */
|
||||
};
|
||||
|
||||
struct drm_i915_gem_pwrite {
|
||||
/** Handle for the object being written to. */
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
/** Offset into the object to write to */
|
||||
uint64_t offset;
|
||||
/** Length of data to write */
|
||||
uint64_t size;
|
||||
/** Pointer to read the data from. */
|
||||
uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */
|
||||
};
|
||||
|
||||
struct drm_i915_gem_mmap {
|
||||
/** Handle for the object being mapped. */
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
/** Offset in the object to map. */
|
||||
uint64_t offset;
|
||||
/**
|
||||
* Length of data to map.
|
||||
*
|
||||
* The value will be page-aligned.
|
||||
*/
|
||||
uint64_t size;
|
||||
/** Returned pointer the data was mapped at */
|
||||
uint64_t addr_ptr; /* void *, but pointers are not 32/64 compatible */
|
||||
};
|
||||
|
||||
struct drm_i915_gem_mmap_gtt {
|
||||
/** Handle for the object being mapped. */
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
/**
|
||||
* Fake offset to use for subsequent mmap call
|
||||
*
|
||||
* This is a fixed-size type for 32/64 compatibility.
|
||||
*/
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_set_domain {
|
||||
/** Handle for the object */
|
||||
uint32_t handle;
|
||||
|
||||
/** New read domains */
|
||||
uint32_t read_domains;
|
||||
|
||||
/** New write domain */
|
||||
uint32_t write_domain;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_sw_finish {
|
||||
/** Handle for the object */
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_relocation_entry {
|
||||
/**
|
||||
* Handle of the buffer being pointed to by this relocation entry.
|
||||
*
|
||||
* It's appealing to make this be an index into the mm_validate_entry
|
||||
* list to refer to the buffer, but this allows the driver to create
|
||||
* a relocation list for state buffers and not re-write it per
|
||||
* exec using the buffer.
|
||||
*/
|
||||
uint32_t target_handle;
|
||||
|
||||
/**
|
||||
* Value to be added to the offset of the target buffer to make up
|
||||
* the relocation entry.
|
||||
*/
|
||||
uint32_t delta;
|
||||
|
||||
/** Offset in the buffer the relocation entry will be written into */
|
||||
uint64_t offset;
|
||||
|
||||
/**
|
||||
* Offset value of the target buffer that the relocation entry was last
|
||||
* written as.
|
||||
*
|
||||
* If the buffer has the same offset as last time, we can skip syncing
|
||||
* and writing the relocation. This value is written back out by
|
||||
* the execbuffer ioctl when the relocation is written.
|
||||
*/
|
||||
uint64_t presumed_offset;
|
||||
|
||||
/**
|
||||
* Target memory domains read by this operation.
|
||||
*/
|
||||
uint32_t read_domains;
|
||||
|
||||
/**
|
||||
* Target memory domains written by this operation.
|
||||
*
|
||||
* Note that only one domain may be written by the whole
|
||||
* execbuffer operation, so that where there are conflicts,
|
||||
* the application will get -EINVAL back.
|
||||
*/
|
||||
uint32_t write_domain;
|
||||
};
|
||||
|
||||
/** @{
|
||||
* Intel memory domains
|
||||
*
|
||||
* Most of these just align with the various caches in
|
||||
* the system and are used to flush and invalidate as
|
||||
* objects end up cached in different domains.
|
||||
*/
|
||||
/** CPU cache */
|
||||
#define I915_GEM_DOMAIN_CPU 0x00000001
|
||||
/** Render cache, used by 2D and 3D drawing */
|
||||
#define I915_GEM_DOMAIN_RENDER 0x00000002
|
||||
/** Sampler cache, used by texture engine */
|
||||
#define I915_GEM_DOMAIN_SAMPLER 0x00000004
|
||||
/** Command queue, used to load batch buffers */
|
||||
#define I915_GEM_DOMAIN_COMMAND 0x00000008
|
||||
/** Instruction cache, used by shader programs */
|
||||
#define I915_GEM_DOMAIN_INSTRUCTION 0x00000010
|
||||
/** Vertex address cache */
|
||||
#define I915_GEM_DOMAIN_VERTEX 0x00000020
|
||||
/** GTT domain - aperture and scanout */
|
||||
#define I915_GEM_DOMAIN_GTT 0x00000040
|
||||
/** @} */
|
||||
|
||||
struct drm_i915_gem_exec_object {
|
||||
/**
|
||||
* User's handle for a buffer to be bound into the GTT for this
|
||||
* operation.
|
||||
*/
|
||||
uint32_t handle;
|
||||
|
||||
/** Number of relocations to be performed on this buffer */
|
||||
uint32_t relocation_count;
|
||||
/**
|
||||
* Pointer to array of struct drm_i915_gem_relocation_entry containing
|
||||
* the relocations to be performed in this buffer.
|
||||
*/
|
||||
uint64_t relocs_ptr;
|
||||
|
||||
/** Required alignment in graphics aperture */
|
||||
uint64_t alignment;
|
||||
|
||||
/**
|
||||
* Returned value of the updated offset of the object, for future
|
||||
* presumed_offset writes.
|
||||
*/
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_execbuffer {
|
||||
/**
|
||||
* List of buffers to be validated with their relocations to be
|
||||
* performend on them.
|
||||
*
|
||||
* This is a pointer to an array of struct drm_i915_gem_validate_entry.
|
||||
*
|
||||
* These buffers must be listed in an order such that all relocations
|
||||
* a buffer is performing refer to buffers that have already appeared
|
||||
* in the validate list.
|
||||
*/
|
||||
uint64_t buffers_ptr;
|
||||
uint32_t buffer_count;
|
||||
|
||||
/** Offset in the batchbuffer to start execution from. */
|
||||
uint32_t batch_start_offset;
|
||||
/** Bytes used in batchbuffer from batch_start_offset */
|
||||
uint32_t batch_len;
|
||||
uint32_t DR1;
|
||||
uint32_t DR4;
|
||||
uint32_t num_cliprects;
|
||||
uint64_t cliprects_ptr; /* struct drm_clip_rect *cliprects */
|
||||
};
|
||||
|
||||
struct drm_i915_gem_exec_object2 {
|
||||
/**
|
||||
* User's handle for a buffer to be bound into the GTT for this
|
||||
* operation.
|
||||
*/
|
||||
uint32_t handle;
|
||||
|
||||
/** Number of relocations to be performed on this buffer */
|
||||
uint32_t relocation_count;
|
||||
/**
|
||||
* Pointer to array of struct drm_i915_gem_relocation_entry containing
|
||||
* the relocations to be performed in this buffer.
|
||||
*/
|
||||
uint64_t relocs_ptr;
|
||||
|
||||
/** Required alignment in graphics aperture */
|
||||
uint64_t alignment;
|
||||
|
||||
/**
|
||||
* Returned value of the updated offset of the object, for future
|
||||
* presumed_offset writes.
|
||||
*/
|
||||
uint64_t offset;
|
||||
|
||||
#define EXEC_OBJECT_NEEDS_FENCE (1<<0)
|
||||
uint64_t flags;
|
||||
uint64_t rsvd1;
|
||||
uint64_t rsvd2;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_execbuffer2 {
|
||||
/**
|
||||
* List of gem_exec_object2 structs
|
||||
*/
|
||||
uint64_t buffers_ptr;
|
||||
uint32_t buffer_count;
|
||||
|
||||
/** Offset in the batchbuffer to start execution from. */
|
||||
uint32_t batch_start_offset;
|
||||
/** Bytes used in batchbuffer from batch_start_offset */
|
||||
uint32_t batch_len;
|
||||
uint32_t DR1;
|
||||
uint32_t DR4;
|
||||
uint32_t num_cliprects;
|
||||
/** This is a struct drm_clip_rect *cliprects */
|
||||
uint64_t cliprects_ptr;
|
||||
#define I915_EXEC_RING_MASK (7<<0)
|
||||
#define I915_EXEC_DEFAULT (0<<0)
|
||||
#define I915_EXEC_RENDER (1<<0)
|
||||
#define I915_EXEC_BSD (2<<0)
|
||||
#define I915_EXEC_BLT (3<<0)
|
||||
|
||||
/* Used for switching the constants addressing mode on gen4+ RENDER ring.
|
||||
* Gen6+ only supports relative addressing to dynamic state (default) and
|
||||
* absolute addressing.
|
||||
*
|
||||
* These flags are ignored for the BSD and BLT rings.
|
||||
*/
|
||||
#define I915_EXEC_CONSTANTS_MASK (3<<6)
|
||||
#define I915_EXEC_CONSTANTS_REL_GENERAL (0<<6) /* default */
|
||||
#define I915_EXEC_CONSTANTS_ABSOLUTE (1<<6)
|
||||
#define I915_EXEC_CONSTANTS_REL_SURFACE (2<<6) /* gen4/5 only */
|
||||
uint64_t flags;
|
||||
uint64_t rsvd1;
|
||||
uint64_t rsvd2;
|
||||
};
|
||||
|
||||
/** Resets the SO write offset registers for transform feedback on gen7. */
|
||||
#define I915_EXEC_GEN7_SOL_RESET (1<<8)
|
||||
|
||||
struct drm_i915_gem_pin {
|
||||
/** Handle of the buffer to be pinned. */
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
|
||||
/** alignment required within the aperture */
|
||||
uint64_t alignment;
|
||||
|
||||
/** Returned GTT offset of the buffer. */
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_unpin {
|
||||
/** Handle of the buffer to be unpinned. */
|
||||
uint32_t handle;
|
||||
uint32_t pad;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_busy {
|
||||
/** Handle of the buffer to check for busy */
|
||||
uint32_t handle;
|
||||
|
||||
/** Return busy status (1 if busy, 0 if idle) */
|
||||
uint32_t busy;
|
||||
};
|
||||
|
||||
#define I915_TILING_NONE 0
|
||||
#define I915_TILING_X 1
|
||||
#define I915_TILING_Y 2
|
||||
|
||||
#define I915_BIT_6_SWIZZLE_NONE 0
|
||||
#define I915_BIT_6_SWIZZLE_9 1
|
||||
#define I915_BIT_6_SWIZZLE_9_10 2
|
||||
#define I915_BIT_6_SWIZZLE_9_11 3
|
||||
#define I915_BIT_6_SWIZZLE_9_10_11 4
|
||||
/* Not seen by userland */
|
||||
#define I915_BIT_6_SWIZZLE_UNKNOWN 5
|
||||
/* Seen by userland. */
|
||||
#define I915_BIT_6_SWIZZLE_9_17 6
|
||||
#define I915_BIT_6_SWIZZLE_9_10_17 7
|
||||
|
||||
struct drm_i915_gem_set_tiling {
|
||||
/** Handle of the buffer to have its tiling state updated */
|
||||
uint32_t handle;
|
||||
|
||||
/**
|
||||
* Tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
|
||||
* I915_TILING_Y).
|
||||
*
|
||||
* This value is to be set on request, and will be updated by the
|
||||
* kernel on successful return with the actual chosen tiling layout.
|
||||
*
|
||||
* The tiling mode may be demoted to I915_TILING_NONE when the system
|
||||
* has bit 6 swizzling that can't be managed correctly by GEM.
|
||||
*
|
||||
* Buffer contents become undefined when changing tiling_mode.
|
||||
*/
|
||||
uint32_t tiling_mode;
|
||||
|
||||
/**
|
||||
* Stride in bytes for the object when in I915_TILING_X or
|
||||
* I915_TILING_Y.
|
||||
*/
|
||||
uint32_t stride;
|
||||
|
||||
/**
|
||||
* Returned address bit 6 swizzling required for CPU access through
|
||||
* mmap mapping.
|
||||
*/
|
||||
uint32_t swizzle_mode;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_get_tiling {
|
||||
/** Handle of the buffer to get tiling state for. */
|
||||
uint32_t handle;
|
||||
|
||||
/**
|
||||
* Current tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
|
||||
* I915_TILING_Y).
|
||||
*/
|
||||
uint32_t tiling_mode;
|
||||
|
||||
/**
|
||||
* Returned address bit 6 swizzling required for CPU access through
|
||||
* mmap mapping.
|
||||
*/
|
||||
uint32_t swizzle_mode;
|
||||
};
|
||||
|
||||
struct drm_i915_gem_get_aperture {
|
||||
/** Total size of the aperture used by i915_gem_execbuffer, in bytes */
|
||||
uint64_t aper_size;
|
||||
|
||||
/**
|
||||
* Available space in the aperture used by i915_gem_execbuffer, in
|
||||
* bytes
|
||||
*/
|
||||
uint64_t aper_available_size;
|
||||
};
|
||||
|
||||
struct drm_i915_get_pipe_from_crtc_id {
|
||||
/** ID of CRTC being requested **/
|
||||
uint32_t crtc_id;
|
||||
|
||||
/** pipe of requested CRTC **/
|
||||
uint32_t pipe;
|
||||
};
|
||||
|
||||
#define I915_MADV_WILLNEED 0
|
||||
#define I915_MADV_DONTNEED 1
|
||||
#define I915_MADV_PURGED_INTERNAL 2 /* internal state */
|
||||
|
||||
struct drm_i915_gem_madvise {
|
||||
/** Handle of the buffer to change the backing store advice */
|
||||
uint32_t handle;
|
||||
|
||||
/* Advice: either the buffer will be needed again in the near future,
|
||||
* or wont be and could be discarded under memory pressure.
|
||||
*/
|
||||
uint32_t madv;
|
||||
|
||||
/** Whether the backing store still exists. */
|
||||
uint32_t retained;
|
||||
};
|
||||
|
||||
#define I915_OVERLAY_TYPE_MASK 0xff
|
||||
#define I915_OVERLAY_YUV_PLANAR 0x01
|
||||
#define I915_OVERLAY_YUV_PACKED 0x02
|
||||
#define I915_OVERLAY_RGB 0x03
|
||||
|
||||
#define I915_OVERLAY_DEPTH_MASK 0xff00
|
||||
#define I915_OVERLAY_RGB24 0x1000
|
||||
#define I915_OVERLAY_RGB16 0x2000
|
||||
#define I915_OVERLAY_RGB15 0x3000
|
||||
#define I915_OVERLAY_YUV422 0x0100
|
||||
#define I915_OVERLAY_YUV411 0x0200
|
||||
#define I915_OVERLAY_YUV420 0x0300
|
||||
#define I915_OVERLAY_YUV410 0x0400
|
||||
|
||||
#define I915_OVERLAY_SWAP_MASK 0xff0000
|
||||
#define I915_OVERLAY_NO_SWAP 0x000000
|
||||
#define I915_OVERLAY_UV_SWAP 0x010000
|
||||
#define I915_OVERLAY_Y_SWAP 0x020000
|
||||
#define I915_OVERLAY_Y_AND_UV_SWAP 0x030000
|
||||
|
||||
#define I915_OVERLAY_FLAGS_MASK 0xff000000
|
||||
#define I915_OVERLAY_ENABLE 0x01000000
|
||||
|
||||
struct drm_intel_overlay_put_image {
|
||||
/* various flags and src format description */
|
||||
uint32_t flags;
|
||||
/* source picture description */
|
||||
uint32_t bo_handle;
|
||||
/* stride values and offsets are in bytes, buffer relative */
|
||||
uint16_t stride_Y; /* stride for packed formats */
|
||||
uint16_t stride_UV;
|
||||
uint32_t offset_Y; /* offset for packet formats */
|
||||
uint32_t offset_U;
|
||||
uint32_t offset_V;
|
||||
/* in pixels */
|
||||
uint16_t src_width;
|
||||
uint16_t src_height;
|
||||
/* to compensate the scaling factors for partially covered surfaces */
|
||||
uint16_t src_scan_width;
|
||||
uint16_t src_scan_height;
|
||||
/* output crtc description */
|
||||
uint32_t crtc_id;
|
||||
uint16_t dst_x;
|
||||
uint16_t dst_y;
|
||||
uint16_t dst_width;
|
||||
uint16_t dst_height;
|
||||
};
|
||||
|
||||
/* flags */
|
||||
#define I915_OVERLAY_UPDATE_ATTRS (1<<0)
|
||||
#define I915_OVERLAY_UPDATE_GAMMA (1<<1)
|
||||
struct drm_intel_overlay_attrs {
|
||||
uint32_t flags;
|
||||
uint32_t color_key;
|
||||
int32_t brightness;
|
||||
uint32_t contrast;
|
||||
uint32_t saturation;
|
||||
uint32_t gamma0;
|
||||
uint32_t gamma1;
|
||||
uint32_t gamma2;
|
||||
uint32_t gamma3;
|
||||
uint32_t gamma4;
|
||||
uint32_t gamma5;
|
||||
};
|
||||
|
||||
/*
|
||||
* Intel sprite handling
|
||||
*
|
||||
* Color keying works with a min/mask/max tuple. Both source and destination
|
||||
* color keying is allowed.
|
||||
*
|
||||
* Source keying:
|
||||
* Sprite pixels within the min & max values, masked against the color channels
|
||||
* specified in the mask field, will be transparent. All other pixels will
|
||||
* be displayed on top of the primary plane. For RGB surfaces, only the min
|
||||
* and mask fields will be used; ranged compares are not allowed.
|
||||
*
|
||||
* Destination keying:
|
||||
* Primary plane pixels that match the min value, masked against the color
|
||||
* channels specified in the mask field, will be replaced by corresponding
|
||||
* pixels from the sprite plane.
|
||||
*
|
||||
* Note that source & destination keying are exclusive; only one can be
|
||||
* active on a given plane.
|
||||
*/
|
||||
|
||||
#define I915_SET_COLORKEY_NONE (1<<0) /* disable color key matching */
|
||||
#define I915_SET_COLORKEY_DESTINATION (1<<1)
|
||||
#define I915_SET_COLORKEY_SOURCE (1<<2)
|
||||
struct drm_intel_sprite_colorkey {
|
||||
uint32_t plane_id;
|
||||
uint32_t min_value;
|
||||
uint32_t channel_mask;
|
||||
uint32_t max_value;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
#endif /* _I915_DRM_H_ */
|
||||
821
sys/dev/drm2/i915/i915_drv.c
Normal file
821
sys/dev/drm2/i915/i915_drv.c
Normal file
|
|
@ -0,0 +1,821 @@
|
|||
/* i915_drv.c -- Intel i915 driver -*- linux-c -*-
|
||||
* Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com
|
||||
*/
|
||||
/*-
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_mm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/drm_pciids.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
|
||||
static drm_pci_id_list_t i915_pciidlist[] = {
|
||||
i915_PCI_IDS
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i830_info = {
|
||||
.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_845g_info = {
|
||||
.gen = 2,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i85x_info = {
|
||||
.gen = 2, .is_i85x = 1, .is_mobile = 1,
|
||||
.cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i865g_info = {
|
||||
.gen = 2,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i915g_info = {
|
||||
.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
static const struct intel_device_info intel_i915gm_info = {
|
||||
.gen = 3, .is_mobile = 1,
|
||||
.cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.supports_tv = 1,
|
||||
};
|
||||
static const struct intel_device_info intel_i945g_info = {
|
||||
.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
};
|
||||
static const struct intel_device_info intel_i945gm_info = {
|
||||
.gen = 3, .is_i945gm = 1, .is_mobile = 1,
|
||||
.has_hotplug = 1, .cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.supports_tv = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i965g_info = {
|
||||
.gen = 4, .is_broadwater = 1,
|
||||
.has_hotplug = 1,
|
||||
.has_overlay = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i965gm_info = {
|
||||
.gen = 4, .is_crestline = 1,
|
||||
.is_mobile = 1, .has_fbc = 1, .has_hotplug = 1,
|
||||
.has_overlay = 1,
|
||||
.supports_tv = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_g33_info = {
|
||||
.gen = 3, .is_g33 = 1,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_overlay = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_g45_info = {
|
||||
.gen = 4, .is_g4x = 1, .need_gfx_hws = 1,
|
||||
.has_pipe_cxsr = 1, .has_hotplug = 1,
|
||||
.has_bsd_ring = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_gm45_info = {
|
||||
.gen = 4, .is_g4x = 1,
|
||||
.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1,
|
||||
.has_pipe_cxsr = 1, .has_hotplug = 1,
|
||||
.supports_tv = 1,
|
||||
.has_bsd_ring = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_pineview_info = {
|
||||
.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_overlay = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ironlake_d_info = {
|
||||
.gen = 5,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_bsd_ring = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ironlake_m_info = {
|
||||
.gen = 5, .is_mobile = 1,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 0, /* disabled due to buggy hardware */
|
||||
.has_bsd_ring = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_sandybridge_d_info = {
|
||||
.gen = 6,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.has_llc = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_sandybridge_m_info = {
|
||||
.gen = 6, .is_mobile = 1,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 1,
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.has_llc = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_d_info = {
|
||||
.is_ivybridge = 1, .gen = 7,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.has_llc = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_m_info = {
|
||||
.is_ivybridge = 1, .gen = 7, .is_mobile = 1,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */
|
||||
.has_bsd_ring = 1,
|
||||
.has_blt_ring = 1,
|
||||
.has_llc = 1,
|
||||
};
|
||||
|
||||
#define INTEL_VGA_DEVICE(id, info_) { \
|
||||
.device = id, \
|
||||
.info = info_, \
|
||||
}
|
||||
|
||||
static const struct intel_gfx_device_id {
|
||||
int device;
|
||||
const struct intel_device_info *info;
|
||||
} pciidlist[] = { /* aka */
|
||||
INTEL_VGA_DEVICE(0x3577, &intel_i830_info),
|
||||
INTEL_VGA_DEVICE(0x2562, &intel_845g_info),
|
||||
INTEL_VGA_DEVICE(0x3582, &intel_i85x_info),
|
||||
INTEL_VGA_DEVICE(0x358e, &intel_i85x_info),
|
||||
INTEL_VGA_DEVICE(0x2572, &intel_i865g_info),
|
||||
INTEL_VGA_DEVICE(0x2582, &intel_i915g_info),
|
||||
INTEL_VGA_DEVICE(0x258a, &intel_i915g_info),
|
||||
INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info),
|
||||
INTEL_VGA_DEVICE(0x2772, &intel_i945g_info),
|
||||
INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info),
|
||||
INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info),
|
||||
INTEL_VGA_DEVICE(0x2972, &intel_i965g_info),
|
||||
INTEL_VGA_DEVICE(0x2982, &intel_i965g_info),
|
||||
INTEL_VGA_DEVICE(0x2992, &intel_i965g_info),
|
||||
INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info),
|
||||
INTEL_VGA_DEVICE(0x29b2, &intel_g33_info),
|
||||
INTEL_VGA_DEVICE(0x29c2, &intel_g33_info),
|
||||
INTEL_VGA_DEVICE(0x29d2, &intel_g33_info),
|
||||
INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info),
|
||||
INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info),
|
||||
INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info),
|
||||
INTEL_VGA_DEVICE(0x2e02, &intel_g45_info),
|
||||
INTEL_VGA_DEVICE(0x2e12, &intel_g45_info),
|
||||
INTEL_VGA_DEVICE(0x2e22, &intel_g45_info),
|
||||
INTEL_VGA_DEVICE(0x2e32, &intel_g45_info),
|
||||
INTEL_VGA_DEVICE(0x2e42, &intel_g45_info),
|
||||
INTEL_VGA_DEVICE(0x2e92, &intel_g45_info),
|
||||
INTEL_VGA_DEVICE(0xa001, &intel_pineview_info),
|
||||
INTEL_VGA_DEVICE(0xa011, &intel_pineview_info),
|
||||
INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info),
|
||||
INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info),
|
||||
INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info),
|
||||
INTEL_VGA_DEVICE(0x0112, &intel_sandybridge_d_info),
|
||||
INTEL_VGA_DEVICE(0x0122, &intel_sandybridge_d_info),
|
||||
INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info),
|
||||
INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info),
|
||||
INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info),
|
||||
INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info),
|
||||
INTEL_VGA_DEVICE(0x0156, &intel_ivybridge_m_info), /* GT1 mobile */
|
||||
INTEL_VGA_DEVICE(0x0166, &intel_ivybridge_m_info), /* GT2 mobile */
|
||||
INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */
|
||||
INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
|
||||
INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
|
||||
INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static int i915_drm_freeze(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
int error;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
drm_kms_helper_poll_disable(dev);
|
||||
|
||||
#if 0
|
||||
pci_save_state(dev->pdev);
|
||||
#endif
|
||||
|
||||
DRM_LOCK(dev);
|
||||
/* If KMS is active, we do the leavevt stuff here */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
error = -i915_gem_idle(dev);
|
||||
if (error) {
|
||||
DRM_UNLOCK(dev);
|
||||
device_printf(dev->device,
|
||||
"GEM idle failed, resume might fail\n");
|
||||
return (error);
|
||||
}
|
||||
drm_irq_uninstall(dev);
|
||||
}
|
||||
|
||||
i915_save_state(dev);
|
||||
|
||||
intel_opregion_fini(dev);
|
||||
|
||||
/* Modeset on resume, not lid events */
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_suspend(device_t kdev)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
int error;
|
||||
|
||||
dev = device_get_softc(kdev);
|
||||
if (dev == NULL || dev->dev_private == NULL) {
|
||||
DRM_ERROR("DRM not initialized, aborting suspend.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("starting suspend\n");
|
||||
error = i915_drm_freeze(dev);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = bus_generic_suspend(kdev);
|
||||
DRM_DEBUG_KMS("finished suspend %d\n", error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int i915_drm_thaw(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int error = 0;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
i915_gem_restore_gtt_mappings(dev);
|
||||
}
|
||||
|
||||
i915_restore_state(dev);
|
||||
intel_opregion_setup(dev);
|
||||
|
||||
/* KMS EnterVT equivalent */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
dev_priv->mm.suspended = 0;
|
||||
|
||||
error = i915_gem_init_hw(dev);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
ironlake_init_pch_refclk(dev);
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
sx_xlock(&dev->mode_config.mutex);
|
||||
drm_mode_config_reset(dev);
|
||||
sx_xunlock(&dev->mode_config.mutex);
|
||||
drm_irq_install(dev);
|
||||
|
||||
sx_xlock(&dev->mode_config.mutex);
|
||||
/* Resume the modeset for every activated CRTC */
|
||||
drm_helper_resume_force_mode(dev);
|
||||
sx_xunlock(&dev->mode_config.mutex);
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_enable_rc6(dev);
|
||||
DRM_LOCK(dev);
|
||||
}
|
||||
|
||||
intel_opregion_init(dev);
|
||||
|
||||
dev_priv->modeset_on_lid = 0;
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_resume(device_t kdev)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
int ret;
|
||||
|
||||
dev = device_get_softc(kdev);
|
||||
DRM_DEBUG_KMS("starting resume\n");
|
||||
#if 0
|
||||
if (pci_enable_device(dev->pdev))
|
||||
return -EIO;
|
||||
|
||||
pci_set_master(dev->pdev);
|
||||
#endif
|
||||
|
||||
ret = -i915_drm_thaw(dev);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
drm_kms_helper_poll_enable(dev);
|
||||
ret = bus_generic_resume(kdev);
|
||||
DRM_DEBUG_KMS("finished resume %d\n", ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
i915_probe(device_t kdev)
|
||||
{
|
||||
|
||||
return drm_probe(kdev, i915_pciidlist);
|
||||
}
|
||||
|
||||
int i915_modeset;
|
||||
|
||||
static int
|
||||
i915_attach(device_t kdev)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
|
||||
dev = device_get_softc(kdev);
|
||||
if (i915_modeset == 1)
|
||||
i915_driver_info.driver_features |= DRIVER_MODESET;
|
||||
dev->driver = &i915_driver_info;
|
||||
return (drm_attach(kdev, i915_pciidlist));
|
||||
}
|
||||
|
||||
const struct intel_device_info *
|
||||
i915_get_device_id(int device)
|
||||
{
|
||||
const struct intel_gfx_device_id *did;
|
||||
|
||||
for (did = &pciidlist[0]; did->device != 0; did++) {
|
||||
if (did->device != device)
|
||||
continue;
|
||||
return (did->info);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static device_method_t i915_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, i915_probe),
|
||||
DEVMETHOD(device_attach, i915_attach),
|
||||
DEVMETHOD(device_suspend, i915_suspend),
|
||||
DEVMETHOD(device_resume, i915_resume),
|
||||
DEVMETHOD(device_detach, drm_detach),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t i915_driver = {
|
||||
"drmn",
|
||||
i915_methods,
|
||||
sizeof(struct drm_device)
|
||||
};
|
||||
|
||||
extern devclass_t drm_devclass;
|
||||
DRIVER_MODULE_ORDERED(i915kms, vgapci, i915_driver, drm_devclass, 0, 0,
|
||||
SI_ORDER_ANY);
|
||||
MODULE_DEPEND(i915kms, drmn, 1, 1, 1);
|
||||
MODULE_DEPEND(i915kms, agp, 1, 1, 1);
|
||||
MODULE_DEPEND(i915kms, iicbus, 1, 1, 1);
|
||||
MODULE_DEPEND(i915kms, iic, 1, 1, 1);
|
||||
MODULE_DEPEND(i915kms, iicbb, 1, 1, 1);
|
||||
|
||||
int intel_iommu_enabled = 0;
|
||||
TUNABLE_INT("drm.i915.intel_iommu_enabled", &intel_iommu_enabled);
|
||||
|
||||
int i915_semaphores = -1;
|
||||
TUNABLE_INT("drm.i915.semaphores", &i915_semaphores);
|
||||
static int i915_try_reset = 1;
|
||||
TUNABLE_INT("drm.i915.try_reset", &i915_try_reset);
|
||||
unsigned int i915_lvds_downclock = 0;
|
||||
TUNABLE_INT("drm.i915.lvds_downclock", &i915_lvds_downclock);
|
||||
int i915_vbt_sdvo_panel_type = -1;
|
||||
TUNABLE_INT("drm.i915.vbt_sdvo_panel_type", &i915_vbt_sdvo_panel_type);
|
||||
unsigned int i915_powersave = 1;
|
||||
TUNABLE_INT("drm.i915.powersave", &i915_powersave);
|
||||
int i915_enable_fbc = 0;
|
||||
TUNABLE_INT("drm.i915.enable_fbc", &i915_enable_fbc);
|
||||
int i915_enable_rc6 = 0;
|
||||
TUNABLE_INT("drm.i915.enable_rc6", &i915_enable_rc6);
|
||||
int i915_panel_use_ssc = -1;
|
||||
TUNABLE_INT("drm.i915.panel_use_ssc", &i915_panel_use_ssc);
|
||||
int i915_panel_ignore_lid = 0;
|
||||
TUNABLE_INT("drm.i915.panel_ignore_lid", &i915_panel_ignore_lid);
|
||||
int i915_modeset = 1;
|
||||
TUNABLE_INT("drm.i915.modeset", &i915_modeset);
|
||||
int i915_enable_ppgtt = -1;
|
||||
TUNABLE_INT("drm.i915.enable_ppgtt", &i915_enable_ppgtt);
|
||||
int i915_enable_hangcheck = 1;
|
||||
TUNABLE_INT("drm.i915.enable_hangcheck", &i915_enable_hangcheck);
|
||||
|
||||
#define PCI_VENDOR_INTEL 0x8086
|
||||
#define INTEL_PCH_DEVICE_ID_MASK 0xff00
|
||||
#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00
|
||||
#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00
|
||||
#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00
|
||||
|
||||
void
|
||||
intel_detect_pch(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
device_t pch;
|
||||
uint32_t id;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
pch = pci_find_class(PCIC_BRIDGE, PCIS_BRIDGE_ISA);
|
||||
if (pch != NULL && pci_get_vendor(pch) == PCI_VENDOR_INTEL) {
|
||||
id = pci_get_device(pch) & INTEL_PCH_DEVICE_ID_MASK;
|
||||
if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
|
||||
dev_priv->pch_type = PCH_IBX;
|
||||
DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
|
||||
} else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
|
||||
dev_priv->pch_type = PCH_CPT;
|
||||
DRM_DEBUG_KMS("Found CougarPoint PCH\n");
|
||||
} else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
|
||||
/* PantherPoint is CPT compatible */
|
||||
dev_priv->pch_type = PCH_CPT;
|
||||
DRM_DEBUG_KMS("Found PatherPoint PCH\n");
|
||||
} else
|
||||
DRM_DEBUG_KMS("No PCH detected\n");
|
||||
} else
|
||||
DRM_DEBUG_KMS("No Intel PCI-ISA bridge found\n");
|
||||
}
|
||||
|
||||
void
|
||||
__gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1))
|
||||
DELAY(10000);
|
||||
|
||||
I915_WRITE_NOTRACE(FORCEWAKE, 1);
|
||||
POSTING_READ(FORCEWAKE);
|
||||
|
||||
count = 0;
|
||||
while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0)
|
||||
DELAY(10000);
|
||||
}
|
||||
|
||||
void
|
||||
__gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1))
|
||||
DELAY(10000);
|
||||
|
||||
I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 1);
|
||||
POSTING_READ(FORCEWAKE_MT);
|
||||
|
||||
count = 0;
|
||||
while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1) == 0)
|
||||
DELAY(10000);
|
||||
}
|
||||
|
||||
void
|
||||
gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
|
||||
mtx_lock(&dev_priv->gt_lock);
|
||||
if (dev_priv->forcewake_count++ == 0)
|
||||
dev_priv->display.force_wake_get(dev_priv);
|
||||
mtx_unlock(&dev_priv->gt_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
u32 gtfifodbg;
|
||||
|
||||
gtfifodbg = I915_READ_NOTRACE(GTFIFODBG);
|
||||
if ((gtfifodbg & GT_FIFO_CPU_ERROR_MASK) != 0) {
|
||||
printf("MMIO read or write has been dropped %x\n", gtfifodbg);
|
||||
I915_WRITE_NOTRACE(GTFIFODBG, GT_FIFO_CPU_ERROR_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
__gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
|
||||
I915_WRITE_NOTRACE(FORCEWAKE, 0);
|
||||
/* The below doubles as a POSTING_READ */
|
||||
gen6_gt_check_fifodbg(dev_priv);
|
||||
}
|
||||
|
||||
void
|
||||
__gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
|
||||
I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0);
|
||||
/* The below doubles as a POSTING_READ */
|
||||
gen6_gt_check_fifodbg(dev_priv);
|
||||
}
|
||||
|
||||
void
|
||||
gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
|
||||
mtx_lock(&dev_priv->gt_lock);
|
||||
if (--dev_priv->forcewake_count == 0)
|
||||
dev_priv->display.force_wake_put(dev_priv);
|
||||
mtx_unlock(&dev_priv->gt_lock);
|
||||
}
|
||||
|
||||
int
|
||||
__gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dev_priv->gt_fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) {
|
||||
int loop = 500;
|
||||
u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
|
||||
while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) {
|
||||
DELAY(10000);
|
||||
fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
|
||||
}
|
||||
if (loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES) {
|
||||
printf("%s loop\n", __func__);
|
||||
++ret;
|
||||
}
|
||||
dev_priv->gt_fifo_count = fifo;
|
||||
}
|
||||
dev_priv->gt_fifo_count--;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
i8xx_do_reset(struct drm_device *dev, u8 flags)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int onems;
|
||||
|
||||
if (IS_I85X(dev))
|
||||
return -ENODEV;
|
||||
|
||||
onems = hz / 1000;
|
||||
if (onems == 0)
|
||||
onems = 1;
|
||||
|
||||
I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830);
|
||||
POSTING_READ(D_STATE);
|
||||
|
||||
if (IS_I830(dev) || IS_845G(dev)) {
|
||||
I915_WRITE(DEBUG_RESET_I830,
|
||||
DEBUG_RESET_DISPLAY |
|
||||
DEBUG_RESET_RENDER |
|
||||
DEBUG_RESET_FULL);
|
||||
POSTING_READ(DEBUG_RESET_I830);
|
||||
pause("i8xxrst1", onems);
|
||||
|
||||
I915_WRITE(DEBUG_RESET_I830, 0);
|
||||
POSTING_READ(DEBUG_RESET_I830);
|
||||
}
|
||||
|
||||
pause("i8xxrst2", onems);
|
||||
|
||||
I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830);
|
||||
POSTING_READ(D_STATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i965_reset_complete(struct drm_device *dev)
|
||||
{
|
||||
u8 gdrst;
|
||||
|
||||
gdrst = pci_read_config(dev->device, I965_GDRST, 1);
|
||||
return (gdrst & 0x1);
|
||||
}
|
||||
|
||||
static int
|
||||
i965_do_reset(struct drm_device *dev, u8 flags)
|
||||
{
|
||||
u8 gdrst;
|
||||
|
||||
/*
|
||||
* Set the domains we want to reset (GRDOM/bits 2 and 3) as
|
||||
* well as the reset bit (GR/bit 0). Setting the GR bit
|
||||
* triggers the reset; when done, the hardware will clear it.
|
||||
*/
|
||||
gdrst = pci_read_config(dev->device, I965_GDRST, 1);
|
||||
pci_write_config(dev->device, I965_GDRST, gdrst | flags | 0x1, 1);
|
||||
|
||||
return (_intel_wait_for(dev, i965_reset_complete(dev), 500, 1,
|
||||
"915rst"));
|
||||
}
|
||||
|
||||
static int
|
||||
ironlake_do_reset(struct drm_device *dev, u8 flags)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
u32 gdrst;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
|
||||
I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1);
|
||||
return (_intel_wait_for(dev,
|
||||
(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1) != 0,
|
||||
500, 1, "915rst"));
|
||||
}
|
||||
|
||||
static int
|
||||
gen6_do_reset(struct drm_device *dev, u8 flags)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
int ret;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
/* Hold gt_lock across reset to prevent any register access
|
||||
* with forcewake not set correctly
|
||||
*/
|
||||
mtx_lock(&dev_priv->gt_lock);
|
||||
|
||||
/* Reset the chip */
|
||||
|
||||
/* GEN6_GDRST is not in the gt power well, no need to check
|
||||
* for fifo space for the write or forcewake the chip for
|
||||
* the read
|
||||
*/
|
||||
I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL);
|
||||
|
||||
/* Spin waiting for the device to ack the reset request */
|
||||
ret = _intel_wait_for(dev,
|
||||
(I915_READ(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0,
|
||||
500, 1, "915rst");
|
||||
|
||||
/* If reset with a user forcewake, try to restore, otherwise turn it off */
|
||||
if (dev_priv->forcewake_count)
|
||||
dev_priv->display.force_wake_get(dev_priv);
|
||||
else
|
||||
dev_priv->display.force_wake_put(dev_priv);
|
||||
|
||||
/* Restore fifo count */
|
||||
dev_priv->gt_fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES);
|
||||
|
||||
mtx_unlock(&dev_priv->gt_lock);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
i915_reset(struct drm_device *dev, u8 flags)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
/*
|
||||
* We really should only reset the display subsystem if we actually
|
||||
* need to
|
||||
*/
|
||||
bool need_display = true;
|
||||
int ret;
|
||||
|
||||
if (!i915_try_reset)
|
||||
return (0);
|
||||
|
||||
if (!sx_try_xlock(&dev->dev_struct_lock))
|
||||
return (-EBUSY);
|
||||
|
||||
i915_gem_reset(dev);
|
||||
|
||||
ret = -ENODEV;
|
||||
if (time_second - dev_priv->last_gpu_reset < 5) {
|
||||
DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
|
||||
} else {
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 7:
|
||||
case 6:
|
||||
ret = gen6_do_reset(dev, flags);
|
||||
break;
|
||||
case 5:
|
||||
ret = ironlake_do_reset(dev, flags);
|
||||
break;
|
||||
case 4:
|
||||
ret = i965_do_reset(dev, flags);
|
||||
break;
|
||||
case 2:
|
||||
ret = i8xx_do_reset(dev, flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
dev_priv->last_gpu_reset = time_second;
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to reset chip.\n");
|
||||
DRM_UNLOCK(dev);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET) ||
|
||||
!dev_priv->mm.suspended) {
|
||||
dev_priv->mm.suspended = 0;
|
||||
|
||||
i915_gem_init_swizzling(dev);
|
||||
|
||||
dev_priv->rings[RCS].init(&dev_priv->rings[RCS]);
|
||||
if (HAS_BSD(dev))
|
||||
dev_priv->rings[VCS].init(&dev_priv->rings[VCS]);
|
||||
if (HAS_BLT(dev))
|
||||
dev_priv->rings[BCS].init(&dev_priv->rings[BCS]);
|
||||
|
||||
i915_gem_init_ppgtt(dev);
|
||||
|
||||
drm_irq_uninstall(dev);
|
||||
drm_mode_config_reset(dev);
|
||||
DRM_UNLOCK(dev);
|
||||
drm_irq_install(dev);
|
||||
DRM_LOCK(dev);
|
||||
}
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
if (need_display) {
|
||||
sx_xlock(&dev->mode_config.mutex);
|
||||
drm_helper_resume_force_mode(dev);
|
||||
sx_xunlock(&dev->mode_config.mutex);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define __i915_read(x, y) \
|
||||
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
|
||||
u##x val = 0; \
|
||||
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
|
||||
mtx_lock(&dev_priv->gt_lock); \
|
||||
if (dev_priv->forcewake_count == 0) \
|
||||
dev_priv->display.force_wake_get(dev_priv); \
|
||||
val = DRM_READ##y(dev_priv->mmio_map, reg); \
|
||||
if (dev_priv->forcewake_count == 0) \
|
||||
dev_priv->display.force_wake_put(dev_priv); \
|
||||
mtx_unlock(&dev_priv->gt_lock); \
|
||||
} else { \
|
||||
val = DRM_READ##y(dev_priv->mmio_map, reg); \
|
||||
} \
|
||||
trace_i915_reg_rw(false, reg, val, sizeof(val)); \
|
||||
return val; \
|
||||
}
|
||||
|
||||
__i915_read(8, 8)
|
||||
__i915_read(16, 16)
|
||||
__i915_read(32, 32)
|
||||
__i915_read(64, 64)
|
||||
#undef __i915_read
|
||||
|
||||
#define __i915_write(x, y) \
|
||||
void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
|
||||
u32 __fifo_ret = 0; \
|
||||
trace_i915_reg_rw(true, reg, val, sizeof(val)); \
|
||||
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
|
||||
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
|
||||
} \
|
||||
DRM_WRITE##y(dev_priv->mmio_map, reg, val); \
|
||||
if (__predict_false(__fifo_ret)) { \
|
||||
gen6_gt_check_fifodbg(dev_priv); \
|
||||
} \
|
||||
}
|
||||
__i915_write(8, 8)
|
||||
__i915_write(16, 16)
|
||||
__i915_write(32, 32)
|
||||
__i915_write(64, 64)
|
||||
#undef __i915_write
|
||||
1481
sys/dev/drm2/i915/i915_drv.h
Normal file
1481
sys/dev/drm2/i915/i915_drv.h
Normal file
File diff suppressed because it is too large
Load diff
3760
sys/dev/drm2/i915/i915_gem.c
Normal file
3760
sys/dev/drm2/i915/i915_gem.c
Normal file
File diff suppressed because it is too large
Load diff
213
sys/dev/drm2/i915/i915_gem_evict.c
Normal file
213
sys/dev/drm2/i915/i915_gem_evict.c
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Copyright © 2008-2010 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Chris Wilson <chris@chris-wilson.co.uuk>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
|
||||
static bool
|
||||
mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
|
||||
{
|
||||
list_add(&obj->exec_list, unwind);
|
||||
return drm_mm_scan_add_block(obj->gtt_space);
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_evict_something(struct drm_device *dev, int min_size,
|
||||
unsigned alignment, bool mappable)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct list_head eviction_list, unwind_list;
|
||||
struct drm_i915_gem_object *obj;
|
||||
int ret = 0;
|
||||
|
||||
CTR4(KTR_DRM, "evict_something %p %d %u %d", dev, min_size,
|
||||
alignment, mappable);
|
||||
|
||||
/*
|
||||
* The goal is to evict objects and amalgamate space in LRU order.
|
||||
* The oldest idle objects reside on the inactive list, which is in
|
||||
* retirement order. The next objects to retire are those on the (per
|
||||
* ring) active list that do not have an outstanding flush. Once the
|
||||
* hardware reports completion (the seqno is updated after the
|
||||
* batchbuffer has been finished) the clean buffer objects would
|
||||
* be retired to the inactive list. Any dirty objects would be added
|
||||
* to the tail of the flushing list. So after processing the clean
|
||||
* active objects we need to emit a MI_FLUSH to retire the flushing
|
||||
* list, hence the retirement order of the flushing list is in
|
||||
* advance of the dirty objects on the active lists.
|
||||
*
|
||||
* The retirement sequence is thus:
|
||||
* 1. Inactive objects (already retired)
|
||||
* 2. Clean active objects
|
||||
* 3. Flushing list
|
||||
* 4. Dirty active objects.
|
||||
*
|
||||
* On each list, the oldest objects lie at the HEAD with the freshest
|
||||
* object on the TAIL.
|
||||
*/
|
||||
|
||||
INIT_LIST_HEAD(&unwind_list);
|
||||
if (mappable)
|
||||
drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size,
|
||||
alignment, 0,
|
||||
dev_priv->mm.gtt_mappable_end);
|
||||
else
|
||||
drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
|
||||
|
||||
/* First see if there is a large enough contiguous idle region... */
|
||||
list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
|
||||
if (mark_free(obj, &unwind_list))
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Now merge in the soon-to-be-expired objects... */
|
||||
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
|
||||
/* Does the object require an outstanding flush? */
|
||||
if (obj->base.write_domain || obj->pin_count)
|
||||
continue;
|
||||
|
||||
if (mark_free(obj, &unwind_list))
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Finally add anything with a pending flush (in order of retirement) */
|
||||
list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) {
|
||||
if (obj->pin_count)
|
||||
continue;
|
||||
|
||||
if (mark_free(obj, &unwind_list))
|
||||
goto found;
|
||||
}
|
||||
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
|
||||
if (!obj->base.write_domain || obj->pin_count)
|
||||
continue;
|
||||
|
||||
if (mark_free(obj, &unwind_list))
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* Nothing found, clean up and bail out! */
|
||||
while (!list_empty(&unwind_list)) {
|
||||
obj = list_first_entry(&unwind_list,
|
||||
struct drm_i915_gem_object,
|
||||
exec_list);
|
||||
|
||||
ret = drm_mm_scan_remove_block(obj->gtt_space);
|
||||
KASSERT(ret == 0, ("drm_mm_scan_remove_block failed %d", ret));
|
||||
|
||||
list_del_init(&obj->exec_list);
|
||||
}
|
||||
|
||||
/* We expect the caller to unpin, evict all and try again, or give up.
|
||||
* So calling i915_gem_evict_everything() is unnecessary.
|
||||
*/
|
||||
return -ENOSPC;
|
||||
|
||||
found:
|
||||
/* drm_mm doesn't allow any other other operations while
|
||||
* scanning, therefore store to be evicted objects on a
|
||||
* temporary list. */
|
||||
INIT_LIST_HEAD(&eviction_list);
|
||||
while (!list_empty(&unwind_list)) {
|
||||
obj = list_first_entry(&unwind_list,
|
||||
struct drm_i915_gem_object,
|
||||
exec_list);
|
||||
if (drm_mm_scan_remove_block(obj->gtt_space)) {
|
||||
list_move(&obj->exec_list, &eviction_list);
|
||||
drm_gem_object_reference(&obj->base);
|
||||
continue;
|
||||
}
|
||||
list_del_init(&obj->exec_list);
|
||||
}
|
||||
|
||||
/* Unbinding will emit any required flushes */
|
||||
while (!list_empty(&eviction_list)) {
|
||||
obj = list_first_entry(&eviction_list,
|
||||
struct drm_i915_gem_object,
|
||||
exec_list);
|
||||
if (ret == 0)
|
||||
ret = i915_gem_object_unbind(obj);
|
||||
|
||||
list_del_init(&obj->exec_list);
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
bool lists_empty;
|
||||
|
||||
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
|
||||
list_empty(&dev_priv->mm.flushing_list) &&
|
||||
list_empty(&dev_priv->mm.active_list));
|
||||
if (lists_empty)
|
||||
return -ENOSPC;
|
||||
|
||||
CTR2(KTR_DRM, "evict_everything %p %d", dev, purgeable_only);
|
||||
|
||||
/* Flush everything (on to the inactive lists) and evict */
|
||||
ret = i915_gpu_idle(dev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
KASSERT(list_empty(&dev_priv->mm.flushing_list),
|
||||
("flush list not empty"));
|
||||
|
||||
return i915_gem_evict_inactive(dev, purgeable_only);
|
||||
}
|
||||
|
||||
/** Unbinds all inactive objects. */
|
||||
int
|
||||
i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj, *next;
|
||||
|
||||
CTR2(KTR_DRM, "evict_inactive %p %d", dev, purgeable_only);
|
||||
|
||||
list_for_each_entry_safe(obj, next,
|
||||
&dev_priv->mm.inactive_list, mm_list) {
|
||||
if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) {
|
||||
int ret = i915_gem_object_unbind(obj);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1528
sys/dev/drm2/i915/i915_gem_execbuffer.c
Normal file
1528
sys/dev/drm2/i915/i915_gem_execbuffer.c
Normal file
File diff suppressed because it is too large
Load diff
329
sys/dev/drm2/i915/i915_gem_gtt.c
Normal file
329
sys/dev/drm2/i915/i915_gem_gtt.c
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
* Copyright © 2010 Daniel Vetter
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/sf_buf.h>
|
||||
|
||||
/* PPGTT support for Sandybdrige/Gen6 and later */
|
||||
static void
|
||||
i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
|
||||
unsigned first_entry, unsigned num_entries)
|
||||
{
|
||||
uint32_t *pt_vaddr;
|
||||
uint32_t scratch_pte;
|
||||
struct sf_buf *sf;
|
||||
unsigned act_pd, first_pte, last_pte, i;
|
||||
|
||||
act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
|
||||
scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr);
|
||||
scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC;
|
||||
|
||||
while (num_entries) {
|
||||
last_pte = first_pte + num_entries;
|
||||
if (last_pte > I915_PPGTT_PT_ENTRIES)
|
||||
last_pte = I915_PPGTT_PT_ENTRIES;
|
||||
|
||||
sched_pin();
|
||||
sf = sf_buf_alloc(ppgtt->pt_pages[act_pd], SFB_CPUPRIVATE);
|
||||
pt_vaddr = (uint32_t *)(uintptr_t)sf_buf_kva(sf);
|
||||
|
||||
for (i = first_pte; i < last_pte; i++)
|
||||
pt_vaddr[i] = scratch_pte;
|
||||
|
||||
sf_buf_free(sf);
|
||||
sched_unpin();
|
||||
|
||||
num_entries -= last_pte - first_pte;
|
||||
first_pte = 0;
|
||||
act_pd++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct i915_hw_ppgtt *ppgtt;
|
||||
u_int first_pd_entry_in_global_pt, i;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
/*
|
||||
* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
|
||||
* entries. For aliasing ppgtt support we just steal them at the end for
|
||||
* now.
|
||||
*/
|
||||
first_pd_entry_in_global_pt = 512 * 1024 - I915_PPGTT_PD_ENTRIES;
|
||||
|
||||
ppgtt = malloc(sizeof(*ppgtt), DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
|
||||
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
|
||||
ppgtt->pt_pages = malloc(sizeof(vm_page_t) * ppgtt->num_pd_entries,
|
||||
DRM_I915_GEM, M_WAITOK | M_ZERO);
|
||||
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
ppgtt->pt_pages[i] = vm_page_alloc(NULL, 0,
|
||||
VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED |
|
||||
VM_ALLOC_ZERO);
|
||||
if (ppgtt->pt_pages[i] == NULL) {
|
||||
dev_priv->mm.aliasing_ppgtt = ppgtt;
|
||||
i915_gem_cleanup_aliasing_ppgtt(dev);
|
||||
return (-ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt.scratch_page_dma;
|
||||
|
||||
i915_ppgtt_clear_range(ppgtt, 0, ppgtt->num_pd_entries *
|
||||
I915_PPGTT_PT_ENTRIES);
|
||||
ppgtt->pd_offset = (first_pd_entry_in_global_pt) * sizeof(uint32_t);
|
||||
dev_priv->mm.aliasing_ppgtt = ppgtt;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt, unsigned first_entry,
|
||||
unsigned num_entries, vm_page_t *pages, uint32_t pte_flags)
|
||||
{
|
||||
uint32_t *pt_vaddr, pte;
|
||||
struct sf_buf *sf;
|
||||
unsigned act_pd, first_pte;
|
||||
unsigned last_pte, i;
|
||||
vm_paddr_t page_addr;
|
||||
|
||||
act_pd = first_entry / I915_PPGTT_PT_ENTRIES;
|
||||
first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
|
||||
|
||||
while (num_entries) {
|
||||
last_pte = first_pte + num_entries;
|
||||
if (last_pte > I915_PPGTT_PT_ENTRIES)
|
||||
last_pte = I915_PPGTT_PT_ENTRIES;
|
||||
|
||||
sched_pin();
|
||||
sf = sf_buf_alloc(ppgtt->pt_pages[act_pd], SFB_CPUPRIVATE);
|
||||
pt_vaddr = (uint32_t *)(uintptr_t)sf_buf_kva(sf);
|
||||
|
||||
for (i = first_pte; i < last_pte; i++) {
|
||||
page_addr = VM_PAGE_TO_PHYS(*pages);
|
||||
pte = GEN6_PTE_ADDR_ENCODE(page_addr);
|
||||
pt_vaddr[i] = pte | pte_flags;
|
||||
|
||||
pages++;
|
||||
}
|
||||
|
||||
sf_buf_free(sf);
|
||||
sched_unpin();
|
||||
|
||||
num_entries -= last_pte - first_pte;
|
||||
first_pte = 0;
|
||||
act_pd++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_object *obj, enum i915_cache_level cache_level)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_private *dev_priv;
|
||||
uint32_t pte_flags;
|
||||
|
||||
dev = obj->base.dev;
|
||||
dev_priv = dev->dev_private;
|
||||
pte_flags = GEN6_PTE_VALID;
|
||||
|
||||
switch (cache_level) {
|
||||
case I915_CACHE_LLC_MLC:
|
||||
pte_flags |= GEN6_PTE_CACHE_LLC_MLC;
|
||||
break;
|
||||
case I915_CACHE_LLC:
|
||||
pte_flags |= GEN6_PTE_CACHE_LLC;
|
||||
break;
|
||||
case I915_CACHE_NONE:
|
||||
pte_flags |= GEN6_PTE_UNCACHED;
|
||||
break;
|
||||
default:
|
||||
panic("cache mode");
|
||||
}
|
||||
|
||||
i915_ppgtt_insert_pages(ppgtt, obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT, obj->pages, pte_flags);
|
||||
}
|
||||
|
||||
void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
|
||||
struct drm_i915_gem_object *obj)
|
||||
{
|
||||
i915_ppgtt_clear_range(ppgtt, obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
void
|
||||
i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct i915_hw_ppgtt *ppgtt;
|
||||
vm_page_t m;
|
||||
int i;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
ppgtt = dev_priv->mm.aliasing_ppgtt;
|
||||
if (ppgtt == NULL)
|
||||
return;
|
||||
dev_priv->mm.aliasing_ppgtt = NULL;
|
||||
|
||||
for (i = 0; i < ppgtt->num_pd_entries; i++) {
|
||||
m = ppgtt->pt_pages[i];
|
||||
if (m != NULL) {
|
||||
vm_page_unwire(m, 0);
|
||||
vm_page_free(m);
|
||||
}
|
||||
}
|
||||
free(ppgtt->pt_pages, DRM_I915_GEM);
|
||||
free(ppgtt, DRM_I915_GEM);
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
cache_level_to_agp_type(struct drm_device *dev, enum i915_cache_level
|
||||
cache_level)
|
||||
{
|
||||
|
||||
switch (cache_level) {
|
||||
case I915_CACHE_LLC_MLC:
|
||||
if (INTEL_INFO(dev)->gen >= 6)
|
||||
return (AGP_USER_CACHED_MEMORY_LLC_MLC);
|
||||
/*
|
||||
* Older chipsets do not have this extra level of CPU
|
||||
* cacheing, so fallthrough and request the PTE simply
|
||||
* as cached.
|
||||
*/
|
||||
case I915_CACHE_LLC:
|
||||
return (AGP_USER_CACHED_MEMORY);
|
||||
|
||||
default:
|
||||
case I915_CACHE_NONE:
|
||||
return (AGP_USER_MEMORY);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
do_idling(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
bool ret = dev_priv->mm.interruptible;
|
||||
|
||||
if (dev_priv->mm.gtt.do_idle_maps) {
|
||||
dev_priv->mm.interruptible = false;
|
||||
if (i915_gpu_idle(dev_priv->dev, false)) {
|
||||
DRM_ERROR("Couldn't idle GPU\n");
|
||||
/* Wait a bit, in hopes it avoids the hang */
|
||||
DELAY(10);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
undo_idling(struct drm_i915_private *dev_priv, bool interruptible)
|
||||
{
|
||||
|
||||
if (dev_priv->mm.gtt.do_idle_maps)
|
||||
dev_priv->mm.interruptible = interruptible;
|
||||
}
|
||||
|
||||
void
|
||||
i915_gem_restore_gtt_mappings(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
/* First fill our portion of the GTT with scratch pages */
|
||||
intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE,
|
||||
(dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
|
||||
|
||||
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
|
||||
i915_gem_clflush_object(obj);
|
||||
i915_gem_gtt_rebind_object(obj, obj->cache_level);
|
||||
}
|
||||
|
||||
intel_gtt_chipset_flush();
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
unsigned int agp_type;
|
||||
|
||||
agp_type = cache_level_to_agp_type(obj->base.dev, obj->cache_level);
|
||||
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT, obj->pages, agp_type);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
|
||||
enum i915_cache_level cache_level)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_private *dev_priv;
|
||||
unsigned int agp_type;
|
||||
|
||||
dev = obj->base.dev;
|
||||
dev_priv = dev->dev_private;
|
||||
agp_type = cache_level_to_agp_type(dev, cache_level);
|
||||
|
||||
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT, obj->pages, agp_type);
|
||||
}
|
||||
|
||||
void
|
||||
i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
bool interruptible;
|
||||
|
||||
dev = obj->base.dev;
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
interruptible = do_idling(dev_priv);
|
||||
|
||||
intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
|
||||
obj->base.size >> PAGE_SHIFT);
|
||||
|
||||
undo_idling(dev_priv, interruptible);
|
||||
}
|
||||
495
sys/dev/drm2/i915/i915_gem_tiling.c
Normal file
495
sys/dev/drm2/i915/i915_gem_tiling.c
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
/*
|
||||
* Copyright © 2008 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
|
||||
#include <sys/sf_buf.h>
|
||||
|
||||
/** @file i915_gem_tiling.c
|
||||
*
|
||||
* Support for managing tiling state of buffer objects.
|
||||
*
|
||||
* The idea behind tiling is to increase cache hit rates by rearranging
|
||||
* pixel data so that a group of pixel accesses are in the same cacheline.
|
||||
* Performance improvement from doing this on the back/depth buffer are on
|
||||
* the order of 30%.
|
||||
*
|
||||
* Intel architectures make this somewhat more complicated, though, by
|
||||
* adjustments made to addressing of data when the memory is in interleaved
|
||||
* mode (matched pairs of DIMMS) to improve memory bandwidth.
|
||||
* For interleaved memory, the CPU sends every sequential 64 bytes
|
||||
* to an alternate memory channel so it can get the bandwidth from both.
|
||||
*
|
||||
* The GPU also rearranges its accesses for increased bandwidth to interleaved
|
||||
* memory, and it matches what the CPU does for non-tiled. However, when tiled
|
||||
* it does it a little differently, since one walks addresses not just in the
|
||||
* X direction but also Y. So, along with alternating channels when bit
|
||||
* 6 of the address flips, it also alternates when other bits flip -- Bits 9
|
||||
* (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
|
||||
* are common to both the 915 and 965-class hardware.
|
||||
*
|
||||
* The CPU also sometimes XORs in higher bits as well, to improve
|
||||
* bandwidth doing strided access like we do so frequently in graphics. This
|
||||
* is called "Channel XOR Randomization" in the MCH documentation. The result
|
||||
* is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
|
||||
* decode.
|
||||
*
|
||||
* All of this bit 6 XORing has an effect on our memory management,
|
||||
* as we need to make sure that the 3d driver can correctly address object
|
||||
* contents.
|
||||
*
|
||||
* If we don't have interleaved memory, all tiling is safe and no swizzling is
|
||||
* required.
|
||||
*
|
||||
* When bit 17 is XORed in, we simply refuse to tile at all. Bit
|
||||
* 17 is not just a page offset, so as we page an objet out and back in,
|
||||
* individual pages in it will have different bit 17 addresses, resulting in
|
||||
* each 64 bytes being swapped with its neighbor!
|
||||
*
|
||||
* Otherwise, if interleaved, we have to tell the 3d driver what the address
|
||||
* swizzling it needs to do is, since it's writing with the CPU to the pages
|
||||
* (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
|
||||
* pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
|
||||
* required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
|
||||
* to match what the GPU expects.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Detects bit 6 swizzling of address lookup between IGD access and CPU
|
||||
* access through main memory.
|
||||
*/
|
||||
void
|
||||
i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 6) {
|
||||
uint32_t dimm_c0, dimm_c1;
|
||||
dimm_c0 = I915_READ(MAD_DIMM_C0);
|
||||
dimm_c1 = I915_READ(MAD_DIMM_C1);
|
||||
dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
|
||||
dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK;
|
||||
/* Enable swizzling when the channels are populated with
|
||||
* identically sized dimms. We don't need to check the 3rd
|
||||
* channel because no cpu with gpu attached ships in that
|
||||
* configuration. Also, swizzling only makes sense for 2
|
||||
* channels anyway. */
|
||||
if (dimm_c0 == dimm_c1) {
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_9;
|
||||
} else {
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||
}
|
||||
} else if (IS_GEN5(dev)) {
|
||||
/* On Ironlake whatever DRAM config, GPU always do
|
||||
* same swizzling setup.
|
||||
*/
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_9;
|
||||
} else if (IS_GEN2(dev)) {
|
||||
/* As far as we know, the 865 doesn't have these bit 6
|
||||
* swizzling issues.
|
||||
*/
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||
} else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) {
|
||||
uint32_t dcc;
|
||||
|
||||
/* On 9xx chipsets, channel interleave by the CPU is
|
||||
* determined by DCC. For single-channel, neither the CPU
|
||||
* nor the GPU do swizzling. For dual channel interleaved,
|
||||
* the GPU's interleave is bit 9 and 10 for X tiled, and bit
|
||||
* 9 for Y tiled. The CPU's interleave is independent, and
|
||||
* can be based on either bit 11 (haven't seen this yet) or
|
||||
* bit 17 (common).
|
||||
*/
|
||||
dcc = I915_READ(DCC);
|
||||
switch (dcc & DCC_ADDRESSING_MODE_MASK) {
|
||||
case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
|
||||
case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||
break;
|
||||
case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
|
||||
if (dcc & DCC_CHANNEL_XOR_DISABLE) {
|
||||
/* This is the base swizzling by the GPU for
|
||||
* tiled buffers.
|
||||
*/
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_9;
|
||||
} else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) {
|
||||
/* Bit 11 swizzling by the CPU in addition. */
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_9_11;
|
||||
} else {
|
||||
/* Bit 17 swizzling by the CPU in addition. */
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_9_10_17;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_9_17;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (dcc == 0xffffffff) {
|
||||
DRM_ERROR("Couldn't read from MCHBAR. "
|
||||
"Disabling tiling.\n");
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
}
|
||||
} else {
|
||||
/* The 965, G33, and newer, have a very flexible memory
|
||||
* configuration. It will enable dual-channel mode
|
||||
* (interleaving) on as much memory as it can, and the GPU
|
||||
* will additionally sometimes enable different bit 6
|
||||
* swizzling for tiled objects from the CPU.
|
||||
*
|
||||
* Here's what I found on the G965:
|
||||
* slot fill memory size swizzling
|
||||
* 0A 0B 1A 1B 1-ch 2-ch
|
||||
* 512 0 0 0 512 0 O
|
||||
* 512 0 512 0 16 1008 X
|
||||
* 512 0 0 512 16 1008 X
|
||||
* 0 512 0 512 16 1008 X
|
||||
* 1024 1024 1024 0 2048 1024 O
|
||||
*
|
||||
* We could probably detect this based on either the DRB
|
||||
* matching, which was the case for the swizzling required in
|
||||
* the table above, or from the 1-ch value being less than
|
||||
* the minimum size of a rank.
|
||||
*/
|
||||
if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
|
||||
} else {
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_9;
|
||||
}
|
||||
}
|
||||
|
||||
dev_priv->mm.bit_6_swizzle_x = swizzle_x;
|
||||
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
|
||||
}
|
||||
|
||||
/* Check pitch constriants for all chips & tiling formats */
|
||||
static bool
|
||||
i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
|
||||
{
|
||||
int tile_width;
|
||||
|
||||
/* Linear is always fine */
|
||||
if (tiling_mode == I915_TILING_NONE)
|
||||
return (true);
|
||||
|
||||
if (IS_GEN2(dev) ||
|
||||
(tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
|
||||
tile_width = 128;
|
||||
else
|
||||
tile_width = 512;
|
||||
|
||||
/* check maximum stride & object size */
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
/* i965 stores the end address of the gtt mapping in the fence
|
||||
* reg, so dont bother to check the size */
|
||||
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
|
||||
return (false);
|
||||
} else {
|
||||
if (stride > 8192)
|
||||
return (false);
|
||||
|
||||
if (IS_GEN3(dev)) {
|
||||
if (size > I830_FENCE_MAX_SIZE_VAL << 20)
|
||||
return (false);
|
||||
} else {
|
||||
if (size > I830_FENCE_MAX_SIZE_VAL << 19)
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
/* 965+ just needs multiples of tile width */
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
if (stride & (tile_width - 1))
|
||||
return (false);
|
||||
return (true);
|
||||
}
|
||||
|
||||
/* Pre-965 needs power of two tile widths */
|
||||
if (stride < tile_width)
|
||||
return (false);
|
||||
|
||||
if (stride & (stride - 1))
|
||||
return (false);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/* Is the current GTT allocation valid for the change in tiling? */
|
||||
static bool
|
||||
i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode)
|
||||
{
|
||||
u32 size;
|
||||
|
||||
if (tiling_mode == I915_TILING_NONE)
|
||||
return (true);
|
||||
|
||||
if (INTEL_INFO(obj->base.dev)->gen >= 4)
|
||||
return (true);
|
||||
|
||||
if (INTEL_INFO(obj->base.dev)->gen == 3) {
|
||||
if (obj->gtt_offset & ~I915_FENCE_START_MASK)
|
||||
return (false);
|
||||
} else {
|
||||
if (obj->gtt_offset & ~I830_FENCE_START_MASK)
|
||||
return (false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Previous chips need to be aligned to the size of the smallest
|
||||
* fence register that can contain the object.
|
||||
*/
|
||||
if (INTEL_INFO(obj->base.dev)->gen == 3)
|
||||
size = 1024*1024;
|
||||
else
|
||||
size = 512*1024;
|
||||
|
||||
while (size < obj->base.size)
|
||||
size <<= 1;
|
||||
|
||||
if (obj->gtt_space->size != size)
|
||||
return (false);
|
||||
|
||||
if (obj->gtt_offset & (size - 1))
|
||||
return (false);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tiling mode of an object, returning the required swizzling of
|
||||
* bit 6 of addresses in the object.
|
||||
*/
|
||||
int
|
||||
i915_gem_set_tiling(struct drm_device *dev, void *data,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct drm_i915_gem_set_tiling *args = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
|
||||
if (&obj->base == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (!i915_tiling_ok(dev,
|
||||
args->stride, obj->base.size, args->tiling_mode)) {
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj->pin_count) {
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (args->tiling_mode == I915_TILING_NONE) {
|
||||
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
|
||||
args->stride = 0;
|
||||
} else {
|
||||
if (args->tiling_mode == I915_TILING_X)
|
||||
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
|
||||
else
|
||||
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
|
||||
|
||||
/* Hide bit 17 swizzling from the user. This prevents old Mesa
|
||||
* from aborting the application on sw fallbacks to bit 17,
|
||||
* and we use the pread/pwrite bit17 paths to swizzle for it.
|
||||
* If there was a user that was relying on the swizzle
|
||||
* information for drm_intel_bo_map()ed reads/writes this would
|
||||
* break it, but we don't have any of those.
|
||||
*/
|
||||
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17)
|
||||
args->swizzle_mode = I915_BIT_6_SWIZZLE_9;
|
||||
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
|
||||
args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10;
|
||||
|
||||
/* If we can't handle the swizzling, make it untiled. */
|
||||
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
|
||||
args->tiling_mode = I915_TILING_NONE;
|
||||
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
|
||||
args->stride = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (args->tiling_mode != obj->tiling_mode ||
|
||||
args->stride != obj->stride) {
|
||||
/* We need to rebind the object if its current allocation
|
||||
* no longer meets the alignment restrictions for its new
|
||||
* tiling mode. Otherwise we can just leave it alone, but
|
||||
* need to ensure that any fence register is cleared.
|
||||
*/
|
||||
i915_gem_release_mmap(obj);
|
||||
|
||||
obj->map_and_fenceable = obj->gtt_space == NULL ||
|
||||
(obj->gtt_offset + obj->base.size <=
|
||||
dev_priv->mm.gtt_mappable_end &&
|
||||
i915_gem_object_fence_ok(obj, args->tiling_mode));
|
||||
|
||||
/* Rebind if we need a change of alignment */
|
||||
if (!obj->map_and_fenceable) {
|
||||
uint32_t unfenced_alignment =
|
||||
i915_gem_get_unfenced_gtt_alignment(dev,
|
||||
obj->base.size, args->tiling_mode);
|
||||
if (obj->gtt_offset & (unfenced_alignment - 1))
|
||||
ret = i915_gem_object_unbind(obj);
|
||||
}
|
||||
if (ret == 0) {
|
||||
obj->tiling_changed = true;
|
||||
obj->tiling_mode = args->tiling_mode;
|
||||
obj->stride = args->stride;
|
||||
}
|
||||
}
|
||||
/* we have to maintain this existing ABI... */
|
||||
args->stride = obj->stride;
|
||||
args->tiling_mode = obj->tiling_mode;
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current tiling mode and required bit 6 swizzling for the object.
|
||||
*/
|
||||
int
|
||||
i915_gem_get_tiling(struct drm_device *dev, void *data,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct drm_i915_gem_get_tiling *args = data;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
|
||||
if (&obj->base == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
args->tiling_mode = obj->tiling_mode;
|
||||
switch (obj->tiling_mode) {
|
||||
case I915_TILING_X:
|
||||
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
|
||||
break;
|
||||
case I915_TILING_Y:
|
||||
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
|
||||
break;
|
||||
case I915_TILING_NONE:
|
||||
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("unknown tiling mode\n");
|
||||
}
|
||||
|
||||
/* Hide bit 17 from the user -- see comment in i915_gem_set_tiling */
|
||||
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17)
|
||||
args->swizzle_mode = I915_BIT_6_SWIZZLE_9;
|
||||
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
|
||||
args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10;
|
||||
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap every 64 bytes of this page around, to account for it having a new
|
||||
* bit 17 of its physical address and therefore being interpreted differently
|
||||
* by the GPU.
|
||||
*/
|
||||
static void
|
||||
i915_gem_swizzle_page(vm_page_t m)
|
||||
{
|
||||
char temp[64];
|
||||
char *vaddr;
|
||||
struct sf_buf *sf;
|
||||
int i;
|
||||
|
||||
/* XXXKIB sleep */
|
||||
sf = sf_buf_alloc(m, SFB_DEFAULT);
|
||||
vaddr = (char *)sf_buf_kva(sf);
|
||||
|
||||
for (i = 0; i < PAGE_SIZE; i += 128) {
|
||||
memcpy(temp, &vaddr[i], 64);
|
||||
memcpy(&vaddr[i], &vaddr[i + 64], 64);
|
||||
memcpy(&vaddr[i + 64], temp, 64);
|
||||
}
|
||||
|
||||
sf_buf_free(sf);
|
||||
}
|
||||
|
||||
void
|
||||
i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
int page_count = obj->base.size >> PAGE_SHIFT;
|
||||
int i;
|
||||
|
||||
if (obj->bit_17 == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < page_count; i++) {
|
||||
char new_bit_17 = VM_PAGE_TO_PHYS(obj->pages[i]) >> 17;
|
||||
if ((new_bit_17 & 0x1) !=
|
||||
(test_bit(i, obj->bit_17) != 0)) {
|
||||
i915_gem_swizzle_page(obj->pages[i]);
|
||||
vm_page_dirty(obj->pages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
int page_count = obj->base.size >> PAGE_SHIFT;
|
||||
int i;
|
||||
|
||||
if (obj->bit_17 == NULL) {
|
||||
obj->bit_17 = malloc(BITS_TO_LONGS(page_count) *
|
||||
sizeof(long), DRM_I915_GEM, M_WAITOK);
|
||||
}
|
||||
|
||||
/* XXXKIB: review locking, atomics might be not needed there */
|
||||
for (i = 0; i < page_count; i++) {
|
||||
if (VM_PAGE_TO_PHYS(obj->pages[i]) & (1 << 17))
|
||||
set_bit(i, obj->bit_17);
|
||||
else
|
||||
clear_bit(i, obj->bit_17);
|
||||
}
|
||||
}
|
||||
2278
sys/dev/drm2/i915/i915_irq.c
Normal file
2278
sys/dev/drm2/i915/i915_irq.c
Normal file
File diff suppressed because it is too large
Load diff
3876
sys/dev/drm2/i915/i915_reg.h
Normal file
3876
sys/dev/drm2/i915/i915_reg.h
Normal file
File diff suppressed because it is too large
Load diff
909
sys/dev/drm2/i915/i915_suspend.c
Normal file
909
sys/dev/drm2/i915/i915_suspend.c
Normal file
|
|
@ -0,0 +1,909 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2008 (c) Intel Corporation
|
||||
* Jesse Barnes <jbarnes@virtuousgeek.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpll_reg;
|
||||
|
||||
/* On IVB, 3rd pipe shares PLL with another one */
|
||||
if (pipe > 1)
|
||||
return false;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
dpll_reg = PCH_DPLL(pipe);
|
||||
else
|
||||
dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B;
|
||||
|
||||
return (I915_READ(dpll_reg) & DPLL_VCO_ENABLE);
|
||||
}
|
||||
|
||||
static void i915_save_palette(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B);
|
||||
u32 *array;
|
||||
int i;
|
||||
|
||||
if (!i915_pipe_enabled(dev, pipe))
|
||||
return;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B;
|
||||
|
||||
if (pipe == PIPE_A)
|
||||
array = dev_priv->save_palette_a;
|
||||
else
|
||||
array = dev_priv->save_palette_b;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
array[i] = I915_READ(reg + (i << 2));
|
||||
}
|
||||
|
||||
static void i915_restore_palette(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B);
|
||||
u32 *array;
|
||||
int i;
|
||||
|
||||
if (!i915_pipe_enabled(dev, pipe))
|
||||
return;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B;
|
||||
|
||||
if (pipe == PIPE_A)
|
||||
array = dev_priv->save_palette_a;
|
||||
else
|
||||
array = dev_priv->save_palette_b;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
I915_WRITE(reg + (i << 2), array[i]);
|
||||
}
|
||||
|
||||
static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
I915_WRITE8(index_port, reg);
|
||||
return I915_READ8(data_port);
|
||||
}
|
||||
|
||||
static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
I915_READ8(st01);
|
||||
I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
|
||||
return I915_READ8(VGA_AR_DATA_READ);
|
||||
}
|
||||
|
||||
static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
I915_READ8(st01);
|
||||
I915_WRITE8(VGA_AR_INDEX, palette_enable | reg);
|
||||
I915_WRITE8(VGA_AR_DATA_WRITE, val);
|
||||
}
|
||||
|
||||
static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
I915_WRITE8(index_port, reg);
|
||||
I915_WRITE8(data_port, val);
|
||||
}
|
||||
|
||||
static void i915_save_vga(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
u16 cr_index, cr_data, st01;
|
||||
|
||||
/* VGA color palette registers */
|
||||
dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK);
|
||||
|
||||
/* MSR bits */
|
||||
dev_priv->saveMSR = I915_READ8(VGA_MSR_READ);
|
||||
if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
|
||||
cr_index = VGA_CR_INDEX_CGA;
|
||||
cr_data = VGA_CR_DATA_CGA;
|
||||
st01 = VGA_ST01_CGA;
|
||||
} else {
|
||||
cr_index = VGA_CR_INDEX_MDA;
|
||||
cr_data = VGA_CR_DATA_MDA;
|
||||
st01 = VGA_ST01_MDA;
|
||||
}
|
||||
|
||||
/* CRT controller regs */
|
||||
i915_write_indexed(dev, cr_index, cr_data, 0x11,
|
||||
i915_read_indexed(dev, cr_index, cr_data, 0x11) &
|
||||
(~0x80));
|
||||
for (i = 0; i <= 0x24; i++)
|
||||
dev_priv->saveCR[i] =
|
||||
i915_read_indexed(dev, cr_index, cr_data, i);
|
||||
/* Make sure we don't turn off CR group 0 writes */
|
||||
dev_priv->saveCR[0x11] &= ~0x80;
|
||||
|
||||
/* Attribute controller registers */
|
||||
I915_READ8(st01);
|
||||
dev_priv->saveAR_INDEX = I915_READ8(VGA_AR_INDEX);
|
||||
for (i = 0; i <= 0x14; i++)
|
||||
dev_priv->saveAR[i] = i915_read_ar(dev, st01, i, 0);
|
||||
I915_READ8(st01);
|
||||
I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX);
|
||||
I915_READ8(st01);
|
||||
|
||||
/* Graphics controller registers */
|
||||
for (i = 0; i < 9; i++)
|
||||
dev_priv->saveGR[i] =
|
||||
i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i);
|
||||
|
||||
dev_priv->saveGR[0x10] =
|
||||
i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10);
|
||||
dev_priv->saveGR[0x11] =
|
||||
i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11);
|
||||
dev_priv->saveGR[0x18] =
|
||||
i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18);
|
||||
|
||||
/* Sequencer registers */
|
||||
for (i = 0; i < 8; i++)
|
||||
dev_priv->saveSR[i] =
|
||||
i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i);
|
||||
}
|
||||
|
||||
static void i915_restore_vga(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
u16 cr_index, cr_data, st01;
|
||||
|
||||
/* MSR bits */
|
||||
I915_WRITE8(VGA_MSR_WRITE, dev_priv->saveMSR);
|
||||
if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) {
|
||||
cr_index = VGA_CR_INDEX_CGA;
|
||||
cr_data = VGA_CR_DATA_CGA;
|
||||
st01 = VGA_ST01_CGA;
|
||||
} else {
|
||||
cr_index = VGA_CR_INDEX_MDA;
|
||||
cr_data = VGA_CR_DATA_MDA;
|
||||
st01 = VGA_ST01_MDA;
|
||||
}
|
||||
|
||||
/* Sequencer registers, don't write SR07 */
|
||||
for (i = 0; i < 7; i++)
|
||||
i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i,
|
||||
dev_priv->saveSR[i]);
|
||||
|
||||
/* CRT controller regs */
|
||||
/* Enable CR group 0 writes */
|
||||
i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]);
|
||||
for (i = 0; i <= 0x24; i++)
|
||||
i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->saveCR[i]);
|
||||
|
||||
/* Graphics controller regs */
|
||||
for (i = 0; i < 9; i++)
|
||||
i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i,
|
||||
dev_priv->saveGR[i]);
|
||||
|
||||
i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10,
|
||||
dev_priv->saveGR[0x10]);
|
||||
i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11,
|
||||
dev_priv->saveGR[0x11]);
|
||||
i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18,
|
||||
dev_priv->saveGR[0x18]);
|
||||
|
||||
/* Attribute controller registers */
|
||||
I915_READ8(st01); /* switch back to index mode */
|
||||
for (i = 0; i <= 0x14; i++)
|
||||
i915_write_ar(dev, st01, i, dev_priv->saveAR[i], 0);
|
||||
I915_READ8(st01); /* switch back to index mode */
|
||||
I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX | 0x20);
|
||||
I915_READ8(st01);
|
||||
|
||||
/* VGA color palette registers */
|
||||
I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
|
||||
}
|
||||
|
||||
static void i915_save_modeset_reg(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
/* Cursor state */
|
||||
dev_priv->saveCURACNTR = I915_READ(_CURACNTR);
|
||||
dev_priv->saveCURAPOS = I915_READ(_CURAPOS);
|
||||
dev_priv->saveCURABASE = I915_READ(_CURABASE);
|
||||
dev_priv->saveCURBCNTR = I915_READ(_CURBCNTR);
|
||||
dev_priv->saveCURBPOS = I915_READ(_CURBPOS);
|
||||
dev_priv->saveCURBBASE = I915_READ(_CURBBASE);
|
||||
if (IS_GEN2(dev))
|
||||
dev_priv->saveCURSIZE = I915_READ(CURSIZE);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
|
||||
dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
|
||||
}
|
||||
|
||||
/* Pipe & plane A info */
|
||||
dev_priv->savePIPEACONF = I915_READ(_PIPEACONF);
|
||||
dev_priv->savePIPEASRC = I915_READ(_PIPEASRC);
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->saveFPA0 = I915_READ(_PCH_FPA0);
|
||||
dev_priv->saveFPA1 = I915_READ(_PCH_FPA1);
|
||||
dev_priv->saveDPLL_A = I915_READ(_PCH_DPLL_A);
|
||||
} else {
|
||||
dev_priv->saveFPA0 = I915_READ(_FPA0);
|
||||
dev_priv->saveFPA1 = I915_READ(_FPA1);
|
||||
dev_priv->saveDPLL_A = I915_READ(_DPLL_A);
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
dev_priv->saveDPLL_A_MD = I915_READ(_DPLL_A_MD);
|
||||
dev_priv->saveHTOTAL_A = I915_READ(_HTOTAL_A);
|
||||
dev_priv->saveHBLANK_A = I915_READ(_HBLANK_A);
|
||||
dev_priv->saveHSYNC_A = I915_READ(_HSYNC_A);
|
||||
dev_priv->saveVTOTAL_A = I915_READ(_VTOTAL_A);
|
||||
dev_priv->saveVBLANK_A = I915_READ(_VBLANK_A);
|
||||
dev_priv->saveVSYNC_A = I915_READ(_VSYNC_A);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
dev_priv->saveBCLRPAT_A = I915_READ(_BCLRPAT_A);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1);
|
||||
dev_priv->savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1);
|
||||
dev_priv->savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1);
|
||||
dev_priv->savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1);
|
||||
|
||||
dev_priv->saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL);
|
||||
dev_priv->saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL);
|
||||
|
||||
dev_priv->savePFA_CTL_1 = I915_READ(_PFA_CTL_1);
|
||||
dev_priv->savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ);
|
||||
dev_priv->savePFA_WIN_POS = I915_READ(_PFA_WIN_POS);
|
||||
|
||||
dev_priv->saveTRANSACONF = I915_READ(_TRANSACONF);
|
||||
dev_priv->saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A);
|
||||
dev_priv->saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A);
|
||||
dev_priv->saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A);
|
||||
dev_priv->saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A);
|
||||
dev_priv->saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A);
|
||||
dev_priv->saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A);
|
||||
}
|
||||
|
||||
dev_priv->saveDSPACNTR = I915_READ(_DSPACNTR);
|
||||
dev_priv->saveDSPASTRIDE = I915_READ(_DSPASTRIDE);
|
||||
dev_priv->saveDSPASIZE = I915_READ(_DSPASIZE);
|
||||
dev_priv->saveDSPAPOS = I915_READ(_DSPAPOS);
|
||||
dev_priv->saveDSPAADDR = I915_READ(_DSPAADDR);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
dev_priv->saveDSPASURF = I915_READ(_DSPASURF);
|
||||
dev_priv->saveDSPATILEOFF = I915_READ(_DSPATILEOFF);
|
||||
}
|
||||
i915_save_palette(dev, PIPE_A);
|
||||
dev_priv->savePIPEASTAT = I915_READ(_PIPEASTAT);
|
||||
|
||||
/* Pipe & plane B info */
|
||||
dev_priv->savePIPEBCONF = I915_READ(_PIPEBCONF);
|
||||
dev_priv->savePIPEBSRC = I915_READ(_PIPEBSRC);
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->saveFPB0 = I915_READ(_PCH_FPB0);
|
||||
dev_priv->saveFPB1 = I915_READ(_PCH_FPB1);
|
||||
dev_priv->saveDPLL_B = I915_READ(_PCH_DPLL_B);
|
||||
} else {
|
||||
dev_priv->saveFPB0 = I915_READ(_FPB0);
|
||||
dev_priv->saveFPB1 = I915_READ(_FPB1);
|
||||
dev_priv->saveDPLL_B = I915_READ(_DPLL_B);
|
||||
}
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
dev_priv->saveDPLL_B_MD = I915_READ(_DPLL_B_MD);
|
||||
dev_priv->saveHTOTAL_B = I915_READ(_HTOTAL_B);
|
||||
dev_priv->saveHBLANK_B = I915_READ(_HBLANK_B);
|
||||
dev_priv->saveHSYNC_B = I915_READ(_HSYNC_B);
|
||||
dev_priv->saveVTOTAL_B = I915_READ(_VTOTAL_B);
|
||||
dev_priv->saveVBLANK_B = I915_READ(_VBLANK_B);
|
||||
dev_priv->saveVSYNC_B = I915_READ(_VSYNC_B);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
dev_priv->saveBCLRPAT_B = I915_READ(_BCLRPAT_B);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1);
|
||||
dev_priv->savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1);
|
||||
dev_priv->savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1);
|
||||
dev_priv->savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1);
|
||||
|
||||
dev_priv->saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL);
|
||||
dev_priv->saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL);
|
||||
|
||||
dev_priv->savePFB_CTL_1 = I915_READ(_PFB_CTL_1);
|
||||
dev_priv->savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ);
|
||||
dev_priv->savePFB_WIN_POS = I915_READ(_PFB_WIN_POS);
|
||||
|
||||
dev_priv->saveTRANSBCONF = I915_READ(_TRANSBCONF);
|
||||
dev_priv->saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B);
|
||||
dev_priv->saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B);
|
||||
dev_priv->saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B);
|
||||
dev_priv->saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B);
|
||||
dev_priv->saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B);
|
||||
dev_priv->saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B);
|
||||
}
|
||||
|
||||
dev_priv->saveDSPBCNTR = I915_READ(_DSPBCNTR);
|
||||
dev_priv->saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE);
|
||||
dev_priv->saveDSPBSIZE = I915_READ(_DSPBSIZE);
|
||||
dev_priv->saveDSPBPOS = I915_READ(_DSPBPOS);
|
||||
dev_priv->saveDSPBADDR = I915_READ(_DSPBADDR);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
dev_priv->saveDSPBSURF = I915_READ(_DSPBSURF);
|
||||
dev_priv->saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF);
|
||||
}
|
||||
i915_save_palette(dev, PIPE_B);
|
||||
dev_priv->savePIPEBSTAT = I915_READ(_PIPEBSTAT);
|
||||
|
||||
/* Fences */
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 7:
|
||||
case 6:
|
||||
for (i = 0; i < 16; i++)
|
||||
dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
|
||||
break;
|
||||
case 5:
|
||||
case 4:
|
||||
for (i = 0; i < 16; i++)
|
||||
dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
|
||||
break;
|
||||
case 3:
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
for (i = 0; i < 8; i++)
|
||||
dev_priv->saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
|
||||
case 2:
|
||||
for (i = 0; i < 8; i++)
|
||||
dev_priv->saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void i915_restore_modeset_reg(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int dpll_a_reg, fpa0_reg, fpa1_reg;
|
||||
int dpll_b_reg, fpb0_reg, fpb1_reg;
|
||||
int i;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
/* Fences */
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 7:
|
||||
case 6:
|
||||
for (i = 0; i < 16; i++)
|
||||
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]);
|
||||
break;
|
||||
case 5:
|
||||
case 4:
|
||||
for (i = 0; i < 16; i++)
|
||||
I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->saveFENCE[i]);
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
for (i = 0; i < 8; i++)
|
||||
I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]);
|
||||
for (i = 0; i < 8; i++)
|
||||
I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->saveFENCE[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dpll_a_reg = _PCH_DPLL_A;
|
||||
dpll_b_reg = _PCH_DPLL_B;
|
||||
fpa0_reg = _PCH_FPA0;
|
||||
fpb0_reg = _PCH_FPB0;
|
||||
fpa1_reg = _PCH_FPA1;
|
||||
fpb1_reg = _PCH_FPB1;
|
||||
} else {
|
||||
dpll_a_reg = _DPLL_A;
|
||||
dpll_b_reg = _DPLL_B;
|
||||
fpa0_reg = _FPA0;
|
||||
fpb0_reg = _FPB0;
|
||||
fpa1_reg = _FPA1;
|
||||
fpb1_reg = _FPB1;
|
||||
}
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(PCH_DREF_CONTROL, dev_priv->savePCH_DREF_CONTROL);
|
||||
I915_WRITE(DISP_ARB_CTL, dev_priv->saveDISP_ARB_CTL);
|
||||
}
|
||||
|
||||
/* Pipe & plane A info */
|
||||
/* Prime the clock */
|
||||
if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
|
||||
I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A &
|
||||
~DPLL_VCO_ENABLE);
|
||||
POSTING_READ(dpll_a_reg);
|
||||
DRM_UDELAY(150);
|
||||
}
|
||||
I915_WRITE(fpa0_reg, dev_priv->saveFPA0);
|
||||
I915_WRITE(fpa1_reg, dev_priv->saveFPA1);
|
||||
/* Actually enable it */
|
||||
I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A);
|
||||
POSTING_READ(dpll_a_reg);
|
||||
DRM_UDELAY(150);
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_DPLL_A_MD, dev_priv->saveDPLL_A_MD);
|
||||
POSTING_READ(_DPLL_A_MD);
|
||||
}
|
||||
DRM_UDELAY(150);
|
||||
|
||||
/* Restore mode */
|
||||
I915_WRITE(_HTOTAL_A, dev_priv->saveHTOTAL_A);
|
||||
I915_WRITE(_HBLANK_A, dev_priv->saveHBLANK_A);
|
||||
I915_WRITE(_HSYNC_A, dev_priv->saveHSYNC_A);
|
||||
I915_WRITE(_VTOTAL_A, dev_priv->saveVTOTAL_A);
|
||||
I915_WRITE(_VBLANK_A, dev_priv->saveVBLANK_A);
|
||||
I915_WRITE(_VSYNC_A, dev_priv->saveVSYNC_A);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(_BCLRPAT_A, dev_priv->saveBCLRPAT_A);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1);
|
||||
I915_WRITE(_PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1);
|
||||
I915_WRITE(_PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1);
|
||||
I915_WRITE(_PIPEA_LINK_N1, dev_priv->savePIPEA_LINK_N1);
|
||||
|
||||
I915_WRITE(_FDI_RXA_CTL, dev_priv->saveFDI_RXA_CTL);
|
||||
I915_WRITE(_FDI_TXA_CTL, dev_priv->saveFDI_TXA_CTL);
|
||||
|
||||
I915_WRITE(_PFA_CTL_1, dev_priv->savePFA_CTL_1);
|
||||
I915_WRITE(_PFA_WIN_SZ, dev_priv->savePFA_WIN_SZ);
|
||||
I915_WRITE(_PFA_WIN_POS, dev_priv->savePFA_WIN_POS);
|
||||
|
||||
I915_WRITE(_TRANSACONF, dev_priv->saveTRANSACONF);
|
||||
I915_WRITE(_TRANS_HTOTAL_A, dev_priv->saveTRANS_HTOTAL_A);
|
||||
I915_WRITE(_TRANS_HBLANK_A, dev_priv->saveTRANS_HBLANK_A);
|
||||
I915_WRITE(_TRANS_HSYNC_A, dev_priv->saveTRANS_HSYNC_A);
|
||||
I915_WRITE(_TRANS_VTOTAL_A, dev_priv->saveTRANS_VTOTAL_A);
|
||||
I915_WRITE(_TRANS_VBLANK_A, dev_priv->saveTRANS_VBLANK_A);
|
||||
I915_WRITE(_TRANS_VSYNC_A, dev_priv->saveTRANS_VSYNC_A);
|
||||
}
|
||||
|
||||
/* Restore plane info */
|
||||
I915_WRITE(_DSPASIZE, dev_priv->saveDSPASIZE);
|
||||
I915_WRITE(_DSPAPOS, dev_priv->saveDSPAPOS);
|
||||
I915_WRITE(_PIPEASRC, dev_priv->savePIPEASRC);
|
||||
I915_WRITE(_DSPAADDR, dev_priv->saveDSPAADDR);
|
||||
I915_WRITE(_DSPASTRIDE, dev_priv->saveDSPASTRIDE);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
I915_WRITE(_DSPASURF, dev_priv->saveDSPASURF);
|
||||
I915_WRITE(_DSPATILEOFF, dev_priv->saveDSPATILEOFF);
|
||||
}
|
||||
|
||||
I915_WRITE(_PIPEACONF, dev_priv->savePIPEACONF);
|
||||
|
||||
i915_restore_palette(dev, PIPE_A);
|
||||
/* Enable the plane */
|
||||
I915_WRITE(_DSPACNTR, dev_priv->saveDSPACNTR);
|
||||
I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR));
|
||||
|
||||
/* Pipe & plane B info */
|
||||
if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
|
||||
I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B &
|
||||
~DPLL_VCO_ENABLE);
|
||||
POSTING_READ(dpll_b_reg);
|
||||
DRM_UDELAY(150);
|
||||
}
|
||||
I915_WRITE(fpb0_reg, dev_priv->saveFPB0);
|
||||
I915_WRITE(fpb1_reg, dev_priv->saveFPB1);
|
||||
/* Actually enable it */
|
||||
I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
|
||||
POSTING_READ(dpll_b_reg);
|
||||
DRM_UDELAY(150);
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_DPLL_B_MD, dev_priv->saveDPLL_B_MD);
|
||||
POSTING_READ(_DPLL_B_MD);
|
||||
}
|
||||
DRM_UDELAY(150);
|
||||
|
||||
/* Restore mode */
|
||||
I915_WRITE(_HTOTAL_B, dev_priv->saveHTOTAL_B);
|
||||
I915_WRITE(_HBLANK_B, dev_priv->saveHBLANK_B);
|
||||
I915_WRITE(_HSYNC_B, dev_priv->saveHSYNC_B);
|
||||
I915_WRITE(_VTOTAL_B, dev_priv->saveVTOTAL_B);
|
||||
I915_WRITE(_VBLANK_B, dev_priv->saveVBLANK_B);
|
||||
I915_WRITE(_VSYNC_B, dev_priv->saveVSYNC_B);
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(_BCLRPAT_B, dev_priv->saveBCLRPAT_B);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(_PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1);
|
||||
I915_WRITE(_PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1);
|
||||
I915_WRITE(_PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1);
|
||||
I915_WRITE(_PIPEB_LINK_N1, dev_priv->savePIPEB_LINK_N1);
|
||||
|
||||
I915_WRITE(_FDI_RXB_CTL, dev_priv->saveFDI_RXB_CTL);
|
||||
I915_WRITE(_FDI_TXB_CTL, dev_priv->saveFDI_TXB_CTL);
|
||||
|
||||
I915_WRITE(_PFB_CTL_1, dev_priv->savePFB_CTL_1);
|
||||
I915_WRITE(_PFB_WIN_SZ, dev_priv->savePFB_WIN_SZ);
|
||||
I915_WRITE(_PFB_WIN_POS, dev_priv->savePFB_WIN_POS);
|
||||
|
||||
I915_WRITE(_TRANSBCONF, dev_priv->saveTRANSBCONF);
|
||||
I915_WRITE(_TRANS_HTOTAL_B, dev_priv->saveTRANS_HTOTAL_B);
|
||||
I915_WRITE(_TRANS_HBLANK_B, dev_priv->saveTRANS_HBLANK_B);
|
||||
I915_WRITE(_TRANS_HSYNC_B, dev_priv->saveTRANS_HSYNC_B);
|
||||
I915_WRITE(_TRANS_VTOTAL_B, dev_priv->saveTRANS_VTOTAL_B);
|
||||
I915_WRITE(_TRANS_VBLANK_B, dev_priv->saveTRANS_VBLANK_B);
|
||||
I915_WRITE(_TRANS_VSYNC_B, dev_priv->saveTRANS_VSYNC_B);
|
||||
}
|
||||
|
||||
/* Restore plane info */
|
||||
I915_WRITE(_DSPBSIZE, dev_priv->saveDSPBSIZE);
|
||||
I915_WRITE(_DSPBPOS, dev_priv->saveDSPBPOS);
|
||||
I915_WRITE(_PIPEBSRC, dev_priv->savePIPEBSRC);
|
||||
I915_WRITE(_DSPBADDR, dev_priv->saveDSPBADDR);
|
||||
I915_WRITE(_DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
I915_WRITE(_DSPBSURF, dev_priv->saveDSPBSURF);
|
||||
I915_WRITE(_DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
|
||||
}
|
||||
|
||||
I915_WRITE(_PIPEBCONF, dev_priv->savePIPEBCONF);
|
||||
|
||||
i915_restore_palette(dev, PIPE_B);
|
||||
/* Enable the plane */
|
||||
I915_WRITE(_DSPBCNTR, dev_priv->saveDSPBCNTR);
|
||||
I915_WRITE(_DSPBADDR, I915_READ(_DSPBADDR));
|
||||
|
||||
/* Cursor state */
|
||||
I915_WRITE(_CURAPOS, dev_priv->saveCURAPOS);
|
||||
I915_WRITE(_CURACNTR, dev_priv->saveCURACNTR);
|
||||
I915_WRITE(_CURABASE, dev_priv->saveCURABASE);
|
||||
I915_WRITE(_CURBPOS, dev_priv->saveCURBPOS);
|
||||
I915_WRITE(_CURBCNTR, dev_priv->saveCURBCNTR);
|
||||
I915_WRITE(_CURBBASE, dev_priv->saveCURBBASE);
|
||||
if (IS_GEN2(dev))
|
||||
I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void i915_save_display(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* Display arbitration control */
|
||||
dev_priv->saveDSPARB = I915_READ(DSPARB);
|
||||
|
||||
/* This is only meaningful in non-KMS mode */
|
||||
/* Don't save them in KMS mode */
|
||||
i915_save_modeset_reg(dev);
|
||||
|
||||
/* CRT state */
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->saveADPA = I915_READ(PCH_ADPA);
|
||||
} else {
|
||||
dev_priv->saveADPA = I915_READ(ADPA);
|
||||
}
|
||||
|
||||
/* LVDS state */
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
|
||||
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1);
|
||||
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
|
||||
dev_priv->saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL);
|
||||
dev_priv->saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2);
|
||||
dev_priv->saveLVDS = I915_READ(PCH_LVDS);
|
||||
} else {
|
||||
dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
|
||||
dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
|
||||
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
|
||||
dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
|
||||
if (INTEL_INFO(dev)->gen >= 4)
|
||||
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
|
||||
if (IS_MOBILE(dev) && !IS_I830(dev))
|
||||
dev_priv->saveLVDS = I915_READ(LVDS);
|
||||
}
|
||||
|
||||
if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
|
||||
dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS);
|
||||
dev_priv->savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS);
|
||||
dev_priv->savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR);
|
||||
} else {
|
||||
dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
|
||||
dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
|
||||
dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
|
||||
}
|
||||
|
||||
/* Display Port state */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
dev_priv->saveDP_B = I915_READ(DP_B);
|
||||
dev_priv->saveDP_C = I915_READ(DP_C);
|
||||
dev_priv->saveDP_D = I915_READ(DP_D);
|
||||
dev_priv->savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M);
|
||||
dev_priv->savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M);
|
||||
dev_priv->savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N);
|
||||
dev_priv->savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N);
|
||||
dev_priv->savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M);
|
||||
dev_priv->savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M);
|
||||
dev_priv->savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N);
|
||||
dev_priv->savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N);
|
||||
}
|
||||
/* FIXME: save TV & SDVO state */
|
||||
|
||||
/* Only save FBC state on the platform that supports FBC */
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
|
||||
} else if (IS_GM45(dev)) {
|
||||
dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
|
||||
} else {
|
||||
dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
|
||||
dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
|
||||
dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
|
||||
dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL);
|
||||
}
|
||||
}
|
||||
|
||||
/* VGA state */
|
||||
dev_priv->saveVGA0 = I915_READ(VGA0);
|
||||
dev_priv->saveVGA1 = I915_READ(VGA1);
|
||||
dev_priv->saveVGA_PD = I915_READ(VGA_PD);
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
dev_priv->saveVGACNTRL = I915_READ(CPU_VGACNTRL);
|
||||
else
|
||||
dev_priv->saveVGACNTRL = I915_READ(VGACNTRL);
|
||||
|
||||
i915_save_vga(dev);
|
||||
}
|
||||
|
||||
static void i915_restore_display(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* Display arbitration */
|
||||
I915_WRITE(DSPARB, dev_priv->saveDSPARB);
|
||||
|
||||
/* Display port ratios (must be done before clock is set) */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->savePIPEA_GMCH_DATA_M);
|
||||
I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->savePIPEB_GMCH_DATA_M);
|
||||
I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->savePIPEA_GMCH_DATA_N);
|
||||
I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->savePIPEB_GMCH_DATA_N);
|
||||
I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->savePIPEA_DP_LINK_M);
|
||||
I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->savePIPEB_DP_LINK_M);
|
||||
I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N);
|
||||
I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N);
|
||||
}
|
||||
|
||||
/* This is only meaningful in non-KMS mode */
|
||||
/* Don't restore them in KMS mode */
|
||||
i915_restore_modeset_reg(dev);
|
||||
|
||||
/* CRT state */
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(PCH_ADPA, dev_priv->saveADPA);
|
||||
else
|
||||
I915_WRITE(ADPA, dev_priv->saveADPA);
|
||||
|
||||
/* LVDS state */
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(PCH_LVDS, dev_priv->saveLVDS);
|
||||
} else if (IS_MOBILE(dev) && !IS_I830(dev))
|
||||
I915_WRITE(LVDS, dev_priv->saveLVDS);
|
||||
|
||||
if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->saveBLC_PWM_CTL);
|
||||
I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->saveBLC_PWM_CTL2);
|
||||
I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->saveBLC_CPU_PWM_CTL);
|
||||
I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->saveBLC_CPU_PWM_CTL2);
|
||||
I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS);
|
||||
I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
|
||||
I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
|
||||
I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
|
||||
I915_WRITE(RSTDBYCTL,
|
||||
dev_priv->saveMCHBAR_RENDER_STANDBY);
|
||||
} else {
|
||||
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
|
||||
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
|
||||
I915_WRITE(BLC_HIST_CTL, dev_priv->saveBLC_HIST_CTL);
|
||||
I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS);
|
||||
I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
|
||||
I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
|
||||
I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
|
||||
}
|
||||
|
||||
/* Display Port state */
|
||||
if (SUPPORTS_INTEGRATED_DP(dev)) {
|
||||
I915_WRITE(DP_B, dev_priv->saveDP_B);
|
||||
I915_WRITE(DP_C, dev_priv->saveDP_C);
|
||||
I915_WRITE(DP_D, dev_priv->saveDP_D);
|
||||
}
|
||||
/* FIXME: restore TV & SDVO state */
|
||||
|
||||
/* only restore FBC info on the platform that supports FBC*/
|
||||
intel_disable_fbc(dev);
|
||||
if (I915_HAS_FBC(dev)) {
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
|
||||
} else if (IS_GM45(dev)) {
|
||||
I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE);
|
||||
} else {
|
||||
I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE);
|
||||
I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE);
|
||||
I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2);
|
||||
I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL);
|
||||
}
|
||||
}
|
||||
/* VGA state */
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(CPU_VGACNTRL, dev_priv->saveVGACNTRL);
|
||||
else
|
||||
I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL);
|
||||
|
||||
I915_WRITE(VGA0, dev_priv->saveVGA0);
|
||||
I915_WRITE(VGA1, dev_priv->saveVGA1);
|
||||
I915_WRITE(VGA_PD, dev_priv->saveVGA_PD);
|
||||
POSTING_READ(VGA_PD);
|
||||
DRM_UDELAY(150);
|
||||
|
||||
i915_restore_vga(dev);
|
||||
}
|
||||
|
||||
int i915_save_state(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
dev_priv->saveLBB = pci_read_config(dev->device, LBB, 1);
|
||||
|
||||
/* Hardware status page */
|
||||
dev_priv->saveHWS = I915_READ(HWS_PGA);
|
||||
|
||||
i915_save_display(dev);
|
||||
|
||||
/* Interrupt state */
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->saveDEIER = I915_READ(DEIER);
|
||||
dev_priv->saveDEIMR = I915_READ(DEIMR);
|
||||
dev_priv->saveGTIER = I915_READ(GTIER);
|
||||
dev_priv->saveGTIMR = I915_READ(GTIMR);
|
||||
dev_priv->saveFDI_RXA_IMR = I915_READ(_FDI_RXA_IMR);
|
||||
dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR);
|
||||
dev_priv->saveMCHBAR_RENDER_STANDBY =
|
||||
I915_READ(RSTDBYCTL);
|
||||
dev_priv->savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG);
|
||||
} else {
|
||||
dev_priv->saveIER = I915_READ(IER);
|
||||
dev_priv->saveIMR = I915_READ(IMR);
|
||||
}
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_disable_drps(dev);
|
||||
if (INTEL_INFO(dev)->gen >= 6)
|
||||
gen6_disable_rps(dev);
|
||||
|
||||
/* Cache mode state */
|
||||
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
|
||||
|
||||
/* Memory Arbitration state */
|
||||
dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
|
||||
|
||||
/* Scratch space */
|
||||
for (i = 0; i < 16; i++) {
|
||||
dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2));
|
||||
dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2));
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i915_restore_state(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int i;
|
||||
|
||||
pci_write_config(dev->device, LBB, dev_priv->saveLBB, 1);
|
||||
|
||||
|
||||
/* Hardware status page */
|
||||
I915_WRITE(HWS_PGA, dev_priv->saveHWS);
|
||||
|
||||
i915_restore_display(dev);
|
||||
|
||||
/* Interrupt state */
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(DEIER, dev_priv->saveDEIER);
|
||||
I915_WRITE(DEIMR, dev_priv->saveDEIMR);
|
||||
I915_WRITE(GTIER, dev_priv->saveGTIER);
|
||||
I915_WRITE(GTIMR, dev_priv->saveGTIMR);
|
||||
I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR);
|
||||
I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR);
|
||||
I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->savePCH_PORT_HOTPLUG);
|
||||
} else {
|
||||
I915_WRITE(IER, dev_priv->saveIER);
|
||||
I915_WRITE(IMR, dev_priv->saveIMR);
|
||||
}
|
||||
DRM_UNLOCK(dev);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
intel_init_clock_gating(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
ironlake_enable_drps(dev);
|
||||
intel_init_emon(dev);
|
||||
}
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 6) {
|
||||
gen6_enable_rps(dev_priv);
|
||||
gen6_update_ring_freq(dev_priv);
|
||||
}
|
||||
|
||||
DRM_LOCK(dev);
|
||||
|
||||
/* Cache mode state */
|
||||
I915_WRITE(CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
|
||||
|
||||
/* Memory arbitration state */
|
||||
I915_WRITE(MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000);
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]);
|
||||
I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i]);
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
|
||||
|
||||
intel_iic_reset(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
737
sys/dev/drm2/i915/intel_bios.c
Normal file
737
sys/dev/drm2/i915/intel_bios.c
Normal file
|
|
@ -0,0 +1,737 @@
|
|||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_dp_helper.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_bios.h>
|
||||
|
||||
#define SLAVE_ADDR1 0x70
|
||||
#define SLAVE_ADDR2 0x72
|
||||
|
||||
static int panel_type;
|
||||
|
||||
static void *
|
||||
find_section(struct bdb_header *bdb, int section_id)
|
||||
{
|
||||
u8 *base = (u8 *)bdb;
|
||||
int index = 0;
|
||||
u16 total, current_size;
|
||||
u8 current_id;
|
||||
|
||||
/* skip to first section */
|
||||
index += bdb->header_size;
|
||||
total = bdb->bdb_size;
|
||||
|
||||
/* walk the sections looking for section_id */
|
||||
while (index < total) {
|
||||
current_id = *(base + index);
|
||||
index++;
|
||||
current_size = *((u16 *)(base + index));
|
||||
index += 2;
|
||||
if (current_id == section_id)
|
||||
return base + index;
|
||||
index += current_size;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u16
|
||||
get_blocksize(void *p)
|
||||
{
|
||||
u16 *block_ptr, block_size;
|
||||
|
||||
block_ptr = (u16 *)((char *)p - 2);
|
||||
block_size = *block_ptr;
|
||||
return block_size;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
|
||||
const struct lvds_dvo_timing *dvo_timing)
|
||||
{
|
||||
panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
|
||||
dvo_timing->hactive_lo;
|
||||
panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
|
||||
((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
|
||||
panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
|
||||
dvo_timing->hsync_pulse_width;
|
||||
panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
|
||||
((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
|
||||
|
||||
panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
|
||||
dvo_timing->vactive_lo;
|
||||
panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
|
||||
dvo_timing->vsync_off;
|
||||
panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
|
||||
dvo_timing->vsync_pulse_width;
|
||||
panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
|
||||
((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
|
||||
panel_fixed_mode->clock = dvo_timing->clock * 10;
|
||||
panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
if (dvo_timing->hsync_positive)
|
||||
panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||
else
|
||||
panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC;
|
||||
|
||||
if (dvo_timing->vsync_positive)
|
||||
panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
||||
else
|
||||
panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
|
||||
|
||||
/* Some VBTs have bogus h/vtotal values */
|
||||
if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
|
||||
panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
|
||||
if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal)
|
||||
panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1;
|
||||
|
||||
drm_mode_set_name(panel_fixed_mode);
|
||||
}
|
||||
|
||||
static bool
|
||||
lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a,
|
||||
const struct lvds_dvo_timing *b)
|
||||
{
|
||||
if (a->hactive_hi != b->hactive_hi ||
|
||||
a->hactive_lo != b->hactive_lo)
|
||||
return false;
|
||||
|
||||
if (a->hsync_off_hi != b->hsync_off_hi ||
|
||||
a->hsync_off_lo != b->hsync_off_lo)
|
||||
return false;
|
||||
|
||||
if (a->hsync_pulse_width != b->hsync_pulse_width)
|
||||
return false;
|
||||
|
||||
if (a->hblank_hi != b->hblank_hi ||
|
||||
a->hblank_lo != b->hblank_lo)
|
||||
return false;
|
||||
|
||||
if (a->vactive_hi != b->vactive_hi ||
|
||||
a->vactive_lo != b->vactive_lo)
|
||||
return false;
|
||||
|
||||
if (a->vsync_off != b->vsync_off)
|
||||
return false;
|
||||
|
||||
if (a->vsync_pulse_width != b->vsync_pulse_width)
|
||||
return false;
|
||||
|
||||
if (a->vblank_hi != b->vblank_hi ||
|
||||
a->vblank_lo != b->vblank_lo)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct lvds_dvo_timing *
|
||||
get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
|
||||
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs,
|
||||
int index)
|
||||
{
|
||||
/*
|
||||
* the size of fp_timing varies on the different platform.
|
||||
* So calculate the DVO timing relative offset in LVDS data
|
||||
* entry to get the DVO timing entry
|
||||
*/
|
||||
|
||||
int lfp_data_size =
|
||||
lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
|
||||
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
|
||||
int dvo_timing_offset =
|
||||
lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
|
||||
lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
|
||||
const char *entry = (const char *)lvds_lfp_data->data +
|
||||
lfp_data_size * index;
|
||||
|
||||
return (const struct lvds_dvo_timing *)(entry + dvo_timing_offset);
|
||||
}
|
||||
|
||||
/* Try to find integrated panel data */
|
||||
static void
|
||||
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
const struct bdb_lvds_options *lvds_options;
|
||||
const struct bdb_lvds_lfp_data *lvds_lfp_data;
|
||||
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
|
||||
const struct lvds_dvo_timing *panel_dvo_timing;
|
||||
struct drm_display_mode *panel_fixed_mode;
|
||||
int i, downclock;
|
||||
|
||||
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
|
||||
if (!lvds_options)
|
||||
return;
|
||||
|
||||
dev_priv->lvds_dither = lvds_options->pixel_dither;
|
||||
if (lvds_options->panel_type == 0xff)
|
||||
return;
|
||||
|
||||
panel_type = lvds_options->panel_type;
|
||||
|
||||
lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
|
||||
if (!lvds_lfp_data)
|
||||
return;
|
||||
|
||||
lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS);
|
||||
if (!lvds_lfp_data_ptrs)
|
||||
return;
|
||||
|
||||
dev_priv->lvds_vbt = 1;
|
||||
|
||||
panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
|
||||
lvds_lfp_data_ptrs,
|
||||
lvds_options->panel_type);
|
||||
|
||||
panel_fixed_mode = malloc(sizeof(*panel_fixed_mode), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);
|
||||
|
||||
dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
|
||||
|
||||
DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
|
||||
drm_mode_debug_printmodeline(panel_fixed_mode);
|
||||
|
||||
/*
|
||||
* Iterate over the LVDS panel timing info to find the lowest clock
|
||||
* for the native resolution.
|
||||
*/
|
||||
downclock = panel_dvo_timing->clock;
|
||||
for (i = 0; i < 16; i++) {
|
||||
const struct lvds_dvo_timing *dvo_timing;
|
||||
|
||||
dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
|
||||
lvds_lfp_data_ptrs,
|
||||
i);
|
||||
if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) &&
|
||||
dvo_timing->clock < downclock)
|
||||
downclock = dvo_timing->clock;
|
||||
}
|
||||
|
||||
if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
|
||||
dev_priv->lvds_downclock_avail = 1;
|
||||
dev_priv->lvds_downclock = downclock * 10;
|
||||
DRM_DEBUG("LVDS downclock is found in VBT. "
|
||||
"Normal Clock %dKHz, downclock %dKHz\n",
|
||||
panel_fixed_mode->clock, 10 * downclock);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to find sdvo panel data */
|
||||
static void
|
||||
parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct lvds_dvo_timing *dvo_timing;
|
||||
struct drm_display_mode *panel_fixed_mode;
|
||||
int index;
|
||||
|
||||
index = i915_vbt_sdvo_panel_type;
|
||||
if (index == -1) {
|
||||
struct bdb_sdvo_lvds_options *sdvo_lvds_options;
|
||||
|
||||
sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
|
||||
if (!sdvo_lvds_options)
|
||||
return;
|
||||
|
||||
index = sdvo_lvds_options->panel_type;
|
||||
}
|
||||
|
||||
dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS);
|
||||
if (!dvo_timing)
|
||||
return;
|
||||
|
||||
panel_fixed_mode = malloc(sizeof(*panel_fixed_mode), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
fill_detail_timing_data(panel_fixed_mode, dvo_timing + index);
|
||||
|
||||
dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode;
|
||||
|
||||
DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n");
|
||||
drm_mode_debug_printmodeline(panel_fixed_mode);
|
||||
}
|
||||
|
||||
static int intel_bios_ssc_frequency(struct drm_device *dev,
|
||||
bool alternate)
|
||||
{
|
||||
switch (INTEL_INFO(dev)->gen) {
|
||||
case 2:
|
||||
return alternate ? 66 : 48;
|
||||
case 3:
|
||||
case 4:
|
||||
return alternate ? 100 : 96;
|
||||
default:
|
||||
return alternate ? 100 : 120;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_general_features(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct bdb_general_features *general;
|
||||
|
||||
general = find_section(bdb, BDB_GENERAL_FEATURES);
|
||||
if (general) {
|
||||
dev_priv->int_tv_support = general->int_tv_support;
|
||||
dev_priv->int_crt_support = general->int_crt_support;
|
||||
dev_priv->lvds_use_ssc = general->enable_ssc;
|
||||
dev_priv->lvds_ssc_freq =
|
||||
intel_bios_ssc_frequency(dev, general->ssc_freq);
|
||||
dev_priv->display_clock_mode = general->display_clock_mode;
|
||||
DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d\n",
|
||||
dev_priv->int_tv_support,
|
||||
dev_priv->int_crt_support,
|
||||
dev_priv->lvds_use_ssc,
|
||||
dev_priv->lvds_ssc_freq,
|
||||
dev_priv->display_clock_mode);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_general_definitions(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct bdb_general_definitions *general;
|
||||
|
||||
general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||
if (general) {
|
||||
u16 block_size = get_blocksize(general);
|
||||
if (block_size >= sizeof(*general)) {
|
||||
int bus_pin = general->crt_ddc_gmbus_pin;
|
||||
DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
|
||||
if (bus_pin >= 1 && bus_pin <= 6)
|
||||
dev_priv->crt_ddc_pin = bus_pin;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
|
||||
block_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct sdvo_device_mapping *p_mapping;
|
||||
struct bdb_general_definitions *p_defs;
|
||||
struct child_device_config *p_child;
|
||||
int i, child_device_num, count;
|
||||
u16 block_size;
|
||||
|
||||
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||
if (!p_defs) {
|
||||
DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
|
||||
return;
|
||||
}
|
||||
/* judge whether the size of child device meets the requirements.
|
||||
* If the child device size obtained from general definition block
|
||||
* is different with sizeof(struct child_device_config), skip the
|
||||
* parsing of sdvo device info
|
||||
*/
|
||||
if (p_defs->child_dev_size != sizeof(*p_child)) {
|
||||
/* different child dev size . Ignore it */
|
||||
DRM_DEBUG_KMS("different child size is found. Invalid.\n");
|
||||
return;
|
||||
}
|
||||
/* get the block size of general definitions */
|
||||
block_size = get_blocksize(p_defs);
|
||||
/* get the number of child device */
|
||||
child_device_num = (block_size - sizeof(*p_defs)) /
|
||||
sizeof(*p_child);
|
||||
count = 0;
|
||||
for (i = 0; i < child_device_num; i++) {
|
||||
p_child = &(p_defs->devices[i]);
|
||||
if (!p_child->device_type) {
|
||||
/* skip the device block if device type is invalid */
|
||||
continue;
|
||||
}
|
||||
if (p_child->slave_addr != SLAVE_ADDR1 &&
|
||||
p_child->slave_addr != SLAVE_ADDR2) {
|
||||
/*
|
||||
* If the slave address is neither 0x70 nor 0x72,
|
||||
* it is not a SDVO device. Skip it.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (p_child->dvo_port != DEVICE_PORT_DVOB &&
|
||||
p_child->dvo_port != DEVICE_PORT_DVOC) {
|
||||
/* skip the incorrect SDVO port */
|
||||
DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n");
|
||||
continue;
|
||||
}
|
||||
DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on"
|
||||
" %s port\n",
|
||||
p_child->slave_addr,
|
||||
(p_child->dvo_port == DEVICE_PORT_DVOB) ?
|
||||
"SDVOB" : "SDVOC");
|
||||
p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]);
|
||||
if (!p_mapping->initialized) {
|
||||
p_mapping->dvo_port = p_child->dvo_port;
|
||||
p_mapping->slave_addr = p_child->slave_addr;
|
||||
p_mapping->dvo_wiring = p_child->dvo_wiring;
|
||||
p_mapping->ddc_pin = p_child->ddc_pin;
|
||||
p_mapping->i2c_pin = p_child->i2c_pin;
|
||||
p_mapping->initialized = 1;
|
||||
DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n",
|
||||
p_mapping->dvo_port,
|
||||
p_mapping->slave_addr,
|
||||
p_mapping->dvo_wiring,
|
||||
p_mapping->ddc_pin,
|
||||
p_mapping->i2c_pin);
|
||||
} else {
|
||||
DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
|
||||
"two SDVO device.\n");
|
||||
}
|
||||
if (p_child->slave2_addr) {
|
||||
/* Maybe this is a SDVO device with multiple inputs */
|
||||
/* And the mapping info is not added */
|
||||
DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this"
|
||||
" is a SDVO device with multiple inputs.\n");
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
/* No SDVO device info is found */
|
||||
DRM_DEBUG_KMS("No SDVO device info is found in VBT\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_driver_features(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct bdb_driver_features *driver;
|
||||
|
||||
driver = find_section(bdb, BDB_DRIVER_FEATURES);
|
||||
if (!driver)
|
||||
return;
|
||||
|
||||
if (SUPPORTS_EDP(dev) &&
|
||||
driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
|
||||
dev_priv->edp.support = 1;
|
||||
|
||||
if (driver->dual_frequency)
|
||||
dev_priv->render_reclock_avail = true;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
||||
{
|
||||
struct bdb_edp *edp;
|
||||
struct edp_power_seq *edp_pps;
|
||||
struct edp_link_params *edp_link_params;
|
||||
|
||||
edp = find_section(bdb, BDB_EDP);
|
||||
if (!edp) {
|
||||
if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
|
||||
DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
|
||||
"supported, assume %dbpp panel color "
|
||||
"depth.\n",
|
||||
dev_priv->edp.bpp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch ((edp->color_depth >> (panel_type * 2)) & 3) {
|
||||
case EDP_18BPP:
|
||||
dev_priv->edp.bpp = 18;
|
||||
break;
|
||||
case EDP_24BPP:
|
||||
dev_priv->edp.bpp = 24;
|
||||
break;
|
||||
case EDP_30BPP:
|
||||
dev_priv->edp.bpp = 30;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the eDP sequencing and link info */
|
||||
edp_pps = &edp->power_seqs[panel_type];
|
||||
edp_link_params = &edp->link_params[panel_type];
|
||||
|
||||
dev_priv->edp.pps = *edp_pps;
|
||||
|
||||
dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
|
||||
DP_LINK_BW_1_62;
|
||||
switch (edp_link_params->lanes) {
|
||||
case 0:
|
||||
dev_priv->edp.lanes = 1;
|
||||
break;
|
||||
case 1:
|
||||
dev_priv->edp.lanes = 2;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
dev_priv->edp.lanes = 4;
|
||||
break;
|
||||
}
|
||||
switch (edp_link_params->preemphasis) {
|
||||
case 0:
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
|
||||
break;
|
||||
case 1:
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
|
||||
break;
|
||||
case 2:
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
|
||||
break;
|
||||
case 3:
|
||||
dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
|
||||
break;
|
||||
}
|
||||
switch (edp_link_params->vswing) {
|
||||
case 0:
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
|
||||
break;
|
||||
case 1:
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
|
||||
break;
|
||||
case 2:
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
|
||||
break;
|
||||
case 3:
|
||||
dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_device_mapping(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct bdb_general_definitions *p_defs;
|
||||
struct child_device_config *p_child, *child_dev_ptr;
|
||||
int i, child_device_num, count;
|
||||
u16 block_size;
|
||||
|
||||
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||
if (!p_defs) {
|
||||
DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
|
||||
return;
|
||||
}
|
||||
/* judge whether the size of child device meets the requirements.
|
||||
* If the child device size obtained from general definition block
|
||||
* is different with sizeof(struct child_device_config), skip the
|
||||
* parsing of sdvo device info
|
||||
*/
|
||||
if (p_defs->child_dev_size != sizeof(*p_child)) {
|
||||
/* different child dev size . Ignore it */
|
||||
DRM_DEBUG_KMS("different child size is found. Invalid.\n");
|
||||
return;
|
||||
}
|
||||
/* get the block size of general definitions */
|
||||
block_size = get_blocksize(p_defs);
|
||||
/* get the number of child device */
|
||||
child_device_num = (block_size - sizeof(*p_defs)) /
|
||||
sizeof(*p_child);
|
||||
count = 0;
|
||||
/* get the number of child device that is present */
|
||||
for (i = 0; i < child_device_num; i++) {
|
||||
p_child = &(p_defs->devices[i]);
|
||||
if (!p_child->device_type) {
|
||||
/* skip the device block if device type is invalid */
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
if (!count) {
|
||||
DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
|
||||
return;
|
||||
}
|
||||
dev_priv->child_dev = malloc(sizeof(*p_child) * count, DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
dev_priv->child_dev_num = count;
|
||||
count = 0;
|
||||
for (i = 0; i < child_device_num; i++) {
|
||||
p_child = &(p_defs->devices[i]);
|
||||
if (!p_child->device_type) {
|
||||
/* skip the device block if device type is invalid */
|
||||
continue;
|
||||
}
|
||||
child_dev_ptr = dev_priv->child_dev + count;
|
||||
count++;
|
||||
memcpy((void *)child_dev_ptr, (void *)p_child,
|
||||
sizeof(*p_child));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
init_vbt_defaults(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
|
||||
dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
|
||||
|
||||
/* LFP panel data */
|
||||
dev_priv->lvds_dither = 1;
|
||||
dev_priv->lvds_vbt = 0;
|
||||
|
||||
/* SDVO panel data */
|
||||
dev_priv->sdvo_lvds_vbt_mode = NULL;
|
||||
|
||||
/* general features */
|
||||
dev_priv->int_tv_support = 1;
|
||||
dev_priv->int_crt_support = 1;
|
||||
|
||||
/* Default to using SSC */
|
||||
dev_priv->lvds_use_ssc = 1;
|
||||
dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
|
||||
DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq);
|
||||
|
||||
/* eDP data */
|
||||
dev_priv->edp.bpp = 18;
|
||||
}
|
||||
|
||||
static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
|
||||
{
|
||||
DRM_DEBUG_KMS("Falling back to manually reading VBT from "
|
||||
"VBIOS ROM for %s\n",
|
||||
id->ident);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id intel_no_opregion_vbt[] = {
|
||||
{
|
||||
.callback = intel_no_opregion_vbt_callback,
|
||||
.ident = "ThinkCentre A57",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* intel_parse_bios - find VBT and initialize settings from the BIOS
|
||||
* @dev: DRM device
|
||||
*
|
||||
* Loads the Video BIOS and checks that the VBT exists. Sets scratch registers
|
||||
* to appropriate values.
|
||||
*
|
||||
* Returns 0 on success, nonzero on failure.
|
||||
*/
|
||||
bool
|
||||
intel_parse_bios(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct bdb_header *bdb = NULL;
|
||||
u8 *bios;
|
||||
|
||||
init_vbt_defaults(dev_priv);
|
||||
|
||||
/* XXX Should this validation be moved to intel_opregion.c? */
|
||||
if (!dmi_check_system(intel_no_opregion_vbt) && dev_priv->opregion.vbt) {
|
||||
struct vbt_header *vbt = dev_priv->opregion.vbt;
|
||||
if (memcmp(vbt->signature, "$VBT", 4) == 0) {
|
||||
DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n",
|
||||
vbt->signature);
|
||||
bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
|
||||
} else
|
||||
dev_priv->opregion.vbt = NULL;
|
||||
}
|
||||
bios = NULL;
|
||||
|
||||
#if 1
|
||||
if (bdb == NULL) {
|
||||
KIB_NOTYET();
|
||||
return (-1);
|
||||
}
|
||||
#else
|
||||
if (bdb == NULL) {
|
||||
struct vbt_header *vbt = NULL;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
bios = pci_map_rom(pdev, &size);
|
||||
if (!bios)
|
||||
return -1;
|
||||
|
||||
/* Scour memory looking for the VBT signature */
|
||||
for (i = 0; i + 4 < size; i++) {
|
||||
if (!memcmp(bios + i, "$VBT", 4)) {
|
||||
vbt = (struct vbt_header *)(bios + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vbt) {
|
||||
DRM_DEBUG_DRIVER("VBT signature missing\n");
|
||||
pci_unmap_rom(pdev, bios);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Grab useful general definitions */
|
||||
parse_general_features(dev_priv, bdb);
|
||||
parse_general_definitions(dev_priv, bdb);
|
||||
parse_lfp_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_device_mapping(dev_priv, bdb);
|
||||
parse_device_mapping(dev_priv, bdb);
|
||||
parse_driver_features(dev_priv, bdb);
|
||||
parse_edp(dev_priv, bdb);
|
||||
|
||||
#if 0
|
||||
if (bios)
|
||||
pci_unmap_rom(pdev, bios);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure that vital registers have been initialised, even if the BIOS
|
||||
* is absent or just failing to do its job.
|
||||
*/
|
||||
void intel_setup_bios(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* Set the Panel Power On/Off timings if uninitialized. */
|
||||
if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) {
|
||||
/* Set T2 to 40ms and T5 to 200ms */
|
||||
I915_WRITE(PP_ON_DELAYS, 0x019007d0);
|
||||
|
||||
/* Set T3 to 35ms and Tx to 200ms */
|
||||
I915_WRITE(PP_OFF_DELAYS, 0x015e07d0);
|
||||
}
|
||||
}
|
||||
620
sys/dev/drm2/i915/intel_bios.h
Normal file
620
sys/dev/drm2/i915/intel_bios.h
Normal file
|
|
@ -0,0 +1,620 @@
|
|||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _I830_BIOS_H_
|
||||
#define _I830_BIOS_H_
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
|
||||
struct vbt_header {
|
||||
u8 signature[20]; /**< Always starts with 'VBT$' */
|
||||
u16 version; /**< decimal */
|
||||
u16 header_size; /**< in bytes */
|
||||
u16 vbt_size; /**< in bytes */
|
||||
u8 vbt_checksum;
|
||||
u8 reserved0;
|
||||
u32 bdb_offset; /**< from beginning of VBT */
|
||||
u32 aim_offset[4]; /**< from beginning of VBT */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bdb_header {
|
||||
u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */
|
||||
u16 version; /**< decimal */
|
||||
u16 header_size; /**< in bytes */
|
||||
u16 bdb_size; /**< in bytes */
|
||||
};
|
||||
|
||||
/* strictly speaking, this is a "skip" block, but it has interesting info */
|
||||
struct vbios_data {
|
||||
u8 type; /* 0 == desktop, 1 == mobile */
|
||||
u8 relstage;
|
||||
u8 chipset;
|
||||
u8 lvds_present:1;
|
||||
u8 tv_present:1;
|
||||
u8 rsvd2:6; /* finish byte */
|
||||
u8 rsvd3[4];
|
||||
u8 signon[155];
|
||||
u8 copyright[61];
|
||||
u16 code_segment;
|
||||
u8 dos_boot_mode;
|
||||
u8 bandwidth_percent;
|
||||
u8 rsvd4; /* popup memory size */
|
||||
u8 resize_pci_bios;
|
||||
u8 rsvd5; /* is crt already on ddc2 */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* There are several types of BIOS data blocks (BDBs), each block has
|
||||
* an ID and size in the first 3 bytes (ID in first, size in next 2).
|
||||
* Known types are listed below.
|
||||
*/
|
||||
#define BDB_GENERAL_FEATURES 1
|
||||
#define BDB_GENERAL_DEFINITIONS 2
|
||||
#define BDB_OLD_TOGGLE_LIST 3
|
||||
#define BDB_MODE_SUPPORT_LIST 4
|
||||
#define BDB_GENERIC_MODE_TABLE 5
|
||||
#define BDB_EXT_MMIO_REGS 6
|
||||
#define BDB_SWF_IO 7
|
||||
#define BDB_SWF_MMIO 8
|
||||
#define BDB_DOT_CLOCK_TABLE 9
|
||||
#define BDB_MODE_REMOVAL_TABLE 10
|
||||
#define BDB_CHILD_DEVICE_TABLE 11
|
||||
#define BDB_DRIVER_FEATURES 12
|
||||
#define BDB_DRIVER_PERSISTENCE 13
|
||||
#define BDB_EXT_TABLE_PTRS 14
|
||||
#define BDB_DOT_CLOCK_OVERRIDE 15
|
||||
#define BDB_DISPLAY_SELECT 16
|
||||
/* 17 rsvd */
|
||||
#define BDB_DRIVER_ROTATION 18
|
||||
#define BDB_DISPLAY_REMOVE 19
|
||||
#define BDB_OEM_CUSTOM 20
|
||||
#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */
|
||||
#define BDB_SDVO_LVDS_OPTIONS 22
|
||||
#define BDB_SDVO_PANEL_DTDS 23
|
||||
#define BDB_SDVO_LVDS_PNP_IDS 24
|
||||
#define BDB_SDVO_LVDS_POWER_SEQ 25
|
||||
#define BDB_TV_OPTIONS 26
|
||||
#define BDB_EDP 27
|
||||
#define BDB_LVDS_OPTIONS 40
|
||||
#define BDB_LVDS_LFP_DATA_PTRS 41
|
||||
#define BDB_LVDS_LFP_DATA 42
|
||||
#define BDB_LVDS_BACKLIGHT 43
|
||||
#define BDB_LVDS_POWER 44
|
||||
#define BDB_SKIP 254 /* VBIOS private block, ignore */
|
||||
|
||||
struct bdb_general_features {
|
||||
/* bits 1 */
|
||||
u8 panel_fitting:2;
|
||||
u8 flexaim:1;
|
||||
u8 msg_enable:1;
|
||||
u8 clear_screen:3;
|
||||
u8 color_flip:1;
|
||||
|
||||
/* bits 2 */
|
||||
u8 download_ext_vbt:1;
|
||||
u8 enable_ssc:1;
|
||||
u8 ssc_freq:1;
|
||||
u8 enable_lfp_on_override:1;
|
||||
u8 disable_ssc_ddt:1;
|
||||
u8 rsvd7:1;
|
||||
u8 display_clock_mode:1;
|
||||
u8 rsvd8:1; /* finish byte */
|
||||
|
||||
/* bits 3 */
|
||||
u8 disable_smooth_vision:1;
|
||||
u8 single_dvi:1;
|
||||
u8 rsvd9:6; /* finish byte */
|
||||
|
||||
/* bits 4 */
|
||||
u8 legacy_monitor_detect;
|
||||
|
||||
/* bits 5 */
|
||||
u8 int_crt_support:1;
|
||||
u8 int_tv_support:1;
|
||||
u8 int_efp_support:1;
|
||||
u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */
|
||||
u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */
|
||||
u8 rsvd11:3; /* finish byte */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* pre-915 */
|
||||
#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */
|
||||
#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */
|
||||
#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */
|
||||
#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */
|
||||
|
||||
/* Pre 915 */
|
||||
#define DEVICE_TYPE_NONE 0x00
|
||||
#define DEVICE_TYPE_CRT 0x01
|
||||
#define DEVICE_TYPE_TV 0x09
|
||||
#define DEVICE_TYPE_EFP 0x12
|
||||
#define DEVICE_TYPE_LFP 0x22
|
||||
/* On 915+ */
|
||||
#define DEVICE_TYPE_CRT_DPMS 0x6001
|
||||
#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001
|
||||
#define DEVICE_TYPE_TV_COMPOSITE 0x0209
|
||||
#define DEVICE_TYPE_TV_MACROVISION 0x0289
|
||||
#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c
|
||||
#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609
|
||||
#define DEVICE_TYPE_TV_SCART 0x0209
|
||||
#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009
|
||||
#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012
|
||||
#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052
|
||||
#define DEVICE_TYPE_EFP_DVI_I 0x6053
|
||||
#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152
|
||||
#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2
|
||||
#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062
|
||||
#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162
|
||||
#define DEVICE_TYPE_LFP_PANELLINK 0x5012
|
||||
#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042
|
||||
#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062
|
||||
#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162
|
||||
#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2
|
||||
|
||||
#define DEVICE_CFG_NONE 0x00
|
||||
#define DEVICE_CFG_12BIT_DVOB 0x01
|
||||
#define DEVICE_CFG_12BIT_DVOC 0x02
|
||||
#define DEVICE_CFG_24BIT_DVOBC 0x09
|
||||
#define DEVICE_CFG_24BIT_DVOCB 0x0a
|
||||
#define DEVICE_CFG_DUAL_DVOB 0x11
|
||||
#define DEVICE_CFG_DUAL_DVOC 0x12
|
||||
#define DEVICE_CFG_DUAL_DVOBC 0x13
|
||||
#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19
|
||||
#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a
|
||||
|
||||
#define DEVICE_WIRE_NONE 0x00
|
||||
#define DEVICE_WIRE_DVOB 0x01
|
||||
#define DEVICE_WIRE_DVOC 0x02
|
||||
#define DEVICE_WIRE_DVOBC 0x03
|
||||
#define DEVICE_WIRE_DVOBB 0x05
|
||||
#define DEVICE_WIRE_DVOCC 0x06
|
||||
#define DEVICE_WIRE_DVOB_MASTER 0x0d
|
||||
#define DEVICE_WIRE_DVOC_MASTER 0x0e
|
||||
|
||||
#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */
|
||||
#define DEVICE_PORT_DVOB 0x01
|
||||
#define DEVICE_PORT_DVOC 0x02
|
||||
|
||||
struct child_device_config {
|
||||
u16 handle;
|
||||
u16 device_type;
|
||||
u8 device_id[10]; /* ascii string */
|
||||
u16 addin_offset;
|
||||
u8 dvo_port; /* See Device_PORT_* above */
|
||||
u8 i2c_pin;
|
||||
u8 slave_addr;
|
||||
u8 ddc_pin;
|
||||
u16 edid_ptr;
|
||||
u8 dvo_cfg; /* See DEVICE_CFG_* above */
|
||||
u8 dvo2_port;
|
||||
u8 i2c2_pin;
|
||||
u8 slave2_addr;
|
||||
u8 ddc2_pin;
|
||||
u8 capabilities;
|
||||
u8 dvo_wiring;/* See DEVICE_WIRE_* above */
|
||||
u8 dvo2_wiring;
|
||||
u16 extended_type;
|
||||
u8 dvo_function;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bdb_general_definitions {
|
||||
/* DDC GPIO */
|
||||
u8 crt_ddc_gmbus_pin;
|
||||
|
||||
/* DPMS bits */
|
||||
u8 dpms_acpi:1;
|
||||
u8 skip_boot_crt_detect:1;
|
||||
u8 dpms_aim:1;
|
||||
u8 rsvd1:5; /* finish byte */
|
||||
|
||||
/* boot device bits */
|
||||
u8 boot_display[2];
|
||||
u8 child_dev_size;
|
||||
|
||||
/*
|
||||
* Device info:
|
||||
* If TV is present, it'll be at devices[0].
|
||||
* LVDS will be next, either devices[0] or [1], if present.
|
||||
* On some platforms the number of device is 6. But could be as few as
|
||||
* 4 if both TV and LVDS are missing.
|
||||
* And the device num is related with the size of general definition
|
||||
* block. It is obtained by using the following formula:
|
||||
* number = (block_size - sizeof(bdb_general_definitions))/
|
||||
* sizeof(child_device_config);
|
||||
*/
|
||||
struct child_device_config devices[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bdb_lvds_options {
|
||||
u8 panel_type;
|
||||
u8 rsvd1;
|
||||
/* LVDS capabilities, stored in a dword */
|
||||
u8 pfit_mode:2;
|
||||
u8 pfit_text_mode_enhanced:1;
|
||||
u8 pfit_gfx_mode_enhanced:1;
|
||||
u8 pfit_ratio_auto:1;
|
||||
u8 pixel_dither:1;
|
||||
u8 lvds_edid:1;
|
||||
u8 rsvd2:1;
|
||||
u8 rsvd4;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* LFP pointer table contains entries to the struct below */
|
||||
struct bdb_lvds_lfp_data_ptr {
|
||||
u16 fp_timing_offset; /* offsets are from start of bdb */
|
||||
u8 fp_table_size;
|
||||
u16 dvo_timing_offset;
|
||||
u8 dvo_table_size;
|
||||
u16 panel_pnp_id_offset;
|
||||
u8 pnp_table_size;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bdb_lvds_lfp_data_ptrs {
|
||||
u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */
|
||||
struct bdb_lvds_lfp_data_ptr ptr[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* LFP data has 3 blocks per entry */
|
||||
struct lvds_fp_timing {
|
||||
u16 x_res;
|
||||
u16 y_res;
|
||||
u32 lvds_reg;
|
||||
u32 lvds_reg_val;
|
||||
u32 pp_on_reg;
|
||||
u32 pp_on_reg_val;
|
||||
u32 pp_off_reg;
|
||||
u32 pp_off_reg_val;
|
||||
u32 pp_cycle_reg;
|
||||
u32 pp_cycle_reg_val;
|
||||
u32 pfit_reg;
|
||||
u32 pfit_reg_val;
|
||||
u16 terminator;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct lvds_dvo_timing {
|
||||
u16 clock; /**< In 10khz */
|
||||
u8 hactive_lo;
|
||||
u8 hblank_lo;
|
||||
u8 hblank_hi:4;
|
||||
u8 hactive_hi:4;
|
||||
u8 vactive_lo;
|
||||
u8 vblank_lo;
|
||||
u8 vblank_hi:4;
|
||||
u8 vactive_hi:4;
|
||||
u8 hsync_off_lo;
|
||||
u8 hsync_pulse_width;
|
||||
u8 vsync_pulse_width:4;
|
||||
u8 vsync_off:4;
|
||||
u8 rsvd0:6;
|
||||
u8 hsync_off_hi:2;
|
||||
u8 h_image;
|
||||
u8 v_image;
|
||||
u8 max_hv;
|
||||
u8 h_border;
|
||||
u8 v_border;
|
||||
u8 rsvd1:3;
|
||||
u8 digital:2;
|
||||
u8 vsync_positive:1;
|
||||
u8 hsync_positive:1;
|
||||
u8 rsvd2:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct lvds_pnp_id {
|
||||
u16 mfg_name;
|
||||
u16 product_code;
|
||||
u32 serial;
|
||||
u8 mfg_week;
|
||||
u8 mfg_year;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bdb_lvds_lfp_data_entry {
|
||||
struct lvds_fp_timing fp_timing;
|
||||
struct lvds_dvo_timing dvo_timing;
|
||||
struct lvds_pnp_id pnp_id;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bdb_lvds_lfp_data {
|
||||
struct bdb_lvds_lfp_data_entry data[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct aimdb_header {
|
||||
char signature[16];
|
||||
char oem_device[20];
|
||||
u16 aimdb_version;
|
||||
u16 aimdb_header_size;
|
||||
u16 aimdb_size;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct aimdb_block {
|
||||
u8 aimdb_id;
|
||||
u16 aimdb_size;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct vch_panel_data {
|
||||
u16 fp_timing_offset;
|
||||
u8 fp_timing_size;
|
||||
u16 dvo_timing_offset;
|
||||
u8 dvo_timing_size;
|
||||
u16 text_fitting_offset;
|
||||
u8 text_fitting_size;
|
||||
u16 graphics_fitting_offset;
|
||||
u8 graphics_fitting_size;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct vch_bdb_22 {
|
||||
struct aimdb_block aimdb_block;
|
||||
struct vch_panel_data panels[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bdb_sdvo_lvds_options {
|
||||
u8 panel_backlight;
|
||||
u8 h40_set_panel_type;
|
||||
u8 panel_type;
|
||||
u8 ssc_clk_freq;
|
||||
u16 als_low_trip;
|
||||
u16 als_high_trip;
|
||||
u8 sclalarcoeff_tab_row_num;
|
||||
u8 sclalarcoeff_tab_row_size;
|
||||
u8 coefficient[8];
|
||||
u8 panel_misc_bits_1;
|
||||
u8 panel_misc_bits_2;
|
||||
u8 panel_misc_bits_3;
|
||||
u8 panel_misc_bits_4;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
#define BDB_DRIVER_FEATURE_NO_LVDS 0
|
||||
#define BDB_DRIVER_FEATURE_INT_LVDS 1
|
||||
#define BDB_DRIVER_FEATURE_SDVO_LVDS 2
|
||||
#define BDB_DRIVER_FEATURE_EDP 3
|
||||
|
||||
struct bdb_driver_features {
|
||||
u8 boot_dev_algorithm:1;
|
||||
u8 block_display_switch:1;
|
||||
u8 allow_display_switch:1;
|
||||
u8 hotplug_dvo:1;
|
||||
u8 dual_view_zoom:1;
|
||||
u8 int15h_hook:1;
|
||||
u8 sprite_in_clone:1;
|
||||
u8 primary_lfp_id:1;
|
||||
|
||||
u16 boot_mode_x;
|
||||
u16 boot_mode_y;
|
||||
u8 boot_mode_bpp;
|
||||
u8 boot_mode_refresh;
|
||||
|
||||
u16 enable_lfp_primary:1;
|
||||
u16 selective_mode_pruning:1;
|
||||
u16 dual_frequency:1;
|
||||
u16 render_clock_freq:1; /* 0: high freq; 1: low freq */
|
||||
u16 nt_clone_support:1;
|
||||
u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */
|
||||
u16 sprite_display_assign:1; /* 0: secondary; 1: primary */
|
||||
u16 cui_aspect_scaling:1;
|
||||
u16 preserve_aspect_ratio:1;
|
||||
u16 sdvo_device_power_down:1;
|
||||
u16 crt_hotplug:1;
|
||||
u16 lvds_config:2;
|
||||
u16 tv_hotplug:1;
|
||||
u16 hdmi_config:2;
|
||||
|
||||
u8 static_display:1;
|
||||
u8 reserved2:7;
|
||||
u16 legacy_crt_max_x;
|
||||
u16 legacy_crt_max_y;
|
||||
u8 legacy_crt_max_refresh;
|
||||
|
||||
u8 hdmi_termination;
|
||||
u8 custom_vbt_version;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define EDP_18BPP 0
|
||||
#define EDP_24BPP 1
|
||||
#define EDP_30BPP 2
|
||||
#define EDP_RATE_1_62 0
|
||||
#define EDP_RATE_2_7 1
|
||||
#define EDP_LANE_1 0
|
||||
#define EDP_LANE_2 1
|
||||
#define EDP_LANE_4 3
|
||||
#define EDP_PREEMPHASIS_NONE 0
|
||||
#define EDP_PREEMPHASIS_3_5dB 1
|
||||
#define EDP_PREEMPHASIS_6dB 2
|
||||
#define EDP_PREEMPHASIS_9_5dB 3
|
||||
#define EDP_VSWING_0_4V 0
|
||||
#define EDP_VSWING_0_6V 1
|
||||
#define EDP_VSWING_0_8V 2
|
||||
#define EDP_VSWING_1_2V 3
|
||||
|
||||
struct edp_power_seq {
|
||||
u16 t1_t3;
|
||||
u16 t8;
|
||||
u16 t9;
|
||||
u16 t10;
|
||||
u16 t11_t12;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct edp_link_params {
|
||||
u8 rate:4;
|
||||
u8 lanes:4;
|
||||
u8 preemphasis:4;
|
||||
u8 vswing:4;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct bdb_edp {
|
||||
struct edp_power_seq power_seqs[16];
|
||||
u32 color_depth;
|
||||
struct edp_link_params link_params[16];
|
||||
u32 sdrrs_msa_timing_delay;
|
||||
|
||||
/* ith bit indicates enabled/disabled for (i+1)th panel */
|
||||
u16 edp_s3d_feature;
|
||||
u16 edp_t3_optimization;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
void intel_setup_bios(struct drm_device *dev);
|
||||
bool intel_parse_bios(struct drm_device *dev);
|
||||
|
||||
/*
|
||||
* Driver<->VBIOS interaction occurs through scratch bits in
|
||||
* GR18 & SWF*.
|
||||
*/
|
||||
|
||||
/* GR18 bits are set on display switch and hotkey events */
|
||||
#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */
|
||||
#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */
|
||||
#define GR18_HK_NONE (0x0<<3)
|
||||
#define GR18_HK_LFP_STRETCH (0x1<<3)
|
||||
#define GR18_HK_TOGGLE_DISP (0x2<<3)
|
||||
#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */
|
||||
#define GR18_HK_POPUP_DISABLED (0x6<<3)
|
||||
#define GR18_HK_POPUP_ENABLED (0x7<<3)
|
||||
#define GR18_HK_PFIT (0x8<<3)
|
||||
#define GR18_HK_APM_CHANGE (0xa<<3)
|
||||
#define GR18_HK_MULTIPLE (0xc<<3)
|
||||
#define GR18_USER_INT_EN (1<<2)
|
||||
#define GR18_A0000_FLUSH_EN (1<<1)
|
||||
#define GR18_SMM_EN (1<<0)
|
||||
|
||||
/* Set by driver, cleared by VBIOS */
|
||||
#define SWF00_YRES_SHIFT 16
|
||||
#define SWF00_XRES_SHIFT 0
|
||||
#define SWF00_RES_MASK 0xffff
|
||||
|
||||
/* Set by VBIOS at boot time and driver at runtime */
|
||||
#define SWF01_TV2_FORMAT_SHIFT 8
|
||||
#define SWF01_TV1_FORMAT_SHIFT 0
|
||||
#define SWF01_TV_FORMAT_MASK 0xffff
|
||||
|
||||
#define SWF10_VBIOS_BLC_I2C_EN (1<<29)
|
||||
#define SWF10_GTT_OVERRIDE_EN (1<<28)
|
||||
#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */
|
||||
#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24)
|
||||
#define SWF10_OLD_TOGGLE 0x0
|
||||
#define SWF10_TOGGLE_LIST_1 0x1
|
||||
#define SWF10_TOGGLE_LIST_2 0x2
|
||||
#define SWF10_TOGGLE_LIST_3 0x3
|
||||
#define SWF10_TOGGLE_LIST_4 0x4
|
||||
#define SWF10_PANNING_EN (1<<23)
|
||||
#define SWF10_DRIVER_LOADED (1<<22)
|
||||
#define SWF10_EXTENDED_DESKTOP (1<<21)
|
||||
#define SWF10_EXCLUSIVE_MODE (1<<20)
|
||||
#define SWF10_OVERLAY_EN (1<<19)
|
||||
#define SWF10_PLANEB_HOLDOFF (1<<18)
|
||||
#define SWF10_PLANEA_HOLDOFF (1<<17)
|
||||
#define SWF10_VGA_HOLDOFF (1<<16)
|
||||
#define SWF10_ACTIVE_DISP_MASK 0xffff
|
||||
#define SWF10_PIPEB_LFP2 (1<<15)
|
||||
#define SWF10_PIPEB_EFP2 (1<<14)
|
||||
#define SWF10_PIPEB_TV2 (1<<13)
|
||||
#define SWF10_PIPEB_CRT2 (1<<12)
|
||||
#define SWF10_PIPEB_LFP (1<<11)
|
||||
#define SWF10_PIPEB_EFP (1<<10)
|
||||
#define SWF10_PIPEB_TV (1<<9)
|
||||
#define SWF10_PIPEB_CRT (1<<8)
|
||||
#define SWF10_PIPEA_LFP2 (1<<7)
|
||||
#define SWF10_PIPEA_EFP2 (1<<6)
|
||||
#define SWF10_PIPEA_TV2 (1<<5)
|
||||
#define SWF10_PIPEA_CRT2 (1<<4)
|
||||
#define SWF10_PIPEA_LFP (1<<3)
|
||||
#define SWF10_PIPEA_EFP (1<<2)
|
||||
#define SWF10_PIPEA_TV (1<<1)
|
||||
#define SWF10_PIPEA_CRT (1<<0)
|
||||
|
||||
#define SWF11_MEMORY_SIZE_SHIFT 16
|
||||
#define SWF11_SV_TEST_EN (1<<15)
|
||||
#define SWF11_IS_AGP (1<<14)
|
||||
#define SWF11_DISPLAY_HOLDOFF (1<<13)
|
||||
#define SWF11_DPMS_REDUCED (1<<12)
|
||||
#define SWF11_IS_VBE_MODE (1<<11)
|
||||
#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */
|
||||
#define SWF11_DPMS_MASK 0x07
|
||||
#define SWF11_DPMS_OFF (1<<2)
|
||||
#define SWF11_DPMS_SUSPEND (1<<1)
|
||||
#define SWF11_DPMS_STANDBY (1<<0)
|
||||
#define SWF11_DPMS_ON 0
|
||||
|
||||
#define SWF14_GFX_PFIT_EN (1<<31)
|
||||
#define SWF14_TEXT_PFIT_EN (1<<30)
|
||||
#define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */
|
||||
#define SWF14_POPUP_EN (1<<28)
|
||||
#define SWF14_DISPLAY_HOLDOFF (1<<27)
|
||||
#define SWF14_DISP_DETECT_EN (1<<26)
|
||||
#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */
|
||||
#define SWF14_DRIVER_STATUS (1<<24)
|
||||
#define SWF14_OS_TYPE_WIN9X (1<<23)
|
||||
#define SWF14_OS_TYPE_WINNT (1<<22)
|
||||
/* 21:19 rsvd */
|
||||
#define SWF14_PM_TYPE_MASK 0x00070000
|
||||
#define SWF14_PM_ACPI_VIDEO (0x4 << 16)
|
||||
#define SWF14_PM_ACPI (0x3 << 16)
|
||||
#define SWF14_PM_APM_12 (0x2 << 16)
|
||||
#define SWF14_PM_APM_11 (0x1 << 16)
|
||||
#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */
|
||||
/* if GR18 indicates a display switch */
|
||||
#define SWF14_DS_PIPEB_LFP2_EN (1<<15)
|
||||
#define SWF14_DS_PIPEB_EFP2_EN (1<<14)
|
||||
#define SWF14_DS_PIPEB_TV2_EN (1<<13)
|
||||
#define SWF14_DS_PIPEB_CRT2_EN (1<<12)
|
||||
#define SWF14_DS_PIPEB_LFP_EN (1<<11)
|
||||
#define SWF14_DS_PIPEB_EFP_EN (1<<10)
|
||||
#define SWF14_DS_PIPEB_TV_EN (1<<9)
|
||||
#define SWF14_DS_PIPEB_CRT_EN (1<<8)
|
||||
#define SWF14_DS_PIPEA_LFP2_EN (1<<7)
|
||||
#define SWF14_DS_PIPEA_EFP2_EN (1<<6)
|
||||
#define SWF14_DS_PIPEA_TV2_EN (1<<5)
|
||||
#define SWF14_DS_PIPEA_CRT2_EN (1<<4)
|
||||
#define SWF14_DS_PIPEA_LFP_EN (1<<3)
|
||||
#define SWF14_DS_PIPEA_EFP_EN (1<<2)
|
||||
#define SWF14_DS_PIPEA_TV_EN (1<<1)
|
||||
#define SWF14_DS_PIPEA_CRT_EN (1<<0)
|
||||
/* if GR18 indicates a panel fitting request */
|
||||
#define SWF14_PFIT_EN (1<<0) /* 0 means disable */
|
||||
/* if GR18 indicates an APM change request */
|
||||
#define SWF14_APM_HIBERNATE 0x4
|
||||
#define SWF14_APM_SUSPEND 0x3
|
||||
#define SWF14_APM_STANDBY 0x1
|
||||
#define SWF14_APM_RESTORE 0x0
|
||||
|
||||
/* Add the device class for LFP, TV, HDMI */
|
||||
#define DEVICE_TYPE_INT_LFP 0x1022
|
||||
#define DEVICE_TYPE_INT_TV 0x1009
|
||||
#define DEVICE_TYPE_HDMI 0x60D2
|
||||
#define DEVICE_TYPE_DP 0x68C6
|
||||
#define DEVICE_TYPE_eDP 0x78C6
|
||||
|
||||
/* define the DVO port for HDMI output type */
|
||||
#define DVO_B 1
|
||||
#define DVO_C 2
|
||||
#define DVO_D 3
|
||||
|
||||
/* define the PORT for DP output type */
|
||||
#define PORT_IDPB 7
|
||||
#define PORT_IDPC 8
|
||||
#define PORT_IDPD 9
|
||||
|
||||
#endif /* _I830_BIOS_H_ */
|
||||
624
sys/dev/drm2/i915/intel_crt.c
Normal file
624
sys/dev/drm2/i915/intel_crt.c
Normal file
|
|
@ -0,0 +1,624 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_crtc_helper.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
/* Here's the desired hotplug mode */
|
||||
#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \
|
||||
ADPA_CRT_HOTPLUG_WARMUP_10MS | \
|
||||
ADPA_CRT_HOTPLUG_SAMPLE_4S | \
|
||||
ADPA_CRT_HOTPLUG_VOLTAGE_50 | \
|
||||
ADPA_CRT_HOTPLUG_VOLREF_325MV | \
|
||||
ADPA_CRT_HOTPLUG_ENABLE)
|
||||
|
||||
struct intel_crt {
|
||||
struct intel_encoder base;
|
||||
bool force_hotplug_required;
|
||||
};
|
||||
|
||||
static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(intel_attached_encoder(connector),
|
||||
struct intel_crt, base);
|
||||
}
|
||||
|
||||
static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 temp, reg;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
reg = PCH_ADPA;
|
||||
else
|
||||
reg = ADPA;
|
||||
|
||||
temp = I915_READ(reg);
|
||||
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
|
||||
temp &= ~ADPA_DAC_ENABLE;
|
||||
|
||||
switch (mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
temp |= ADPA_DAC_ENABLE;
|
||||
break;
|
||||
case DRM_MODE_DPMS_STANDBY:
|
||||
temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
I915_WRITE(reg, temp);
|
||||
}
|
||||
|
||||
static int intel_crt_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
|
||||
int max_clock = 0;
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
if (mode->clock < 25000)
|
||||
return MODE_CLOCK_LOW;
|
||||
|
||||
if (IS_GEN2(dev))
|
||||
max_clock = 350000;
|
||||
else
|
||||
max_clock = 400000;
|
||||
if (mode->clock > max_clock)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static bool intel_crt_mode_fixup(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void intel_crt_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int dpll_md_reg;
|
||||
u32 adpa, dpll_md;
|
||||
u32 adpa_reg;
|
||||
|
||||
dpll_md_reg = DPLL_MD(intel_crtc->pipe);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
adpa_reg = PCH_ADPA;
|
||||
else
|
||||
adpa_reg = ADPA;
|
||||
|
||||
/*
|
||||
* Disable separate mode multiplier used when cloning SDVO to CRT
|
||||
* XXX this needs to be adjusted when we really are cloning
|
||||
*/
|
||||
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
|
||||
dpll_md = I915_READ(dpll_md_reg);
|
||||
I915_WRITE(dpll_md_reg,
|
||||
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
|
||||
}
|
||||
|
||||
adpa = ADPA_HOTPLUG_BITS;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
adpa |= ADPA_VSYNC_ACTIVE_HIGH;
|
||||
|
||||
/* For CPT allow 3 pipe config, for others just use A or B */
|
||||
if (HAS_PCH_CPT(dev))
|
||||
adpa |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
|
||||
else if (intel_crtc->pipe == 0)
|
||||
adpa |= ADPA_PIPE_A_SELECT;
|
||||
else
|
||||
adpa |= ADPA_PIPE_B_SELECT;
|
||||
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(BCLRPAT(intel_crtc->pipe), 0);
|
||||
|
||||
I915_WRITE(adpa_reg, adpa);
|
||||
}
|
||||
|
||||
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_crt *crt = intel_attached_crt(connector);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 adpa;
|
||||
bool ret;
|
||||
|
||||
/* The first time through, trigger an explicit detection cycle */
|
||||
if (crt->force_hotplug_required) {
|
||||
bool turn_off_dac = HAS_PCH_SPLIT(dev);
|
||||
u32 save_adpa;
|
||||
|
||||
crt->force_hotplug_required = 0;
|
||||
|
||||
save_adpa = adpa = I915_READ(PCH_ADPA);
|
||||
DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
|
||||
|
||||
adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
|
||||
if (turn_off_dac)
|
||||
adpa &= ~ADPA_DAC_ENABLE;
|
||||
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
||||
1000, 1, "915crt"))
|
||||
DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER\n");
|
||||
|
||||
if (turn_off_dac) {
|
||||
I915_WRITE(PCH_ADPA, save_adpa);
|
||||
POSTING_READ(PCH_ADPA);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the status to see if both blue and green are on now */
|
||||
adpa = I915_READ(PCH_ADPA);
|
||||
if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
|
||||
ret = true;
|
||||
else
|
||||
ret = false;
|
||||
DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
|
||||
*
|
||||
* Not for i915G/i915GM
|
||||
*
|
||||
* \return true if CRT is connected.
|
||||
* \return false if CRT is disconnected.
|
||||
*/
|
||||
static bool intel_crt_detect_hotplug(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 hotplug_en, orig, stat;
|
||||
bool ret = false;
|
||||
int i, tries = 0;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
return intel_ironlake_crt_detect_hotplug(connector);
|
||||
|
||||
/*
|
||||
* On 4 series desktop, CRT detect sequence need to be done twice
|
||||
* to get a reliable result.
|
||||
*/
|
||||
|
||||
if (IS_G4X(dev) && !IS_GM45(dev))
|
||||
tries = 2;
|
||||
else
|
||||
tries = 1;
|
||||
hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN);
|
||||
hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
|
||||
|
||||
for (i = 0; i < tries ; i++) {
|
||||
/* turn on the FORCE_DETECT */
|
||||
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
|
||||
/* wait for FORCE_DETECT to go off */
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0,
|
||||
1000, 1, "915cr2"))
|
||||
DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
|
||||
}
|
||||
|
||||
stat = I915_READ(PORT_HOTPLUG_STAT);
|
||||
if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE)
|
||||
ret = true;
|
||||
|
||||
/* clear the interrupt we just generated, if any */
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
|
||||
|
||||
/* and put the bits back */
|
||||
I915_WRITE(PORT_HOTPLUG_EN, orig);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool intel_crt_detect_ddc(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_crt *crt = intel_attached_crt(connector);
|
||||
struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
|
||||
|
||||
/* CRT should always be at 0, but check anyway */
|
||||
if (crt->base.type != INTEL_OUTPUT_ANALOG)
|
||||
return false;
|
||||
|
||||
if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
|
||||
struct edid *edid;
|
||||
bool is_digital = false;
|
||||
|
||||
edid = drm_get_edid(connector,
|
||||
dev_priv->gmbus[dev_priv->crt_ddc_pin]);
|
||||
/*
|
||||
* This may be a DVI-I connector with a shared DDC
|
||||
* link between analog and digital outputs, so we
|
||||
* have to check the EDID input spec of the attached device.
|
||||
*
|
||||
* On the other hand, what should we do if it is a broken EDID?
|
||||
*/
|
||||
if (edid != NULL) {
|
||||
is_digital = edid->input & DRM_EDID_INPUT_DIGITAL;
|
||||
connector->display_info.raw_edid = NULL;
|
||||
free(edid, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
if (!is_digital) {
|
||||
DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
|
||||
return true;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_crt_load_detect(struct intel_crt *crt)
|
||||
{
|
||||
struct drm_device *dev = crt->base.base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
|
||||
uint32_t save_bclrpat;
|
||||
uint32_t save_vtotal;
|
||||
uint32_t vtotal, vactive;
|
||||
uint32_t vsample;
|
||||
uint32_t vblank, vblank_start, vblank_end;
|
||||
uint32_t dsl;
|
||||
uint32_t bclrpat_reg;
|
||||
uint32_t vtotal_reg;
|
||||
uint32_t vblank_reg;
|
||||
uint32_t vsync_reg;
|
||||
uint32_t pipeconf_reg;
|
||||
uint32_t pipe_dsl_reg;
|
||||
uint8_t st00;
|
||||
enum drm_connector_status status;
|
||||
|
||||
DRM_DEBUG_KMS("starting load-detect on CRT\n");
|
||||
|
||||
bclrpat_reg = BCLRPAT(pipe);
|
||||
vtotal_reg = VTOTAL(pipe);
|
||||
vblank_reg = VBLANK(pipe);
|
||||
vsync_reg = VSYNC(pipe);
|
||||
pipeconf_reg = PIPECONF(pipe);
|
||||
pipe_dsl_reg = PIPEDSL(pipe);
|
||||
|
||||
save_bclrpat = I915_READ(bclrpat_reg);
|
||||
save_vtotal = I915_READ(vtotal_reg);
|
||||
vblank = I915_READ(vblank_reg);
|
||||
|
||||
vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
|
||||
vactive = (save_vtotal & 0x7ff) + 1;
|
||||
|
||||
vblank_start = (vblank & 0xfff) + 1;
|
||||
vblank_end = ((vblank >> 16) & 0xfff) + 1;
|
||||
|
||||
/* Set the border color to purple. */
|
||||
I915_WRITE(bclrpat_reg, 0x500050);
|
||||
|
||||
if (!IS_GEN2(dev)) {
|
||||
uint32_t pipeconf = I915_READ(pipeconf_reg);
|
||||
I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
|
||||
POSTING_READ(pipeconf_reg);
|
||||
/* Wait for next Vblank to substitue
|
||||
* border color for Color info */
|
||||
intel_wait_for_vblank(dev, pipe);
|
||||
st00 = I915_READ8(VGA_MSR_WRITE);
|
||||
status = ((st00 & (1 << 4)) != 0) ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
|
||||
I915_WRITE(pipeconf_reg, pipeconf);
|
||||
} else {
|
||||
bool restore_vblank = false;
|
||||
int count, detect;
|
||||
|
||||
/*
|
||||
* If there isn't any border, add some.
|
||||
* Yes, this will flicker
|
||||
*/
|
||||
if (vblank_start <= vactive && vblank_end >= vtotal) {
|
||||
uint32_t vsync = I915_READ(vsync_reg);
|
||||
uint32_t vsync_start = (vsync & 0xffff) + 1;
|
||||
|
||||
vblank_start = vsync_start;
|
||||
I915_WRITE(vblank_reg,
|
||||
(vblank_start - 1) |
|
||||
((vblank_end - 1) << 16));
|
||||
restore_vblank = true;
|
||||
}
|
||||
/* sample in the vertical border, selecting the larger one */
|
||||
if (vblank_start - vactive >= vtotal - vblank_end)
|
||||
vsample = (vblank_start + vactive) >> 1;
|
||||
else
|
||||
vsample = (vtotal + vblank_end) >> 1;
|
||||
|
||||
/*
|
||||
* Wait for the border to be displayed
|
||||
*/
|
||||
while (I915_READ(pipe_dsl_reg) >= vactive)
|
||||
;
|
||||
while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample)
|
||||
;
|
||||
/*
|
||||
* Watch ST00 for an entire scanline
|
||||
*/
|
||||
detect = 0;
|
||||
count = 0;
|
||||
do {
|
||||
count++;
|
||||
/* Read the ST00 VGA status register */
|
||||
st00 = I915_READ8(VGA_MSR_WRITE);
|
||||
if (st00 & (1 << 4))
|
||||
detect++;
|
||||
} while ((I915_READ(pipe_dsl_reg) == dsl));
|
||||
|
||||
/* restore vblank if necessary */
|
||||
if (restore_vblank)
|
||||
I915_WRITE(vblank_reg, vblank);
|
||||
/*
|
||||
* If more than 3/4 of the scanline detected a monitor,
|
||||
* then it is assumed to be present. This works even on i830,
|
||||
* where there isn't any way to force the border color across
|
||||
* the screen
|
||||
*/
|
||||
status = detect * 4 > count * 3 ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
}
|
||||
|
||||
/* Restore previous settings */
|
||||
I915_WRITE(bclrpat_reg, save_bclrpat);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_crt_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_crt *crt = intel_attached_crt(connector);
|
||||
enum drm_connector_status status;
|
||||
struct intel_load_detect_pipe tmp;
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
if (intel_crt_detect_hotplug(connector)) {
|
||||
DRM_DEBUG_KMS("CRT detected via hotplug\n");
|
||||
return connector_status_connected;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("CRT not detected via hotplug\n");
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
if (intel_crt_detect_ddc(connector))
|
||||
return connector_status_connected;
|
||||
|
||||
if (!force)
|
||||
return connector->status;
|
||||
|
||||
/* for pre-945g platforms use load detect */
|
||||
if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
|
||||
&tmp)) {
|
||||
if (intel_crt_detect_ddc(connector))
|
||||
status = connector_status_connected;
|
||||
else
|
||||
status = intel_crt_load_detect(crt);
|
||||
intel_release_load_detect_pipe(&crt->base, connector,
|
||||
&tmp);
|
||||
} else
|
||||
status = connector_status_unknown;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void intel_crt_destroy(struct drm_connector *connector)
|
||||
{
|
||||
|
||||
#if 0
|
||||
drm_sysfs_connector_remove(connector);
|
||||
#endif
|
||||
drm_connector_cleanup(connector);
|
||||
free(connector, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
static int intel_crt_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ret = intel_ddc_get_modes(connector,
|
||||
dev_priv->gmbus[dev_priv->crt_ddc_pin]);
|
||||
if (ret || !IS_G4X(dev))
|
||||
return ret;
|
||||
|
||||
/* Try to probe digital port for output in DVI-I -> VGA mode. */
|
||||
return (intel_ddc_get_modes(connector,
|
||||
dev_priv->gmbus[GMBUS_PORT_DPB]));
|
||||
}
|
||||
|
||||
static int intel_crt_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_crt_reset(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_crt *crt = intel_attached_crt(connector);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
crt->force_hotplug_required = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines for controlling stuff on the analog port
|
||||
*/
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
|
||||
.dpms = intel_crt_dpms,
|
||||
.mode_fixup = intel_crt_mode_fixup,
|
||||
.prepare = intel_encoder_prepare,
|
||||
.commit = intel_encoder_commit,
|
||||
.mode_set = intel_crt_mode_set,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_crt_connector_funcs = {
|
||||
.reset = intel_crt_reset,
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.detect = intel_crt_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = intel_crt_destroy,
|
||||
.set_property = intel_crt_set_property,
|
||||
};
|
||||
|
||||
static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
|
||||
.mode_valid = intel_crt_mode_valid,
|
||||
.get_modes = intel_crt_get_modes,
|
||||
.best_encoder = intel_best_encoder,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs intel_crt_enc_funcs = {
|
||||
.destroy = intel_encoder_destroy,
|
||||
};
|
||||
|
||||
static int intel_no_crt_dmi_callback(const struct dmi_system_id *id)
|
||||
{
|
||||
DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id intel_no_crt[] = {
|
||||
{
|
||||
.callback = intel_no_crt_dmi_callback,
|
||||
.ident = "ACER ZGB",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
void intel_crt_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct intel_crt *crt;
|
||||
struct intel_connector *intel_connector;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/* Skip machines without VGA that falsely report hotplug events */
|
||||
if (dmi_check_system(intel_no_crt))
|
||||
return;
|
||||
|
||||
crt = malloc(sizeof(struct intel_crt), DRM_MEM_KMS, M_WAITOK | M_ZERO);
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
connector = &intel_connector->base;
|
||||
drm_connector_init(dev, &intel_connector->base,
|
||||
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
|
||||
|
||||
drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
|
||||
DRM_MODE_ENCODER_DAC);
|
||||
|
||||
intel_connector_attach_encoder(intel_connector, &crt->base);
|
||||
|
||||
crt->base.type = INTEL_OUTPUT_ANALOG;
|
||||
crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
|
||||
1 << INTEL_ANALOG_CLONE_BIT |
|
||||
1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
crt->base.crtc_mask = (1 << 0) | (1 << 1);
|
||||
if (IS_GEN2(dev))
|
||||
connector->interlace_allowed = 0;
|
||||
else
|
||||
connector->interlace_allowed = 1;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
|
||||
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
|
||||
|
||||
#if 0
|
||||
drm_sysfs_connector_add(connector);
|
||||
#endif
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev))
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
else
|
||||
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
|
||||
/*
|
||||
* Configure the automatic hotplug detection stuff
|
||||
*/
|
||||
crt->force_hotplug_required = 0;
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
u32 adpa;
|
||||
|
||||
adpa = I915_READ(PCH_ADPA);
|
||||
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
|
||||
adpa |= ADPA_HOTPLUG_BITS;
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
POSTING_READ(PCH_ADPA);
|
||||
|
||||
DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
|
||||
crt->force_hotplug_required = 1;
|
||||
}
|
||||
|
||||
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
|
||||
}
|
||||
9532
sys/dev/drm2/i915/intel_display.c
Normal file
9532
sys/dev/drm2/i915/intel_display.c
Normal file
File diff suppressed because it is too large
Load diff
2562
sys/dev/drm2/i915/intel_dp.c
Normal file
2562
sys/dev/drm2/i915/intel_dp.c
Normal file
File diff suppressed because it is too large
Load diff
428
sys/dev/drm2/i915/intel_drv.h
Normal file
428
sys/dev/drm2/i915/intel_drv.h
Normal file
|
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
|
||||
* Copyright (c) 2007-2008 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef DRM_INTEL_DRV_H
|
||||
#define DRM_INTEL_DRV_H
|
||||
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_crtc_helper.h>
|
||||
#include <dev/drm2/drm_fb_helper.h>
|
||||
|
||||
#define _intel_wait_for(DEV, COND, MS, W, WMSG) \
|
||||
({ \
|
||||
int end, ret; \
|
||||
\
|
||||
end = ticks + (MS) * hz / 1000; \
|
||||
ret = 0; \
|
||||
\
|
||||
while (!(COND)) { \
|
||||
if (time_after(ticks, end)) { \
|
||||
ret = -ETIMEDOUT; \
|
||||
break; \
|
||||
} \
|
||||
if (W) \
|
||||
pause((WMSG), 1); \
|
||||
else \
|
||||
DELAY(1000); \
|
||||
} \
|
||||
\
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define KHz(x) (1000*x)
|
||||
#define MHz(x) KHz(1000*x)
|
||||
|
||||
/* store information about an Ixxx DVO */
|
||||
/* The i830->i865 use multiple DVOs with multiple i2cs */
|
||||
/* the i915, i945 have a single sDVO i2c bus - which is different */
|
||||
#define MAX_OUTPUTS 6
|
||||
/* maximum connectors per crtcs in the mode set */
|
||||
#define INTELFB_CONN_LIMIT 4
|
||||
|
||||
#define INTEL_I2C_BUS_DVO 1
|
||||
#define INTEL_I2C_BUS_SDVO 2
|
||||
|
||||
/* these are outputs from the chip - integrated only
|
||||
external chips are via DVO or SDVO output */
|
||||
#define INTEL_OUTPUT_UNUSED 0
|
||||
#define INTEL_OUTPUT_ANALOG 1
|
||||
#define INTEL_OUTPUT_DVO 2
|
||||
#define INTEL_OUTPUT_SDVO 3
|
||||
#define INTEL_OUTPUT_LVDS 4
|
||||
#define INTEL_OUTPUT_TVOUT 5
|
||||
#define INTEL_OUTPUT_HDMI 6
|
||||
#define INTEL_OUTPUT_DISPLAYPORT 7
|
||||
#define INTEL_OUTPUT_EDP 8
|
||||
|
||||
/* Intel Pipe Clone Bit */
|
||||
#define INTEL_HDMIB_CLONE_BIT 1
|
||||
#define INTEL_HDMIC_CLONE_BIT 2
|
||||
#define INTEL_HDMID_CLONE_BIT 3
|
||||
#define INTEL_HDMIE_CLONE_BIT 4
|
||||
#define INTEL_HDMIF_CLONE_BIT 5
|
||||
#define INTEL_SDVO_NON_TV_CLONE_BIT 6
|
||||
#define INTEL_SDVO_TV_CLONE_BIT 7
|
||||
#define INTEL_SDVO_LVDS_CLONE_BIT 8
|
||||
#define INTEL_ANALOG_CLONE_BIT 9
|
||||
#define INTEL_TV_CLONE_BIT 10
|
||||
#define INTEL_DP_B_CLONE_BIT 11
|
||||
#define INTEL_DP_C_CLONE_BIT 12
|
||||
#define INTEL_DP_D_CLONE_BIT 13
|
||||
#define INTEL_LVDS_CLONE_BIT 14
|
||||
#define INTEL_DVO_TMDS_CLONE_BIT 15
|
||||
#define INTEL_DVO_LVDS_CLONE_BIT 16
|
||||
#define INTEL_EDP_CLONE_BIT 17
|
||||
|
||||
#define INTEL_DVO_CHIP_NONE 0
|
||||
#define INTEL_DVO_CHIP_LVDS 1
|
||||
#define INTEL_DVO_CHIP_TMDS 2
|
||||
#define INTEL_DVO_CHIP_TVOUT 4
|
||||
|
||||
/* drm_display_mode->private_flags */
|
||||
#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
|
||||
#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
|
||||
#define INTEL_MODE_DP_FORCE_6BPC (0x10)
|
||||
/* This flag must be set by the encoder's mode_fixup if it changes the crtc
|
||||
* timings in the mode to prevent the crtc fixup from overwriting them.
|
||||
* Currently only lvds needs that. */
|
||||
#define INTEL_MODE_CRTC_TIMINGS_SET (0x20)
|
||||
|
||||
static inline void
|
||||
intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
|
||||
int multiplier)
|
||||
{
|
||||
mode->clock *= multiplier;
|
||||
mode->private_flags |= multiplier;
|
||||
}
|
||||
|
||||
static inline int
|
||||
intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
|
||||
{
|
||||
return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
|
||||
}
|
||||
|
||||
struct intel_framebuffer {
|
||||
struct drm_framebuffer base;
|
||||
struct drm_i915_gem_object *obj;
|
||||
};
|
||||
|
||||
struct intel_fbdev {
|
||||
struct drm_fb_helper helper;
|
||||
struct intel_framebuffer ifb;
|
||||
struct list_head fbdev_list;
|
||||
struct drm_display_mode *our_mode;
|
||||
};
|
||||
|
||||
struct intel_encoder {
|
||||
struct drm_encoder base;
|
||||
int type;
|
||||
bool needs_tv_clock;
|
||||
void (*hot_plug)(struct intel_encoder *);
|
||||
int crtc_mask;
|
||||
int clone_mask;
|
||||
};
|
||||
|
||||
struct intel_connector {
|
||||
struct drm_connector base;
|
||||
struct intel_encoder *encoder;
|
||||
};
|
||||
|
||||
struct intel_crtc {
|
||||
struct drm_crtc base;
|
||||
enum pipe pipe;
|
||||
enum plane plane;
|
||||
u8 lut_r[256], lut_g[256], lut_b[256];
|
||||
int dpms_mode;
|
||||
bool active; /* is the crtc on? independent of the dpms mode */
|
||||
bool busy; /* is scanout buffer being updated frequently? */
|
||||
struct callout idle_callout;
|
||||
bool lowfreq_avail;
|
||||
struct intel_overlay *overlay;
|
||||
struct intel_unpin_work *unpin_work;
|
||||
int fdi_lanes;
|
||||
|
||||
struct drm_i915_gem_object *cursor_bo;
|
||||
uint32_t cursor_addr;
|
||||
int16_t cursor_x, cursor_y;
|
||||
int16_t cursor_width, cursor_height;
|
||||
bool cursor_visible;
|
||||
unsigned int bpp;
|
||||
|
||||
bool no_pll; /* tertiary pipe for IVB */
|
||||
bool use_pll_a;
|
||||
};
|
||||
|
||||
struct intel_plane {
|
||||
struct drm_plane base;
|
||||
enum pipe pipe;
|
||||
struct drm_i915_gem_object *obj;
|
||||
bool primary_disabled;
|
||||
int max_downscale;
|
||||
u32 lut_r[1024], lut_g[1024], lut_b[1024];
|
||||
void (*update_plane)(struct drm_plane *plane,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_i915_gem_object *obj,
|
||||
int crtc_x, int crtc_y,
|
||||
unsigned int crtc_w, unsigned int crtc_h,
|
||||
uint32_t x, uint32_t y,
|
||||
uint32_t src_w, uint32_t src_h);
|
||||
void (*disable_plane)(struct drm_plane *plane);
|
||||
int (*update_colorkey)(struct drm_plane *plane,
|
||||
struct drm_intel_sprite_colorkey *key);
|
||||
void (*get_colorkey)(struct drm_plane *plane,
|
||||
struct drm_intel_sprite_colorkey *key);
|
||||
};
|
||||
|
||||
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
|
||||
#define to_intel_connector(x) container_of(x, struct intel_connector, base)
|
||||
#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
|
||||
#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
|
||||
#define to_intel_plane(x) container_of(x, struct intel_plane, base)
|
||||
|
||||
#define DIP_HEADER_SIZE 5
|
||||
|
||||
#define DIP_TYPE_AVI 0x82
|
||||
#define DIP_VERSION_AVI 0x2
|
||||
#define DIP_LEN_AVI 13
|
||||
|
||||
#define DIP_TYPE_SPD 0x83
|
||||
#define DIP_VERSION_SPD 0x1
|
||||
#define DIP_LEN_SPD 25
|
||||
#define DIP_SPD_UNKNOWN 0
|
||||
#define DIP_SPD_DSTB 0x1
|
||||
#define DIP_SPD_DVDP 0x2
|
||||
#define DIP_SPD_DVHS 0x3
|
||||
#define DIP_SPD_HDDVR 0x4
|
||||
#define DIP_SPD_DVC 0x5
|
||||
#define DIP_SPD_DSC 0x6
|
||||
#define DIP_SPD_VCD 0x7
|
||||
#define DIP_SPD_GAME 0x8
|
||||
#define DIP_SPD_PC 0x9
|
||||
#define DIP_SPD_BD 0xa
|
||||
#define DIP_SPD_SCD 0xb
|
||||
|
||||
struct dip_infoframe {
|
||||
uint8_t type; /* HB0 */
|
||||
uint8_t ver; /* HB1 */
|
||||
uint8_t len; /* HB2 - body len, not including checksum */
|
||||
uint8_t ecc; /* Header ECC */
|
||||
uint8_t checksum; /* PB0 */
|
||||
union {
|
||||
struct {
|
||||
/* PB1 - Y 6:5, A 4:4, B 3:2, S 1:0 */
|
||||
uint8_t Y_A_B_S;
|
||||
/* PB2 - C 7:6, M 5:4, R 3:0 */
|
||||
uint8_t C_M_R;
|
||||
/* PB3 - ITC 7:7, EC 6:4, Q 3:2, SC 1:0 */
|
||||
uint8_t ITC_EC_Q_SC;
|
||||
/* PB4 - VIC 6:0 */
|
||||
uint8_t VIC;
|
||||
/* PB5 - PR 3:0 */
|
||||
uint8_t PR;
|
||||
/* PB6 to PB13 */
|
||||
uint16_t top_bar_end;
|
||||
uint16_t bottom_bar_start;
|
||||
uint16_t left_bar_end;
|
||||
uint16_t right_bar_start;
|
||||
} avi;
|
||||
struct {
|
||||
uint8_t vn[8];
|
||||
uint8_t pd[16];
|
||||
uint8_t sdi;
|
||||
} spd;
|
||||
uint8_t payload[27];
|
||||
} __attribute__ ((packed)) body;
|
||||
} __attribute__((packed));
|
||||
|
||||
static inline struct drm_crtc *
|
||||
intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
return dev_priv->pipe_to_crtc_mapping[pipe];
|
||||
}
|
||||
|
||||
static inline struct drm_crtc *
|
||||
intel_get_crtc_for_plane(struct drm_device *dev, int plane)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
return dev_priv->plane_to_crtc_mapping[plane];
|
||||
}
|
||||
|
||||
struct intel_unpin_work {
|
||||
struct task task;
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_gem_object *old_fb_obj;
|
||||
struct drm_i915_gem_object *pending_flip_obj;
|
||||
struct drm_pending_vblank_event *event;
|
||||
int pending;
|
||||
bool enable_stall_check;
|
||||
};
|
||||
|
||||
struct intel_fbc_work {
|
||||
struct timeout_task task;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_framebuffer *fb;
|
||||
int interval;
|
||||
};
|
||||
|
||||
int intel_ddc_get_modes(struct drm_connector *c, device_t adapter);
|
||||
extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
|
||||
|
||||
extern void intel_attach_force_audio_property(struct drm_connector *connector);
|
||||
extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
|
||||
|
||||
extern void intel_crt_init(struct drm_device *dev);
|
||||
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
|
||||
void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
|
||||
extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
|
||||
extern void intel_dvo_init(struct drm_device *dev);
|
||||
extern void intel_tv_init(struct drm_device *dev);
|
||||
extern void intel_mark_busy(struct drm_device *dev,
|
||||
struct drm_i915_gem_object *obj);
|
||||
extern bool intel_lvds_init(struct drm_device *dev);
|
||||
extern void intel_dp_init(struct drm_device *dev, int dp_reg);
|
||||
void
|
||||
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern bool intel_dpd_is_edp(struct drm_device *dev);
|
||||
extern void intel_edp_link_config(struct intel_encoder *, int *, int *);
|
||||
extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
|
||||
extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
|
||||
|
||||
/* intel_panel.c */
|
||||
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void intel_pch_panel_fitting(struct drm_device *dev,
|
||||
int fitting_mode,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
|
||||
extern u32 intel_panel_get_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
|
||||
extern int intel_panel_setup_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_enable_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_disable_backlight(struct drm_device *dev);
|
||||
extern void intel_panel_destroy_backlight(struct drm_device *dev);
|
||||
extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);
|
||||
|
||||
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
|
||||
extern void intel_encoder_prepare(struct drm_encoder *encoder);
|
||||
extern void intel_encoder_commit(struct drm_encoder *encoder);
|
||||
extern void intel_encoder_destroy(struct drm_encoder *encoder);
|
||||
|
||||
static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
|
||||
{
|
||||
return to_intel_connector(connector)->encoder;
|
||||
}
|
||||
|
||||
extern void intel_connector_attach_encoder(struct intel_connector *connector,
|
||||
struct intel_encoder *encoder);
|
||||
extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
|
||||
|
||||
extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
|
||||
struct drm_crtc *crtc);
|
||||
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
|
||||
extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
|
||||
|
||||
struct intel_load_detect_pipe {
|
||||
struct drm_framebuffer *release_fb;
|
||||
bool load_detect_temp;
|
||||
int dpms_mode;
|
||||
};
|
||||
extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
|
||||
struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
struct intel_load_detect_pipe *old);
|
||||
extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
|
||||
struct drm_connector *connector,
|
||||
struct intel_load_detect_pipe *old);
|
||||
|
||||
extern void intelfb_restore(void);
|
||||
extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
|
||||
u16 blue, int regno);
|
||||
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
|
||||
u16 *blue, int regno);
|
||||
extern void intel_enable_clock_gating(struct drm_device *dev);
|
||||
extern void ironlake_enable_drps(struct drm_device *dev);
|
||||
extern void ironlake_disable_drps(struct drm_device *dev);
|
||||
extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
|
||||
extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
|
||||
extern void gen6_disable_rps(struct drm_device *dev);
|
||||
extern void intel_init_emon(struct drm_device *dev);
|
||||
|
||||
extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
|
||||
struct drm_i915_gem_object *obj,
|
||||
struct intel_ring_buffer *pipelined);
|
||||
extern void intel_unpin_fb_obj(struct drm_i915_gem_object *obj);
|
||||
|
||||
extern int intel_framebuffer_init(struct drm_device *dev,
|
||||
struct intel_framebuffer *ifb,
|
||||
struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_i915_gem_object *obj);
|
||||
extern int intel_fbdev_init(struct drm_device *dev);
|
||||
extern void intel_fbdev_fini(struct drm_device *dev);
|
||||
|
||||
extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
|
||||
extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
|
||||
extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
|
||||
|
||||
extern void intel_setup_overlay(struct drm_device *dev);
|
||||
extern void intel_cleanup_overlay(struct drm_device *dev);
|
||||
extern int intel_overlay_switch_off(struct intel_overlay *overlay);
|
||||
extern int intel_overlay_put_image(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
extern int intel_overlay_attrs(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
extern void intel_fb_output_poll_changed(struct drm_device *dev);
|
||||
extern void intel_fb_restore_mode(struct drm_device *dev);
|
||||
|
||||
extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
|
||||
bool state);
|
||||
#define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
|
||||
#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
|
||||
|
||||
extern void intel_init_clock_gating(struct drm_device *dev);
|
||||
extern void intel_write_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode);
|
||||
extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
|
||||
|
||||
/* For use by IVB LP watermark workaround in intel_sprite.c */
|
||||
extern void sandybridge_update_wm(struct drm_device *dev);
|
||||
extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
|
||||
uint32_t sprite_width,
|
||||
int pixel_size);
|
||||
extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
#endif
|
||||
270
sys/dev/drm2/i915/intel_fb.c
Normal file
270
sys/dev/drm2/i915/intel_fb.c
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright © 2007 David Airlie
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* David Airlie
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_fb_helper.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
static int intelfb_create(struct intel_fbdev *ifbdev,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct drm_device *dev = ifbdev->helper.dev;
|
||||
#if 0
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct fb_info *info;
|
||||
#endif
|
||||
struct drm_framebuffer *fb;
|
||||
struct drm_mode_fb_cmd2 mode_cmd;
|
||||
struct drm_i915_gem_object *obj;
|
||||
int size, ret;
|
||||
|
||||
/* we don't do packed 24bpp */
|
||||
if (sizes->surface_bpp == 24)
|
||||
sizes->surface_bpp = 32;
|
||||
|
||||
mode_cmd.width = sizes->surface_width;
|
||||
mode_cmd.height = sizes->surface_height;
|
||||
|
||||
mode_cmd.pitches[0] = roundup2(mode_cmd.width * ((sizes->surface_bpp + 7) /
|
||||
8), 64);
|
||||
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
|
||||
sizes->surface_depth);
|
||||
|
||||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
size = roundup2(size, PAGE_SIZE);
|
||||
obj = i915_gem_alloc_object(dev, size);
|
||||
if (!obj) {
|
||||
DRM_ERROR("failed to allocate framebuffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DRM_LOCK(dev);
|
||||
|
||||
/* Flush everything out, we'll be doing GTT only from now on */
|
||||
ret = intel_pin_and_fence_fb_obj(dev, obj, false);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin fb: %d\n", ret);
|
||||
goto out_unref;
|
||||
}
|
||||
|
||||
#if 0
|
||||
info = framebuffer_alloc(0, device);
|
||||
if (!info) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unpin;
|
||||
}
|
||||
|
||||
info->par = ifbdev;
|
||||
#endif
|
||||
|
||||
ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
|
||||
if (ret)
|
||||
goto out_unpin;
|
||||
|
||||
fb = &ifbdev->ifb.base;
|
||||
|
||||
ifbdev->helper.fb = fb;
|
||||
#if 0
|
||||
ifbdev->helper.fbdev = info;
|
||||
|
||||
strcpy(info->fix.id, "inteldrmfb");
|
||||
|
||||
info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
|
||||
info->fbops = &intelfb_ops;
|
||||
|
||||
ret = fb_alloc_cmap(&info->cmap, 256, 0);
|
||||
if (ret) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unpin;
|
||||
}
|
||||
/* setup aperture base/size for vesafb takeover */
|
||||
info->apertures = alloc_apertures(1);
|
||||
if (!info->apertures) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unpin;
|
||||
}
|
||||
info->apertures->ranges[0].base = dev->mode_config.fb_base;
|
||||
info->apertures->ranges[0].size =
|
||||
dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
|
||||
|
||||
info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
|
||||
info->fix.smem_len = size;
|
||||
|
||||
info->screen_base = ioremap_wc(dev->agp->base + obj->gtt_offset, size);
|
||||
if (!info->screen_base) {
|
||||
ret = -ENOSPC;
|
||||
goto out_unpin;
|
||||
}
|
||||
info->screen_size = size;
|
||||
|
||||
// memset(info->screen_base, 0, size);
|
||||
|
||||
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
|
||||
drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
|
||||
|
||||
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
|
||||
#endif
|
||||
|
||||
DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
|
||||
fb->width, fb->height,
|
||||
obj->gtt_offset, obj);
|
||||
|
||||
DRM_UNLOCK(dev);
|
||||
#if 1
|
||||
KIB_NOTYET();
|
||||
#else
|
||||
vga_switcheroo_client_fb_set(dev->pdev, info);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
out_unpin:
|
||||
i915_gem_object_unpin(obj);
|
||||
out_unref:
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
DRM_UNLOCK(dev);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
|
||||
struct drm_fb_helper_surface_size *sizes)
|
||||
{
|
||||
struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
|
||||
int new_fb = 0;
|
||||
int ret;
|
||||
|
||||
if (!helper->fb) {
|
||||
ret = intelfb_create(ifbdev, sizes);
|
||||
if (ret)
|
||||
return ret;
|
||||
new_fb = 1;
|
||||
}
|
||||
return new_fb;
|
||||
}
|
||||
|
||||
static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
|
||||
.gamma_set = intel_crtc_fb_gamma_set,
|
||||
.gamma_get = intel_crtc_fb_gamma_get,
|
||||
.fb_probe = intel_fb_find_or_create_single,
|
||||
};
|
||||
|
||||
static void intel_fbdev_destroy(struct drm_device *dev,
|
||||
struct intel_fbdev *ifbdev)
|
||||
{
|
||||
#if 0
|
||||
struct fb_info *info;
|
||||
#endif
|
||||
struct intel_framebuffer *ifb = &ifbdev->ifb;
|
||||
|
||||
#if 0
|
||||
if (ifbdev->helper.fbdev) {
|
||||
info = ifbdev->helper.fbdev;
|
||||
unregister_framebuffer(info);
|
||||
iounmap(info->screen_base);
|
||||
if (info->cmap.len)
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
framebuffer_release(info);
|
||||
}
|
||||
#endif
|
||||
|
||||
drm_fb_helper_fini(&ifbdev->helper);
|
||||
|
||||
drm_framebuffer_cleanup(&ifb->base);
|
||||
if (ifb->obj) {
|
||||
drm_gem_object_unreference_unlocked(&ifb->obj->base);
|
||||
ifb->obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int intel_fbdev_init(struct drm_device *dev)
|
||||
{
|
||||
struct intel_fbdev *ifbdev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ifbdev = malloc(sizeof(struct intel_fbdev), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
dev_priv->fbdev = ifbdev;
|
||||
ifbdev->helper.funcs = &intel_fb_helper_funcs;
|
||||
|
||||
ret = drm_fb_helper_init(dev, &ifbdev->helper,
|
||||
dev_priv->num_pipe,
|
||||
INTELFB_CONN_LIMIT);
|
||||
if (ret) {
|
||||
free(ifbdev, DRM_MEM_KMS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
|
||||
drm_fb_helper_initial_config(&ifbdev->helper, 32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_fbdev_fini(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
if (!dev_priv->fbdev)
|
||||
return;
|
||||
|
||||
intel_fbdev_destroy(dev, dev_priv->fbdev);
|
||||
free(dev_priv->fbdev, DRM_MEM_KMS);
|
||||
dev_priv->fbdev = NULL;
|
||||
}
|
||||
|
||||
void intel_fb_output_poll_changed(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
|
||||
}
|
||||
|
||||
void intel_fb_restore_mode(struct drm_device *dev)
|
||||
{
|
||||
int ret;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_mode_config *config = &dev->mode_config;
|
||||
struct drm_plane *plane;
|
||||
|
||||
sx_xlock(&dev->mode_config.mutex);
|
||||
|
||||
ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
|
||||
if (ret)
|
||||
DRM_DEBUG("failed to restore crtc mode\n");
|
||||
|
||||
/* Be sure to shut off any planes that may be active */
|
||||
list_for_each_entry(plane, &config->plane_list, head)
|
||||
plane->funcs->disable_plane(plane);
|
||||
|
||||
sx_xunlock(&dev->mode_config.mutex);
|
||||
}
|
||||
576
sys/dev/drm2/i915/intel_hdmi.c
Normal file
576
sys/dev/drm2/i915/intel_hdmi.c
Normal file
|
|
@ -0,0 +1,576 @@
|
|||
/*
|
||||
* Copyright 2006 Dave Airlie <airlied@linux.ie>
|
||||
* Copyright © 2006-2009 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/drm_crtc.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
struct intel_hdmi {
|
||||
struct intel_encoder base;
|
||||
u32 sdvox_reg;
|
||||
int ddc_bus;
|
||||
uint32_t color_range;
|
||||
bool has_hdmi_sink;
|
||||
bool has_audio;
|
||||
enum hdmi_force_audio force_audio;
|
||||
void (*write_infoframe)(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame);
|
||||
};
|
||||
|
||||
static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct intel_hdmi, base.base);
|
||||
}
|
||||
|
||||
static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(intel_attached_encoder(connector),
|
||||
struct intel_hdmi, base);
|
||||
}
|
||||
|
||||
void intel_dip_infoframe_csum(struct dip_infoframe *frame)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)frame;
|
||||
uint8_t sum = 0;
|
||||
unsigned i;
|
||||
|
||||
frame->checksum = 0;
|
||||
frame->ecc = 0;
|
||||
|
||||
for (i = 0; i < frame->len + DIP_HEADER_SIZE; i++)
|
||||
sum += data[i];
|
||||
|
||||
frame->checksum = 0x100 - sum;
|
||||
}
|
||||
|
||||
static u32 intel_infoframe_index(struct dip_infoframe *frame)
|
||||
{
|
||||
u32 flags = 0;
|
||||
|
||||
switch (frame->type) {
|
||||
case DIP_TYPE_AVI:
|
||||
flags |= VIDEO_DIP_SELECT_AVI;
|
||||
break;
|
||||
case DIP_TYPE_SPD:
|
||||
flags |= VIDEO_DIP_SELECT_SPD;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG("unknown info frame type %d\n", frame->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static u32 intel_infoframe_flags(struct dip_infoframe *frame)
|
||||
{
|
||||
u32 flags = 0;
|
||||
|
||||
switch (frame->type) {
|
||||
case DIP_TYPE_AVI:
|
||||
flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC;
|
||||
break;
|
||||
case DIP_TYPE_SPD:
|
||||
flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_VSYNC;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG("unknown info frame type %d\n", frame->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void i9xx_write_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
{
|
||||
uint32_t *data = (uint32_t *)frame;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 port, flags, val = I915_READ(VIDEO_DIP_CTL);
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
|
||||
|
||||
/* XXX first guess at handling video port, is this corrent? */
|
||||
if (intel_hdmi->sdvox_reg == SDVOB)
|
||||
port = VIDEO_DIP_PORT_B;
|
||||
else if (intel_hdmi->sdvox_reg == SDVOC)
|
||||
port = VIDEO_DIP_PORT_C;
|
||||
else
|
||||
return;
|
||||
|
||||
flags = intel_infoframe_index(frame);
|
||||
|
||||
val &= ~VIDEO_DIP_SELECT_MASK;
|
||||
|
||||
I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(VIDEO_DIP_DATA, *data);
|
||||
data++;
|
||||
}
|
||||
|
||||
flags |= intel_infoframe_flags(frame);
|
||||
|
||||
I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
|
||||
}
|
||||
|
||||
static void ironlake_write_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
{
|
||||
uint32_t *data = (uint32_t *)frame;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
|
||||
unsigned i, len = DIP_HEADER_SIZE + frame->len;
|
||||
u32 flags, val = I915_READ(reg);
|
||||
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
flags = intel_infoframe_index(frame);
|
||||
|
||||
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
|
||||
|
||||
I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
|
||||
data++;
|
||||
}
|
||||
|
||||
flags |= intel_infoframe_flags(frame);
|
||||
|
||||
I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
|
||||
}
|
||||
|
||||
static void intel_set_infoframe(struct drm_encoder *encoder,
|
||||
struct dip_infoframe *frame)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
|
||||
if (!intel_hdmi->has_hdmi_sink)
|
||||
return;
|
||||
|
||||
intel_dip_infoframe_csum(frame);
|
||||
intel_hdmi->write_infoframe(encoder, frame);
|
||||
}
|
||||
|
||||
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
|
||||
{
|
||||
struct dip_infoframe avi_if = {
|
||||
.type = DIP_TYPE_AVI,
|
||||
.ver = DIP_VERSION_AVI,
|
||||
.len = DIP_LEN_AVI,
|
||||
};
|
||||
|
||||
intel_set_infoframe(encoder, &avi_if);
|
||||
}
|
||||
|
||||
static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
|
||||
{
|
||||
struct dip_infoframe spd_if;
|
||||
|
||||
memset(&spd_if, 0, sizeof(spd_if));
|
||||
spd_if.type = DIP_TYPE_SPD;
|
||||
spd_if.ver = DIP_VERSION_SPD;
|
||||
spd_if.len = DIP_LEN_SPD;
|
||||
strcpy(spd_if.body.spd.vn, "Intel");
|
||||
strcpy(spd_if.body.spd.pd, "Integrated gfx");
|
||||
spd_if.body.spd.sdi = DIP_SPD_PC;
|
||||
|
||||
intel_set_infoframe(encoder, &spd_if);
|
||||
}
|
||||
|
||||
static void intel_hdmi_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 sdvox;
|
||||
|
||||
sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
sdvox |= intel_hdmi->color_range;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||
sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
|
||||
|
||||
if (intel_crtc->bpp > 24)
|
||||
sdvox |= COLOR_FORMAT_12bpc;
|
||||
else
|
||||
sdvox |= COLOR_FORMAT_8bpc;
|
||||
|
||||
/* Required on CPT */
|
||||
if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
|
||||
sdvox |= HDMI_MODE_SELECT;
|
||||
|
||||
if (intel_hdmi->has_audio) {
|
||||
DRM_DEBUG_KMS("Enabling HDMI audio on pipe %c\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
sdvox |= SDVO_AUDIO_ENABLE;
|
||||
sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
|
||||
intel_write_eld(encoder, adjusted_mode);
|
||||
}
|
||||
|
||||
if (HAS_PCH_CPT(dev))
|
||||
sdvox |= PORT_TRANS_SEL_CPT(intel_crtc->pipe);
|
||||
else if (intel_crtc->pipe == 1)
|
||||
sdvox |= SDVO_PIPE_B_SELECT;
|
||||
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
intel_hdmi_set_avi_infoframe(encoder);
|
||||
intel_hdmi_set_spd_infoframe(encoder);
|
||||
}
|
||||
|
||||
static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
u32 temp;
|
||||
u32 enable_bits = SDVO_ENABLE;
|
||||
|
||||
if (intel_hdmi->has_audio)
|
||||
enable_bits |= SDVO_AUDIO_ENABLE;
|
||||
|
||||
temp = I915_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
/* HW workaround, need to toggle enable bit off and on for 12bpc, but
|
||||
* we do this anyway which shows more stable in testing.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp & ~SDVO_ENABLE);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
}
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON) {
|
||||
temp &= ~enable_bits;
|
||||
} else {
|
||||
temp |= enable_bits;
|
||||
}
|
||||
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
|
||||
/* HW workaround, need to write this twice for issue that may result
|
||||
* in first write getting masked.
|
||||
*/
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
I915_WRITE(intel_hdmi->sdvox_reg, temp);
|
||||
POSTING_READ(intel_hdmi->sdvox_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static int intel_hdmi_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
if (mode->clock > 165000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
if (mode->clock < 20000)
|
||||
return MODE_CLOCK_LOW;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
return MODE_NO_DBLESCAN;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
struct edid *edid;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
intel_hdmi->has_hdmi_sink = false;
|
||||
intel_hdmi->has_audio = false;
|
||||
edid = drm_get_edid(connector, dev_priv->gmbus[intel_hdmi->ddc_bus]);
|
||||
|
||||
if (edid) {
|
||||
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
|
||||
status = connector_status_connected;
|
||||
if (intel_hdmi->force_audio != HDMI_AUDIO_OFF_DVI)
|
||||
intel_hdmi->has_hdmi_sink =
|
||||
drm_detect_hdmi_monitor(edid);
|
||||
intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
|
||||
}
|
||||
connector->display_info.raw_edid = NULL;
|
||||
free(edid, DRM_MEM_KMS);
|
||||
} else {
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] got no edid, ddc port %d\n",
|
||||
connector->base.id, drm_get_connector_name(connector),
|
||||
intel_hdmi->ddc_bus);
|
||||
}
|
||||
|
||||
if (status == connector_status_connected) {
|
||||
if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO)
|
||||
intel_hdmi->has_audio =
|
||||
(intel_hdmi->force_audio == HDMI_AUDIO_ON);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int intel_hdmi_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
|
||||
/* We should parse the EDID data and find out if it's an HDMI sink so
|
||||
* we can send audio to it.
|
||||
*/
|
||||
|
||||
return intel_ddc_get_modes(connector,
|
||||
dev_priv->gmbus[intel_hdmi->ddc_bus]);
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_hdmi_detect_audio(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
struct edid *edid;
|
||||
bool has_audio = false;
|
||||
|
||||
edid = drm_get_edid(connector, dev_priv->gmbus[intel_hdmi->ddc_bus]);
|
||||
if (edid) {
|
||||
if (edid->input & DRM_EDID_INPUT_DIGITAL)
|
||||
has_audio = drm_detect_monitor_audio(edid);
|
||||
|
||||
connector->display_info.raw_edid = NULL;
|
||||
free(edid, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
return has_audio;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_hdmi_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ret = drm_connector_property_set_value(connector, property, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (property == dev_priv->force_audio_property) {
|
||||
enum hdmi_force_audio i = val;
|
||||
bool has_audio;
|
||||
|
||||
if (i == intel_hdmi->force_audio)
|
||||
return 0;
|
||||
|
||||
intel_hdmi->force_audio = i;
|
||||
|
||||
if (i == HDMI_AUDIO_AUTO)
|
||||
has_audio = intel_hdmi_detect_audio(connector);
|
||||
else
|
||||
has_audio = (i == HDMI_AUDIO_ON);
|
||||
|
||||
if (i == HDMI_AUDIO_OFF_DVI)
|
||||
intel_hdmi->has_hdmi_sink = 0;
|
||||
|
||||
intel_hdmi->has_audio = has_audio;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (property == dev_priv->broadcast_rgb_property) {
|
||||
if (val == !!intel_hdmi->color_range)
|
||||
return 0;
|
||||
|
||||
intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
done:
|
||||
if (intel_hdmi->base.base.crtc) {
|
||||
struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
|
||||
drm_crtc_helper_set_mode(crtc, &crtc->mode,
|
||||
crtc->x, crtc->y,
|
||||
crtc->fb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_hdmi_destroy(struct drm_connector *connector)
|
||||
{
|
||||
#if 0
|
||||
drm_sysfs_connector_remove(connector);
|
||||
#endif
|
||||
drm_connector_cleanup(connector);
|
||||
free(connector, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
|
||||
.dpms = intel_hdmi_dpms,
|
||||
.mode_fixup = intel_hdmi_mode_fixup,
|
||||
.prepare = intel_encoder_prepare,
|
||||
.mode_set = intel_hdmi_mode_set,
|
||||
.commit = intel_encoder_commit,
|
||||
};
|
||||
|
||||
static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.detect = intel_hdmi_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = intel_hdmi_set_property,
|
||||
.destroy = intel_hdmi_destroy,
|
||||
};
|
||||
|
||||
static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
|
||||
.get_modes = intel_hdmi_get_modes,
|
||||
.mode_valid = intel_hdmi_mode_valid,
|
||||
.best_encoder = intel_best_encoder,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
|
||||
.destroy = intel_encoder_destroy,
|
||||
};
|
||||
|
||||
static void
|
||||
intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
|
||||
{
|
||||
intel_attach_force_audio_property(connector);
|
||||
intel_attach_broadcast_rgb_property(connector);
|
||||
}
|
||||
|
||||
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_connector *connector;
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct intel_connector *intel_connector;
|
||||
struct intel_hdmi *intel_hdmi;
|
||||
int i;
|
||||
|
||||
intel_hdmi = malloc(sizeof(struct intel_hdmi), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
intel_connector = malloc(sizeof(struct intel_connector), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
intel_encoder = &intel_hdmi->base;
|
||||
drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
connector = &intel_connector->base;
|
||||
drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_HDMIA);
|
||||
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
|
||||
|
||||
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
connector->interlace_allowed = 1;
|
||||
connector->doublescan_allowed = 0;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
|
||||
/* Set up the DDC bus. */
|
||||
if (sdvox_reg == SDVOB) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
|
||||
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == SDVOC) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
|
||||
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == HDMIB) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
|
||||
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == HDMIC) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
|
||||
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
|
||||
} else if (sdvox_reg == HDMID) {
|
||||
intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
|
||||
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
|
||||
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
|
||||
}
|
||||
|
||||
|
||||
intel_hdmi->sdvox_reg = sdvox_reg;
|
||||
|
||||
if (!HAS_PCH_SPLIT(dev)) {
|
||||
intel_hdmi->write_infoframe = i9xx_write_infoframe;
|
||||
I915_WRITE(VIDEO_DIP_CTL, 0);
|
||||
} else {
|
||||
intel_hdmi->write_infoframe = ironlake_write_infoframe;
|
||||
for_each_pipe(i)
|
||||
I915_WRITE(TVIDEO_DIP_CTL(i), 0);
|
||||
}
|
||||
|
||||
drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
|
||||
|
||||
intel_hdmi_add_properties(intel_hdmi, connector);
|
||||
|
||||
intel_connector_attach_encoder(intel_connector, intel_encoder);
|
||||
#if 0
|
||||
drm_sysfs_connector_add(connector);
|
||||
#endif
|
||||
|
||||
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
|
||||
* 0xd. Failure to do so will result in spurious interrupts being
|
||||
* generated on the port when a cable is not attached.
|
||||
*/
|
||||
if (IS_G4X(dev) && !IS_GM45(dev)) {
|
||||
u32 temp = I915_READ(PEG_BAND_GAP_DATA);
|
||||
I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
|
||||
}
|
||||
}
|
||||
716
sys/dev/drm2/i915/intel_iic.c
Normal file
716
sys/dev/drm2/i915/intel_iic.c
Normal file
|
|
@ -0,0 +1,716 @@
|
|||
/*
|
||||
* Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
|
||||
* Copyright © 2006-2008,2010 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Chris Wilson <chris@chris-wilson.co.uk>
|
||||
*
|
||||
* Copyright (c) 2011 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Konstantin Belousov under sponsorship from
|
||||
* the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/iicbus/iic.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
#include <dev/iicbus/iicbus.h>
|
||||
#include "iicbus_if.h"
|
||||
#include "iicbb_if.h"
|
||||
|
||||
static int intel_iic_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs);
|
||||
static void intel_teardown_gmbus_m(struct drm_device *dev, int m);
|
||||
|
||||
/* Intel GPIO access functions */
|
||||
|
||||
#define I2C_RISEFALL_TIME 10
|
||||
|
||||
struct intel_iic_softc {
|
||||
struct drm_device *drm_dev;
|
||||
device_t iic_dev;
|
||||
bool force_bit_dev;
|
||||
char name[32];
|
||||
uint32_t reg;
|
||||
uint32_t reg0;
|
||||
};
|
||||
|
||||
static void
|
||||
intel_iic_quirk_set(struct drm_i915_private *dev_priv, bool enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* When using bit bashing for I2C, this bit needs to be set to 1 */
|
||||
if (!IS_PINEVIEW(dev_priv->dev))
|
||||
return;
|
||||
|
||||
val = I915_READ(DSPCLK_GATE_D);
|
||||
if (enable)
|
||||
val |= DPCUNIT_CLOCK_GATE_DISABLE;
|
||||
else
|
||||
val &= ~DPCUNIT_CLOCK_GATE_DISABLE;
|
||||
I915_WRITE(DSPCLK_GATE_D, val);
|
||||
}
|
||||
|
||||
static u32
|
||||
intel_iic_get_reserved(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_private *dev_priv;
|
||||
u32 reserved;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
dev = sc->drm_dev;
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
if (!IS_I830(dev) && !IS_845G(dev)) {
|
||||
reserved = I915_READ_NOTRACE(sc->reg) &
|
||||
(GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE);
|
||||
} else {
|
||||
reserved = 0;
|
||||
}
|
||||
|
||||
return (reserved);
|
||||
}
|
||||
|
||||
void
|
||||
intel_iic_reset(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
I915_WRITE(PCH_GMBUS0, 0);
|
||||
else
|
||||
I915_WRITE(GMBUS0, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbus_reset(device_t idev, u_char speed, u_char addr, u_char *oldaddr)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_device *dev;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
dev = sc->drm_dev;
|
||||
|
||||
intel_iic_reset(dev);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_iicbb_setsda(device_t idev, int val)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
u32 reserved;
|
||||
u32 data_bits;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
|
||||
reserved = intel_iic_get_reserved(idev);
|
||||
if (val)
|
||||
data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
|
||||
else
|
||||
data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
|
||||
GPIO_DATA_VAL_MASK;
|
||||
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved | data_bits);
|
||||
POSTING_READ(sc->reg);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_iicbb_setscl(device_t idev, int val)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
u32 clock_bits, reserved;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
|
||||
reserved = intel_iic_get_reserved(idev);
|
||||
if (val)
|
||||
clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
|
||||
else
|
||||
clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
|
||||
GPIO_CLOCK_VAL_MASK;
|
||||
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved | clock_bits);
|
||||
POSTING_READ(sc->reg);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_getsda(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
u32 reserved;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
|
||||
reserved = intel_iic_get_reserved(idev);
|
||||
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_DATA_DIR_MASK);
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved);
|
||||
return ((I915_READ_NOTRACE(sc->reg) & GPIO_DATA_VAL_IN) != 0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_getscl(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
u32 reserved;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
|
||||
reserved = intel_iic_get_reserved(idev);
|
||||
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_CLOCK_DIR_MASK);
|
||||
I915_WRITE_NOTRACE(sc->reg, reserved);
|
||||
return ((I915_READ_NOTRACE(sc->reg) & GPIO_CLOCK_VAL_IN) != 0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_gmbus_transfer(device_t idev, struct iic_msg *msgs, uint32_t nmsgs)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
u8 *buf;
|
||||
int error, i, reg_offset, unit;
|
||||
u32 val, loop;
|
||||
u16 len;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
unit = device_get_unit(idev);
|
||||
|
||||
sx_xlock(&dev_priv->gmbus_sx);
|
||||
if (sc->force_bit_dev) {
|
||||
error = intel_iic_quirk_xfer(dev_priv->bbbus[unit], msgs, nmsgs);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
|
||||
|
||||
I915_WRITE(GMBUS0 + reg_offset, sc->reg0);
|
||||
|
||||
for (i = 0; i < nmsgs; i++) {
|
||||
len = msgs[i].len;
|
||||
buf = msgs[i].buf;
|
||||
|
||||
if ((msgs[i].flags & IIC_M_RD) != 0) {
|
||||
I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT |
|
||||
(i + 1 == nmsgs ? GMBUS_CYCLE_STOP : 0) |
|
||||
(len << GMBUS_BYTE_COUNT_SHIFT) |
|
||||
(msgs[i].slave << GMBUS_SLAVE_ADDR_SHIFT) |
|
||||
GMBUS_SLAVE_READ | GMBUS_SW_RDY);
|
||||
POSTING_READ(GMBUS2 + reg_offset);
|
||||
do {
|
||||
loop = 0;
|
||||
|
||||
if (_intel_wait_for(sc->drm_dev,
|
||||
(I915_READ(GMBUS2 + reg_offset) &
|
||||
(GMBUS_SATOER | GMBUS_HW_RDY)) != 0,
|
||||
50, 1, "915gbr"))
|
||||
goto timeout;
|
||||
if ((I915_READ(GMBUS2 + reg_offset) &
|
||||
GMBUS_SATOER) != 0)
|
||||
goto clear_err;
|
||||
|
||||
val = I915_READ(GMBUS3 + reg_offset);
|
||||
do {
|
||||
*buf++ = val & 0xff;
|
||||
val >>= 8;
|
||||
} while (--len != 0 && ++loop < 4);
|
||||
} while (len != 0);
|
||||
} else {
|
||||
val = loop = 0;
|
||||
do {
|
||||
val |= *buf++ << (8 * loop);
|
||||
} while (--len != 0 && ++loop < 4);
|
||||
|
||||
I915_WRITE(GMBUS3 + reg_offset, val);
|
||||
I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT |
|
||||
(i + 1 == nmsgs ? GMBUS_CYCLE_STOP : 0) |
|
||||
(msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
|
||||
(msgs[i].slave << GMBUS_SLAVE_ADDR_SHIFT) |
|
||||
GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
|
||||
POSTING_READ(GMBUS2+reg_offset);
|
||||
|
||||
while (len != 0) {
|
||||
if (_intel_wait_for(sc->drm_dev,
|
||||
(I915_READ(GMBUS2 + reg_offset) &
|
||||
(GMBUS_SATOER | GMBUS_HW_RDY)) != 0,
|
||||
50, 1, "915gbw"))
|
||||
goto timeout;
|
||||
if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
|
||||
goto clear_err;
|
||||
|
||||
val = loop = 0;
|
||||
do {
|
||||
val |= *buf++ << (8 * loop);
|
||||
} while (--len != 0 && ++loop < 4);
|
||||
|
||||
I915_WRITE(GMBUS3 + reg_offset, val);
|
||||
POSTING_READ(GMBUS2 + reg_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 1 < nmsgs && _intel_wait_for(sc->drm_dev,
|
||||
(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER |
|
||||
GMBUS_HW_WAIT_PHASE)) != 0,
|
||||
50, 1, "915gbh"))
|
||||
goto timeout;
|
||||
if ((I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) != 0)
|
||||
goto clear_err;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
done:
|
||||
/* Mark the GMBUS interface as disabled after waiting for idle.
|
||||
* We will re-enable it at the start of the next xfer,
|
||||
* till then let it sleep.
|
||||
*/
|
||||
if (_intel_wait_for(dev,
|
||||
(I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
|
||||
10, 1, "915gbu"))
|
||||
DRM_INFO("GMBUS timed out waiting for idle\n");
|
||||
I915_WRITE(GMBUS0 + reg_offset, 0);
|
||||
out:
|
||||
sx_xunlock(&dev_priv->gmbus_sx);
|
||||
return (error);
|
||||
|
||||
clear_err:
|
||||
/* Toggle the Software Clear Interrupt bit. This has the effect
|
||||
* of resetting the GMBUS controller and so clearing the
|
||||
* BUS_ERROR raised by the slave's NAK.
|
||||
*/
|
||||
I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
|
||||
I915_WRITE(GMBUS1 + reg_offset, 0);
|
||||
error = EIO;
|
||||
goto done;
|
||||
|
||||
timeout:
|
||||
DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
|
||||
sc->reg0 & 0xff, sc->name);
|
||||
I915_WRITE(GMBUS0 + reg_offset, 0);
|
||||
|
||||
/*
|
||||
* Hardware may not support GMBUS over these pins?
|
||||
* Try GPIO bitbanging instead.
|
||||
*/
|
||||
sc->force_bit_dev = true;
|
||||
|
||||
error = intel_iic_quirk_xfer(dev_priv->bbbus[unit], msgs, nmsgs);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void
|
||||
intel_gmbus_set_speed(device_t idev, int speed)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
|
||||
sc = device_get_softc(device_get_parent(idev));
|
||||
|
||||
sc->reg0 = (sc->reg0 & ~(0x3 << 8)) | speed;
|
||||
}
|
||||
|
||||
void
|
||||
intel_gmbus_force_bit(device_t idev, bool force_bit)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
|
||||
sc = device_get_softc(device_get_parent(idev));
|
||||
sc->force_bit_dev = force_bit;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iic_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs)
|
||||
{
|
||||
device_t bridge_dev;
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
bridge_dev = device_get_parent(device_get_parent(idev));
|
||||
sc = device_get_softc(bridge_dev);
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
|
||||
intel_iic_reset(sc->drm_dev);
|
||||
intel_iic_quirk_set(dev_priv, true);
|
||||
IICBB_SETSDA(bridge_dev, 1);
|
||||
IICBB_SETSCL(bridge_dev, 1);
|
||||
DELAY(I2C_RISEFALL_TIME);
|
||||
|
||||
/* convert slave addresses to format expected by iicbb */
|
||||
for (i = 0; i < nmsgs; i++) {
|
||||
msgs[i].slave <<= 1;
|
||||
/* force use of repeated start instead of default stop+start */
|
||||
if (i != (nmsgs - 1))
|
||||
msgs[i].flags |= IIC_M_NOSTOP;
|
||||
}
|
||||
ret = iicbus_transfer(idev, msgs, nmsgs);
|
||||
/* restore the addresses */
|
||||
for (i = 0; i < nmsgs; i++)
|
||||
msgs[i].slave >>= 1;
|
||||
IICBB_SETSDA(bridge_dev, 1);
|
||||
IICBB_SETSCL(bridge_dev, 1);
|
||||
intel_iic_quirk_set(dev_priv, false);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static const char *gpio_names[GMBUS_NUM_PORTS] = {
|
||||
"disabled",
|
||||
"ssc",
|
||||
"vga",
|
||||
"panel",
|
||||
"dpc",
|
||||
"dpb",
|
||||
"reserved",
|
||||
"dpd",
|
||||
};
|
||||
|
||||
static int
|
||||
intel_gmbus_probe(device_t dev)
|
||||
{
|
||||
|
||||
return (BUS_PROBE_SPECIFIC);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_gmbus_attach(device_t idev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct intel_iic_softc *sc;
|
||||
int pin;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
sc->drm_dev = device_get_softc(device_get_parent(idev));
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
pin = device_get_unit(idev);
|
||||
|
||||
snprintf(sc->name, sizeof(sc->name), "gmbus bus %s", gpio_names[pin]);
|
||||
device_set_desc(idev, sc->name);
|
||||
|
||||
/* By default use a conservative clock rate */
|
||||
sc->reg0 = pin | GMBUS_RATE_100KHZ;
|
||||
|
||||
/* XXX force bit banging until GMBUS is fully debugged */
|
||||
if (IS_GEN2(sc->drm_dev)) {
|
||||
sc->force_bit_dev = true;
|
||||
}
|
||||
|
||||
/* add bus interface device */
|
||||
sc->iic_dev = device_add_child(idev, "iicbus", -1);
|
||||
if (sc->iic_dev == NULL)
|
||||
return (ENXIO);
|
||||
device_quiet(sc->iic_dev);
|
||||
bus_generic_attach(idev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_gmbus_detach(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
device_t child;
|
||||
int u;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
u = device_get_unit(idev);
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
|
||||
child = sc->iic_dev;
|
||||
bus_generic_detach(idev);
|
||||
if (child != NULL)
|
||||
device_delete_child(idev, child);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_probe(device_t dev)
|
||||
{
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_attach(device_t idev)
|
||||
{
|
||||
static const int map_pin_to_reg[] = {
|
||||
0,
|
||||
GPIOB,
|
||||
GPIOA,
|
||||
GPIOC,
|
||||
GPIOD,
|
||||
GPIOE,
|
||||
0,
|
||||
GPIOF
|
||||
};
|
||||
|
||||
struct intel_iic_softc *sc;
|
||||
struct drm_i915_private *dev_priv;
|
||||
int pin;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
sc->drm_dev = device_get_softc(device_get_parent(idev));
|
||||
dev_priv = sc->drm_dev->dev_private;
|
||||
pin = device_get_unit(idev);
|
||||
|
||||
snprintf(sc->name, sizeof(sc->name), "i915 iicbb %s", gpio_names[pin]);
|
||||
device_set_desc(idev, sc->name);
|
||||
|
||||
sc->reg0 = pin | GMBUS_RATE_100KHZ;
|
||||
sc->reg = map_pin_to_reg[pin];
|
||||
if (HAS_PCH_SPLIT(dev_priv->dev))
|
||||
sc->reg += PCH_GPIOA - GPIOA;
|
||||
|
||||
/* add generic bit-banging code */
|
||||
sc->iic_dev = device_add_child(idev, "iicbb", -1);
|
||||
if (sc->iic_dev == NULL)
|
||||
return (ENXIO);
|
||||
device_quiet(sc->iic_dev);
|
||||
bus_generic_attach(idev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_iicbb_detach(device_t idev)
|
||||
{
|
||||
struct intel_iic_softc *sc;
|
||||
device_t child;
|
||||
|
||||
sc = device_get_softc(idev);
|
||||
child = sc->iic_dev;
|
||||
bus_generic_detach(idev);
|
||||
if (child)
|
||||
device_delete_child(idev, child);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t intel_gmbus_methods[] = {
|
||||
DEVMETHOD(device_probe, intel_gmbus_probe),
|
||||
DEVMETHOD(device_attach, intel_gmbus_attach),
|
||||
DEVMETHOD(device_detach, intel_gmbus_detach),
|
||||
DEVMETHOD(iicbus_reset, intel_iicbus_reset),
|
||||
DEVMETHOD(iicbus_transfer, intel_gmbus_transfer),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
static driver_t intel_gmbus_driver = {
|
||||
"intel_gmbus",
|
||||
intel_gmbus_methods,
|
||||
sizeof(struct intel_iic_softc)
|
||||
};
|
||||
static devclass_t intel_gmbus_devclass;
|
||||
DRIVER_MODULE_ORDERED(intel_gmbus, drmn, intel_gmbus_driver,
|
||||
intel_gmbus_devclass, 0, 0, SI_ORDER_FIRST);
|
||||
DRIVER_MODULE(iicbus, intel_gmbus, iicbus_driver, iicbus_devclass, 0, 0);
|
||||
|
||||
static device_method_t intel_iicbb_methods[] = {
|
||||
DEVMETHOD(device_probe, intel_iicbb_probe),
|
||||
DEVMETHOD(device_attach, intel_iicbb_attach),
|
||||
DEVMETHOD(device_detach, intel_iicbb_detach),
|
||||
|
||||
DEVMETHOD(bus_add_child, bus_generic_add_child),
|
||||
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
||||
|
||||
DEVMETHOD(iicbb_callback, iicbus_null_callback),
|
||||
DEVMETHOD(iicbb_reset, intel_iicbus_reset),
|
||||
DEVMETHOD(iicbb_setsda, intel_iicbb_setsda),
|
||||
DEVMETHOD(iicbb_setscl, intel_iicbb_setscl),
|
||||
DEVMETHOD(iicbb_getsda, intel_iicbb_getsda),
|
||||
DEVMETHOD(iicbb_getscl, intel_iicbb_getscl),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
static driver_t intel_iicbb_driver = {
|
||||
"intel_iicbb",
|
||||
intel_iicbb_methods,
|
||||
sizeof(struct intel_iic_softc)
|
||||
};
|
||||
static devclass_t intel_iicbb_devclass;
|
||||
DRIVER_MODULE_ORDERED(intel_iicbb, drmn, intel_iicbb_driver,
|
||||
intel_iicbb_devclass, 0, 0, SI_ORDER_FIRST);
|
||||
DRIVER_MODULE(iicbb, intel_iicbb, iicbb_driver, iicbb_devclass, 0, 0);
|
||||
|
||||
int
|
||||
intel_setup_gmbus(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
device_t iic_dev;
|
||||
int i, ret;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
sx_init(&dev_priv->gmbus_sx, "gmbus");
|
||||
dev_priv->gmbus_bridge = malloc(sizeof(device_t) * GMBUS_NUM_PORTS,
|
||||
DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
|
||||
dev_priv->bbbus_bridge = malloc(sizeof(device_t) * GMBUS_NUM_PORTS,
|
||||
DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
|
||||
dev_priv->gmbus = malloc(sizeof(device_t) * GMBUS_NUM_PORTS,
|
||||
DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
|
||||
dev_priv->bbbus = malloc(sizeof(device_t) * GMBUS_NUM_PORTS,
|
||||
DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
|
||||
|
||||
/*
|
||||
* The Giant there is recursed, most likely. Normally, the
|
||||
* intel_setup_gmbus() is called from the attach method of the
|
||||
* driver.
|
||||
*/
|
||||
mtx_lock(&Giant);
|
||||
for (i = 0; i < GMBUS_NUM_PORTS; i++) {
|
||||
/*
|
||||
* Initialized bbbus_bridge before gmbus_bridge, since
|
||||
* gmbus may decide to force quirk transfer in the
|
||||
* attachment code.
|
||||
*/
|
||||
dev_priv->bbbus_bridge[i] = device_add_child(dev->device,
|
||||
"intel_iicbb", i);
|
||||
if (dev_priv->bbbus_bridge[i] == NULL) {
|
||||
DRM_ERROR("bbbus bridge %d creation failed\n", i);
|
||||
ret = ENXIO;
|
||||
goto err;
|
||||
}
|
||||
device_quiet(dev_priv->bbbus_bridge[i]);
|
||||
ret = device_probe_and_attach(dev_priv->bbbus_bridge[i]);
|
||||
if (ret != 0) {
|
||||
DRM_ERROR("bbbus bridge %d attach failed, %d\n", i,
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
iic_dev = device_find_child(dev_priv->bbbus_bridge[i], "iicbb",
|
||||
-1);
|
||||
if (iic_dev == NULL) {
|
||||
DRM_ERROR("bbbus bridge doesn't have iicbb child\n");
|
||||
goto err;
|
||||
}
|
||||
iic_dev = device_find_child(iic_dev, "iicbus", -1);
|
||||
if (iic_dev == NULL) {
|
||||
DRM_ERROR(
|
||||
"bbbus bridge doesn't have iicbus grandchild\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev_priv->bbbus[i] = iic_dev;
|
||||
|
||||
dev_priv->gmbus_bridge[i] = device_add_child(dev->device,
|
||||
"intel_gmbus", i);
|
||||
if (dev_priv->gmbus_bridge[i] == NULL) {
|
||||
DRM_ERROR("gmbus bridge %d creation failed\n", i);
|
||||
ret = ENXIO;
|
||||
goto err;
|
||||
}
|
||||
device_quiet(dev_priv->gmbus_bridge[i]);
|
||||
ret = device_probe_and_attach(dev_priv->gmbus_bridge[i]);
|
||||
if (ret != 0) {
|
||||
DRM_ERROR("gmbus bridge %d attach failed, %d\n", i,
|
||||
ret);
|
||||
ret = ENXIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
iic_dev = device_find_child(dev_priv->gmbus_bridge[i],
|
||||
"iicbus", -1);
|
||||
if (iic_dev == NULL) {
|
||||
DRM_ERROR("gmbus bridge doesn't have iicbus child\n");
|
||||
goto err;
|
||||
}
|
||||
dev_priv->gmbus[i] = iic_dev;
|
||||
|
||||
intel_iic_reset(dev);
|
||||
}
|
||||
|
||||
mtx_unlock(&Giant);
|
||||
return (0);
|
||||
|
||||
err:
|
||||
intel_teardown_gmbus_m(dev, i);
|
||||
mtx_unlock(&Giant);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_teardown_gmbus_m(struct drm_device *dev, int m)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
free(dev_priv->gmbus, DRM_MEM_DRIVER);
|
||||
dev_priv->gmbus = NULL;
|
||||
free(dev_priv->bbbus, DRM_MEM_DRIVER);
|
||||
dev_priv->bbbus = NULL;
|
||||
free(dev_priv->gmbus_bridge, DRM_MEM_DRIVER);
|
||||
dev_priv->gmbus_bridge = NULL;
|
||||
free(dev_priv->bbbus_bridge, DRM_MEM_DRIVER);
|
||||
dev_priv->bbbus_bridge = NULL;
|
||||
sx_destroy(&dev_priv->gmbus_sx);
|
||||
}
|
||||
|
||||
void
|
||||
intel_teardown_gmbus(struct drm_device *dev)
|
||||
{
|
||||
|
||||
mtx_lock(&Giant);
|
||||
intel_teardown_gmbus_m(dev, GMBUS_NUM_PORTS);
|
||||
mtx_unlock(&Giant);
|
||||
}
|
||||
1125
sys/dev/drm2/i915/intel_lvds.c
Normal file
1125
sys/dev/drm2/i915/intel_lvds.c
Normal file
File diff suppressed because it is too large
Load diff
143
sys/dev/drm2/i915/intel_modes.c
Normal file
143
sys/dev/drm2/i915/intel_modes.c
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
|
||||
* Copyright (c) 2007, 2010 Intel Corporation
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/drm_edid.h>
|
||||
#include <dev/iicbus/iiconf.h>
|
||||
|
||||
/**
|
||||
* intel_ddc_probe
|
||||
*
|
||||
*/
|
||||
bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
|
||||
u8 out_buf[] = { 0x0, 0x0};
|
||||
u8 buf[2];
|
||||
struct iic_msg msgs[] = {
|
||||
{
|
||||
.slave = DDC_ADDR,
|
||||
.flags = IIC_M_WR,
|
||||
.len = 1,
|
||||
.buf = out_buf,
|
||||
},
|
||||
{
|
||||
.slave = DDC_ADDR,
|
||||
.flags = IIC_M_RD,
|
||||
.len = 1,
|
||||
.buf = buf,
|
||||
}
|
||||
};
|
||||
|
||||
return (iicbus_transfer(dev_priv->gmbus[ddc_bus], msgs, 2)
|
||||
== 0/* XXXKIB 2*/);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_ddc_get_modes - get modelist from monitor
|
||||
* @connector: DRM connector device to use
|
||||
* @adapter: i2c adapter
|
||||
*
|
||||
* Fetch the EDID information from @connector using the DDC bus.
|
||||
*/
|
||||
int
|
||||
intel_ddc_get_modes(struct drm_connector *connector, device_t adapter)
|
||||
{
|
||||
struct edid *edid;
|
||||
int ret = 0;
|
||||
|
||||
edid = drm_get_edid(connector, adapter);
|
||||
if (edid) {
|
||||
drm_mode_connector_update_edid_property(connector, edid);
|
||||
ret = drm_add_edid_modes(connector, edid);
|
||||
drm_edid_to_eld(connector, edid);
|
||||
connector->display_info.raw_edid = NULL;
|
||||
free(edid, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_prop_enum_list force_audio_names[] = {
|
||||
{ HDMI_AUDIO_OFF_DVI, "force-dvi" },
|
||||
{ HDMI_AUDIO_OFF, "off" },
|
||||
{ HDMI_AUDIO_AUTO, "auto" },
|
||||
{ HDMI_AUDIO_ON, "on" },
|
||||
};
|
||||
|
||||
void
|
||||
intel_attach_force_audio_property(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_property *prop;
|
||||
|
||||
prop = dev_priv->force_audio_property;
|
||||
if (prop == NULL) {
|
||||
prop = drm_property_create_enum(dev, 0,
|
||||
"audio",
|
||||
force_audio_names,
|
||||
DRM_ARRAY_SIZE(force_audio_names));
|
||||
if (prop == NULL)
|
||||
return;
|
||||
|
||||
dev_priv->force_audio_property = prop;
|
||||
}
|
||||
drm_connector_attach_property(connector, prop, 0);
|
||||
}
|
||||
|
||||
static const struct drm_prop_enum_list broadcast_rgb_names[] = {
|
||||
{ 0, "Full" },
|
||||
{ 1, "Limited 16:235" },
|
||||
};
|
||||
|
||||
void
|
||||
intel_attach_broadcast_rgb_property(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_property *prop;
|
||||
|
||||
prop = dev_priv->broadcast_rgb_property;
|
||||
if (prop == NULL) {
|
||||
prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
|
||||
"Broadcast RGB",
|
||||
broadcast_rgb_names,
|
||||
DRM_ARRAY_SIZE(broadcast_rgb_names));
|
||||
if (prop == NULL)
|
||||
return;
|
||||
|
||||
dev_priv->broadcast_rgb_property = prop;
|
||||
}
|
||||
|
||||
drm_connector_attach_property(connector, prop, 0);
|
||||
}
|
||||
550
sys/dev/drm2/i915/intel_opregion.c
Normal file
550
sys/dev/drm2/i915/intel_opregion.c
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
* Copyright 2008 Intel Corporation <hong.liu@intel.com>
|
||||
* Copyright 2008 Red Hat <mjg@redhat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
#define PCI_ASLE 0xe4
|
||||
#define PCI_ASLS 0xfc
|
||||
|
||||
#define OPREGION_HEADER_OFFSET 0
|
||||
#define OPREGION_ACPI_OFFSET 0x100
|
||||
#define ACPI_CLID 0x01ac /* current lid state indicator */
|
||||
#define ACPI_CDCK 0x01b0 /* current docking state indicator */
|
||||
#define OPREGION_SWSCI_OFFSET 0x200
|
||||
#define OPREGION_ASLE_OFFSET 0x300
|
||||
#define OPREGION_VBT_OFFSET 0x400
|
||||
|
||||
#define OPREGION_SIGNATURE "IntelGraphicsMem"
|
||||
#define MBOX_ACPI (1<<0)
|
||||
#define MBOX_SWSCI (1<<1)
|
||||
#define MBOX_ASLE (1<<2)
|
||||
|
||||
struct opregion_header {
|
||||
u8 signature[16];
|
||||
u32 size;
|
||||
u32 opregion_ver;
|
||||
u8 bios_ver[32];
|
||||
u8 vbios_ver[16];
|
||||
u8 driver_ver[16];
|
||||
u32 mboxes;
|
||||
u8 reserved[164];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* OpRegion mailbox #1: public ACPI methods */
|
||||
struct opregion_acpi {
|
||||
u32 drdy; /* driver readiness */
|
||||
u32 csts; /* notification status */
|
||||
u32 cevt; /* current event */
|
||||
u8 rsvd1[20];
|
||||
u32 didl[8]; /* supported display devices ID list */
|
||||
u32 cpdl[8]; /* currently presented display list */
|
||||
u32 cadl[8]; /* currently active display list */
|
||||
u32 nadl[8]; /* next active devices list */
|
||||
u32 aslp; /* ASL sleep time-out */
|
||||
u32 tidx; /* toggle table index */
|
||||
u32 chpd; /* current hotplug enable indicator */
|
||||
u32 clid; /* current lid state*/
|
||||
u32 cdck; /* current docking state */
|
||||
u32 sxsw; /* Sx state resume */
|
||||
u32 evts; /* ASL supported events */
|
||||
u32 cnot; /* current OS notification */
|
||||
u32 nrdy; /* driver status */
|
||||
u8 rsvd2[60];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* OpRegion mailbox #2: SWSCI */
|
||||
struct opregion_swsci {
|
||||
u32 scic; /* SWSCI command|status|data */
|
||||
u32 parm; /* command parameters */
|
||||
u32 dslp; /* driver sleep time-out */
|
||||
u8 rsvd[244];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* OpRegion mailbox #3: ASLE */
|
||||
struct opregion_asle {
|
||||
u32 ardy; /* driver readiness */
|
||||
u32 aslc; /* ASLE interrupt command */
|
||||
u32 tche; /* technology enabled indicator */
|
||||
u32 alsi; /* current ALS illuminance reading */
|
||||
u32 bclp; /* backlight brightness to set */
|
||||
u32 pfit; /* panel fitting state */
|
||||
u32 cblv; /* current brightness level */
|
||||
u16 bclm[20]; /* backlight level duty cycle mapping table */
|
||||
u32 cpfm; /* current panel fitting mode */
|
||||
u32 epfm; /* enabled panel fitting modes */
|
||||
u8 plut[74]; /* panel LUT and identifier */
|
||||
u32 pfmb; /* PWM freq and min brightness */
|
||||
u8 rsvd[102];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* ASLE irq request bits */
|
||||
#define ASLE_SET_ALS_ILLUM (1 << 0)
|
||||
#define ASLE_SET_BACKLIGHT (1 << 1)
|
||||
#define ASLE_SET_PFIT (1 << 2)
|
||||
#define ASLE_SET_PWM_FREQ (1 << 3)
|
||||
#define ASLE_REQ_MSK 0xf
|
||||
|
||||
/* response bits of ASLE irq request */
|
||||
#define ASLE_ALS_ILLUM_FAILED (1<<10)
|
||||
#define ASLE_BACKLIGHT_FAILED (1<<12)
|
||||
#define ASLE_PFIT_FAILED (1<<14)
|
||||
#define ASLE_PWM_FREQ_FAILED (1<<16)
|
||||
|
||||
/* ASLE backlight brightness to set */
|
||||
#define ASLE_BCLP_VALID (1<<31)
|
||||
#define ASLE_BCLP_MSK (~(1<<31))
|
||||
|
||||
/* ASLE panel fitting request */
|
||||
#define ASLE_PFIT_VALID (1<<31)
|
||||
#define ASLE_PFIT_CENTER (1<<0)
|
||||
#define ASLE_PFIT_STRETCH_TEXT (1<<1)
|
||||
#define ASLE_PFIT_STRETCH_GFX (1<<2)
|
||||
|
||||
/* PWM frequency and minimum brightness */
|
||||
#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
|
||||
#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
|
||||
#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
|
||||
#define ASLE_PFMB_PWM_VALID (1<<31)
|
||||
|
||||
#define ASLE_CBLV_VALID (1<<31)
|
||||
|
||||
#define ACPI_OTHER_OUTPUT (0<<8)
|
||||
#define ACPI_VGA_OUTPUT (1<<8)
|
||||
#define ACPI_TV_OUTPUT (2<<8)
|
||||
#define ACPI_DIGITAL_OUTPUT (3<<8)
|
||||
#define ACPI_LVDS_OUTPUT (4<<8)
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||
u32 max;
|
||||
|
||||
if (!(bclp & ASLE_BCLP_VALID))
|
||||
return ASLE_BACKLIGHT_FAILED;
|
||||
|
||||
bclp &= ASLE_BCLP_MSK;
|
||||
if (bclp > 255)
|
||||
return ASLE_BACKLIGHT_FAILED;
|
||||
|
||||
max = intel_panel_get_max_backlight(dev);
|
||||
intel_panel_set_backlight(dev, bclp * max / 255);
|
||||
asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
|
||||
{
|
||||
/* alsi is the current ALS reading in lux. 0 indicates below sensor
|
||||
range, 0xffff indicates above sensor range. 1-0xfffe are valid */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
if (pfmb & ASLE_PFMB_PWM_VALID) {
|
||||
u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
|
||||
u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
|
||||
blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
pwm = pwm >> 9;
|
||||
/* FIXME - what do we do with the PWM? */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
|
||||
{
|
||||
/* Panel fitting is currently controlled by the X code, so this is a
|
||||
noop until modesetting support works fully */
|
||||
if (!(pfit & ASLE_PFIT_VALID))
|
||||
return ASLE_PFIT_FAILED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_opregion_asle_intr(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||
u32 asle_stat = 0;
|
||||
u32 asle_req;
|
||||
|
||||
if (!asle)
|
||||
return;
|
||||
|
||||
asle_req = asle->aslc & ASLE_REQ_MSK;
|
||||
|
||||
if (!asle_req) {
|
||||
DRM_DEBUG("non asle set request??\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (asle_req & ASLE_SET_ALS_ILLUM)
|
||||
asle_stat |= asle_set_als_illum(dev, asle->alsi);
|
||||
|
||||
if (asle_req & ASLE_SET_BACKLIGHT)
|
||||
asle_stat |= asle_set_backlight(dev, asle->bclp);
|
||||
|
||||
if (asle_req & ASLE_SET_PFIT)
|
||||
asle_stat |= asle_set_pfit(dev, asle->pfit);
|
||||
|
||||
if (asle_req & ASLE_SET_PWM_FREQ)
|
||||
asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
|
||||
|
||||
asle->aslc = asle_stat;
|
||||
}
|
||||
|
||||
void intel_opregion_gse_intr(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||
u32 asle_stat = 0;
|
||||
u32 asle_req;
|
||||
|
||||
if (!asle)
|
||||
return;
|
||||
|
||||
asle_req = asle->aslc & ASLE_REQ_MSK;
|
||||
|
||||
if (!asle_req) {
|
||||
DRM_DEBUG("non asle set request??\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (asle_req & ASLE_SET_ALS_ILLUM) {
|
||||
DRM_DEBUG("Illum is not supported\n");
|
||||
asle_stat |= ASLE_ALS_ILLUM_FAILED;
|
||||
}
|
||||
|
||||
if (asle_req & ASLE_SET_BACKLIGHT)
|
||||
asle_stat |= asle_set_backlight(dev, asle->bclp);
|
||||
|
||||
if (asle_req & ASLE_SET_PFIT) {
|
||||
DRM_DEBUG("Pfit is not supported\n");
|
||||
asle_stat |= ASLE_PFIT_FAILED;
|
||||
}
|
||||
|
||||
if (asle_req & ASLE_SET_PWM_FREQ) {
|
||||
DRM_DEBUG("PWM freq is not supported\n");
|
||||
asle_stat |= ASLE_PWM_FREQ_FAILED;
|
||||
}
|
||||
|
||||
asle->aslc = asle_stat;
|
||||
}
|
||||
#define ASLE_ALS_EN (1<<0)
|
||||
#define ASLE_BLC_EN (1<<1)
|
||||
#define ASLE_PFIT_EN (1<<2)
|
||||
#define ASLE_PFMB_EN (1<<3)
|
||||
|
||||
void intel_opregion_enable_asle(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct opregion_asle *asle = dev_priv->opregion.asle;
|
||||
|
||||
if (asle) {
|
||||
if (IS_MOBILE(dev))
|
||||
intel_enable_asle(dev);
|
||||
|
||||
asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
|
||||
ASLE_PFMB_EN;
|
||||
asle->ardy = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define ACPI_EV_DISPLAY_SWITCH (1<<0)
|
||||
#define ACPI_EV_LID (1<<1)
|
||||
#define ACPI_EV_DOCK (1<<2)
|
||||
|
||||
static struct intel_opregion *system_opregion;
|
||||
|
||||
static int intel_opregion_video_event(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
/* The only video events relevant to opregion are 0x80. These indicate
|
||||
either a docking event, lid switch or display switch request. In
|
||||
Linux, these are handled by the dock, button and video drivers.
|
||||
*/
|
||||
struct opregion_acpi *acpi;
|
||||
struct acpi_bus_event *event = data;
|
||||
int ret = NOTIFY_OK;
|
||||
|
||||
if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (!system_opregion)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
acpi = system_opregion->acpi;
|
||||
|
||||
if (event->type == 0x80 && !(acpi->cevt & 0x1))
|
||||
ret = NOTIFY_BAD;
|
||||
|
||||
acpi->csts = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct notifier_block intel_opregion_notifier = {
|
||||
.notifier_call = intel_opregion_video_event,
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialise the DIDL field in opregion. This passes a list of devices to
|
||||
* the firmware. Values are defined by section B.4.2 of the ACPI specification
|
||||
* (version 3)
|
||||
*/
|
||||
|
||||
static void intel_didl_outputs(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||
struct drm_connector *connector;
|
||||
acpi_handle handle;
|
||||
struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
|
||||
unsigned long long device_id;
|
||||
acpi_status status;
|
||||
int i = 0;
|
||||
|
||||
handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
|
||||
if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
|
||||
return;
|
||||
|
||||
if (acpi_is_video_device(acpi_dev))
|
||||
acpi_video_bus = acpi_dev;
|
||||
else {
|
||||
list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
|
||||
if (acpi_is_video_device(acpi_cdev)) {
|
||||
acpi_video_bus = acpi_cdev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!acpi_video_bus) {
|
||||
printk(KERN_WARNING "No ACPI video bus found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
|
||||
if (i >= 8) {
|
||||
dev_printk(KERN_ERR, &dev->pdev->dev,
|
||||
"More than 8 outputs detected\n");
|
||||
return;
|
||||
}
|
||||
status =
|
||||
acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
|
||||
NULL, &device_id);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (!device_id)
|
||||
goto blind_set;
|
||||
opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
/* If fewer than 8 outputs, the list must be null terminated */
|
||||
if (i < 8)
|
||||
opregion->acpi->didl[i] = 0;
|
||||
return;
|
||||
|
||||
blind_set:
|
||||
i = 0;
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
int output_type = ACPI_OTHER_OUTPUT;
|
||||
if (i >= 8) {
|
||||
device_printf(dev->device,
|
||||
"More than 8 outputs detected\n");
|
||||
return;
|
||||
}
|
||||
switch (connector->connector_type) {
|
||||
case DRM_MODE_CONNECTOR_VGA:
|
||||
case DRM_MODE_CONNECTOR_DVIA:
|
||||
output_type = ACPI_VGA_OUTPUT;
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_Composite:
|
||||
case DRM_MODE_CONNECTOR_SVIDEO:
|
||||
case DRM_MODE_CONNECTOR_Component:
|
||||
case DRM_MODE_CONNECTOR_9PinDIN:
|
||||
output_type = ACPI_TV_OUTPUT;
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_DVII:
|
||||
case DRM_MODE_CONNECTOR_DVID:
|
||||
case DRM_MODE_CONNECTOR_DisplayPort:
|
||||
case DRM_MODE_CONNECTOR_HDMIA:
|
||||
case DRM_MODE_CONNECTOR_HDMIB:
|
||||
output_type = ACPI_DIGITAL_OUTPUT;
|
||||
break;
|
||||
case DRM_MODE_CONNECTOR_LVDS:
|
||||
output_type = ACPI_LVDS_OUTPUT;
|
||||
break;
|
||||
}
|
||||
opregion->acpi->didl[i] |= (1<<31) | output_type | i;
|
||||
i++;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
void intel_opregion_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||
|
||||
if (!opregion->header)
|
||||
return;
|
||||
|
||||
if (opregion->acpi) {
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
intel_didl_outputs(dev);
|
||||
|
||||
/* Notify BIOS we are ready to handle ACPI video ext notifs.
|
||||
* Right now, all the events are handled by the ACPI video module.
|
||||
* We don't actually need to do anything with them. */
|
||||
opregion->acpi->csts = 0;
|
||||
opregion->acpi->drdy = 1;
|
||||
|
||||
system_opregion = opregion;
|
||||
register_acpi_notifier(&intel_opregion_notifier);
|
||||
}
|
||||
|
||||
if (opregion->asle)
|
||||
intel_opregion_enable_asle(dev);
|
||||
}
|
||||
|
||||
void intel_opregion_fini(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||
|
||||
if (!opregion->header)
|
||||
return;
|
||||
|
||||
if (opregion->acpi) {
|
||||
opregion->acpi->drdy = 0;
|
||||
|
||||
system_opregion = NULL;
|
||||
unregister_acpi_notifier(&intel_opregion_notifier);
|
||||
}
|
||||
|
||||
/* just clear all opregion memory pointers now */
|
||||
iounmap(opregion->header);
|
||||
opregion->header = NULL;
|
||||
opregion->acpi = NULL;
|
||||
opregion->swsci = NULL;
|
||||
opregion->asle = NULL;
|
||||
opregion->vbt = NULL;
|
||||
}
|
||||
#else
|
||||
int
|
||||
intel_opregion_init(struct drm_device *dev)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
intel_opregion_fini(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv;
|
||||
struct intel_opregion *opregion;
|
||||
|
||||
dev_priv = dev->dev_private;
|
||||
opregion = &dev_priv->opregion;
|
||||
|
||||
if (opregion->header == NULL)
|
||||
return;
|
||||
|
||||
pmap_unmapdev((vm_offset_t)opregion->header, OPREGION_SIZE);
|
||||
opregion->header = NULL;
|
||||
opregion->acpi = NULL;
|
||||
opregion->swsci = NULL;
|
||||
opregion->asle = NULL;
|
||||
opregion->vbt = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int intel_opregion_setup(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_opregion *opregion = &dev_priv->opregion;
|
||||
char *base;
|
||||
u32 asls, mboxes;
|
||||
int err = 0;
|
||||
|
||||
asls = pci_read_config(dev->device, PCI_ASLS, 4);
|
||||
DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls);
|
||||
if (asls == 0) {
|
||||
DRM_DEBUG("ACPI OpRegion not supported!\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
base = (void *)pmap_mapbios(asls, OPREGION_SIZE);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
if (memcmp(base, OPREGION_SIGNATURE, 16)) {
|
||||
DRM_DEBUG("opregion signature mismatch\n");
|
||||
err = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
opregion->header = (struct opregion_header *)base;
|
||||
opregion->vbt = base + OPREGION_VBT_OFFSET;
|
||||
|
||||
opregion->lid_state = (u32 *)(base + ACPI_CLID);
|
||||
|
||||
mboxes = opregion->header->mboxes;
|
||||
if (mboxes & MBOX_ACPI) {
|
||||
DRM_DEBUG("Public ACPI methods supported\n");
|
||||
opregion->acpi = (struct opregion_acpi *)(base +
|
||||
OPREGION_ACPI_OFFSET);
|
||||
}
|
||||
|
||||
if (mboxes & MBOX_SWSCI) {
|
||||
DRM_DEBUG("SWSCI supported\n");
|
||||
opregion->swsci = (struct opregion_swsci *)(base +
|
||||
OPREGION_SWSCI_OFFSET);
|
||||
}
|
||||
if (mboxes & MBOX_ASLE) {
|
||||
DRM_DEBUG("ASLE supported\n");
|
||||
opregion->asle = (struct opregion_asle *)(base +
|
||||
OPREGION_ASLE_OFFSET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
pmap_unmapdev((vm_offset_t)base, OPREGION_SIZE);
|
||||
return err;
|
||||
}
|
||||
1582
sys/dev/drm2/i915/intel_overlay.c
Normal file
1582
sys/dev/drm2/i915/intel_overlay.c
Normal file
File diff suppressed because it is too large
Load diff
327
sys/dev/drm2/i915/intel_panel.c
Normal file
327
sys/dev/drm2/i915/intel_panel.c
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
* Copyright © 2006-2010 Intel Corporation
|
||||
* Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Dave Airlie <airlied@linux.ie>
|
||||
* Jesse Barnes <jesse.barnes@intel.com>
|
||||
* Chris Wilson <chris@chris-wilson.co.uk>
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
|
||||
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
|
||||
|
||||
void
|
||||
intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
adjusted_mode->hdisplay = fixed_mode->hdisplay;
|
||||
adjusted_mode->hsync_start = fixed_mode->hsync_start;
|
||||
adjusted_mode->hsync_end = fixed_mode->hsync_end;
|
||||
adjusted_mode->htotal = fixed_mode->htotal;
|
||||
|
||||
adjusted_mode->vdisplay = fixed_mode->vdisplay;
|
||||
adjusted_mode->vsync_start = fixed_mode->vsync_start;
|
||||
adjusted_mode->vsync_end = fixed_mode->vsync_end;
|
||||
adjusted_mode->vtotal = fixed_mode->vtotal;
|
||||
|
||||
adjusted_mode->clock = fixed_mode->clock;
|
||||
}
|
||||
|
||||
/* adjusted_mode has been preset to be the panel's fixed mode */
|
||||
void
|
||||
intel_pch_panel_fitting(struct drm_device *dev,
|
||||
int fitting_mode,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int x, y, width, height;
|
||||
|
||||
x = y = width = height = 0;
|
||||
|
||||
/* Native modes don't need fitting */
|
||||
if (adjusted_mode->hdisplay == mode->hdisplay &&
|
||||
adjusted_mode->vdisplay == mode->vdisplay)
|
||||
goto done;
|
||||
|
||||
switch (fitting_mode) {
|
||||
case DRM_MODE_SCALE_CENTER:
|
||||
width = mode->hdisplay;
|
||||
height = mode->vdisplay;
|
||||
x = (adjusted_mode->hdisplay - width + 1)/2;
|
||||
y = (adjusted_mode->vdisplay - height + 1)/2;
|
||||
break;
|
||||
|
||||
case DRM_MODE_SCALE_ASPECT:
|
||||
/* Scale but preserve the aspect ratio */
|
||||
{
|
||||
u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
|
||||
u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
|
||||
if (scaled_width > scaled_height) { /* pillar */
|
||||
width = scaled_height / mode->vdisplay;
|
||||
if (width & 1)
|
||||
width++;
|
||||
x = (adjusted_mode->hdisplay - width + 1) / 2;
|
||||
y = 0;
|
||||
height = adjusted_mode->vdisplay;
|
||||
} else if (scaled_width < scaled_height) { /* letter */
|
||||
height = scaled_width / mode->hdisplay;
|
||||
if (height & 1)
|
||||
height++;
|
||||
y = (adjusted_mode->vdisplay - height + 1) / 2;
|
||||
x = 0;
|
||||
width = adjusted_mode->hdisplay;
|
||||
} else {
|
||||
x = y = 0;
|
||||
width = adjusted_mode->hdisplay;
|
||||
height = adjusted_mode->vdisplay;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case DRM_MODE_SCALE_FULLSCREEN:
|
||||
x = y = 0;
|
||||
width = adjusted_mode->hdisplay;
|
||||
height = adjusted_mode->vdisplay;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
dev_priv->pch_pf_pos = (x << 16) | y;
|
||||
dev_priv->pch_pf_size = (width << 16) | height;
|
||||
}
|
||||
|
||||
static int is_backlight_combination_mode(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4)
|
||||
return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
|
||||
|
||||
if (IS_GEN2(dev))
|
||||
return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Restore the CTL value if it lost, e.g. GPU reset */
|
||||
|
||||
if (HAS_PCH_SPLIT(dev_priv->dev)) {
|
||||
val = I915_READ(BLC_PWM_PCH_CTL2);
|
||||
if (dev_priv->saveBLC_PWM_CTL2 == 0) {
|
||||
dev_priv->saveBLC_PWM_CTL2 = val;
|
||||
} else if (val == 0) {
|
||||
I915_WRITE(BLC_PWM_PCH_CTL2,
|
||||
dev_priv->saveBLC_PWM_CTL2);
|
||||
val = dev_priv->saveBLC_PWM_CTL2;
|
||||
}
|
||||
} else {
|
||||
val = I915_READ(BLC_PWM_CTL);
|
||||
if (dev_priv->saveBLC_PWM_CTL == 0) {
|
||||
dev_priv->saveBLC_PWM_CTL = val;
|
||||
dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
|
||||
} else if (val == 0) {
|
||||
I915_WRITE(BLC_PWM_CTL,
|
||||
dev_priv->saveBLC_PWM_CTL);
|
||||
I915_WRITE(BLC_PWM_CTL2,
|
||||
dev_priv->saveBLC_PWM_CTL2);
|
||||
val = dev_priv->saveBLC_PWM_CTL;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
u32 intel_panel_get_max_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 max;
|
||||
|
||||
max = i915_read_blc_pwm_ctl(dev_priv);
|
||||
if (max == 0) {
|
||||
/* XXX add code here to query mode clock or hardware clock
|
||||
* and program max PWM appropriately.
|
||||
*/
|
||||
#if 0
|
||||
printf("fixme: max PWM is zero.\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
max >>= 16;
|
||||
} else {
|
||||
if (INTEL_INFO(dev)->gen < 4)
|
||||
max >>= 17;
|
||||
else
|
||||
max >>= 16;
|
||||
|
||||
if (is_backlight_combination_mode(dev))
|
||||
max *= 0xff;
|
||||
}
|
||||
|
||||
DRM_DEBUG("max backlight PWM = %d\n", max);
|
||||
return max;
|
||||
}
|
||||
|
||||
u32 intel_panel_get_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
} else {
|
||||
val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
if (INTEL_INFO(dev)->gen < 4)
|
||||
val >>= 1;
|
||||
|
||||
if (is_backlight_combination_mode(dev)) {
|
||||
u8 lbpc;
|
||||
|
||||
lbpc = pci_read_config(dev->device, PCI_LBPC, 1);
|
||||
val *= lbpc;
|
||||
}
|
||||
}
|
||||
|
||||
DRM_DEBUG("get backlight PWM = %d\n", val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
I915_WRITE(BLC_PWM_CPU_CTL, val | level);
|
||||
}
|
||||
|
||||
static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 tmp;
|
||||
|
||||
DRM_DEBUG("set backlight PWM = %d\n", level);
|
||||
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
return intel_pch_panel_set_backlight(dev, level);
|
||||
|
||||
if (is_backlight_combination_mode(dev)) {
|
||||
u32 max = intel_panel_get_max_backlight(dev);
|
||||
u8 lbpc;
|
||||
|
||||
lbpc = level * 0xfe / max + 1;
|
||||
level /= lbpc;
|
||||
pci_write_config(dev->device, PCI_LBPC, lbpc, 4);
|
||||
}
|
||||
|
||||
tmp = I915_READ(BLC_PWM_CTL);
|
||||
if (INTEL_INFO(dev)->gen < 4)
|
||||
level <<= 1;
|
||||
tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
I915_WRITE(BLC_PWM_CTL, tmp | level);
|
||||
}
|
||||
|
||||
void intel_panel_set_backlight(struct drm_device *dev, u32 level)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
dev_priv->backlight_level = level;
|
||||
if (dev_priv->backlight_enabled)
|
||||
intel_panel_actually_set_backlight(dev, level);
|
||||
}
|
||||
|
||||
void intel_panel_disable_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
dev_priv->backlight_enabled = false;
|
||||
intel_panel_actually_set_backlight(dev, 0);
|
||||
}
|
||||
|
||||
void intel_panel_enable_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->backlight_level == 0)
|
||||
dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
|
||||
|
||||
dev_priv->backlight_enabled = true;
|
||||
intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
|
||||
}
|
||||
|
||||
static void intel_panel_init_backlight(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
dev_priv->backlight_level = intel_panel_get_backlight(dev);
|
||||
dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
|
||||
}
|
||||
|
||||
enum drm_connector_status
|
||||
intel_panel_detect(struct drm_device *dev)
|
||||
{
|
||||
#if 0
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
#endif
|
||||
|
||||
if (i915_panel_ignore_lid)
|
||||
return i915_panel_ignore_lid > 0 ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
|
||||
/* opregion lid state on HP 2540p is wrong at boot up,
|
||||
* appears to be either the BIOS or Linux ACPI fault */
|
||||
#if 0
|
||||
/* Assume that the BIOS does not lie through the OpRegion... */
|
||||
if (dev_priv->opregion.lid_state)
|
||||
return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
#endif
|
||||
|
||||
return connector_status_unknown;
|
||||
}
|
||||
|
||||
int intel_panel_setup_backlight(struct drm_device *dev)
|
||||
{
|
||||
intel_panel_init_backlight(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_panel_destroy_backlight(struct drm_device *dev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
1623
sys/dev/drm2/i915/intel_ringbuffer.c
Normal file
1623
sys/dev/drm2/i915/intel_ringbuffer.c
Normal file
File diff suppressed because it is too large
Load diff
203
sys/dev/drm2/i915/intel_ringbuffer.h
Normal file
203
sys/dev/drm2/i915/intel_ringbuffer.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_RINGBUFFER_H_
|
||||
#define _INTEL_RINGBUFFER_H_
|
||||
|
||||
struct intel_hw_status_page {
|
||||
uint32_t *page_addr;
|
||||
unsigned int gfx_addr;
|
||||
struct drm_i915_gem_object *obj;
|
||||
};
|
||||
|
||||
#define I915_READ_TAIL(ring) I915_READ(RING_TAIL((ring)->mmio_base))
|
||||
#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val)
|
||||
|
||||
#define I915_READ_START(ring) I915_READ(RING_START((ring)->mmio_base))
|
||||
#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val)
|
||||
|
||||
#define I915_READ_HEAD(ring) I915_READ(RING_HEAD((ring)->mmio_base))
|
||||
#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val)
|
||||
|
||||
#define I915_READ_CTL(ring) I915_READ(RING_CTL((ring)->mmio_base))
|
||||
#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val)
|
||||
|
||||
#define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base))
|
||||
#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
|
||||
|
||||
#define I915_READ_NOPID(ring) I915_READ(RING_NOPID((ring)->mmio_base))
|
||||
#define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base))
|
||||
#define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base))
|
||||
|
||||
struct intel_ring_buffer {
|
||||
const char *name;
|
||||
enum intel_ring_id {
|
||||
RCS = 0x0,
|
||||
VCS,
|
||||
BCS,
|
||||
} id;
|
||||
#define I915_NUM_RINGS 3
|
||||
uint32_t mmio_base;
|
||||
void *virtual_start;
|
||||
struct drm_device *dev;
|
||||
struct drm_i915_gem_object *obj;
|
||||
|
||||
uint32_t head;
|
||||
uint32_t tail;
|
||||
int space;
|
||||
int size;
|
||||
int effective_size;
|
||||
struct intel_hw_status_page status_page;
|
||||
|
||||
/** We track the position of the requests in the ring buffer, and
|
||||
* when each is retired we increment last_retired_head as the GPU
|
||||
* must have finished processing the request and so we know we
|
||||
* can advance the ringbuffer up to that position.
|
||||
*
|
||||
* last_retired_head is set to -1 after the value is consumed so
|
||||
* we can detect new retirements.
|
||||
*/
|
||||
u32 last_retired_head;
|
||||
|
||||
struct mtx irq_lock;
|
||||
uint32_t irq_refcount;
|
||||
uint32_t irq_mask;
|
||||
uint32_t irq_seqno; /* last seq seem at irq time */
|
||||
uint32_t trace_irq_seqno;
|
||||
uint32_t waiting_seqno;
|
||||
uint32_t sync_seqno[I915_NUM_RINGS-1];
|
||||
bool (*irq_get)(struct intel_ring_buffer *ring);
|
||||
void (*irq_put)(struct intel_ring_buffer *ring);
|
||||
|
||||
int (*init)(struct intel_ring_buffer *ring);
|
||||
|
||||
void (*write_tail)(struct intel_ring_buffer *ring,
|
||||
uint32_t value);
|
||||
int (*flush)(struct intel_ring_buffer *ring,
|
||||
uint32_t invalidate_domains,
|
||||
uint32_t flush_domains);
|
||||
int (*add_request)(struct intel_ring_buffer *ring,
|
||||
uint32_t *seqno);
|
||||
uint32_t (*get_seqno)(struct intel_ring_buffer *ring);
|
||||
int (*dispatch_execbuffer)(struct intel_ring_buffer *ring,
|
||||
uint32_t offset, uint32_t length);
|
||||
void (*cleanup)(struct intel_ring_buffer *ring);
|
||||
int (*sync_to)(struct intel_ring_buffer *ring,
|
||||
struct intel_ring_buffer *to,
|
||||
u32 seqno);
|
||||
|
||||
u32 semaphore_register[3]; /*our mbox written by others */
|
||||
u32 signal_mbox[2]; /* mboxes this ring signals to */
|
||||
|
||||
/**
|
||||
* List of objects currently involved in rendering from the
|
||||
* ringbuffer.
|
||||
*
|
||||
* Includes buffers having the contents of their GPU caches
|
||||
* flushed, not necessarily primitives. last_rendering_seqno
|
||||
* represents when the rendering involved will be completed.
|
||||
*
|
||||
* A reference is held on the buffer while on this list.
|
||||
*/
|
||||
struct list_head active_list;
|
||||
|
||||
/**
|
||||
* List of breadcrumbs associated with GPU requests currently
|
||||
* outstanding.
|
||||
*/
|
||||
struct list_head request_list;
|
||||
|
||||
/**
|
||||
* List of objects currently pending a GPU write flush.
|
||||
*
|
||||
* All elements on this list will belong to either the
|
||||
* active_list or flushing_list, last_rendering_seqno can
|
||||
* be used to differentiate between the two elements.
|
||||
*/
|
||||
struct list_head gpu_write_list;
|
||||
|
||||
/**
|
||||
* Do we have some not yet emitted requests outstanding?
|
||||
*/
|
||||
uint32_t outstanding_lazy_request;
|
||||
|
||||
drm_local_map_t map;
|
||||
|
||||
void *private;
|
||||
};
|
||||
|
||||
static inline unsigned
|
||||
intel_ring_flag(struct intel_ring_buffer *ring)
|
||||
{
|
||||
return 1 << ring->id;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
intel_ring_sync_index(struct intel_ring_buffer *ring,
|
||||
struct intel_ring_buffer *other)
|
||||
{
|
||||
int idx;
|
||||
|
||||
/*
|
||||
* cs -> 0 = vcs, 1 = bcs
|
||||
* vcs -> 0 = bcs, 1 = cs,
|
||||
* bcs -> 0 = cs, 1 = vcs.
|
||||
*/
|
||||
|
||||
idx = (other - ring) - 1;
|
||||
if (idx < 0)
|
||||
idx += I915_NUM_RINGS;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
intel_read_status_page(struct intel_ring_buffer *ring, int reg)
|
||||
{
|
||||
|
||||
return (atomic_load_acq_32(ring->status_page.page_addr + reg));
|
||||
}
|
||||
|
||||
void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
|
||||
|
||||
int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
|
||||
static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring)
|
||||
{
|
||||
|
||||
return (intel_wait_ring_buffer(ring, ring->size - 8));
|
||||
}
|
||||
|
||||
int intel_ring_begin(struct intel_ring_buffer *ring, int n);
|
||||
|
||||
static inline void intel_ring_emit(struct intel_ring_buffer *ring,
|
||||
uint32_t data)
|
||||
{
|
||||
*(volatile uint32_t *)((char *)ring->virtual_start +
|
||||
ring->tail) = data;
|
||||
ring->tail += 4;
|
||||
}
|
||||
|
||||
void intel_ring_advance(struct intel_ring_buffer *ring);
|
||||
|
||||
uint32_t intel_ring_get_seqno(struct intel_ring_buffer *ring);
|
||||
|
||||
int intel_init_render_ring_buffer(struct drm_device *dev);
|
||||
int intel_init_bsd_ring_buffer(struct drm_device *dev);
|
||||
int intel_init_blt_ring_buffer(struct drm_device *dev);
|
||||
|
||||
u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
|
||||
void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
|
||||
|
||||
static inline u32 intel_ring_get_tail(struct intel_ring_buffer *ring)
|
||||
{
|
||||
return ring->tail;
|
||||
}
|
||||
|
||||
void i915_trace_irq_get(struct intel_ring_buffer *ring, uint32_t seqno);
|
||||
|
||||
/* DRI warts */
|
||||
int intel_render_ring_init_dri(struct drm_device *dev, uint64_t start,
|
||||
uint32_t size);
|
||||
|
||||
#endif /* _INTEL_RINGBUFFER_H_ */
|
||||
2680
sys/dev/drm2/i915/intel_sdvo.c
Normal file
2680
sys/dev/drm2/i915/intel_sdvo.c
Normal file
File diff suppressed because it is too large
Load diff
725
sys/dev/drm2/i915/intel_sdvo_regs.h
Normal file
725
sys/dev/drm2/i915/intel_sdvo_regs.h
Normal file
|
|
@ -0,0 +1,725 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SDVO command definitions and structures.
|
||||
*/
|
||||
|
||||
#define SDVO_OUTPUT_FIRST (0)
|
||||
#define SDVO_OUTPUT_TMDS0 (1 << 0)
|
||||
#define SDVO_OUTPUT_RGB0 (1 << 1)
|
||||
#define SDVO_OUTPUT_CVBS0 (1 << 2)
|
||||
#define SDVO_OUTPUT_SVID0 (1 << 3)
|
||||
#define SDVO_OUTPUT_YPRPB0 (1 << 4)
|
||||
#define SDVO_OUTPUT_SCART0 (1 << 5)
|
||||
#define SDVO_OUTPUT_LVDS0 (1 << 6)
|
||||
#define SDVO_OUTPUT_TMDS1 (1 << 8)
|
||||
#define SDVO_OUTPUT_RGB1 (1 << 9)
|
||||
#define SDVO_OUTPUT_CVBS1 (1 << 10)
|
||||
#define SDVO_OUTPUT_SVID1 (1 << 11)
|
||||
#define SDVO_OUTPUT_YPRPB1 (1 << 12)
|
||||
#define SDVO_OUTPUT_SCART1 (1 << 13)
|
||||
#define SDVO_OUTPUT_LVDS1 (1 << 14)
|
||||
#define SDVO_OUTPUT_LAST (14)
|
||||
|
||||
struct intel_sdvo_caps {
|
||||
u8 vendor_id;
|
||||
u8 device_id;
|
||||
u8 device_rev_id;
|
||||
u8 sdvo_version_major;
|
||||
u8 sdvo_version_minor;
|
||||
unsigned int sdvo_inputs_mask:2;
|
||||
unsigned int smooth_scaling:1;
|
||||
unsigned int sharp_scaling:1;
|
||||
unsigned int up_scaling:1;
|
||||
unsigned int down_scaling:1;
|
||||
unsigned int stall_support:1;
|
||||
unsigned int pad:1;
|
||||
u16 output_flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
/** This matches the EDID DTD structure, more or less */
|
||||
struct intel_sdvo_dtd {
|
||||
struct {
|
||||
u16 clock; /**< pixel clock, in 10kHz units */
|
||||
u8 h_active; /**< lower 8 bits (pixels) */
|
||||
u8 h_blank; /**< lower 8 bits (pixels) */
|
||||
u8 h_high; /**< upper 4 bits each h_active, h_blank */
|
||||
u8 v_active; /**< lower 8 bits (lines) */
|
||||
u8 v_blank; /**< lower 8 bits (lines) */
|
||||
u8 v_high; /**< upper 4 bits each v_active, v_blank */
|
||||
} part1;
|
||||
|
||||
struct {
|
||||
u8 h_sync_off; /**< lower 8 bits, from hblank start */
|
||||
u8 h_sync_width; /**< lower 8 bits (pixels) */
|
||||
/** lower 4 bits each vsync offset, vsync width */
|
||||
u8 v_sync_off_width;
|
||||
/**
|
||||
* 2 high bits of hsync offset, 2 high bits of hsync width,
|
||||
* bits 4-5 of vsync offset, and 2 high bits of vsync width.
|
||||
*/
|
||||
u8 sync_off_width_high;
|
||||
u8 dtd_flags;
|
||||
u8 sdvo_flags;
|
||||
/** bits 6-7 of vsync offset at bits 6-7 */
|
||||
u8 v_sync_off_high;
|
||||
u8 reserved;
|
||||
} part2;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct intel_sdvo_pixel_clock_range {
|
||||
u16 min; /**< pixel clock, in 10kHz units */
|
||||
u16 max; /**< pixel clock, in 10kHz units */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct intel_sdvo_preferred_input_timing_args {
|
||||
u16 clock;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u8 interlace:1;
|
||||
u8 scaled:1;
|
||||
u8 pad:6;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* I2C registers for SDVO */
|
||||
#define SDVO_I2C_ARG_0 0x07
|
||||
#define SDVO_I2C_ARG_1 0x06
|
||||
#define SDVO_I2C_ARG_2 0x05
|
||||
#define SDVO_I2C_ARG_3 0x04
|
||||
#define SDVO_I2C_ARG_4 0x03
|
||||
#define SDVO_I2C_ARG_5 0x02
|
||||
#define SDVO_I2C_ARG_6 0x01
|
||||
#define SDVO_I2C_ARG_7 0x00
|
||||
#define SDVO_I2C_OPCODE 0x08
|
||||
#define SDVO_I2C_CMD_STATUS 0x09
|
||||
#define SDVO_I2C_RETURN_0 0x0a
|
||||
#define SDVO_I2C_RETURN_1 0x0b
|
||||
#define SDVO_I2C_RETURN_2 0x0c
|
||||
#define SDVO_I2C_RETURN_3 0x0d
|
||||
#define SDVO_I2C_RETURN_4 0x0e
|
||||
#define SDVO_I2C_RETURN_5 0x0f
|
||||
#define SDVO_I2C_RETURN_6 0x10
|
||||
#define SDVO_I2C_RETURN_7 0x11
|
||||
#define SDVO_I2C_VENDOR_BEGIN 0x20
|
||||
|
||||
/* Status results */
|
||||
#define SDVO_CMD_STATUS_POWER_ON 0x0
|
||||
#define SDVO_CMD_STATUS_SUCCESS 0x1
|
||||
#define SDVO_CMD_STATUS_NOTSUPP 0x2
|
||||
#define SDVO_CMD_STATUS_INVALID_ARG 0x3
|
||||
#define SDVO_CMD_STATUS_PENDING 0x4
|
||||
#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED 0x5
|
||||
#define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6
|
||||
|
||||
/* SDVO commands, argument/result registers */
|
||||
|
||||
#define SDVO_CMD_RESET 0x01
|
||||
|
||||
/** Returns a struct intel_sdvo_caps */
|
||||
#define SDVO_CMD_GET_DEVICE_CAPS 0x02
|
||||
|
||||
#define SDVO_CMD_GET_FIRMWARE_REV 0x86
|
||||
# define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0
|
||||
# define SDVO_DEVICE_FIRMWARE_MAJOR SDVO_I2C_RETURN_1
|
||||
# define SDVO_DEVICE_FIRMWARE_PATCH SDVO_I2C_RETURN_2
|
||||
|
||||
/**
|
||||
* Reports which inputs are trained (managed to sync).
|
||||
*
|
||||
* Devices must have trained within 2 vsyncs of a mode change.
|
||||
*/
|
||||
#define SDVO_CMD_GET_TRAINED_INPUTS 0x03
|
||||
struct intel_sdvo_get_trained_inputs_response {
|
||||
unsigned int input0_trained:1;
|
||||
unsigned int input1_trained:1;
|
||||
unsigned int pad:6;
|
||||
} __attribute__((packed));
|
||||
|
||||
/** Returns a struct intel_sdvo_output_flags of active outputs. */
|
||||
#define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04
|
||||
|
||||
/**
|
||||
* Sets the current set of active outputs.
|
||||
*
|
||||
* Takes a struct intel_sdvo_output_flags. Must be preceded by a SET_IN_OUT_MAP
|
||||
* on multi-output devices.
|
||||
*/
|
||||
#define SDVO_CMD_SET_ACTIVE_OUTPUTS 0x05
|
||||
|
||||
/**
|
||||
* Returns the current mapping of SDVO inputs to outputs on the device.
|
||||
*
|
||||
* Returns two struct intel_sdvo_output_flags structures.
|
||||
*/
|
||||
#define SDVO_CMD_GET_IN_OUT_MAP 0x06
|
||||
struct intel_sdvo_in_out_map {
|
||||
u16 in0, in1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the current mapping of SDVO inputs to outputs on the device.
|
||||
*
|
||||
* Takes two struct i380_sdvo_output_flags structures.
|
||||
*/
|
||||
#define SDVO_CMD_SET_IN_OUT_MAP 0x07
|
||||
|
||||
/**
|
||||
* Returns a struct intel_sdvo_output_flags of attached displays.
|
||||
*/
|
||||
#define SDVO_CMD_GET_ATTACHED_DISPLAYS 0x0b
|
||||
|
||||
/**
|
||||
* Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging.
|
||||
*/
|
||||
#define SDVO_CMD_GET_HOT_PLUG_SUPPORT 0x0c
|
||||
|
||||
/**
|
||||
* Takes a struct intel_sdvo_output_flags.
|
||||
*/
|
||||
#define SDVO_CMD_SET_ACTIVE_HOT_PLUG 0x0d
|
||||
|
||||
/**
|
||||
* Returns a struct intel_sdvo_output_flags of displays with hot plug
|
||||
* interrupts enabled.
|
||||
*/
|
||||
#define SDVO_CMD_GET_ACTIVE_HOT_PLUG 0x0e
|
||||
|
||||
#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE 0x0f
|
||||
struct intel_sdvo_get_interrupt_event_source_response {
|
||||
u16 interrupt_status;
|
||||
unsigned int ambient_light_interrupt:1;
|
||||
unsigned int hdmi_audio_encrypt_change:1;
|
||||
unsigned int pad:6;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* Selects which input is affected by future input commands.
|
||||
*
|
||||
* Commands affected include SET_INPUT_TIMINGS_PART[12],
|
||||
* GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12],
|
||||
* GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS.
|
||||
*/
|
||||
#define SDVO_CMD_SET_TARGET_INPUT 0x10
|
||||
struct intel_sdvo_set_target_input_args {
|
||||
unsigned int target_1:1;
|
||||
unsigned int pad:7;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* Takes a struct intel_sdvo_output_flags of which outputs are targeted by
|
||||
* future output commands.
|
||||
*
|
||||
* Affected commands inclue SET_OUTPUT_TIMINGS_PART[12],
|
||||
* GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE.
|
||||
*/
|
||||
#define SDVO_CMD_SET_TARGET_OUTPUT 0x11
|
||||
|
||||
#define SDVO_CMD_GET_INPUT_TIMINGS_PART1 0x12
|
||||
#define SDVO_CMD_GET_INPUT_TIMINGS_PART2 0x13
|
||||
#define SDVO_CMD_SET_INPUT_TIMINGS_PART1 0x14
|
||||
#define SDVO_CMD_SET_INPUT_TIMINGS_PART2 0x15
|
||||
#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1 0x16
|
||||
#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2 0x17
|
||||
#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1 0x18
|
||||
#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2 0x19
|
||||
/* Part 1 */
|
||||
# define SDVO_DTD_CLOCK_LOW SDVO_I2C_ARG_0
|
||||
# define SDVO_DTD_CLOCK_HIGH SDVO_I2C_ARG_1
|
||||
# define SDVO_DTD_H_ACTIVE SDVO_I2C_ARG_2
|
||||
# define SDVO_DTD_H_BLANK SDVO_I2C_ARG_3
|
||||
# define SDVO_DTD_H_HIGH SDVO_I2C_ARG_4
|
||||
# define SDVO_DTD_V_ACTIVE SDVO_I2C_ARG_5
|
||||
# define SDVO_DTD_V_BLANK SDVO_I2C_ARG_6
|
||||
# define SDVO_DTD_V_HIGH SDVO_I2C_ARG_7
|
||||
/* Part 2 */
|
||||
# define SDVO_DTD_HSYNC_OFF SDVO_I2C_ARG_0
|
||||
# define SDVO_DTD_HSYNC_WIDTH SDVO_I2C_ARG_1
|
||||
# define SDVO_DTD_VSYNC_OFF_WIDTH SDVO_I2C_ARG_2
|
||||
# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH SDVO_I2C_ARG_3
|
||||
# define SDVO_DTD_DTD_FLAGS SDVO_I2C_ARG_4
|
||||
# define SDVO_DTD_DTD_FLAG_INTERLACED (1 << 7)
|
||||
# define SDVO_DTD_DTD_FLAG_STEREO_MASK (3 << 5)
|
||||
# define SDVO_DTD_DTD_FLAG_INPUT_MASK (3 << 3)
|
||||
# define SDVO_DTD_DTD_FLAG_SYNC_MASK (3 << 1)
|
||||
# define SDVO_DTD_SDVO_FLAS SDVO_I2C_ARG_5
|
||||
# define SDVO_DTD_SDVO_FLAG_STALL (1 << 7)
|
||||
# define SDVO_DTD_SDVO_FLAG_CENTERED (0 << 6)
|
||||
# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT (1 << 6)
|
||||
# define SDVO_DTD_SDVO_FLAG_SCALING_MASK (3 << 4)
|
||||
# define SDVO_DTD_SDVO_FLAG_SCALING_NONE (0 << 4)
|
||||
# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP (1 << 4)
|
||||
# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH (2 << 4)
|
||||
# define SDVO_DTD_VSYNC_OFF_HIGH SDVO_I2C_ARG_6
|
||||
|
||||
/**
|
||||
* Generates a DTD based on the given width, height, and flags.
|
||||
*
|
||||
* This will be supported by any device supporting scaling or interlaced
|
||||
* modes.
|
||||
*/
|
||||
#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING 0x1a
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW SDVO_I2C_ARG_0
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH SDVO_I2C_ARG_1
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW SDVO_I2C_ARG_2
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH SDVO_I2C_ARG_3
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW SDVO_I2C_ARG_4
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH SDVO_I2C_ARG_5
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_FLAGS SDVO_I2C_ARG_6
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED (1 << 0)
|
||||
# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED (1 << 1)
|
||||
|
||||
#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1 0x1b
|
||||
#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2 0x1c
|
||||
|
||||
/** Returns a struct intel_sdvo_pixel_clock_range */
|
||||
#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE 0x1d
|
||||
/** Returns a struct intel_sdvo_pixel_clock_range */
|
||||
#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e
|
||||
|
||||
/** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */
|
||||
#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f
|
||||
|
||||
/** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
|
||||
#define SDVO_CMD_GET_CLOCK_RATE_MULT 0x20
|
||||
/** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
|
||||
#define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21
|
||||
# define SDVO_CLOCK_RATE_MULT_1X (1 << 0)
|
||||
# define SDVO_CLOCK_RATE_MULT_2X (1 << 1)
|
||||
# define SDVO_CLOCK_RATE_MULT_4X (1 << 3)
|
||||
|
||||
#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27
|
||||
/** 6 bytes of bit flags for TV formats shared by all TV format functions */
|
||||
struct intel_sdvo_tv_format {
|
||||
unsigned int ntsc_m:1;
|
||||
unsigned int ntsc_j:1;
|
||||
unsigned int ntsc_443:1;
|
||||
unsigned int pal_b:1;
|
||||
unsigned int pal_d:1;
|
||||
unsigned int pal_g:1;
|
||||
unsigned int pal_h:1;
|
||||
unsigned int pal_i:1;
|
||||
|
||||
unsigned int pal_m:1;
|
||||
unsigned int pal_n:1;
|
||||
unsigned int pal_nc:1;
|
||||
unsigned int pal_60:1;
|
||||
unsigned int secam_b:1;
|
||||
unsigned int secam_d:1;
|
||||
unsigned int secam_g:1;
|
||||
unsigned int secam_k:1;
|
||||
|
||||
unsigned int secam_k1:1;
|
||||
unsigned int secam_l:1;
|
||||
unsigned int secam_60:1;
|
||||
unsigned int hdtv_std_smpte_240m_1080i_59:1;
|
||||
unsigned int hdtv_std_smpte_240m_1080i_60:1;
|
||||
unsigned int hdtv_std_smpte_260m_1080i_59:1;
|
||||
unsigned int hdtv_std_smpte_260m_1080i_60:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080i_50:1;
|
||||
|
||||
unsigned int hdtv_std_smpte_274m_1080i_59:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080i_60:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_23:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_24:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_25:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_29:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_30:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_50:1;
|
||||
|
||||
unsigned int hdtv_std_smpte_274m_1080p_59:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_60:1;
|
||||
unsigned int hdtv_std_smpte_295m_1080i_50:1;
|
||||
unsigned int hdtv_std_smpte_295m_1080p_50:1;
|
||||
unsigned int hdtv_std_smpte_296m_720p_59:1;
|
||||
unsigned int hdtv_std_smpte_296m_720p_60:1;
|
||||
unsigned int hdtv_std_smpte_296m_720p_50:1;
|
||||
unsigned int hdtv_std_smpte_293m_480p_59:1;
|
||||
|
||||
unsigned int hdtv_std_smpte_170m_480i_59:1;
|
||||
unsigned int hdtv_std_iturbt601_576i_50:1;
|
||||
unsigned int hdtv_std_iturbt601_576p_50:1;
|
||||
unsigned int hdtv_std_eia_7702a_480i_60:1;
|
||||
unsigned int hdtv_std_eia_7702a_480p_60:1;
|
||||
unsigned int pad:3;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SDVO_CMD_GET_TV_FORMAT 0x28
|
||||
|
||||
#define SDVO_CMD_SET_TV_FORMAT 0x29
|
||||
|
||||
/** Returns the resolutiosn that can be used with the given TV format */
|
||||
#define SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT 0x83
|
||||
struct intel_sdvo_sdtv_resolution_request {
|
||||
unsigned int ntsc_m:1;
|
||||
unsigned int ntsc_j:1;
|
||||
unsigned int ntsc_443:1;
|
||||
unsigned int pal_b:1;
|
||||
unsigned int pal_d:1;
|
||||
unsigned int pal_g:1;
|
||||
unsigned int pal_h:1;
|
||||
unsigned int pal_i:1;
|
||||
|
||||
unsigned int pal_m:1;
|
||||
unsigned int pal_n:1;
|
||||
unsigned int pal_nc:1;
|
||||
unsigned int pal_60:1;
|
||||
unsigned int secam_b:1;
|
||||
unsigned int secam_d:1;
|
||||
unsigned int secam_g:1;
|
||||
unsigned int secam_k:1;
|
||||
|
||||
unsigned int secam_k1:1;
|
||||
unsigned int secam_l:1;
|
||||
unsigned int secam_60:1;
|
||||
unsigned int pad:5;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct intel_sdvo_sdtv_resolution_reply {
|
||||
unsigned int res_320x200:1;
|
||||
unsigned int res_320x240:1;
|
||||
unsigned int res_400x300:1;
|
||||
unsigned int res_640x350:1;
|
||||
unsigned int res_640x400:1;
|
||||
unsigned int res_640x480:1;
|
||||
unsigned int res_704x480:1;
|
||||
unsigned int res_704x576:1;
|
||||
|
||||
unsigned int res_720x350:1;
|
||||
unsigned int res_720x400:1;
|
||||
unsigned int res_720x480:1;
|
||||
unsigned int res_720x540:1;
|
||||
unsigned int res_720x576:1;
|
||||
unsigned int res_768x576:1;
|
||||
unsigned int res_800x600:1;
|
||||
unsigned int res_832x624:1;
|
||||
|
||||
unsigned int res_920x766:1;
|
||||
unsigned int res_1024x768:1;
|
||||
unsigned int res_1280x1024:1;
|
||||
unsigned int pad:5;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Get supported resolution with squire pixel aspect ratio that can be
|
||||
scaled for the requested HDTV format */
|
||||
#define SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT 0x85
|
||||
|
||||
struct intel_sdvo_hdtv_resolution_request {
|
||||
unsigned int hdtv_std_smpte_240m_1080i_59:1;
|
||||
unsigned int hdtv_std_smpte_240m_1080i_60:1;
|
||||
unsigned int hdtv_std_smpte_260m_1080i_59:1;
|
||||
unsigned int hdtv_std_smpte_260m_1080i_60:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080i_50:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080i_59:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080i_60:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_23:1;
|
||||
|
||||
unsigned int hdtv_std_smpte_274m_1080p_24:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_25:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_29:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_30:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_50:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_59:1;
|
||||
unsigned int hdtv_std_smpte_274m_1080p_60:1;
|
||||
unsigned int hdtv_std_smpte_295m_1080i_50:1;
|
||||
|
||||
unsigned int hdtv_std_smpte_295m_1080p_50:1;
|
||||
unsigned int hdtv_std_smpte_296m_720p_59:1;
|
||||
unsigned int hdtv_std_smpte_296m_720p_60:1;
|
||||
unsigned int hdtv_std_smpte_296m_720p_50:1;
|
||||
unsigned int hdtv_std_smpte_293m_480p_59:1;
|
||||
unsigned int hdtv_std_smpte_170m_480i_59:1;
|
||||
unsigned int hdtv_std_iturbt601_576i_50:1;
|
||||
unsigned int hdtv_std_iturbt601_576p_50:1;
|
||||
|
||||
unsigned int hdtv_std_eia_7702a_480i_60:1;
|
||||
unsigned int hdtv_std_eia_7702a_480p_60:1;
|
||||
unsigned int pad:6;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct intel_sdvo_hdtv_resolution_reply {
|
||||
unsigned int res_640x480:1;
|
||||
unsigned int res_800x600:1;
|
||||
unsigned int res_1024x768:1;
|
||||
unsigned int res_1280x960:1;
|
||||
unsigned int res_1400x1050:1;
|
||||
unsigned int res_1600x1200:1;
|
||||
unsigned int res_1920x1440:1;
|
||||
unsigned int res_2048x1536:1;
|
||||
|
||||
unsigned int res_2560x1920:1;
|
||||
unsigned int res_3200x2400:1;
|
||||
unsigned int res_3840x2880:1;
|
||||
unsigned int pad1:5;
|
||||
|
||||
unsigned int res_848x480:1;
|
||||
unsigned int res_1064x600:1;
|
||||
unsigned int res_1280x720:1;
|
||||
unsigned int res_1360x768:1;
|
||||
unsigned int res_1704x960:1;
|
||||
unsigned int res_1864x1050:1;
|
||||
unsigned int res_1920x1080:1;
|
||||
unsigned int res_2128x1200:1;
|
||||
|
||||
unsigned int res_2560x1400:1;
|
||||
unsigned int res_2728x1536:1;
|
||||
unsigned int res_3408x1920:1;
|
||||
unsigned int res_4264x2400:1;
|
||||
unsigned int res_5120x2880:1;
|
||||
unsigned int pad2:3;
|
||||
|
||||
unsigned int res_768x480:1;
|
||||
unsigned int res_960x600:1;
|
||||
unsigned int res_1152x720:1;
|
||||
unsigned int res_1124x768:1;
|
||||
unsigned int res_1536x960:1;
|
||||
unsigned int res_1680x1050:1;
|
||||
unsigned int res_1728x1080:1;
|
||||
unsigned int res_1920x1200:1;
|
||||
|
||||
unsigned int res_2304x1440:1;
|
||||
unsigned int res_2456x1536:1;
|
||||
unsigned int res_3072x1920:1;
|
||||
unsigned int res_3840x2400:1;
|
||||
unsigned int res_4608x2880:1;
|
||||
unsigned int pad3:3;
|
||||
|
||||
unsigned int res_1280x1024:1;
|
||||
unsigned int pad4:7;
|
||||
|
||||
unsigned int res_1280x768:1;
|
||||
unsigned int pad5:7;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Get supported power state returns info for encoder and monitor, rely on
|
||||
last SetTargetInput and SetTargetOutput calls */
|
||||
#define SDVO_CMD_GET_SUPPORTED_POWER_STATES 0x2a
|
||||
/* Get power state returns info for encoder and monitor, rely on last
|
||||
SetTargetInput and SetTargetOutput calls */
|
||||
#define SDVO_CMD_GET_POWER_STATE 0x2b
|
||||
#define SDVO_CMD_GET_ENCODER_POWER_STATE 0x2b
|
||||
#define SDVO_CMD_SET_ENCODER_POWER_STATE 0x2c
|
||||
# define SDVO_ENCODER_STATE_ON (1 << 0)
|
||||
# define SDVO_ENCODER_STATE_STANDBY (1 << 1)
|
||||
# define SDVO_ENCODER_STATE_SUSPEND (1 << 2)
|
||||
# define SDVO_ENCODER_STATE_OFF (1 << 3)
|
||||
# define SDVO_MONITOR_STATE_ON (1 << 4)
|
||||
# define SDVO_MONITOR_STATE_STANDBY (1 << 5)
|
||||
# define SDVO_MONITOR_STATE_SUSPEND (1 << 6)
|
||||
# define SDVO_MONITOR_STATE_OFF (1 << 7)
|
||||
|
||||
#define SDVO_CMD_GET_MAX_PANEL_POWER_SEQUENCING 0x2d
|
||||
#define SDVO_CMD_GET_PANEL_POWER_SEQUENCING 0x2e
|
||||
#define SDVO_CMD_SET_PANEL_POWER_SEQUENCING 0x2f
|
||||
/**
|
||||
* The panel power sequencing parameters are in units of milliseconds.
|
||||
* The high fields are bits 8:9 of the 10-bit values.
|
||||
*/
|
||||
struct sdvo_panel_power_sequencing {
|
||||
u8 t0;
|
||||
u8 t1;
|
||||
u8 t2;
|
||||
u8 t3;
|
||||
u8 t4;
|
||||
|
||||
unsigned int t0_high:2;
|
||||
unsigned int t1_high:2;
|
||||
unsigned int t2_high:2;
|
||||
unsigned int t3_high:2;
|
||||
|
||||
unsigned int t4_high:2;
|
||||
unsigned int pad:6;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL 0x30
|
||||
struct sdvo_max_backlight_reply {
|
||||
u8 max_value;
|
||||
u8 default_value;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SDVO_CMD_GET_BACKLIGHT_LEVEL 0x31
|
||||
#define SDVO_CMD_SET_BACKLIGHT_LEVEL 0x32
|
||||
|
||||
#define SDVO_CMD_GET_AMBIENT_LIGHT 0x33
|
||||
struct sdvo_get_ambient_light_reply {
|
||||
u16 trip_low;
|
||||
u16 trip_high;
|
||||
u16 value;
|
||||
} __attribute__((packed));
|
||||
#define SDVO_CMD_SET_AMBIENT_LIGHT 0x34
|
||||
struct sdvo_set_ambient_light_reply {
|
||||
u16 trip_low;
|
||||
u16 trip_high;
|
||||
unsigned int enable:1;
|
||||
unsigned int pad:7;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Set display power state */
|
||||
#define SDVO_CMD_SET_DISPLAY_POWER_STATE 0x7d
|
||||
# define SDVO_DISPLAY_STATE_ON (1 << 0)
|
||||
# define SDVO_DISPLAY_STATE_STANDBY (1 << 1)
|
||||
# define SDVO_DISPLAY_STATE_SUSPEND (1 << 2)
|
||||
# define SDVO_DISPLAY_STATE_OFF (1 << 3)
|
||||
|
||||
#define SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS 0x84
|
||||
struct intel_sdvo_enhancements_reply {
|
||||
unsigned int flicker_filter:1;
|
||||
unsigned int flicker_filter_adaptive:1;
|
||||
unsigned int flicker_filter_2d:1;
|
||||
unsigned int saturation:1;
|
||||
unsigned int hue:1;
|
||||
unsigned int brightness:1;
|
||||
unsigned int contrast:1;
|
||||
unsigned int overscan_h:1;
|
||||
|
||||
unsigned int overscan_v:1;
|
||||
unsigned int hpos:1;
|
||||
unsigned int vpos:1;
|
||||
unsigned int sharpness:1;
|
||||
unsigned int dot_crawl:1;
|
||||
unsigned int dither:1;
|
||||
unsigned int tv_chroma_filter:1;
|
||||
unsigned int tv_luma_filter:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Picture enhancement limits below are dependent on the current TV format,
|
||||
* and thus need to be queried and set after it.
|
||||
*/
|
||||
#define SDVO_CMD_GET_MAX_FLICKER_FILTER 0x4d
|
||||
#define SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE 0x7b
|
||||
#define SDVO_CMD_GET_MAX_FLICKER_FILTER_2D 0x52
|
||||
#define SDVO_CMD_GET_MAX_SATURATION 0x55
|
||||
#define SDVO_CMD_GET_MAX_HUE 0x58
|
||||
#define SDVO_CMD_GET_MAX_BRIGHTNESS 0x5b
|
||||
#define SDVO_CMD_GET_MAX_CONTRAST 0x5e
|
||||
#define SDVO_CMD_GET_MAX_OVERSCAN_H 0x61
|
||||
#define SDVO_CMD_GET_MAX_OVERSCAN_V 0x64
|
||||
#define SDVO_CMD_GET_MAX_HPOS 0x67
|
||||
#define SDVO_CMD_GET_MAX_VPOS 0x6a
|
||||
#define SDVO_CMD_GET_MAX_SHARPNESS 0x6d
|
||||
#define SDVO_CMD_GET_MAX_TV_CHROMA_FILTER 0x74
|
||||
#define SDVO_CMD_GET_MAX_TV_LUMA_FILTER 0x77
|
||||
struct intel_sdvo_enhancement_limits_reply {
|
||||
u16 max_value;
|
||||
u16 default_value;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SDVO_CMD_GET_LVDS_PANEL_INFORMATION 0x7f
|
||||
#define SDVO_CMD_SET_LVDS_PANEL_INFORMATION 0x80
|
||||
# define SDVO_LVDS_COLOR_DEPTH_18 (0 << 0)
|
||||
# define SDVO_LVDS_COLOR_DEPTH_24 (1 << 0)
|
||||
# define SDVO_LVDS_CONNECTOR_SPWG (0 << 2)
|
||||
# define SDVO_LVDS_CONNECTOR_OPENLDI (1 << 2)
|
||||
# define SDVO_LVDS_SINGLE_CHANNEL (0 << 4)
|
||||
# define SDVO_LVDS_DUAL_CHANNEL (1 << 4)
|
||||
|
||||
#define SDVO_CMD_GET_FLICKER_FILTER 0x4e
|
||||
#define SDVO_CMD_SET_FLICKER_FILTER 0x4f
|
||||
#define SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE 0x50
|
||||
#define SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE 0x51
|
||||
#define SDVO_CMD_GET_FLICKER_FILTER_2D 0x53
|
||||
#define SDVO_CMD_SET_FLICKER_FILTER_2D 0x54
|
||||
#define SDVO_CMD_GET_SATURATION 0x56
|
||||
#define SDVO_CMD_SET_SATURATION 0x57
|
||||
#define SDVO_CMD_GET_HUE 0x59
|
||||
#define SDVO_CMD_SET_HUE 0x5a
|
||||
#define SDVO_CMD_GET_BRIGHTNESS 0x5c
|
||||
#define SDVO_CMD_SET_BRIGHTNESS 0x5d
|
||||
#define SDVO_CMD_GET_CONTRAST 0x5f
|
||||
#define SDVO_CMD_SET_CONTRAST 0x60
|
||||
#define SDVO_CMD_GET_OVERSCAN_H 0x62
|
||||
#define SDVO_CMD_SET_OVERSCAN_H 0x63
|
||||
#define SDVO_CMD_GET_OVERSCAN_V 0x65
|
||||
#define SDVO_CMD_SET_OVERSCAN_V 0x66
|
||||
#define SDVO_CMD_GET_HPOS 0x68
|
||||
#define SDVO_CMD_SET_HPOS 0x69
|
||||
#define SDVO_CMD_GET_VPOS 0x6b
|
||||
#define SDVO_CMD_SET_VPOS 0x6c
|
||||
#define SDVO_CMD_GET_SHARPNESS 0x6e
|
||||
#define SDVO_CMD_SET_SHARPNESS 0x6f
|
||||
#define SDVO_CMD_GET_TV_CHROMA_FILTER 0x75
|
||||
#define SDVO_CMD_SET_TV_CHROMA_FILTER 0x76
|
||||
#define SDVO_CMD_GET_TV_LUMA_FILTER 0x78
|
||||
#define SDVO_CMD_SET_TV_LUMA_FILTER 0x79
|
||||
struct intel_sdvo_enhancements_arg {
|
||||
u16 value;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SDVO_CMD_GET_DOT_CRAWL 0x70
|
||||
#define SDVO_CMD_SET_DOT_CRAWL 0x71
|
||||
# define SDVO_DOT_CRAWL_ON (1 << 0)
|
||||
# define SDVO_DOT_CRAWL_DEFAULT_ON (1 << 1)
|
||||
|
||||
#define SDVO_CMD_GET_DITHER 0x72
|
||||
#define SDVO_CMD_SET_DITHER 0x73
|
||||
# define SDVO_DITHER_ON (1 << 0)
|
||||
# define SDVO_DITHER_DEFAULT_ON (1 << 1)
|
||||
|
||||
#define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a
|
||||
# define SDVO_CONTROL_BUS_PROM (1 << 0)
|
||||
# define SDVO_CONTROL_BUS_DDC1 (1 << 1)
|
||||
# define SDVO_CONTROL_BUS_DDC2 (1 << 2)
|
||||
# define SDVO_CONTROL_BUS_DDC3 (1 << 3)
|
||||
|
||||
/* HDMI op codes */
|
||||
#define SDVO_CMD_GET_SUPP_ENCODE 0x9d
|
||||
#define SDVO_CMD_GET_ENCODE 0x9e
|
||||
#define SDVO_CMD_SET_ENCODE 0x9f
|
||||
#define SDVO_ENCODE_DVI 0x0
|
||||
#define SDVO_ENCODE_HDMI 0x1
|
||||
#define SDVO_CMD_SET_PIXEL_REPLI 0x8b
|
||||
#define SDVO_CMD_GET_PIXEL_REPLI 0x8c
|
||||
#define SDVO_CMD_GET_COLORIMETRY_CAP 0x8d
|
||||
#define SDVO_CMD_SET_COLORIMETRY 0x8e
|
||||
#define SDVO_COLORIMETRY_RGB256 0x0
|
||||
#define SDVO_COLORIMETRY_RGB220 0x1
|
||||
#define SDVO_COLORIMETRY_YCrCb422 0x3
|
||||
#define SDVO_COLORIMETRY_YCrCb444 0x4
|
||||
#define SDVO_CMD_GET_COLORIMETRY 0x8f
|
||||
#define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90
|
||||
#define SDVO_CMD_SET_AUDIO_STAT 0x91
|
||||
#define SDVO_CMD_GET_AUDIO_STAT 0x92
|
||||
#define SDVO_CMD_SET_HBUF_INDEX 0x93
|
||||
#define SDVO_CMD_GET_HBUF_INDEX 0x94
|
||||
#define SDVO_CMD_GET_HBUF_INFO 0x95
|
||||
#define SDVO_CMD_SET_HBUF_AV_SPLIT 0x96
|
||||
#define SDVO_CMD_GET_HBUF_AV_SPLIT 0x97
|
||||
#define SDVO_CMD_SET_HBUF_DATA 0x98
|
||||
#define SDVO_CMD_GET_HBUF_DATA 0x99
|
||||
#define SDVO_CMD_SET_HBUF_TXRATE 0x9a
|
||||
#define SDVO_CMD_GET_HBUF_TXRATE 0x9b
|
||||
#define SDVO_HBUF_TX_DISABLED (0 << 6)
|
||||
#define SDVO_HBUF_TX_ONCE (2 << 6)
|
||||
#define SDVO_HBUF_TX_VSYNC (3 << 6)
|
||||
#define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c
|
||||
#define SDVO_NEED_TO_STALL (1 << 7)
|
||||
|
||||
struct intel_sdvo_encode {
|
||||
u8 dvi_rev;
|
||||
u8 hdmi_rev;
|
||||
} __attribute__ ((packed));
|
||||
669
sys/dev/drm2/i915/intel_sprite.c
Normal file
669
sys/dev/drm2/i915/intel_sprite.c
Normal file
|
|
@ -0,0 +1,669 @@
|
|||
/*
|
||||
* Copyright © 2011 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Jesse Barnes <jbarnes@virtuousgeek.org>
|
||||
*
|
||||
* New plane/sprite handling.
|
||||
*
|
||||
* The older chips had a separate interface for programming plane related
|
||||
* registers; newer ones are much simpler and we can use the new DRM plane
|
||||
* support.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/drm2/drmP.h>
|
||||
#include <dev/drm2/drm.h>
|
||||
#include <dev/drm2/i915/i915_drm.h>
|
||||
#include <dev/drm2/i915/i915_drv.h>
|
||||
#include <dev/drm2/i915/intel_drv.h>
|
||||
#include <dev/drm2/drm_fourcc.h>
|
||||
|
||||
static void
|
||||
ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
|
||||
unsigned int crtc_w, unsigned int crtc_h,
|
||||
uint32_t x, uint32_t y,
|
||||
uint32_t src_w, uint32_t src_h)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int pipe = intel_plane->pipe;
|
||||
u32 sprctl, sprscale = 0;
|
||||
int pixel_size;
|
||||
|
||||
sprctl = I915_READ(SPRCTL(pipe));
|
||||
|
||||
/* Mask out pixel format bits in case we change it */
|
||||
sprctl &= ~SPRITE_PIXFORMAT_MASK;
|
||||
sprctl &= ~SPRITE_RGB_ORDER_RGBX;
|
||||
sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
|
||||
|
||||
switch (fb->pixel_format) {
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
sprctl |= SPRITE_FORMAT_RGBX888;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
case DRM_FORMAT_YUYV:
|
||||
sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_YVYU:
|
||||
sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_UYVY:
|
||||
sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_VYUY:
|
||||
sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
|
||||
sprctl |= DVS_FORMAT_RGBX888;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
sprctl |= SPRITE_TILED;
|
||||
|
||||
/* must disable */
|
||||
sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
|
||||
sprctl |= SPRITE_ENABLE;
|
||||
|
||||
/* Sizes are 0 based */
|
||||
src_w--;
|
||||
src_h--;
|
||||
crtc_w--;
|
||||
crtc_h--;
|
||||
|
||||
intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
|
||||
|
||||
/*
|
||||
* IVB workaround: must disable low power watermarks for at least
|
||||
* one frame before enabling scaling. LP watermarks can be re-enabled
|
||||
* when scaling is disabled.
|
||||
*/
|
||||
if (crtc_w != src_w || crtc_h != src_h) {
|
||||
dev_priv->sprite_scaling_enabled = true;
|
||||
sandybridge_update_wm(dev);
|
||||
intel_wait_for_vblank(dev, pipe);
|
||||
sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
|
||||
} else {
|
||||
dev_priv->sprite_scaling_enabled = false;
|
||||
/* potentially re-enable LP watermarks */
|
||||
sandybridge_update_wm(dev);
|
||||
}
|
||||
|
||||
I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
|
||||
I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
|
||||
if (obj->tiling_mode != I915_TILING_NONE) {
|
||||
I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
|
||||
} else {
|
||||
unsigned long offset;
|
||||
|
||||
offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
|
||||
I915_WRITE(SPRLINOFF(pipe), offset);
|
||||
}
|
||||
I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
|
||||
I915_WRITE(SPRSCALE(pipe), sprscale);
|
||||
I915_WRITE(SPRCTL(pipe), sprctl);
|
||||
I915_WRITE(SPRSURF(pipe), obj->gtt_offset);
|
||||
POSTING_READ(SPRSURF(pipe));
|
||||
}
|
||||
|
||||
static void
|
||||
ivb_disable_plane(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int pipe = intel_plane->pipe;
|
||||
|
||||
I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
|
||||
/* Can't leave the scaler enabled... */
|
||||
I915_WRITE(SPRSCALE(pipe), 0);
|
||||
/* Activate double buffered register update */
|
||||
I915_WRITE(SPRSURF(pipe), 0);
|
||||
POSTING_READ(SPRSURF(pipe));
|
||||
}
|
||||
|
||||
static int
|
||||
ivb_update_colorkey(struct drm_plane *plane,
|
||||
struct drm_intel_sprite_colorkey *key)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane;
|
||||
u32 sprctl;
|
||||
int ret = 0;
|
||||
|
||||
intel_plane = to_intel_plane(plane);
|
||||
|
||||
I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
|
||||
I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
|
||||
I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
|
||||
|
||||
sprctl = I915_READ(SPRCTL(intel_plane->pipe));
|
||||
sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
|
||||
if (key->flags & I915_SET_COLORKEY_DESTINATION)
|
||||
sprctl |= SPRITE_DEST_KEY;
|
||||
else if (key->flags & I915_SET_COLORKEY_SOURCE)
|
||||
sprctl |= SPRITE_SOURCE_KEY;
|
||||
I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
|
||||
|
||||
POSTING_READ(SPRKEYMSK(intel_plane->pipe));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane;
|
||||
u32 sprctl;
|
||||
|
||||
intel_plane = to_intel_plane(plane);
|
||||
|
||||
key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
|
||||
key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
|
||||
key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
|
||||
key->flags = 0;
|
||||
|
||||
sprctl = I915_READ(SPRCTL(intel_plane->pipe));
|
||||
|
||||
if (sprctl & SPRITE_DEST_KEY)
|
||||
key->flags = I915_SET_COLORKEY_DESTINATION;
|
||||
else if (sprctl & SPRITE_SOURCE_KEY)
|
||||
key->flags = I915_SET_COLORKEY_SOURCE;
|
||||
else
|
||||
key->flags = I915_SET_COLORKEY_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
|
||||
struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
|
||||
unsigned int crtc_w, unsigned int crtc_h,
|
||||
uint32_t x, uint32_t y,
|
||||
uint32_t src_w, uint32_t src_h)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int pipe = intel_plane->pipe, pixel_size;
|
||||
u32 dvscntr, dvsscale = 0;
|
||||
|
||||
dvscntr = I915_READ(DVSCNTR(pipe));
|
||||
|
||||
/* Mask out pixel format bits in case we change it */
|
||||
dvscntr &= ~DVS_PIXFORMAT_MASK;
|
||||
dvscntr &= ~DVS_RGB_ORDER_XBGR;
|
||||
dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
|
||||
|
||||
switch (fb->pixel_format) {
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
dvscntr |= DVS_FORMAT_RGBX888;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
case DRM_FORMAT_YUYV:
|
||||
dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_YVYU:
|
||||
dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_UYVY:
|
||||
dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
case DRM_FORMAT_VYUY:
|
||||
dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
|
||||
pixel_size = 2;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_DRIVER("bad pixel format, assuming RGBX888\n");
|
||||
dvscntr |= DVS_FORMAT_RGBX888;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (obj->tiling_mode != I915_TILING_NONE)
|
||||
dvscntr |= DVS_TILED;
|
||||
|
||||
/* must disable */
|
||||
dvscntr |= DVS_TRICKLE_FEED_DISABLE;
|
||||
dvscntr |= DVS_ENABLE;
|
||||
|
||||
/* Sizes are 0 based */
|
||||
src_w--;
|
||||
src_h--;
|
||||
crtc_w--;
|
||||
crtc_h--;
|
||||
|
||||
intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
|
||||
|
||||
if (crtc_w != src_w || crtc_h != src_h)
|
||||
dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
|
||||
|
||||
I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
|
||||
I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
|
||||
if (obj->tiling_mode != I915_TILING_NONE) {
|
||||
I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
|
||||
} else {
|
||||
unsigned long offset;
|
||||
|
||||
offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
|
||||
I915_WRITE(DVSLINOFF(pipe), offset);
|
||||
}
|
||||
I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
|
||||
I915_WRITE(DVSSCALE(pipe), dvsscale);
|
||||
I915_WRITE(DVSCNTR(pipe), dvscntr);
|
||||
I915_WRITE(DVSSURF(pipe), obj->gtt_offset);
|
||||
POSTING_READ(DVSSURF(pipe));
|
||||
}
|
||||
|
||||
static void
|
||||
snb_disable_plane(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int pipe = intel_plane->pipe;
|
||||
|
||||
I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
|
||||
/* Disable the scaler */
|
||||
I915_WRITE(DVSSCALE(pipe), 0);
|
||||
/* Flush double buffered register updates */
|
||||
I915_WRITE(DVSSURF(pipe), 0);
|
||||
POSTING_READ(DVSSURF(pipe));
|
||||
}
|
||||
|
||||
static void
|
||||
intel_enable_primary(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int reg = DSPCNTR(intel_crtc->plane);
|
||||
|
||||
I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_disable_primary(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int reg = DSPCNTR(intel_crtc->plane);
|
||||
|
||||
I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
|
||||
}
|
||||
|
||||
static int
|
||||
snb_update_colorkey(struct drm_plane *plane,
|
||||
struct drm_intel_sprite_colorkey *key)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane;
|
||||
u32 dvscntr;
|
||||
int ret = 0;
|
||||
|
||||
intel_plane = to_intel_plane(plane);
|
||||
|
||||
I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
|
||||
I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
|
||||
I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
|
||||
|
||||
dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
|
||||
dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
|
||||
if (key->flags & I915_SET_COLORKEY_DESTINATION)
|
||||
dvscntr |= DVS_DEST_KEY;
|
||||
else if (key->flags & I915_SET_COLORKEY_SOURCE)
|
||||
dvscntr |= DVS_SOURCE_KEY;
|
||||
I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
|
||||
|
||||
POSTING_READ(DVSKEYMSK(intel_plane->pipe));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_plane *intel_plane;
|
||||
u32 dvscntr;
|
||||
|
||||
intel_plane = to_intel_plane(plane);
|
||||
|
||||
key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
|
||||
key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
|
||||
key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
|
||||
key->flags = 0;
|
||||
|
||||
dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
|
||||
|
||||
if (dvscntr & DVS_DEST_KEY)
|
||||
key->flags = I915_SET_COLORKEY_DESTINATION;
|
||||
else if (dvscntr & DVS_SOURCE_KEY)
|
||||
key->flags = I915_SET_COLORKEY_SOURCE;
|
||||
else
|
||||
key->flags = I915_SET_COLORKEY_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
|
||||
unsigned int crtc_w, unsigned int crtc_h,
|
||||
uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
struct intel_framebuffer *intel_fb;
|
||||
struct drm_i915_gem_object *obj, *old_obj;
|
||||
int pipe = intel_plane->pipe;
|
||||
int ret = 0;
|
||||
int x = src_x >> 16, y = src_y >> 16;
|
||||
int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay;
|
||||
bool disable_primary = false;
|
||||
|
||||
intel_fb = to_intel_framebuffer(fb);
|
||||
obj = intel_fb->obj;
|
||||
|
||||
old_obj = intel_plane->obj;
|
||||
|
||||
src_w = src_w >> 16;
|
||||
src_h = src_h >> 16;
|
||||
|
||||
/* Pipe must be running... */
|
||||
if (!(I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
if (crtc_x >= primary_w || crtc_y >= primary_h)
|
||||
return -EINVAL;
|
||||
|
||||
/* Don't modify another pipe's plane */
|
||||
if (intel_plane->pipe != intel_crtc->pipe)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Clamp the width & height into the visible area. Note we don't
|
||||
* try to scale the source if part of the visible region is offscreen.
|
||||
* The caller must handle that by adjusting source offset and size.
|
||||
*/
|
||||
if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) {
|
||||
crtc_w += crtc_x;
|
||||
crtc_x = 0;
|
||||
}
|
||||
if ((crtc_x + crtc_w) <= 0) /* Nothing to display */
|
||||
goto out;
|
||||
if ((crtc_x + crtc_w) > primary_w)
|
||||
crtc_w = primary_w - crtc_x;
|
||||
|
||||
if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) {
|
||||
crtc_h += crtc_y;
|
||||
crtc_y = 0;
|
||||
}
|
||||
if ((crtc_y + crtc_h) <= 0) /* Nothing to display */
|
||||
goto out;
|
||||
if (crtc_y + crtc_h > primary_h)
|
||||
crtc_h = primary_h - crtc_y;
|
||||
|
||||
if (!crtc_w || !crtc_h) /* Again, nothing to display */
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* We can take a larger source and scale it down, but
|
||||
* only so much... 16x is the max on SNB.
|
||||
*/
|
||||
if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If the sprite is completely covering the primary plane,
|
||||
* we can disable the primary and save power.
|
||||
*/
|
||||
if ((crtc_x == 0) && (crtc_y == 0) &&
|
||||
(crtc_w == primary_w) && (crtc_h == primary_h))
|
||||
disable_primary = true;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
|
||||
ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
intel_plane->obj = obj;
|
||||
|
||||
/*
|
||||
* Be sure to re-enable the primary before the sprite is no longer
|
||||
* covering it fully.
|
||||
*/
|
||||
if (!disable_primary && intel_plane->primary_disabled) {
|
||||
intel_enable_primary(crtc);
|
||||
intel_plane->primary_disabled = false;
|
||||
}
|
||||
|
||||
intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
|
||||
crtc_w, crtc_h, x, y, src_w, src_h);
|
||||
|
||||
if (disable_primary) {
|
||||
intel_disable_primary(crtc);
|
||||
intel_plane->primary_disabled = true;
|
||||
}
|
||||
|
||||
/* Unpin old obj after new one is active to avoid ugliness */
|
||||
if (old_obj) {
|
||||
/*
|
||||
* It's fairly common to simply update the position of
|
||||
* an existing object. In that case, we don't need to
|
||||
* wait for vblank to avoid ugliness, we only need to
|
||||
* do the pin & ref bookkeeping.
|
||||
*/
|
||||
if (old_obj != obj) {
|
||||
DRM_UNLOCK(dev);
|
||||
intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe);
|
||||
DRM_LOCK(dev);
|
||||
}
|
||||
intel_unpin_fb_obj(old_obj);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
DRM_UNLOCK(dev);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_disable_plane(struct drm_plane *plane)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
int ret = 0;
|
||||
|
||||
if (intel_plane->primary_disabled) {
|
||||
intel_enable_primary(plane->crtc);
|
||||
intel_plane->primary_disabled = false;
|
||||
}
|
||||
|
||||
intel_plane->disable_plane(plane);
|
||||
|
||||
if (!intel_plane->obj)
|
||||
goto out;
|
||||
|
||||
DRM_LOCK(dev);
|
||||
intel_unpin_fb_obj(intel_plane->obj);
|
||||
intel_plane->obj = NULL;
|
||||
DRM_UNLOCK(dev);
|
||||
out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void intel_destroy_plane(struct drm_plane *plane)
|
||||
{
|
||||
struct intel_plane *intel_plane = to_intel_plane(plane);
|
||||
intel_disable_plane(plane);
|
||||
drm_plane_cleanup(plane);
|
||||
free(intel_plane, DRM_MEM_KMS);
|
||||
}
|
||||
|
||||
int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_intel_sprite_colorkey *set = data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_mode_object *obj;
|
||||
struct drm_plane *plane;
|
||||
struct intel_plane *intel_plane;
|
||||
int ret = 0;
|
||||
|
||||
if (!dev_priv)
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure we don't try to enable both src & dest simultaneously */
|
||||
if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
|
||||
return -EINVAL;
|
||||
|
||||
sx_xlock(&dev->mode_config.mutex);
|
||||
|
||||
obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
|
||||
if (!obj) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
plane = obj_to_plane(obj);
|
||||
intel_plane = to_intel_plane(plane);
|
||||
ret = intel_plane->update_colorkey(plane, set);
|
||||
|
||||
out_unlock:
|
||||
sx_xunlock(&dev->mode_config.mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_intel_sprite_colorkey *get = data;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_mode_object *obj;
|
||||
struct drm_plane *plane;
|
||||
struct intel_plane *intel_plane;
|
||||
int ret = 0;
|
||||
|
||||
if (!dev_priv)
|
||||
return -EINVAL;
|
||||
|
||||
sx_xlock(&dev->mode_config.mutex);
|
||||
|
||||
obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
|
||||
if (!obj) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
plane = obj_to_plane(obj);
|
||||
intel_plane = to_intel_plane(plane);
|
||||
intel_plane->get_colorkey(plane, get);
|
||||
|
||||
out_unlock:
|
||||
sx_xunlock(&dev->mode_config.mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_plane_funcs intel_plane_funcs = {
|
||||
.update_plane = intel_update_plane,
|
||||
.disable_plane = intel_disable_plane,
|
||||
.destroy = intel_destroy_plane,
|
||||
};
|
||||
|
||||
static uint32_t snb_plane_formats[] = {
|
||||
DRM_FORMAT_XBGR8888,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_YUYV,
|
||||
DRM_FORMAT_YVYU,
|
||||
DRM_FORMAT_UYVY,
|
||||
DRM_FORMAT_VYUY,
|
||||
};
|
||||
|
||||
int
|
||||
intel_plane_init(struct drm_device *dev, enum pipe pipe)
|
||||
{
|
||||
struct intel_plane *intel_plane;
|
||||
unsigned long possible_crtcs;
|
||||
int ret;
|
||||
|
||||
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
|
||||
return -ENODEV;
|
||||
|
||||
intel_plane = malloc(sizeof(struct intel_plane), DRM_MEM_KMS,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
if (IS_GEN6(dev)) {
|
||||
intel_plane->max_downscale = 16;
|
||||
intel_plane->update_plane = snb_update_plane;
|
||||
intel_plane->disable_plane = snb_disable_plane;
|
||||
intel_plane->update_colorkey = snb_update_colorkey;
|
||||
intel_plane->get_colorkey = snb_get_colorkey;
|
||||
} else if (IS_GEN7(dev)) {
|
||||
intel_plane->max_downscale = 2;
|
||||
intel_plane->update_plane = ivb_update_plane;
|
||||
intel_plane->disable_plane = ivb_disable_plane;
|
||||
intel_plane->update_colorkey = ivb_update_colorkey;
|
||||
intel_plane->get_colorkey = ivb_get_colorkey;
|
||||
}
|
||||
|
||||
intel_plane->pipe = pipe;
|
||||
possible_crtcs = (1 << pipe);
|
||||
ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
|
||||
&intel_plane_funcs, snb_plane_formats,
|
||||
DRM_ARRAY_SIZE(snb_plane_formats), false);
|
||||
if (ret)
|
||||
free(intel_plane, DRM_MEM_KMS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
1609
sys/dev/drm2/i915/intel_tv.c
Normal file
1609
sys/dev/drm2/i915/intel_tv.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue