Merge branch 'linus' into release

Conflicts:
	arch/x86/kernel/cpu/cpufreq/longhaul.c

Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
Len Brown
2009-04-05 02:14:15 -04:00
6737 changed files with 522868 additions and 237884 deletions

View File

@@ -10,7 +10,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o
drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o

View File

@@ -77,7 +77,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info
if (!entry->busaddr[i])
break;
pci_unmap_page(dev->pdev, entry->busaddr[i],
PAGE_SIZE, PCI_DMA_TODEVICE);
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
}
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
@@ -95,13 +95,14 @@ EXPORT_SYMBOL(drm_ati_pcigart_cleanup);
int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
{
struct drm_local_map *map = &gart_info->mapping;
struct drm_sg_mem *entry = dev->sg;
void *address = NULL;
unsigned long pages;
u32 *pci_gart, page_base;
u32 *pci_gart = NULL, page_base, gart_idx;
dma_addr_t bus_address = 0;
int i, j, ret = 0;
int max_pages;
int max_ati_pages, max_real_pages;
if (!entry) {
DRM_ERROR("no scatter/gather memory!\n");
@@ -117,6 +118,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
goto done;
}
pci_gart = gart_info->table_handle->vaddr;
address = gart_info->table_handle->vaddr;
bus_address = gart_info->table_handle->busaddr;
} else {
@@ -127,18 +129,23 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
(unsigned long)address);
}
pci_gart = (u32 *) address;
max_pages = (gart_info->table_size / sizeof(u32));
pages = (entry->pages <= max_pages)
? entry->pages : max_pages;
max_ati_pages = (gart_info->table_size / sizeof(u32));
max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE);
pages = (entry->pages <= max_real_pages)
? entry->pages : max_real_pages;
memset(pci_gart, 0, max_pages * sizeof(u32));
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
memset(pci_gart, 0, max_ati_pages * sizeof(u32));
} else {
memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u32));
}
gart_idx = 0;
for (i = 0; i < pages; i++) {
/* we need to support large memory configurations */
entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i],
0, PAGE_SIZE, PCI_DMA_TODEVICE);
0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
if (entry->busaddr[i] == 0) {
DRM_ERROR("unable to map PCIGART pages!\n");
drm_ati_pcigart_cleanup(dev, gart_info);
@@ -149,19 +156,26 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
page_base = (u32) entry->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
u32 val;
switch(gart_info->gart_reg_if) {
case DRM_ATI_GART_IGP:
*pci_gart = cpu_to_le32((page_base) | 0xc);
val = page_base | 0xc;
break;
case DRM_ATI_GART_PCIE:
*pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
val = (page_base >> 8) | 0xc;
break;
default:
case DRM_ATI_GART_PCI:
*pci_gart = cpu_to_le32(page_base);
val = page_base;
break;
}
pci_gart++;
if (gart_info->gart_table_location ==
DRM_ATI_GART_MAIN)
pci_gart[gart_idx] = cpu_to_le32(val);
else
DRM_WRITE32(map, gart_idx * sizeof(u32), val);
gart_idx++;
page_base += ATI_PCIGART_PAGE_SIZE;
}
}

View File

@@ -34,15 +34,17 @@
*/
#include <linux/vmalloc.h>
#include <linux/log2.h>
#include <asm/shmparam.h>
#include "drmP.h"
unsigned long drm_get_resource_start(struct drm_device *dev, unsigned int resource)
resource_size_t drm_get_resource_start(struct drm_device *dev, unsigned int resource)
{
return pci_resource_start(dev->pdev, resource);
}
EXPORT_SYMBOL(drm_get_resource_start);
unsigned long drm_get_resource_len(struct drm_device *dev, unsigned int resource)
resource_size_t drm_get_resource_len(struct drm_device *dev, unsigned int resource)
{
return pci_resource_len(dev->pdev, resource);
}
@@ -50,24 +52,44 @@ unsigned long drm_get_resource_len(struct drm_device *dev, unsigned int resource
EXPORT_SYMBOL(drm_get_resource_len);
static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
drm_local_map_t *map)
struct drm_local_map *map)
{
struct drm_map_list *entry;
list_for_each_entry(entry, &dev->maplist, head) {
if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) &&
((entry->map->offset == map->offset) ||
((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
/*
* Because the kernel-userspace ABI is fixed at a 32-bit offset
* while PCI resources may live above that, we ignore the map
* offset for maps of type _DRM_FRAMEBUFFER or _DRM_REGISTERS.
* It is assumed that each driver will have only one resource of
* each type.
*/
if (!entry->map ||
map->type != entry->map->type ||
entry->master != dev->primary->master)
continue;
switch (map->type) {
case _DRM_SHM:
if (map->flags != _DRM_CONTAINS_LOCK)
break;
case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER:
return entry;
default: /* Make gcc happy */
;
}
if (entry->map->offset == map->offset)
return entry;
}
return NULL;
}
static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
unsigned long user_token, int hashed_handle)
unsigned long user_token, int hashed_handle, int shm)
{
int use_hashed_handle;
int use_hashed_handle, shift;
unsigned long add;
#if (BITS_PER_LONG == 64)
use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle);
#elif (BITS_PER_LONG == 32)
@@ -83,30 +105,47 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
if (ret != -EINVAL)
return ret;
}
shift = 0;
add = DRM_MAP_HASH_OFFSET >> PAGE_SHIFT;
if (shm && (SHMLBA > PAGE_SIZE)) {
int bits = ilog2(SHMLBA >> PAGE_SHIFT) + 1;
/* For shared memory, we have to preserve the SHMLBA
* bits of the eventual vma->vm_pgoff value during
* mmap(). Otherwise we run into cache aliasing problems
* on some platforms. On these platforms, the pgoff of
* a mmap() request is used to pick a suitable virtual
* address for the mmap() region such that it will not
* cause cache aliasing problems.
*
* Therefore, make sure the SHMLBA relevant bits of the
* hash value we use are equal to those in the original
* kernel virtual address.
*/
shift = bits;
add |= ((user_token >> PAGE_SHIFT) & ((1UL << bits) - 1UL));
}
return drm_ht_just_insert_please(&dev->map_hash, hash,
user_token, 32 - PAGE_SHIFT - 3,
0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
shift, add);
}
/**
* Ioctl to specify a range of memory that is available for mapping by a non-root process.
*
* \param inode device inode.
* \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_map structure.
* \return zero on success or a negative value on error.
* Core function to create a range of memory available for mapping by a
* non-root process.
*
* Adjusts the memory offset to its absolute value according to the mapping
* type. Adds the map to the map list drm_device::maplist. Adds MTRR's where
* applicable and if supported by the kernel.
*/
static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
unsigned int size, enum drm_map_type type,
enum drm_map_flags flags,
struct drm_map_list ** maplist)
{
struct drm_map *map;
struct drm_local_map *map;
struct drm_map_list *list;
drm_dma_handle_t *dmah;
unsigned long user_token;
@@ -129,9 +168,9 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
map->offset, map->size, map->type);
if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n",
(unsigned long long)map->offset, map->size, map->type);
if ((map->offset & (~(resource_size_t)PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
@@ -259,7 +298,8 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EPERM;
}
DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n",
(unsigned long long)map->offset, map->size);
break;
case _DRM_GEM:
@@ -309,7 +349,8 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
/* We do it here so that dev->struct_mutex protects the increment */
user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
map->offset;
ret = drm_map_handle(dev, &list->hash, user_token, 0);
ret = drm_map_handle(dev, &list->hash, user_token, 0,
(map->type == _DRM_SHM));
if (ret) {
if (map->type == _DRM_REGISTERS)
iounmap(map->handle);
@@ -327,9 +368,9 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
return 0;
}
int drm_addmap(struct drm_device * dev, unsigned int offset,
int drm_addmap(struct drm_device * dev, resource_size_t offset,
unsigned int size, enum drm_map_type type,
enum drm_map_flags flags, drm_local_map_t ** map_ptr)
enum drm_map_flags flags, struct drm_local_map ** map_ptr)
{
struct drm_map_list *list;
int rc;
@@ -342,6 +383,17 @@ int drm_addmap(struct drm_device * dev, unsigned int offset,
EXPORT_SYMBOL(drm_addmap);
/**
* Ioctl to specify a range of memory that is available for mapping by a
* non-root process.
*
* \param inode device inode.
* \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_map structure.
* \return zero on success or a negative value on error.
*
*/
int drm_addmap_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -367,19 +419,13 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,
* Remove a map private from list and deallocate resources if the mapping
* isn't in use.
*
* \param inode device inode.
* \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a struct drm_map structure.
* \return zero on success or a negative value on error.
*
* Searches the map on drm_device::maplist, removes it from the list, see if
* its being used, and free any associate resource (such as MTRR's) if it's not
* being on use.
*
* \sa drm_addmap
*/
int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
{
struct drm_map_list *r_list = NULL, *list_t;
drm_dma_handle_t dmah;
@@ -442,7 +488,7 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
}
EXPORT_SYMBOL(drm_rmmap_locked);
int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
int drm_rmmap(struct drm_device *dev, struct drm_local_map *map)
{
int ret;
@@ -462,12 +508,18 @@ EXPORT_SYMBOL(drm_rmmap);
* One use case might be after addmap is allowed for normal users for SHM and
* gets used by drivers that the server doesn't need to care about. This seems
* unlikely.
*
* \param inode device inode.
* \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a struct drm_map structure.
* \return zero on success or a negative value on error.
*/
int drm_rmmap_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_map *request = data;
drm_local_map_t *map = NULL;
struct drm_local_map *map = NULL;
struct drm_map_list *r_list;
int ret;
@@ -1534,7 +1586,7 @@ int drm_mapbufs(struct drm_device *dev, void *data,
&& (dma->flags & _DRM_DMA_USE_SG))
|| (drm_core_check_feature(dev, DRIVER_FB_DMA)
&& (dma->flags & _DRM_DMA_USE_FB))) {
struct drm_map *map = dev->agp_buffer_map;
struct drm_local_map *map = dev->agp_buffer_map;
unsigned long token = dev->agp_buffer_token;
if (!map) {

View File

@@ -143,7 +143,7 @@ int drm_getsareactx(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_ctx_priv_map *request = data;
struct drm_map *map;
struct drm_local_map *map;
struct drm_map_list *_entry;
mutex_lock(&dev->struct_mutex);
@@ -186,7 +186,7 @@ int drm_setsareactx(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_ctx_priv_map *request = data;
struct drm_map *map = NULL;
struct drm_local_map *map = NULL;
struct drm_map_list *r_list = NULL;
mutex_lock(&dev->struct_mutex);

View File

@@ -42,6 +42,26 @@ static struct drm_display_mode std_modes[] = {
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
};
static void drm_mode_validate_flag(struct drm_connector *connector,
int flags)
{
struct drm_display_mode *mode, *t;
if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
return;
list_for_each_entry_safe(mode, t, &connector->modes, head) {
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
!(flags & DRM_MODE_FLAG_INTERLACE))
mode->status = MODE_NO_INTERLACE;
if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
!(flags & DRM_MODE_FLAG_DBLSCAN))
mode->status = MODE_NO_DBLESCAN;
}
return;
}
/**
* drm_helper_probe_connector_modes - get complete set of display modes
* @dev: DRM device
@@ -72,6 +92,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private;
int count = 0;
int mode_flags = 0;
DRM_DEBUG("%s\n", drm_get_connector_name(connector));
/* set all modes to the unverified state */
@@ -96,6 +117,13 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
if (maxX && maxY)
drm_mode_validate_size(dev, &connector->modes, maxX,
maxY, 0);
if (connector->interlace_allowed)
mode_flags |= DRM_MODE_FLAG_INTERLACE;
if (connector->doublescan_allowed)
mode_flags |= DRM_MODE_FLAG_DBLSCAN;
drm_mode_validate_flag(connector, mode_flags);
list_for_each_entry_safe(mode, t, &connector->modes, head) {
if (mode->status == MODE_OK)
mode->status = connector_funcs->mode_valid(connector,
@@ -885,7 +913,6 @@ bool drm_helper_plugged_event(struct drm_device *dev)
/**
* drm_initial_config - setup a sane initial connector configuration
* @dev: DRM device
* @can_grow: this configuration is growable
*
* LOCKING:
* Called at init time, must take mode config lock.
@@ -897,7 +924,7 @@ bool drm_helper_plugged_event(struct drm_device *dev)
* RETURNS:
* Zero if everything went ok, nonzero otherwise.
*/
bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
bool drm_helper_initial_config(struct drm_device *dev)
{
struct drm_connector *connector;
int count = 0;

View File

@@ -0,0 +1,235 @@
/**
* \file drm_debugfs.c
* debugfs support for DRM
*
* \author Ben Gamari <bgamari@gmail.com>
*/
/*
* Created: Sun Dec 21 13:08:50 2008 by bgamari@gmail.com
*
* Copyright 2008 Ben Gamari <bgamari@gmail.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
* 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 <linux/debugfs.h>
#include <linux/seq_file.h>
#include "drmP.h"
#if defined(CONFIG_DEBUG_FS)
/***************************************************
* Initialization, etc.
**************************************************/
static struct drm_info_list drm_debugfs_list[] = {
{"name", drm_name_info, 0},
{"vm", drm_vm_info, 0},
{"clients", drm_clients_info, 0},
{"queues", drm_queues_info, 0},
{"bufs", drm_bufs_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
{"gem_objects", drm_gem_object_info, DRIVER_GEM},
#if DRM_DEBUG_CODE
{"vma", drm_vma_info, 0},
#endif
};
#define DRM_DEBUGFS_ENTRIES ARRAY_SIZE(drm_debugfs_list)
static int drm_debugfs_open(struct inode *inode, struct file *file)
{
struct drm_info_node *node = inode->i_private;
return single_open(file, node->info_ent->show, node);
}
static const struct file_operations drm_debugfs_fops = {
.owner = THIS_MODULE,
.open = drm_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/**
* Initialize a given set of debugfs files for a device
*
* \param files The array of files to create
* \param count The number of files given
* \param root DRI debugfs dir entry.
* \param minor device minor number
* \return Zero on success, non-zero on failure
*
* Create a given set of debugfs files represented by an array of
* gdm_debugfs_lists in the given root directory.
*/
int drm_debugfs_create_files(struct drm_info_list *files, int count,
struct dentry *root, struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct dentry *ent;
struct drm_info_node *tmp;
char name[64];
int i, ret;
for (i = 0; i < count; i++) {
u32 features = files[i].driver_features;
if (features != 0 &&
(dev->driver->driver_features & features) != features)
continue;
tmp = drm_alloc(sizeof(struct drm_info_node),
_DRM_DRIVER);
ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
root, tmp, &drm_debugfs_fops);
if (!ent) {
DRM_ERROR("Cannot create /debugfs/dri/%s/%s\n",
name, files[i].name);
drm_free(tmp, sizeof(struct drm_info_node),
_DRM_DRIVER);
ret = -1;
goto fail;
}
tmp->minor = minor;
tmp->dent = ent;
tmp->info_ent = &files[i];
list_add(&(tmp->list), &(minor->debugfs_nodes.list));
}
return 0;
fail:
drm_debugfs_remove_files(files, count, minor);
return ret;
}
EXPORT_SYMBOL(drm_debugfs_create_files);
/**
* Initialize the DRI debugfs filesystem for a device
*
* \param dev DRM device
* \param minor device minor number
* \param root DRI debugfs dir entry.
*
* Create the DRI debugfs root entry "/debugfs/dri", the device debugfs root entry
* "/debugfs/dri/%minor%/", and each entry in debugfs_list as
* "/debugfs/dri/%minor%/%name%".
*/
int drm_debugfs_init(struct drm_minor *minor, int minor_id,
struct dentry *root)
{
struct drm_device *dev = minor->dev;
char name[64];
int ret;
INIT_LIST_HEAD(&minor->debugfs_nodes.list);
sprintf(name, "%d", minor_id);
minor->debugfs_root = debugfs_create_dir(name, root);
if (!minor->debugfs_root) {
DRM_ERROR("Cannot create /debugfs/dri/%s\n", name);
return -1;
}
ret = drm_debugfs_create_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
if (ret) {
debugfs_remove(minor->debugfs_root);
minor->debugfs_root = NULL;
DRM_ERROR("Failed to create core drm debugfs files\n");
return ret;
}
if (dev->driver->debugfs_init) {
ret = dev->driver->debugfs_init(minor);
if (ret) {
DRM_ERROR("DRM: Driver failed to initialize "
"/debugfs/dri.\n");
return ret;
}
}
return 0;
}
/**
* Remove a list of debugfs files
*
* \param files The list of files
* \param count The number of files
* \param minor The minor of which we should remove the files
* \return always zero.
*
* Remove all debugfs entries created by debugfs_init().
*/
int drm_debugfs_remove_files(struct drm_info_list *files, int count,
struct drm_minor *minor)
{
struct list_head *pos, *q;
struct drm_info_node *tmp;
int i;
for (i = 0; i < count; i++) {
list_for_each_safe(pos, q, &minor->debugfs_nodes.list) {
tmp = list_entry(pos, struct drm_info_node, list);
if (tmp->info_ent == &files[i]) {
debugfs_remove(tmp->dent);
list_del(pos);
drm_free(tmp, sizeof(struct drm_info_node),
_DRM_DRIVER);
}
}
}
return 0;
}
EXPORT_SYMBOL(drm_debugfs_remove_files);
/**
* Cleanup the debugfs filesystem resources.
*
* \param minor device minor number.
* \return always zero.
*
* Remove all debugfs entries created by debugfs_init().
*/
int drm_debugfs_cleanup(struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
if (!minor->debugfs_root)
return 0;
if (dev->driver->debugfs_cleanup)
dev->driver->debugfs_cleanup(minor);
drm_debugfs_remove_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES, minor);
debugfs_remove(minor->debugfs_root);
minor->debugfs_root = NULL;
return 0;
}
#endif /* CONFIG_DEBUG_FS */

View File

@@ -46,9 +46,11 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/debugfs.h>
#include "drmP.h"
#include "drm_core.h"
static int drm_version(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -178,7 +180,7 @@ int drm_lastclose(struct drm_device * dev)
/* Clear AGP information */
if (drm_core_has_AGP(dev) && dev->agp &&
!drm_core_check_feature(dev, DRIVER_MODESET)) {
!drm_core_check_feature(dev, DRIVER_MODESET)) {
struct drm_agp_mem *entry, *tempe;
/* Remove AGP resources, but leave dev->agp
@@ -252,15 +254,19 @@ int drm_lastclose(struct drm_device * dev)
int drm_init(struct drm_driver *driver)
{
struct pci_dev *pdev = NULL;
struct pci_device_id *pid;
const struct pci_device_id *pid;
int i;
DRM_DEBUG("\n");
INIT_LIST_HEAD(&driver->device_list);
if (driver->driver_features & DRIVER_MODESET)
return pci_register_driver(&driver->pci_driver);
/* If not using KMS, fall back to stealth mode manual scanning. */
for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
pid = (struct pci_device_id *)&driver->pci_driver.id_table[i];
pid = &driver->pci_driver.id_table[i];
/* Loop around setting up a DRM device for each PCI device
* matching our ID and device class. If we had the internal
@@ -285,68 +291,17 @@ int drm_init(struct drm_driver *driver)
EXPORT_SYMBOL(drm_init);
/**
* Called via cleanup_module() at module unload time.
*
* Cleans up all DRM device, calling drm_lastclose().
*
* \sa drm_init
*/
static void drm_cleanup(struct drm_device * dev)
{
struct drm_map_list *r_list, *list_temp;
DRM_DEBUG("\n");
if (!dev) {
DRM_ERROR("cleanup called no dev\n");
return;
}
drm_vblank_cleanup(dev);
drm_lastclose(dev);
if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
dev->agp && dev->agp->agp_mtrr >= 0) {
int retval;
retval = mtrr_del(dev->agp->agp_mtrr,
dev->agp->agp_info.aper_base,
dev->agp->agp_info.aper_size * 1024 * 1024);
DRM_DEBUG("mtrr_del=%d\n", retval);
}
if (dev->driver->unload)
dev->driver->unload(dev);
if (drm_core_has_AGP(dev) && dev->agp) {
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
dev->agp = NULL;
}
drm_ht_remove(&dev->map_hash);
drm_ctxbitmap_cleanup(dev);
list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
drm_rmmap(dev, r_list->map);
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_put_minor(&dev->control);
if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_destroy(dev);
drm_put_minor(&dev->primary);
if (drm_put_dev(dev))
DRM_ERROR("Cannot unload module\n");
}
void drm_exit(struct drm_driver *driver)
{
struct drm_device *dev, *tmp;
DRM_DEBUG("\n");
list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
drm_cleanup(dev);
if (driver->driver_features & DRIVER_MODESET) {
pci_unregister_driver(&driver->pci_driver);
} else {
list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
drm_put_dev(dev);
}
DRM_INFO("Module unloaded\n");
}
@@ -382,6 +337,13 @@ static int __init drm_core_init(void)
goto err_p3;
}
drm_debugfs_root = debugfs_create_dir("dri", NULL);
if (!drm_debugfs_root) {
DRM_ERROR("Cannot create /debugfs/dri\n");
ret = -1;
goto err_p3;
}
drm_mem_init();
DRM_INFO("Initialized %s %d.%d.%d %s\n",
@@ -400,6 +362,7 @@ err_p1:
static void __exit drm_core_exit(void)
{
remove_proc_entry("dri", NULL);
debugfs_remove(drm_debugfs_root);
drm_sysfs_destroy();
unregister_chrdev(DRM_MAJOR, "drm");
@@ -458,6 +421,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
drm_ioctl_t *func;
unsigned int nr = DRM_IOCTL_NR(cmd);
int retcode = -EINVAL;
char stack_kdata[128];
char *kdata = NULL;
atomic_inc(&dev->ioctl_count);
@@ -496,10 +460,14 @@ int drm_ioctl(struct inode *inode, struct file *filp,
retcode = -EACCES;
} else {
if (cmd & (IOC_IN | IOC_OUT)) {
kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
if (!kdata) {
retcode = -ENOMEM;
goto err_i1;
if (_IOC_SIZE(cmd) <= sizeof(stack_kdata)) {
kdata = stack_kdata;
} else {
kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
if (!kdata) {
retcode = -ENOMEM;
goto err_i1;
}
}
}
@@ -520,7 +488,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
}
err_i1:
if (kdata)
if (kdata != stack_kdata)
kfree(kdata);
atomic_dec(&dev->ioctl_count);
if (retcode)
@@ -530,7 +498,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
EXPORT_SYMBOL(drm_ioctl);
drm_local_map_t *drm_getsarea(struct drm_device *dev)
struct drm_local_map *drm_getsarea(struct drm_device *dev)
{
struct drm_map_list *entry;

View File

@@ -125,10 +125,8 @@ static bool edid_is_valid(struct edid *edid)
DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
goto bad;
}
if (edid->revision > 3) {
DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision);
goto bad;
}
if (edid->revision > 4)
DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n");
for (i = 0; i < EDID_LENGTH; i++)
csum += raw_edid[i];
@@ -162,7 +160,7 @@ static bool edid_vendor(struct edid *edid, char *vendor)
edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@';
edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) |
((edid->mfg_id[1] & 0xe0) >> 5)) + '@';
edid_vendor[2] = (edid->mfg_id[2] & 0x1f) + '@';
edid_vendor[2] = (edid->mfg_id[1] & 0x1f) + '@';
return !strncmp(edid_vendor, vendor, 3);
}
@@ -550,11 +548,20 @@ static int add_detailed_info(struct drm_connector *connector,
}
#define DDC_ADDR 0x50
unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
/**
* Get EDID information via I2C.
*
* \param adapter : i2c device adaptor
* \param buf : EDID data buffer to be filled
* \param len : EDID data buffer length
* \return 0 on success or -1 on failure.
*
* Try to fetch EDID information by calling i2c driver function.
*/
int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
unsigned char *buf, int len)
{
unsigned char start = 0x0;
unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
struct i2c_msg msgs[] = {
{
.addr = DDC_ADDR,
@@ -564,31 +571,36 @@ unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
}, {
.addr = DDC_ADDR,
.flags = I2C_M_RD,
.len = EDID_LENGTH,
.len = len,
.buf = buf,
}
};
if (!buf) {
dev_warn(&adapter->dev, "unable to allocate memory for EDID "
"block.\n");
return NULL;
}
if (i2c_transfer(adapter, msgs, 2) == 2)
return buf;
return 0;
dev_info(&adapter->dev, "unable to read EDID block.\n");
kfree(buf);
return NULL;
return -1;
}
EXPORT_SYMBOL(drm_do_probe_ddc_edid);
static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
/**
* Get EDID information.
*
* \param adapter : i2c device adaptor.
* \param buf : EDID data buffer to be filled
* \param len : EDID data buffer length
* \return 0 on success or -1 on failure.
*
* Initialize DDC, then fetch EDID information
* by calling drm_do_probe_ddc_edid function.
*/
static int drm_ddc_read(struct i2c_adapter *adapter,
unsigned char *buf, int len)
{
struct i2c_algo_bit_data *algo_data = adapter->algo_data;
unsigned char *edid = NULL;
int i, j;
int ret = -1;
algo_data->setscl(algo_data->data, 1);
@@ -616,7 +628,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
msleep(15);
/* Do the real work */
edid = drm_do_probe_ddc_edid(adapter);
ret = drm_do_probe_ddc_edid(adapter, buf, len);
algo_data->setsda(algo_data->data, 0);
algo_data->setscl(algo_data->data, 0);
msleep(15);
@@ -632,7 +644,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
msleep(15);
algo_data->setscl(algo_data->data, 0);
algo_data->setsda(algo_data->data, 0);
if (edid)
if (ret == 0)
break;
}
/* Release the DDC lines when done or the Apple Cinema HD display
@@ -641,9 +653,31 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
algo_data->setsda(algo_data->data, 1);
algo_data->setscl(algo_data->data, 1);
return edid;
return ret;
}
static int drm_ddc_read_edid(struct drm_connector *connector,
struct i2c_adapter *adapter,
char *buf, int len)
{
int ret;
ret = drm_ddc_read(adapter, buf, len);
if (ret != 0) {
dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
drm_get_connector_name(connector));
goto end;
}
if (!edid_is_valid((struct edid *)buf)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector));
ret = -1;
}
end:
return ret;
}
#define MAX_EDID_EXT_NUM 4
/**
* drm_get_edid - get EDID data, if available
* @connector: connector we're probing
@@ -656,27 +690,118 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
struct edid *drm_get_edid(struct drm_connector *connector,
struct i2c_adapter *adapter)
{
int ret;
struct edid *edid;
edid = (struct edid *)drm_ddc_read(adapter);
if (!edid) {
dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
drm_get_connector_name(connector));
return NULL;
edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1),
GFP_KERNEL);
if (edid == NULL) {
dev_warn(&connector->dev->pdev->dev,
"Failed to allocate EDID\n");
goto end;
}
if (!edid_is_valid(edid)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector));
kfree(edid);
return NULL;
/* Read first EDID block */
ret = drm_ddc_read_edid(connector, adapter,
(unsigned char *)edid, EDID_LENGTH);
if (ret != 0)
goto clean_up;
/* There are EDID extensions to be read */
if (edid->extensions != 0) {
int edid_ext_num = edid->extensions;
if (edid_ext_num > MAX_EDID_EXT_NUM) {
dev_warn(&connector->dev->pdev->dev,
"The number of extension(%d) is "
"over max (%d), actually read number (%d)\n",
edid_ext_num, MAX_EDID_EXT_NUM,
MAX_EDID_EXT_NUM);
/* Reset EDID extension number to be read */
edid_ext_num = MAX_EDID_EXT_NUM;
}
/* Read EDID including extensions too */
ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
EDID_LENGTH * (edid_ext_num + 1));
if (ret != 0)
goto clean_up;
}
connector->display_info.raw_edid = (char *)edid;
goto end;
clean_up:
kfree(edid);
edid = NULL;
end:
return edid;
}
EXPORT_SYMBOL(drm_get_edid);
#define HDMI_IDENTIFIER 0x000C03
#define VENDOR_BLOCK 0x03
/**
* drm_detect_hdmi_monitor - detect whether monitor is hdmi.
* @edid: monitor EDID information
*
* Parse the CEA extension according to CEA-861-B.
* Return true if HDMI, false if not or unknown.
*/
bool drm_detect_hdmi_monitor(struct edid *edid)
{
char *edid_ext = NULL;
int i, hdmi_id, edid_ext_num;
int start_offset, end_offset;
bool is_hdmi = false;
/* No EDID or EDID extensions */
if (edid == NULL || edid->extensions == 0)
goto end;
/* Chose real EDID extension number */
edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ?
MAX_EDID_EXT_NUM : edid->extensions;
/* Find CEA extension */
for (i = 0; i < edid_ext_num; i++) {
edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
/* This block is CEA extension */
if (edid_ext[0] == 0x02)
break;
}
if (i == edid_ext_num)
goto end;
/* Data block offset in CEA extension block */
start_offset = 4;
end_offset = edid_ext[2];
/*
* Because HDMI identifier is in Vendor Specific Block,
* search it from all data blocks of CEA extension.
*/
for (i = start_offset; i < end_offset;
/* Increased by data block len */
i += ((edid_ext[i] & 0x1f) + 1)) {
/* Find vendor specific block */
if ((edid_ext[i] >> 5) == VENDOR_BLOCK) {
hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) |
edid_ext[i + 3] << 16;
/* Find HDMI identifier */
if (hdmi_id == HDMI_IDENTIFIER)
is_hdmi = true;
break;
}
}
end:
return is_hdmi;
}
EXPORT_SYMBOL(drm_detect_hdmi_monitor);
/**
* drm_add_edid_modes - add modes from EDID data, if available
* @connector: connector we're probing

View File

@@ -274,6 +274,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
/* create a new master */
priv->minor->master = drm_master_create(priv->minor);
if (!priv->minor->master) {
mutex_unlock(&dev->struct_mutex);
ret = -ENOMEM;
goto out_free;
}
@@ -337,14 +338,10 @@ int drm_fasync(int fd, struct file *filp, int on)
{
struct drm_file *priv = filp->private_data;
struct drm_device *dev = priv->minor->dev;
int retcode;
DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
(long)old_encode_dev(priv->minor->device));
retcode = fasync_helper(fd, filp, on, &dev->buf_async);
if (retcode < 0)
return retcode;
return 0;
return fasync_helper(fd, filp, on, &dev->buf_async);
}
EXPORT_SYMBOL(drm_fasync);

View File

@@ -502,10 +502,9 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_file *priv = filp->private_data;
struct drm_device *dev = priv->minor->dev;
struct drm_gem_mm *mm = dev->mm_private;
struct drm_map *map = NULL;
struct drm_local_map *map = NULL;
struct drm_gem_object *obj;
struct drm_hash_item *hash;
unsigned long prot;
int ret = 0;
mutex_lock(&dev->struct_mutex);
@@ -538,11 +537,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_ops = obj->dev->driver->gem_vm_ops;
vma->vm_private_data = map->handle;
/* FIXME: use pgprot_writecombine when available */
prot = pgprot_val(vma->vm_page_prot);
#ifdef CONFIG_X86
prot |= _PAGE_CACHE_WC;
#endif
vma->vm_page_prot = __pgprot(prot);
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
/* Take a ref for this mapping of the object, so that the fault
* handler can dereference the mmap offset's pointer to the object.

328
drivers/gpu/drm/drm_info.c Normal file
View File

@@ -0,0 +1,328 @@
/**
* \file drm_info.c
* DRM info file implementations
*
* \author Ben Gamari <bgamari@gmail.com>
*/
/*
* Created: Sun Dec 21 13:09:50 2008 by bgamari@gmail.com
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* Copyright 2008 Ben Gamari <bgamari@gmail.com>
* 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 <linux/seq_file.h>
#include "drmP.h"
/**
* Called when "/proc/dri/.../name" is read.
*
* Prints the device name together with the bus id if available.
*/
int drm_name_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_minor *minor = node->minor;
struct drm_device *dev = minor->dev;
struct drm_master *master = minor->master;
if (!master)
return 0;
if (master->unique) {
seq_printf(m, "%s %s %s\n",
dev->driver->pci_driver.name,
pci_name(dev->pdev), master->unique);
} else {
seq_printf(m, "%s %s\n", dev->driver->pci_driver.name,
pci_name(dev->pdev));
}
return 0;
}
/**
* Called when "/proc/dri/.../vm" is read.
*
* Prints information about all mappings in drm_device::maplist.
*/
int drm_vm_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_local_map *map;
struct drm_map_list *r_list;
/* Hardcoded from _DRM_FRAME_BUFFER,
_DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
_DRM_SCATTER_GATHER and _DRM_CONSISTENT */
const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
const char *type;
int i;
mutex_lock(&dev->struct_mutex);
seq_printf(m, "slot offset size type flags address mtrr\n\n");
i = 0;
list_for_each_entry(r_list, &dev->maplist, head) {
map = r_list->map;
if (!map)
continue;
if (map->type < 0 || map->type > 5)
type = "??";
else
type = types[map->type];
seq_printf(m, "%4d 0x%016llx 0x%08lx %4.4s 0x%02x 0x%08lx ",
i,
(unsigned long long)map->offset,
map->size, type, map->flags,
(unsigned long) r_list->user_token);
if (map->mtrr < 0)
seq_printf(m, "none\n");
else
seq_printf(m, "%4d\n", map->mtrr);
i++;
}
mutex_unlock(&dev->struct_mutex);
return 0;
}
/**
* Called when "/proc/dri/.../queues" is read.
*/
int drm_queues_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
int i;
struct drm_queue *q;
mutex_lock(&dev->struct_mutex);
seq_printf(m, " ctx/flags use fin"
" blk/rw/rwf wait flushed queued"
" locks\n\n");
for (i = 0; i < dev->queue_count; i++) {
q = dev->queuelist[i];
atomic_inc(&q->use_count);
seq_printf(m, "%5d/0x%03x %5d %5d"
" %5d/%c%c/%c%c%c %5Zd\n",
i,
q->flags,
atomic_read(&q->use_count),
atomic_read(&q->finalization),
atomic_read(&q->block_count),
atomic_read(&q->block_read) ? 'r' : '-',
atomic_read(&q->block_write) ? 'w' : '-',
waitqueue_active(&q->read_queue) ? 'r' : '-',
waitqueue_active(&q->write_queue) ? 'w' : '-',
waitqueue_active(&q->flush_queue) ? 'f' : '-',
DRM_BUFCOUNT(&q->waitlist));
atomic_dec(&q->use_count);
}
mutex_unlock(&dev->struct_mutex);
return 0;
}
/**
* Called when "/proc/dri/.../bufs" is read.
*/
int drm_bufs_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_device_dma *dma;
int i, seg_pages;
mutex_lock(&dev->struct_mutex);
dma = dev->dma;
if (!dma) {
mutex_unlock(&dev->struct_mutex);
return 0;
}
seq_printf(m, " o size count free segs pages kB\n\n");
for (i = 0; i <= DRM_MAX_ORDER; i++) {
if (dma->bufs[i].buf_count) {
seg_pages = dma->bufs[i].seg_count * (1 << dma->bufs[i].page_order);
seq_printf(m, "%2d %8d %5d %5d %5d %5d %5ld\n",
i,
dma->bufs[i].buf_size,
dma->bufs[i].buf_count,
atomic_read(&dma->bufs[i].freelist.count),
dma->bufs[i].seg_count,
seg_pages,
seg_pages * PAGE_SIZE / 1024);
}
}
seq_printf(m, "\n");
for (i = 0; i < dma->buf_count; i++) {
if (i && !(i % 32))
seq_printf(m, "\n");
seq_printf(m, " %d", dma->buflist[i]->list);
}
seq_printf(m, "\n");
mutex_unlock(&dev->struct_mutex);
return 0;
}
/**
* Called when "/proc/dri/.../vblank" is read.
*/
int drm_vblank_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
int crtc;
mutex_lock(&dev->struct_mutex);
for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
seq_printf(m, "CRTC %d enable: %d\n",
crtc, atomic_read(&dev->vblank_refcount[crtc]));
seq_printf(m, "CRTC %d counter: %d\n",
crtc, drm_vblank_count(dev, crtc));
seq_printf(m, "CRTC %d last wait: %d\n",
crtc, dev->last_vblank_wait[crtc]);
seq_printf(m, "CRTC %d in modeset: %d\n",
crtc, dev->vblank_inmodeset[crtc]);
}
mutex_unlock(&dev->struct_mutex);
return 0;
}
/**
* Called when "/proc/dri/.../clients" is read.
*
*/
int drm_clients_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_file *priv;
mutex_lock(&dev->struct_mutex);
seq_printf(m, "a dev pid uid magic ioctls\n\n");
list_for_each_entry(priv, &dev->filelist, lhead) {
seq_printf(m, "%c %3d %5d %5d %10u %10lu\n",
priv->authenticated ? 'y' : 'n',
priv->minor->index,
priv->pid,
priv->uid, priv->magic, priv->ioctl_count);
}
mutex_unlock(&dev->struct_mutex);
return 0;
}
int drm_gem_one_name_info(int id, void *ptr, void *data)
{
struct drm_gem_object *obj = ptr;
struct seq_file *m = data;
seq_printf(m, "name %d size %zd\n", obj->name, obj->size);
seq_printf(m, "%6d %8zd %7d %8d\n",
obj->name, obj->size,
atomic_read(&obj->handlecount.refcount),
atomic_read(&obj->refcount.refcount));
return 0;
}
int drm_gem_name_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
seq_printf(m, " name size handles refcount\n");
idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, m);
return 0;
}
int drm_gem_object_info(struct seq_file *m, void* data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
seq_printf(m, "%d objects\n", atomic_read(&dev->object_count));
seq_printf(m, "%d object bytes\n", atomic_read(&dev->object_memory));
seq_printf(m, "%d pinned\n", atomic_read(&dev->pin_count));
seq_printf(m, "%d pin bytes\n", atomic_read(&dev->pin_memory));
seq_printf(m, "%d gtt bytes\n", atomic_read(&dev->gtt_memory));
seq_printf(m, "%d gtt total\n", dev->gtt_total);
return 0;
}
#if DRM_DEBUG_CODE
int drm_vma_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_vma_entry *pt;
struct vm_area_struct *vma;
#if defined(__i386__)
unsigned int pgprot;
#endif
mutex_lock(&dev->struct_mutex);
seq_printf(m, "vma use count: %d, high_memory = %p, 0x%08llx\n",
atomic_read(&dev->vma_count),
high_memory, (u64)virt_to_phys(high_memory));
list_for_each_entry(pt, &dev->vmalist, head) {
vma = pt->vma;
if (!vma)
continue;
seq_printf(m,
"\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
pt->pid, vma->vm_start, vma->vm_end,
vma->vm_flags & VM_READ ? 'r' : '-',
vma->vm_flags & VM_WRITE ? 'w' : '-',
vma->vm_flags & VM_EXEC ? 'x' : '-',
vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
vma->vm_flags & VM_LOCKED ? 'l' : '-',
vma->vm_flags & VM_IO ? 'i' : '-',
vma->vm_pgoff);
#if defined(__i386__)
pgprot = pgprot_val(vma->vm_page_prot);
seq_printf(m, " %c%c%c%c%c%c%c%c%c",
pgprot & _PAGE_PRESENT ? 'p' : '-',
pgprot & _PAGE_RW ? 'w' : 'r',
pgprot & _PAGE_USER ? 'u' : 's',
pgprot & _PAGE_PWT ? 't' : 'b',
pgprot & _PAGE_PCD ? 'u' : 'c',
pgprot & _PAGE_ACCESSED ? 'a' : '-',
pgprot & _PAGE_DIRTY ? 'd' : '-',
pgprot & _PAGE_PSE ? 'm' : 'k',
pgprot & _PAGE_GLOBAL ? 'g' : 'l');
#endif
seq_printf(m, "\n");
}
mutex_unlock(&dev->struct_mutex);
return 0;
}
#endif

View File

@@ -954,6 +954,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
DRM_IOCTL_SG_FREE, (unsigned long)request);
}
#if defined(CONFIG_X86) || defined(CONFIG_IA64)
typedef struct drm_update_draw32 {
drm_drawable_t handle;
unsigned int type;
@@ -984,6 +985,7 @@ static int compat_drm_update_draw(struct file *file, unsigned int cmd,
DRM_IOCTL_UPDATE_DRAW, (unsigned long)request);
return err;
}
#endif
struct drm_wait_vblank_request32 {
enum drm_vblank_seq_type type;
@@ -1066,7 +1068,9 @@ drm_ioctl_compat_t *drm_compat_ioctls[] = {
#endif
[DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC32)] = compat_drm_sg_alloc,
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE32)] = compat_drm_sg_free,
#if defined(CONFIG_X86) || defined(CONFIG_IA64)
[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW32)] = compat_drm_update_draw,
#endif
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
};

View File

@@ -159,7 +159,7 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
#endif /* debug_memory */
void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
{
if (drm_core_has_AGP(dev) &&
dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
@@ -169,7 +169,7 @@ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
}
EXPORT_SYMBOL(drm_core_ioremap);
void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev)
void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev)
{
if (drm_core_has_AGP(dev) &&
dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
@@ -179,7 +179,7 @@ void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev)
}
EXPORT_SYMBOL(drm_core_ioremap_wc);
void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
{
if (!map->handle || !map->size)
return;

View File

@@ -37,58 +37,104 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <linux/seq_file.h>
#include "drmP.h"
static int drm_name_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_vm_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_clients_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_queues_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_bufs_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_vblank_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_gem_name_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_gem_object_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
#if DRM_DEBUG_CODE
static int drm_vma_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
#endif
/***************************************************
* Initialization, etc.
**************************************************/
/**
* Proc file list.
*/
static struct drm_proc_list {
const char *name; /**< file name */
int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/
u32 driver_features; /**< Required driver features for this entry */
} drm_proc_list[] = {
static struct drm_info_list drm_proc_list[] = {
{"name", drm_name_info, 0},
{"mem", drm_mem_info, 0},
{"vm", drm_vm_info, 0},
{"clients", drm_clients_info, 0},
{"queues", drm_queues_info, 0},
{"bufs", drm_bufs_info, 0},
{"vblank", drm_vblank_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
{"gem_objects", drm_gem_object_info, DRIVER_GEM},
#if DRM_DEBUG_CODE
{"vma", drm_vma_info},
{"vma", drm_vma_info, 0},
#endif
};
#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list)
static int drm_proc_open(struct inode *inode, struct file *file)
{
struct drm_info_node* node = PDE(inode)->data;
return single_open(file, node->info_ent->show, node);
}
static const struct file_operations drm_proc_fops = {
.owner = THIS_MODULE,
.open = drm_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/**
* Initialize the DRI proc filesystem for a device.
* Initialize a given set of proc files for a device
*
* \param dev DRM device.
* \param minor device minor number.
* \param files The array of files to create
* \param count The number of files given
* \param root DRI proc dir entry.
* \param minor device minor number
* \return Zero on success, non-zero on failure
*
* Create a given set of proc files represented by an array of
* gdm_proc_lists in the given root directory.
*/
int drm_proc_create_files(struct drm_info_list *files, int count,
struct proc_dir_entry *root, struct drm_minor *minor)
{
struct drm_device *dev = minor->dev;
struct proc_dir_entry *ent;
struct drm_info_node *tmp;
char name[64];
int i, ret;
for (i = 0; i < count; i++) {
u32 features = files[i].driver_features;
if (features != 0 &&
(dev->driver->driver_features & features) != features)
continue;
tmp = drm_alloc(sizeof(struct drm_info_node), _DRM_DRIVER);
ent = create_proc_entry(files[i].name, S_IFREG | S_IRUGO, root);
if (!ent) {
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
name, files[i].name);
drm_free(tmp, sizeof(struct drm_info_node),
_DRM_DRIVER);
ret = -1;
goto fail;
}
ent->proc_fops = &drm_proc_fops;
ent->data = tmp;
tmp->minor = minor;
tmp->info_ent = &files[i];
list_add(&(tmp->list), &(minor->proc_nodes.list));
}
return 0;
fail:
for (i = 0; i < count; i++)
remove_proc_entry(drm_proc_list[i].name, minor->proc_root);
return ret;
}
/**
* Initialize the DRI proc filesystem for a device
*
* \param dev DRM device
* \param minor device minor number
* \param root DRI proc dir entry.
* \param dev_root resulting DRI device proc dir entry.
* \return root entry pointer on success, or NULL on failure.
@@ -101,34 +147,24 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
struct proc_dir_entry *root)
{
struct drm_device *dev = minor->dev;
struct proc_dir_entry *ent;
int i, j, ret;
char name[64];
int ret;
INIT_LIST_HEAD(&minor->proc_nodes.list);
sprintf(name, "%d", minor_id);
minor->dev_root = proc_mkdir(name, root);
if (!minor->dev_root) {
minor->proc_root = proc_mkdir(name, root);
if (!minor->proc_root) {
DRM_ERROR("Cannot create /proc/dri/%s\n", name);
return -1;
}
for (i = 0; i < DRM_PROC_ENTRIES; i++) {
u32 features = drm_proc_list[i].driver_features;
if (features != 0 &&
(dev->driver->driver_features & features) != features)
continue;
ent = create_proc_entry(drm_proc_list[i].name,
S_IFREG | S_IRUGO, minor->dev_root);
if (!ent) {
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
name, drm_proc_list[i].name);
ret = -1;
goto fail;
}
ent->read_proc = drm_proc_list[i].f;
ent->data = minor;
ret = drm_proc_create_files(drm_proc_list, DRM_PROC_ENTRIES,
minor->proc_root, minor);
if (ret) {
remove_proc_entry(name, root);
minor->proc_root = NULL;
DRM_ERROR("Failed to create core drm proc files\n");
return ret;
}
if (dev->driver->proc_init) {
@@ -136,19 +172,32 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
if (ret) {
DRM_ERROR("DRM: Driver failed to initialize "
"/proc/dri.\n");
goto fail;
return ret;
}
}
return 0;
fail:
}
for (j = 0; j < i; j++)
remove_proc_entry(drm_proc_list[i].name,
minor->dev_root);
remove_proc_entry(name, root);
minor->dev_root = NULL;
return ret;
int drm_proc_remove_files(struct drm_info_list *files, int count,
struct drm_minor *minor)
{
struct list_head *pos, *q;
struct drm_info_node *tmp;
int i;
for (i = 0; i < count; i++) {
list_for_each_safe(pos, q, &minor->proc_nodes.list) {
tmp = list_entry(pos, struct drm_info_node, list);
if (tmp->info_ent == &files[i]) {
remove_proc_entry(files[i].name,
minor->proc_root);
list_del(pos);
drm_free(tmp, sizeof(struct drm_info_node),
_DRM_DRIVER);
}
}
}
return 0;
}
/**
@@ -164,570 +213,19 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
{
struct drm_device *dev = minor->dev;
int i;
char name[64];
if (!root || !minor->dev_root)
if (!root || !minor->proc_root)
return 0;
if (dev->driver->proc_cleanup)
dev->driver->proc_cleanup(minor);
for (i = 0; i < DRM_PROC_ENTRIES; i++)
remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
drm_proc_remove_files(drm_proc_list, DRM_PROC_ENTRIES, minor);
sprintf(name, "%d", minor->index);
remove_proc_entry(name, root);
return 0;
}
/**
* Called when "/proc/dri/.../name" is read.
*
* \param buf output buffer.
* \param start start of output data.
* \param offset requested start offset.
* \param request requested number of bytes.
* \param eof whether there is no more data to return.
* \param data private data.
* \return number of written bytes.
*
* Prints the device name together with the bus id if available.
*/
static int drm_name_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_master *master = minor->master;
struct drm_device *dev = minor->dev;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
if (!master)
return 0;
*start = &buf[offset];
*eof = 0;
if (master->unique) {
DRM_PROC_PRINT("%s %s %s\n",
dev->driver->pci_driver.name,
pci_name(dev->pdev), master->unique);
} else {
DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name,
pci_name(dev->pdev));
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
/**
* Called when "/proc/dri/.../vm" is read.
*
* \param buf output buffer.
* \param start start of output data.
* \param offset requested start offset.
* \param request requested number of bytes.
* \param eof whether there is no more data to return.
* \param data private data.
* \return number of written bytes.
*
* Prints information about all mappings in drm_device::maplist.
*/
static int drm__vm_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int len = 0;
struct drm_map *map;
struct drm_map_list *r_list;
/* Hardcoded from _DRM_FRAME_BUFFER,
_DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
_DRM_SCATTER_GATHER and _DRM_CONSISTENT */
const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
const char *type;
int i;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("slot offset size type flags "
"address mtrr\n\n");
i = 0;
list_for_each_entry(r_list, &dev->maplist, head) {
map = r_list->map;
if (!map)
continue;
if (map->type < 0 || map->type > 5)
type = "??";
else
type = types[map->type];
DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
i,
map->offset,
map->size, type, map->flags,
(unsigned long) r_list->user_token);
if (map->mtrr < 0) {
DRM_PROC_PRINT("none\n");
} else {
DRM_PROC_PRINT("%4d\n", map->mtrr);
}
i++;
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
/**
* Simply calls _vm_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_vm_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
ret = drm__vm_info(buf, start, offset, request, eof, data);
mutex_unlock(&dev->struct_mutex);
return ret;
}
/**
* Called when "/proc/dri/.../queues" is read.
*
* \param buf output buffer.
* \param start start of output data.
* \param offset requested start offset.
* \param request requested number of bytes.
* \param eof whether there is no more data to return.
* \param data private data.
* \return number of written bytes.
*/
static int drm__queues_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int len = 0;
int i;
struct drm_queue *q;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT(" ctx/flags use fin"
" blk/rw/rwf wait flushed queued"
" locks\n\n");
for (i = 0; i < dev->queue_count; i++) {
q = dev->queuelist[i];
atomic_inc(&q->use_count);
DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
"%5d/0x%03x %5d %5d"
" %5d/%c%c/%c%c%c %5Zd\n",
i,
q->flags,
atomic_read(&q->use_count),
atomic_read(&q->finalization),
atomic_read(&q->block_count),
atomic_read(&q->block_read) ? 'r' : '-',
atomic_read(&q->block_write) ? 'w' : '-',
waitqueue_active(&q->read_queue) ? 'r' : '-',
waitqueue_active(&q->
write_queue) ? 'w' : '-',
waitqueue_active(&q->
flush_queue) ? 'f' : '-',
DRM_BUFCOUNT(&q->waitlist));
atomic_dec(&q->use_count);
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
/**
* Simply calls _queues_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_queues_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
ret = drm__queues_info(buf, start, offset, request, eof, data);
mutex_unlock(&dev->struct_mutex);
return ret;
}
/**
* Called when "/proc/dri/.../bufs" is read.
*
* \param buf output buffer.
* \param start start of output data.
* \param offset requested start offset.
* \param request requested number of bytes.
* \param eof whether there is no more data to return.
* \param data private data.
* \return number of written bytes.
*/
static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int len = 0;
struct drm_device_dma *dma = dev->dma;
int i;
if (!dma || offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT(" o size count free segs pages kB\n\n");
for (i = 0; i <= DRM_MAX_ORDER; i++) {
if (dma->bufs[i].buf_count)
DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\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))
* PAGE_SIZE / 1024);
}
DRM_PROC_PRINT("\n");
for (i = 0; i < dma->buf_count; i++) {
if (i && !(i % 32))
DRM_PROC_PRINT("\n");
DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
}
DRM_PROC_PRINT("\n");
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
/**
* Simply calls _bufs_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
ret = drm__bufs_info(buf, start, offset, request, eof, data);
mutex_unlock(&dev->struct_mutex);
return ret;
}
/**
* Called when "/proc/dri/.../vblank" is read.
*
* \param buf output buffer.
* \param start start of output data.
* \param offset requested start offset.
* \param request requested number of bytes.
* \param eof whether there is no more data to return.
* \param data private data.
* \return number of written bytes.
*/
static int drm__vblank_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int len = 0;
int crtc;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
DRM_PROC_PRINT("CRTC %d enable: %d\n",
crtc, atomic_read(&dev->vblank_refcount[crtc]));
DRM_PROC_PRINT("CRTC %d counter: %d\n",
crtc, drm_vblank_count(dev, crtc));
DRM_PROC_PRINT("CRTC %d last wait: %d\n",
crtc, dev->last_vblank_wait[crtc]);
DRM_PROC_PRINT("CRTC %d in modeset: %d\n",
crtc, dev->vblank_inmodeset[crtc]);
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
/**
* Simply calls _vblank_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_vblank_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
ret = drm__vblank_info(buf, start, offset, request, eof, data);
mutex_unlock(&dev->struct_mutex);
return ret;
}
/**
* Called when "/proc/dri/.../clients" is read.
*
* \param buf output buffer.
* \param start start of output data.
* \param offset requested start offset.
* \param request requested number of bytes.
* \param eof whether there is no more data to return.
* \param data private data.
* \return number of written bytes.
*/
static int drm__clients_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int len = 0;
struct drm_file *priv;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
list_for_each_entry(priv, &dev->filelist, lhead) {
DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
priv->authenticated ? 'y' : 'n',
priv->minor->index,
priv->pid,
priv->uid, priv->magic, priv->ioctl_count);
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
/**
* Simply calls _clients_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_clients_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
ret = drm__clients_info(buf, start, offset, request, eof, data);
mutex_unlock(&dev->struct_mutex);
return ret;
}
struct drm_gem_name_info_data {
int len;
char *buf;
int eof;
};
static int drm_gem_one_name_info(int id, void *ptr, void *data)
{
struct drm_gem_object *obj = ptr;
struct drm_gem_name_info_data *nid = data;
DRM_INFO("name %d size %zd\n", obj->name, obj->size);
if (nid->eof)
return 0;
nid->len += sprintf(&nid->buf[nid->len],
"%6d %8zd %7d %8d\n",
obj->name, obj->size,
atomic_read(&obj->handlecount.refcount),
atomic_read(&obj->refcount.refcount));
if (nid->len > DRM_PROC_LIMIT) {
nid->eof = 1;
return 0;
}
return 0;
}
static int drm_gem_name_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
struct drm_gem_name_info_data nid;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
nid.len = sprintf(buf, " name size handles refcount\n");
nid.buf = buf;
nid.eof = 0;
idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid);
*start = &buf[offset];
*eof = 0;
if (nid.len > request + offset)
return request;
*eof = 1;
return nid.len - offset;
}
static int drm_gem_object_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count));
DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory));
DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count));
DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory));
DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory));
DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total);
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
#if DRM_DEBUG_CODE
static int drm__vma_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int len = 0;
struct drm_vma_entry *pt;
struct vm_area_struct *vma;
#if defined(__i386__)
unsigned int pgprot;
#endif
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
atomic_read(&dev->vma_count),
high_memory, virt_to_phys(high_memory));
list_for_each_entry(pt, &dev->vmalist, head) {
if (!(vma = pt->vma))
continue;
DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
pt->pid,
vma->vm_start,
vma->vm_end,
vma->vm_flags & VM_READ ? 'r' : '-',
vma->vm_flags & VM_WRITE ? 'w' : '-',
vma->vm_flags & VM_EXEC ? 'x' : '-',
vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
vma->vm_flags & VM_LOCKED ? 'l' : '-',
vma->vm_flags & VM_IO ? 'i' : '-',
vma->vm_pgoff);
#if defined(__i386__)
pgprot = pgprot_val(vma->vm_page_prot);
DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
pgprot & _PAGE_PRESENT ? 'p' : '-',
pgprot & _PAGE_RW ? 'w' : 'r',
pgprot & _PAGE_USER ? 'u' : 's',
pgprot & _PAGE_PWT ? 't' : 'b',
pgprot & _PAGE_PCD ? 'u' : 'c',
pgprot & _PAGE_ACCESSED ? 'a' : '-',
pgprot & _PAGE_DIRTY ? 'd' : '-',
pgprot & _PAGE_PSE ? 'm' : 'k',
pgprot & _PAGE_GLOBAL ? 'g' : 'l');
#endif
DRM_PROC_PRINT("\n");
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int drm_vma_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int ret;
mutex_lock(&dev->struct_mutex);
ret = drm__vma_info(buf, start, offset, request, eof, data);
mutex_unlock(&dev->struct_mutex);
return ret;
}
#endif

View File

@@ -50,6 +50,7 @@ struct idr drm_minors_idr;
struct class *drm_class;
struct proc_dir_entry *drm_proc_root;
struct dentry *drm_debugfs_root;
static int drm_minor_get_id(struct drm_device *dev, int type)
{
@@ -313,7 +314,15 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t
goto err_mem;
}
} else
new_minor->dev_root = NULL;
new_minor->proc_root = NULL;
#if defined(CONFIG_DEBUG_FS)
ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
if (ret) {
DRM_ERROR("DRM: Failed to initialize /debugfs/dri.\n");
goto err_g2;
}
#endif
ret = drm_sysfs_device_add(new_minor);
if (ret) {
@@ -372,6 +381,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
}
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
pci_set_drvdata(pdev, dev);
ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
if (ret)
goto err_g2;
@@ -395,9 +405,9 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
list_add_tail(&dev->driver_item, &driver->device_list);
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, dev->primary->index);
driver->date, pci_name(pdev), dev->primary->index);
return 0;
@@ -409,29 +419,7 @@ err_g1:
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
return ret;
}
/**
* Put a device minor number.
*
* \param dev device data structure
* \return always zero
*
* Cleans up the proc resources. If it is the last minor then release the foreign
* "drm" data, otherwise unregisters the "drm" data, frees the dev list and
* unregisters the character device.
*/
int drm_put_dev(struct drm_device * dev)
{
DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
if (dev->devname) {
drm_free(dev->devname, strlen(dev->devname) + 1,
DRM_MEM_DRIVER);
dev->devname = NULL;
}
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
return 0;
}
EXPORT_SYMBOL(drm_get_dev);
/**
* Put a secondary minor number.
@@ -451,6 +439,10 @@ int drm_put_minor(struct drm_minor **minor_p)
if (minor->type == DRM_MINOR_LEGACY)
drm_proc_cleanup(minor, drm_proc_root);
#if defined(CONFIG_DEBUG_FS)
drm_debugfs_cleanup(minor);
#endif
drm_sysfs_device_remove(minor);
idr_remove(&drm_minors_idr, minor->index);
@@ -459,3 +451,67 @@ int drm_put_minor(struct drm_minor **minor_p)
*minor_p = NULL;
return 0;
}
/**
* Called via drm_exit() at module unload time or when pci device is
* unplugged.
*
* Cleans up all DRM device, calling drm_lastclose().
*
* \sa drm_init
*/
void drm_put_dev(struct drm_device *dev)
{
struct drm_driver *driver = dev->driver;
struct drm_map_list *r_list, *list_temp;
DRM_DEBUG("\n");
if (!dev) {
DRM_ERROR("cleanup called no dev\n");
return;
}
drm_vblank_cleanup(dev);
drm_lastclose(dev);
if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
dev->agp && dev->agp->agp_mtrr >= 0) {
int retval;
retval = mtrr_del(dev->agp->agp_mtrr,
dev->agp->agp_info.aper_base,
dev->agp->agp_info.aper_size * 1024 * 1024);
DRM_DEBUG("mtrr_del=%d\n", retval);
}
if (dev->driver->unload)
dev->driver->unload(dev);
if (drm_core_has_AGP(dev) && dev->agp) {
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
dev->agp = NULL;
}
drm_ht_remove(&dev->map_hash);
drm_ctxbitmap_cleanup(dev);
list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
drm_rmmap(dev, r_list->map);
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_put_minor(&dev->control);
if (driver->driver_features & DRIVER_GEM)
drm_gem_destroy(dev);
drm_put_minor(&dev->primary);
if (dev->devname) {
drm_free(dev->devname, strlen(dev->devname) + 1,
DRM_MEM_DRIVER);
dev->devname = NULL;
}
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
}
EXPORT_SYMBOL(drm_put_dev);

View File

@@ -35,7 +35,9 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
struct drm_minor *drm_minor = to_drm_minor(dev);
struct drm_device *drm_dev = drm_minor->dev;
if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->suspend)
if (drm_minor->type == DRM_MINOR_LEGACY &&
!drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
drm_dev->driver->suspend)
return drm_dev->driver->suspend(drm_dev, state);
return 0;
@@ -53,7 +55,9 @@ static int drm_sysfs_resume(struct device *dev)
struct drm_minor *drm_minor = to_drm_minor(dev);
struct drm_device *drm_dev = drm_minor->dev;
if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->resume)
if (drm_minor->type == DRM_MINOR_LEGACY &&
!drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
drm_dev->driver->resume)
return drm_dev->driver->resume(drm_dev);
return 0;
@@ -118,20 +122,6 @@ void drm_sysfs_destroy(void)
class_destroy(drm_class);
}
static ssize_t show_dri(struct device *device, struct device_attribute *attr,
char *buf)
{
struct drm_minor *drm_minor = to_drm_minor(device);
struct drm_device *drm_dev = drm_minor->dev;
if (drm_dev->driver->dri_library_name)
return drm_dev->driver->dri_library_name(drm_dev, buf);
return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name);
}
static struct device_attribute device_attrs[] = {
__ATTR(dri_library_name, S_IRUGO, show_dri, NULL),
};
/**
* drm_sysfs_device_release - do nothing
* @dev: Linux device
@@ -359,8 +349,8 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
DRM_DEBUG("adding \"%s\" to sysfs\n",
drm_get_connector_name(connector));
snprintf(connector->kdev.bus_id, BUS_ID_SIZE, "card%d-%s",
dev->primary->index, drm_get_connector_name(connector));
dev_set_name(&connector->kdev, "card%d-%s",
dev->primary->index, drm_get_connector_name(connector));
ret = device_register(&connector->kdev);
if (ret) {
@@ -461,6 +451,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev)
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
}
EXPORT_SYMBOL(drm_sysfs_hotplug_event);
/**
* drm_sysfs_device_add - adds a class device to sysfs for a character driver
@@ -474,7 +465,6 @@ void drm_sysfs_hotplug_event(struct drm_device *dev)
int drm_sysfs_device_add(struct drm_minor *minor)
{
int err;
int i, j;
char *minor_str;
minor->kdev.parent = &minor->dev->pdev->dev;
@@ -496,18 +486,8 @@ int drm_sysfs_device_add(struct drm_minor *minor)
goto err_out;
}
for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
err = device_create_file(&minor->kdev, &device_attrs[i]);
if (err)
goto err_out_files;
}
return 0;
err_out_files:
if (i > 0)
for (j = 0; j < i; j++)
device_remove_file(&minor->kdev, &device_attrs[j]);
device_unregister(&minor->kdev);
err_out:
@@ -523,9 +503,5 @@ err_out:
*/
void drm_sysfs_device_remove(struct drm_minor *minor)
{
int i;
for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
device_remove_file(&minor->kdev, &device_attrs[i]);
device_unregister(&minor->kdev);
}

View File

@@ -91,7 +91,7 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_file *priv = vma->vm_file->private_data;
struct drm_device *dev = priv->minor->dev;
struct drm_map *map = NULL;
struct drm_local_map *map = NULL;
struct drm_map_list *r_list;
struct drm_hash_item *hash;
@@ -115,9 +115,9 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
* Using vm_pgoff as a selector forces us to use this unusual
* addressing scheme.
*/
unsigned long offset = (unsigned long)vmf->virtual_address -
vma->vm_start;
unsigned long baddr = map->offset + offset;
resource_size_t offset = (unsigned long)vmf->virtual_address -
vma->vm_start;
resource_size_t baddr = map->offset + offset;
struct drm_agp_mem *agpmem;
struct page *page;
@@ -149,8 +149,10 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
vmf->page = page;
DRM_DEBUG
("baddr = 0x%lx page = 0x%p, offset = 0x%lx, count=%d\n",
baddr, __va(agpmem->memory->memory[offset]), offset,
("baddr = 0x%llx page = 0x%p, offset = 0x%llx, count=%d\n",
(unsigned long long)baddr,
__va(agpmem->memory->memory[offset]),
(unsigned long long)offset,
page_count(page));
return 0;
}
@@ -176,7 +178,7 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
*/
static int drm_do_vm_shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_map *map = (struct drm_map *) vma->vm_private_data;
struct drm_local_map *map = vma->vm_private_data;
unsigned long offset;
unsigned long i;
struct page *page;
@@ -209,7 +211,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
struct drm_file *priv = vma->vm_file->private_data;
struct drm_device *dev = priv->minor->dev;
struct drm_vma_entry *pt, *temp;
struct drm_map *map;
struct drm_local_map *map;
struct drm_map_list *r_list;
int found_maps = 0;
@@ -322,7 +324,7 @@ static int drm_do_vm_dma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
*/
static int drm_do_vm_sg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_map *map = (struct drm_map *) vma->vm_private_data;
struct drm_local_map *map = vma->vm_private_data;
struct drm_file *priv = vma->vm_file->private_data;
struct drm_device *dev = priv->minor->dev;
struct drm_sg_mem *entry = dev->sg;
@@ -512,14 +514,14 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
return 0;
}
unsigned long drm_core_get_map_ofs(struct drm_map * map)
resource_size_t drm_core_get_map_ofs(struct drm_local_map * map)
{
return map->offset;
}
EXPORT_SYMBOL(drm_core_get_map_ofs);
unsigned long drm_core_get_reg_ofs(struct drm_device *dev)
resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
{
#ifdef __alpha__
return dev->hose->dense_mem_base - dev->hose->mem_space->start;
@@ -547,8 +549,8 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
{
struct drm_file *priv = filp->private_data;
struct drm_device *dev = priv->minor->dev;
struct drm_map *map = NULL;
unsigned long offset = 0;
struct drm_local_map *map = NULL;
resource_size_t offset = 0;
struct drm_hash_item *hash;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
@@ -623,9 +625,9 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
vma->vm_page_prot))
return -EAGAIN;
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%lx\n",
" offset = 0x%llx\n",
map->type,
vma->vm_start, vma->vm_end, map->offset + offset);
vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset));
vma->vm_ops = &drm_vm_ops;
break;
case _DRM_CONSISTENT:

View File

@@ -77,8 +77,8 @@ typedef struct _drm_i810_ring_buffer {
} drm_i810_ring_buffer_t;
typedef struct drm_i810_private {
struct drm_map *sarea_map;
struct drm_map *mmio_map;
struct drm_local_map *sarea_map;
struct drm_local_map *mmio_map;
drm_i810_sarea_t *sarea_priv;
drm_i810_ring_buffer_t ring;

View File

@@ -84,8 +84,8 @@ typedef struct _drm_i830_ring_buffer {
} drm_i830_ring_buffer_t;
typedef struct drm_i830_private {
struct drm_map *sarea_map;
struct drm_map *mmio_map;
struct drm_local_map *sarea_map;
struct drm_local_map *mmio_map;
drm_i830_sarea_t *sarea_priv;
drm_i830_ring_buffer_t ring;

View File

@@ -7,7 +7,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
i915_suspend.o \
i915_gem.o \
i915_gem_debug.o \
i915_gem_proc.o \
i915_gem_debugfs.o \
i915_gem_tiling.o \
intel_display.o \
intel_crt.o \

View File

@@ -41,7 +41,6 @@
int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
u32 last_acthd = I915_READ(acthd_reg);
@@ -58,8 +57,12 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
if (ring->space >= n)
return 0;
if (master_priv->sarea_priv)
master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
if (dev->primary->master) {
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
if (master_priv->sarea_priv)
master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
}
if (ring->head != last_head)
i = 0;
@@ -356,7 +359,7 @@ static int validate_cmd(int cmd)
return ret;
}
static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwords)
static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
@@ -370,8 +373,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
for (i = 0; i < dwords;) {
int cmd, sz;
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
return -EINVAL;
cmd = buffer[i];
if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
return -EINVAL;
@@ -379,11 +381,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
OUT_RING(cmd);
while (++i, --sz) {
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
sizeof(cmd))) {
return -EINVAL;
}
OUT_RING(cmd);
OUT_RING(buffer[i]);
}
}
@@ -397,17 +395,13 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
int
i915_emit_box(struct drm_device *dev,
struct drm_clip_rect __user *boxes,
struct drm_clip_rect *boxes,
int i, int DR1, int DR4)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_clip_rect box;
struct drm_clip_rect box = boxes[i];
RING_LOCALS;
if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
return -EFAULT;
}
if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
DRM_ERROR("Bad box %d,%d..%d,%d\n",
box.x1, box.y1, box.x2, box.y2);
@@ -460,7 +454,9 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
}
static int i915_dispatch_cmdbuffer(struct drm_device * dev,
drm_i915_cmdbuffer_t * cmd)
drm_i915_cmdbuffer_t *cmd,
struct drm_clip_rect *cliprects,
void *cmdbuf)
{
int nbox = cmd->num_cliprects;
int i = 0, count, ret;
@@ -476,13 +472,13 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
for (i = 0; i < count; i++) {
if (i < nbox) {
ret = i915_emit_box(dev, cmd->cliprects, i,
ret = i915_emit_box(dev, cliprects, i,
cmd->DR1, cmd->DR4);
if (ret)
return ret;
}
ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4);
ret = i915_emit_cmds(dev, cmdbuf, cmd->sz / 4);
if (ret)
return ret;
}
@@ -492,10 +488,10 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
}
static int i915_dispatch_batchbuffer(struct drm_device * dev,
drm_i915_batchbuffer_t * batch)
drm_i915_batchbuffer_t * batch,
struct drm_clip_rect *cliprects)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_clip_rect __user *boxes = batch->cliprects;
int nbox = batch->num_cliprects;
int i = 0, count;
RING_LOCALS;
@@ -511,7 +507,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
for (i = 0; i < count; i++) {
if (i < nbox) {
int ret = i915_emit_box(dev, boxes, i,
int ret = i915_emit_box(dev, cliprects, i,
batch->DR1, batch->DR4);
if (ret)
return ret;
@@ -626,6 +622,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
master_priv->sarea_priv;
drm_i915_batchbuffer_t *batch = data;
int ret;
struct drm_clip_rect *cliprects = NULL;
if (!dev_priv->allow_batchbuffer) {
DRM_ERROR("Batchbuffer ioctl disabled\n");
@@ -637,17 +634,35 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
batch->num_cliprects *
sizeof(struct drm_clip_rect)))
return -EFAULT;
if (batch->num_cliprects < 0)
return -EINVAL;
if (batch->num_cliprects) {
cliprects = drm_calloc(batch->num_cliprects,
sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
if (cliprects == NULL)
return -ENOMEM;
ret = copy_from_user(cliprects, batch->cliprects,
batch->num_cliprects *
sizeof(struct drm_clip_rect));
if (ret != 0)
goto fail_free;
}
mutex_lock(&dev->struct_mutex);
ret = i915_dispatch_batchbuffer(dev, batch);
ret = i915_dispatch_batchbuffer(dev, batch, cliprects);
mutex_unlock(&dev->struct_mutex);
if (sarea_priv)
sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
fail_free:
drm_free(cliprects,
batch->num_cliprects * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
return ret;
}
@@ -659,6 +674,8 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
master_priv->sarea_priv;
drm_i915_cmdbuffer_t *cmdbuf = data;
struct drm_clip_rect *cliprects = NULL;
void *batch_data;
int ret;
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
@@ -666,25 +683,50 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
if (cmdbuf->num_cliprects &&
DRM_VERIFYAREA_READ(cmdbuf->cliprects,
cmdbuf->num_cliprects *
sizeof(struct drm_clip_rect))) {
DRM_ERROR("Fault accessing cliprects\n");
return -EFAULT;
if (cmdbuf->num_cliprects < 0)
return -EINVAL;
batch_data = drm_alloc(cmdbuf->sz, DRM_MEM_DRIVER);
if (batch_data == NULL)
return -ENOMEM;
ret = copy_from_user(batch_data, cmdbuf->buf, cmdbuf->sz);
if (ret != 0)
goto fail_batch_free;
if (cmdbuf->num_cliprects) {
cliprects = drm_calloc(cmdbuf->num_cliprects,
sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
if (cliprects == NULL)
goto fail_batch_free;
ret = copy_from_user(cliprects, cmdbuf->cliprects,
cmdbuf->num_cliprects *
sizeof(struct drm_clip_rect));
if (ret != 0)
goto fail_clip_free;
}
mutex_lock(&dev->struct_mutex);
ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
ret = i915_dispatch_cmdbuffer(dev, cmdbuf, cliprects, batch_data);
mutex_unlock(&dev->struct_mutex);
if (ret) {
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
return ret;
goto fail_batch_free;
}
if (sarea_priv)
sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return 0;
fail_batch_free:
drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER);
fail_clip_free:
drm_free(cliprects,
cmdbuf->num_cliprects * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
return ret;
}
static int i915_flip_bufs(struct drm_device *dev, void *data,
@@ -880,7 +922,7 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
* Some of the preallocated space is taken by the GTT
* and popup. GTT is 1K per MB of aperture size, and popup is 4K.
*/
if (IS_G4X(dev))
if (IS_G4X(dev) || IS_IGD(dev))
overhead = 4096;
else
overhead = (*aperture_size / 1024) + 4096;
@@ -988,13 +1030,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
if (ret)
goto destroy_ringbuffer;
/* FIXME: re-add hotplug support */
#if 0
ret = drm_hotplug_init(dev);
if (ret)
goto destroy_ringbuffer;
#endif
/* Always safe in the mode setting case. */
/* FIXME: do pre/post-mode set stuff in core KMS code */
dev->vblank_disable_allowed = 1;
@@ -1007,7 +1042,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
intel_modeset_init(dev);
drm_helper_initial_config(dev, false);
drm_helper_initial_config(dev);
return 0;
@@ -1057,7 +1092,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
int i915_driver_load(struct drm_device *dev, unsigned long flags)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long base, size;
resource_size_t base, size;
int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
/* i915 has 4 more counters */

View File

@@ -42,6 +42,8 @@ module_param_named(modeset, i915_modeset, int, 0400);
unsigned int i915_fbpercrtc = 0;
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
static struct drm_driver driver;
static struct pci_device_id pciidlist[] = {
i915_PCI_IDS
};
@@ -117,6 +119,36 @@ static int i915_resume(struct drm_device *dev)
return ret;
}
static int __devinit
i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
return drm_get_dev(pdev, ent, &driver);
}
static void
i915_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
drm_put_dev(dev);
}
static int
i915_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
return i915_suspend(dev, state);
}
static int
i915_pci_resume(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
return i915_resume(dev);
}
static struct vm_operations_struct i915_gem_vm_ops = {
.fault = i915_gem_fault,
.open = drm_gem_vm_open,
@@ -150,8 +182,10 @@ static struct drm_driver driver = {
.get_reg_ofs = drm_core_get_reg_ofs,
.master_create = i915_master_create,
.master_destroy = i915_master_destroy,
.proc_init = i915_gem_proc_init,
.proc_cleanup = i915_gem_proc_cleanup,
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = i915_gem_debugfs_init,
.debugfs_cleanup = i915_gem_debugfs_cleanup,
#endif
.gem_init_object = i915_gem_init_object,
.gem_free_object = i915_gem_free_object,
.gem_vm_ops = &i915_gem_vm_ops,
@@ -172,6 +206,12 @@ static struct drm_driver driver = {
.pci_driver = {
.name = DRIVER_NAME,
.id_table = pciidlist,
.probe = i915_pci_probe,
.remove = i915_pci_remove,
#ifdef CONFIG_PM
.resume = i915_pci_resume,
.suspend = i915_pci_suspend,
#endif
},
.name = DRIVER_NAME,

View File

@@ -159,6 +159,9 @@ typedef struct drm_i915_private {
u32 irq_mask_reg;
u32 pipestat[2];
u32 hotplug_supported_mask;
struct work_struct hotplug_work;
int tex_lru_log_granularity;
int allow_batchbuffer;
struct mem_block *agp_heap;
@@ -297,6 +300,7 @@ typedef struct drm_i915_private {
*
* A reference is held on the buffer while on this list.
*/
spinlock_t active_list_lock;
struct list_head active_list;
/**
@@ -404,7 +408,8 @@ struct drm_i915_gem_object {
/** AGP memory structure for our GTT binding. */
DRM_AGP_MEM *agp_mem;
struct page **page_list;
struct page **pages;
int pages_refcount;
/**
* Current offset of the object in GTT space.
@@ -519,7 +524,7 @@ extern int i915_driver_device_is_agp(struct drm_device * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
extern int i915_emit_box(struct drm_device *dev,
struct drm_clip_rect __user *boxes,
struct drm_clip_rect *boxes,
int i, int DR1, int DR4);
/* i915_irq.c */
@@ -604,8 +609,6 @@ int i915_gem_get_tiling(struct drm_device *dev, void *data,
int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
void i915_gem_load(struct drm_device *dev);
int i915_gem_proc_init(struct drm_minor *minor);
void i915_gem_proc_cleanup(struct drm_minor *minor);
int i915_gem_init_object(struct drm_gem_object *obj);
void i915_gem_free_object(struct drm_gem_object *obj);
int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment);
@@ -649,6 +652,10 @@ void i915_gem_dump_object(struct drm_gem_object *obj, int len,
const char *where, uint32_t mark);
void i915_dump_lru(struct drm_device *dev, const char *where);
/* i915_debugfs.c */
int i915_gem_debugfs_init(struct drm_minor *minor);
void i915_gem_debugfs_cleanup(struct drm_minor *minor);
/* i915_suspend.c */
extern int i915_save_state(struct drm_device *dev);
extern int i915_restore_state(struct drm_device *dev);
@@ -784,15 +791,21 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
(dev)->pci_device == 0x2E22 || \
IS_GM45(dev))
#define IS_IGDG(dev) ((dev)->pci_device == 0xa001)
#define IS_IGDGM(dev) ((dev)->pci_device == 0xa011)
#define IS_IGD(dev) (IS_IGDG(dev) || IS_IGDGM(dev))
#define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \
(dev)->pci_device == 0x29B2 || \
(dev)->pci_device == 0x29D2)
(dev)->pci_device == 0x29D2 || \
(IS_IGD(dev)))
#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \
IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev))
#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev))
IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev) || \
IS_IGD(dev))
#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev))
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
@@ -801,6 +814,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
IS_I915GM(dev)))
#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev))
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024)

File diff suppressed because it is too large Load Diff

View File

@@ -105,12 +105,14 @@ i915_dump_lru(struct drm_device *dev, const char *where)
struct drm_i915_gem_object *obj_priv;
DRM_INFO("active list %s {\n", where);
spin_lock(&dev_priv->mm.active_list_lock);
list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
list)
{
DRM_INFO(" %p: %08x\n", obj_priv,
obj_priv->last_rendering_seqno);
}
spin_unlock(&dev_priv->mm.active_list_lock);
DRM_INFO("}\n");
DRM_INFO("flushing list %s {\n", where);
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,

View File

@@ -0,0 +1,263 @@
/*
* 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>
* Keith Packard <keithp@keithp.com>
*
*/
#include <linux/seq_file.h>
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"
#define DRM_I915_RING_DEBUG 1
#if defined(CONFIG_DEBUG_FS)
#define ACTIVE_LIST 1
#define FLUSHING_LIST 2
#define INACTIVE_LIST 3
static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv)
{
if (obj_priv->user_pin_count > 0)
return "P";
else if (obj_priv->pin_count > 0)
return "p";
else
return " ";
}
static const char *get_tiling_flag(struct drm_i915_gem_object *obj_priv)
{
switch (obj_priv->tiling_mode) {
default:
case I915_TILING_NONE: return " ";
case I915_TILING_X: return "X";
case I915_TILING_Y: return "Y";
}
}
static int i915_gem_object_list_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
uintptr_t list = (uintptr_t) node->info_ent->data;
struct list_head *head;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
spinlock_t *lock = NULL;
switch (list) {
case ACTIVE_LIST:
seq_printf(m, "Active:\n");
lock = &dev_priv->mm.active_list_lock;
spin_lock(lock);
head = &dev_priv->mm.active_list;
break;
case INACTIVE_LIST:
seq_printf(m, "Inctive:\n");
head = &dev_priv->mm.inactive_list;
break;
case FLUSHING_LIST:
seq_printf(m, "Flushing:\n");
head = &dev_priv->mm.flushing_list;
break;
default:
DRM_INFO("Ooops, unexpected list\n");
return 0;
}
list_for_each_entry(obj_priv, head, list)
{
struct drm_gem_object *obj = obj_priv->obj;
seq_printf(m, " %p: %s %08x %08x %d",
obj,
get_pin_flag(obj_priv),
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
if (obj->name)
seq_printf(m, " (name: %d)", obj->name);
if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
seq_printf(m, " (fence: %d\n", obj_priv->fence_reg);
seq_printf(m, "\n");
}
if (lock)
spin_unlock(lock);
return 0;
}
static int i915_gem_request_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_request *gem_request;
seq_printf(m, "Request:\n");
list_for_each_entry(gem_request, &dev_priv->mm.request_list, list) {
seq_printf(m, " %d @ %d\n",
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies));
}
return 0;
}
static int i915_gem_seqno_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
if (dev_priv->hw_status_page != NULL) {
seq_printf(m, "Current sequence: %d\n",
i915_get_gem_seqno(dev));
} else {
seq_printf(m, "Current sequence: hws uninitialized\n");
}
seq_printf(m, "Waiter sequence: %d\n",
dev_priv->mm.waiting_gem_seqno);
seq_printf(m, "IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
return 0;
}
static int i915_interrupt_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
seq_printf(m, "Interrupt enable: %08x\n",
I915_READ(IER));
seq_printf(m, "Interrupt identity: %08x\n",
I915_READ(IIR));
seq_printf(m, "Interrupt mask: %08x\n",
I915_READ(IMR));
seq_printf(m, "Pipe A stat: %08x\n",
I915_READ(PIPEASTAT));
seq_printf(m, "Pipe B stat: %08x\n",
I915_READ(PIPEBSTAT));
seq_printf(m, "Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received));
if (dev_priv->hw_status_page != NULL) {
seq_printf(m, "Current sequence: %d\n",
i915_get_gem_seqno(dev));
} else {
seq_printf(m, "Current sequence: hws uninitialized\n");
}
seq_printf(m, "Waiter sequence: %d\n",
dev_priv->mm.waiting_gem_seqno);
seq_printf(m, "IRQ sequence: %d\n",
dev_priv->mm.irq_gem_seqno);
return 0;
}
static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
for (i = 0; i < dev_priv->num_fence_regs; i++) {
struct drm_gem_object *obj = dev_priv->fence_regs[i].obj;
if (obj == NULL) {
seq_printf(m, "Fenced object[%2d] = unused\n", i);
} else {
struct drm_i915_gem_object *obj_priv;
obj_priv = obj->driver_private;
seq_printf(m, "Fenced object[%2d] = %p: %s "
"%08x %08zx %08x %s %08x %08x %d",
i, obj, get_pin_flag(obj_priv),
obj_priv->gtt_offset,
obj->size, obj_priv->stride,
get_tiling_flag(obj_priv),
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
if (obj->name)
seq_printf(m, " (name: %d)", obj->name);
seq_printf(m, "\n");
}
}
return 0;
}
static int i915_hws_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
volatile u32 *hws;
hws = (volatile u32 *)dev_priv->hw_status_page;
if (hws == NULL)
return 0;
for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) {
seq_printf(m, "0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
i * 4,
hws[i], hws[i + 1], hws[i + 2], hws[i + 3]);
}
return 0;
}
static struct drm_info_list i915_gem_debugfs_list[] = {
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
{"i915_gem_request", i915_gem_request_info, 0},
{"i915_gem_seqno", i915_gem_seqno_info, 0},
{"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
{"i915_gem_interrupt", i915_interrupt_info, 0},
{"i915_gem_hws", i915_hws_info, 0},
};
#define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list)
int i915_gem_debugfs_init(struct drm_minor *minor)
{
return drm_debugfs_create_files(i915_gem_debugfs_list,
I915_GEM_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
}
void i915_gem_debugfs_cleanup(struct drm_minor *minor)
{
drm_debugfs_remove_files(i915_gem_debugfs_list,
I915_GEM_DEBUGFS_ENTRIES, minor);
}
#endif /* CONFIG_DEBUG_FS */

View File

@@ -1,334 +0,0 @@
/*
* 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>
* Keith Packard <keithp@keithp.com>
*
*/
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"
static int i915_gem_active_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Active:\n");
list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
list)
{
struct drm_gem_object *obj = obj_priv->obj;
if (obj->name) {
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
obj, obj->name,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
} else {
DRM_PROC_PRINT(" %p: %08x %08x %d\n",
obj,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
}
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_gem_flushing_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Flushing:\n");
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
list)
{
struct drm_gem_object *obj = obj_priv->obj;
if (obj->name) {
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
obj, obj->name,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
} else {
DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
}
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_gem_inactive_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Inactive:\n");
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list,
list)
{
struct drm_gem_object *obj = obj_priv->obj;
if (obj->name) {
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
obj, obj->name,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
} else {
DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
}
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_gem_request_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_request *gem_request;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Request:\n");
list_for_each_entry(gem_request, &dev_priv->mm.request_list,
list)
{
DRM_PROC_PRINT(" %d @ %d\n",
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies));
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_gem_seqno_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
if (dev_priv->hw_status_page != NULL) {
DRM_PROC_PRINT("Current sequence: %d\n",
i915_get_gem_seqno(dev));
} else {
DRM_PROC_PRINT("Current sequence: hws uninitialized\n");
}
DRM_PROC_PRINT("Waiter sequence: %d\n",
dev_priv->mm.waiting_gem_seqno);
DRM_PROC_PRINT("IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_interrupt_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Interrupt enable: %08x\n",
I915_READ(IER));
DRM_PROC_PRINT("Interrupt identity: %08x\n",
I915_READ(IIR));
DRM_PROC_PRINT("Interrupt mask: %08x\n",
I915_READ(IMR));
DRM_PROC_PRINT("Pipe A stat: %08x\n",
I915_READ(PIPEASTAT));
DRM_PROC_PRINT("Pipe B stat: %08x\n",
I915_READ(PIPEBSTAT));
DRM_PROC_PRINT("Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received));
if (dev_priv->hw_status_page != NULL) {
DRM_PROC_PRINT("Current sequence: %d\n",
i915_get_gem_seqno(dev));
} else {
DRM_PROC_PRINT("Current sequence: hws uninitialized\n");
}
DRM_PROC_PRINT("Waiter sequence: %d\n",
dev_priv->mm.waiting_gem_seqno);
DRM_PROC_PRINT("IRQ sequence: %d\n",
dev_priv->mm.irq_gem_seqno);
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_hws_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int len = 0, i;
volatile u32 *hws;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
hws = (volatile u32 *)dev_priv->hw_status_page;
if (hws == NULL) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) {
DRM_PROC_PRINT("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
i * 4,
hws[i], hws[i + 1], hws[i + 2], hws[i + 3]);
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static struct drm_proc_list {
/** file name */
const char *name;
/** proc callback*/
int (*f) (char *, char **, off_t, int, int *, void *);
} i915_gem_proc_list[] = {
{"i915_gem_active", i915_gem_active_info},
{"i915_gem_flushing", i915_gem_flushing_info},
{"i915_gem_inactive", i915_gem_inactive_info},
{"i915_gem_request", i915_gem_request_info},
{"i915_gem_seqno", i915_gem_seqno_info},
{"i915_gem_interrupt", i915_interrupt_info},
{"i915_gem_hws", i915_hws_info},
};
#define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
int i915_gem_proc_init(struct drm_minor *minor)
{
struct proc_dir_entry *ent;
int i, j;
for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) {
ent = create_proc_entry(i915_gem_proc_list[i].name,
S_IFREG | S_IRUGO, minor->dev_root);
if (!ent) {
DRM_ERROR("Cannot create /proc/dri/.../%s\n",
i915_gem_proc_list[i].name);
for (j = 0; j < i; j++)
remove_proc_entry(i915_gem_proc_list[i].name,
minor->dev_root);
return -1;
}
ent->read_proc = i915_gem_proc_list[i].f;
ent->data = minor;
}
return 0;
}
void i915_gem_proc_cleanup(struct drm_minor *minor)
{
int i;
if (!minor->dev_root)
return;
for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
}

View File

@@ -96,16 +96,16 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
*/
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
} else if ((!IS_I965G(dev) && !IS_G33(dev)) || IS_I965GM(dev) ||
IS_GM45(dev)) {
} else if (IS_MOBILE(dev)) {
uint32_t dcc;
/* On 915-945 and GM965, channel interleave by the CPU is
* determined by DCC. The CPU will alternate based on bit 6
* in interleaved mode, and the GPU will then also alternate
* on bit 6, 9, and 10 for X, but the CPU may also optionally
* alternate based on bit 17 (XOR not disabled and XOR
* bit == 17).
/* On mobile 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) {
@@ -115,19 +115,18 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
break;
case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
if (IS_I915G(dev) || IS_I915GM(dev) ||
dcc & DCC_CHANNEL_XOR_DISABLE) {
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 ((IS_I965GM(dev) || IS_GM45(dev)) &&
(dcc & DCC_CHANNEL_XOR_BIT_17) == 0) {
/* GM965/GM45 does either bit 11 or bit 17
* swizzling.
*/
} 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 or perhaps other swizzling */
/* Bit 17 swizzling by the CPU in addition. */
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
}
@@ -217,6 +216,22 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
else
tile_width = 512;
/* check maximum stride & object size */
if (IS_I965G(dev)) {
/* 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 (IS_I9XX(dev)) {
if (stride / tile_width > I830_FENCE_MAX_PITCH_VAL ||
size > (I830_FENCE_MAX_SIZE_VAL << 20))
return false;
} else {
if (stride / 128 > I830_FENCE_MAX_PITCH_VAL ||
size > (I830_FENCE_MAX_SIZE_VAL << 19))
return false;
}
/* 965+ just needs multiples of tile width */
if (IS_I965G(dev)) {
if (stride & (tile_width - 1))

View File

@@ -48,10 +48,6 @@
/** Interrupts that we mask and unmask at runtime. */
#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
/** These are all of the interrupts used by the driver */
#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \
I915_INTERRUPT_ENABLE_VAR)
#define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\
PIPE_VBLANK_INTERRUPT_STATUS)
@@ -187,6 +183,19 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
return I915_READ(reg);
}
/*
* Handle hotplug events outside the interrupt handler proper.
*/
static void i915_hotplug_work_func(struct work_struct *work)
{
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
hotplug_work);
struct drm_device *dev = dev_priv->dev;
/* Just fire off a uevent and let userspace tell us what to do */
drm_sysfs_hotplug_event(dev);
}
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -244,6 +253,20 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
ret = IRQ_HANDLED;
/* Consume port. Then clear IIR or we'll miss events */
if ((I915_HAS_HOTPLUG(dev)) &&
(iir & I915_DISPLAY_PORT_INTERRUPT)) {
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
DRM_DEBUG("hotplug event received, stat 0x%08x\n",
hotplug_status);
if (hotplug_status & dev_priv->hotplug_supported_mask)
schedule_work(&dev_priv->hotplug_work);
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
I915_READ(PORT_HOTPLUG_STAT);
}
I915_WRITE(IIR, iir);
new_iir = I915_READ(IIR); /* Flush posted writes */
@@ -528,17 +551,24 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
atomic_set(&dev_priv->irq_received, 0);
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
}
I915_WRITE(HWSTAM, 0xeffe);
I915_WRITE(PIPEASTAT, 0);
I915_WRITE(PIPEBSTAT, 0);
I915_WRITE(IMR, 0xffffffff);
I915_WRITE(IER, 0x0);
(void) I915_READ(IER);
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
}
int i915_driver_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
@@ -550,13 +580,35 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
dev_priv->pipestat[0] = 0;
dev_priv->pipestat[1] = 0;
if (I915_HAS_HOTPLUG(dev)) {
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
/* Leave other bits alone */
hotplug_en |= HOTPLUG_EN_MASK;
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS |
TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS |
SDVOB_HOTPLUG_INT_STATUS;
if (IS_G4X(dev)) {
dev_priv->hotplug_supported_mask |=
HDMIB_HOTPLUG_INT_STATUS |
HDMIC_HOTPLUG_INT_STATUS |
HDMID_HOTPLUG_INT_STATUS;
}
/* Enable in IER... */
enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
/* and unmask in IMR */
i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT);
}
/* Disable pipe interrupt enables, clear pending pipe status */
I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
/* Clear pending interrupt status */
I915_WRITE(IIR, I915_READ(IIR));
I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
I915_WRITE(IER, enable_mask);
I915_WRITE(IMR, dev_priv->irq_mask_reg);
(void) I915_READ(IER);
@@ -575,6 +627,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
dev_priv->vblank_pipe = 0;
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
}
I915_WRITE(HWSTAM, 0xffffffff);
I915_WRITE(PIPEASTAT, 0);
I915_WRITE(PIPEBSTAT, 0);

View File

@@ -190,6 +190,8 @@
#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8)
#define I830_FENCE_PITCH_SHIFT 4
#define I830_FENCE_REG_VALID (1<<0)
#define I830_FENCE_MAX_PITCH_VAL 0x10
#define I830_FENCE_MAX_SIZE_VAL (1<<8)
#define I915_FENCE_START_MASK 0x0ff00000
#define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8)
@@ -198,6 +200,7 @@
#define I965_FENCE_PITCH_SHIFT 2
#define I965_FENCE_TILING_Y_SHIFT 1
#define I965_FENCE_REG_VALID (1<<0)
#define I965_FENCE_MAX_PITCH_VAL 0x0400
/*
* Instruction and interrupt control regs
@@ -359,6 +362,7 @@
#define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
#define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
#define DPLL_FPA01_P1_POST_DIV_MASK_IGD 0x00ff8000 /* IGD */
#define I915_FIFO_UNDERRUN_STATUS (1UL<<31)
#define I915_CRC_ERROR_ENABLE (1UL<<29)
@@ -435,6 +439,7 @@
*/
#define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000
#define DPLL_FPA01_P1_POST_DIV_SHIFT 16
#define DPLL_FPA01_P1_POST_DIV_SHIFT_IGD 15
/* i830, required in DVO non-gang */
#define PLL_P2_DIVIDE_BY_4 (1 << 23)
#define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */
@@ -501,10 +506,12 @@
#define FPB0 0x06048
#define FPB1 0x0604c
#define FP_N_DIV_MASK 0x003f0000
#define FP_N_IGD_DIV_MASK 0x00ff0000
#define FP_N_DIV_SHIFT 16
#define FP_M1_DIV_MASK 0x00003f00
#define FP_M1_DIV_SHIFT 8
#define FP_M2_DIV_MASK 0x0000003f
#define FP_M2_IGD_DIV_MASK 0x000000ff
#define FP_M2_DIV_SHIFT 0
#define DPLL_TEST 0x606c
#define DPLLB_TEST_SDVO_DIV_1 (0 << 22)
@@ -629,6 +636,30 @@
#define TV_HOTPLUG_INT_EN (1 << 18)
#define CRT_HOTPLUG_INT_EN (1 << 9)
#define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
#define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8)
/* must use period 64 on GM45 according to docs */
#define CRT_HOTPLUG_ACTIVATION_PERIOD_64 (1 << 8)
#define CRT_HOTPLUG_DAC_ON_TIME_2M (0 << 7)
#define CRT_HOTPLUG_DAC_ON_TIME_4M (1 << 7)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_40 (0 << 5)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_50 (1 << 5)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_60 (2 << 5)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_70 (3 << 5)
#define CRT_HOTPLUG_VOLTAGE_COMPARE_MASK (3 << 5)
#define CRT_HOTPLUG_DETECT_DELAY_1G (0 << 4)
#define CRT_HOTPLUG_DETECT_DELAY_2G (1 << 4)
#define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2)
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
#define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */
#define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f
#define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \
HDMIC_HOTPLUG_INT_EN | \
HDMID_HOTPLUG_INT_EN | \
SDVOB_HOTPLUG_INT_EN | \
SDVOC_HOTPLUG_INT_EN | \
TV_HOTPLUG_INT_EN | \
CRT_HOTPLUG_INT_EN)
#define PORT_HOTPLUG_STAT 0x61114
#define HDMIB_HOTPLUG_INT_STATUS (1 << 29)
@@ -856,7 +887,7 @@
*/
# define TV_ENC_C0_FIX (1 << 10)
/** Bits that must be preserved by software */
# define TV_CTL_SAVE ((3 << 8) | (3 << 6))
# define TV_CTL_SAVE ((1 << 11) | (3 << 9) | (7 << 6) | 0xf)
# define TV_FUSE_STATE_MASK (3 << 4)
/** Read-only state that reports all features enabled */
# define TV_FUSE_STATE_ENABLED (0 << 4)

View File

@@ -162,13 +162,13 @@ struct bdb_lvds_options {
u8 panel_type;
u8 rsvd1;
/* LVDS capabilities, stored in a dword */
u8 rsvd2:1;
u8 lvds_edid:1;
u8 pixel_dither:1;
u8 pfit_ratio_auto:1;
u8 pfit_gfx_mode_enhanced:1;
u8 pfit_text_mode_enhanced:1;
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));

View File

@@ -41,7 +41,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
temp = I915_READ(ADPA);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp &= ~ADPA_DAC_ENABLE;
temp |= ADPA_DAC_ENABLE;
switch(mode) {
case DRM_MODE_DPMS_ON:
@@ -64,11 +64,21 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
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 > 400000 || mode->clock < 25000)
return MODE_CLOCK_RANGE;
if (mode->clock < 25000)
return MODE_CLOCK_LOW;
if (!IS_I9XX(dev))
max_clock = 350000;
else
max_clock = 400000;
if (mode->clock > max_clock)
return MODE_CLOCK_HIGH;
return MODE_OK;
}
@@ -113,10 +123,13 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
adpa |= ADPA_VSYNC_ACTIVE_HIGH;
if (intel_crtc->pipe == 0)
if (intel_crtc->pipe == 0) {
adpa |= ADPA_PIPE_A_SELECT;
else
I915_WRITE(BCLRPAT_A, 0);
} else {
adpa |= ADPA_PIPE_B_SELECT;
I915_WRITE(BCLRPAT_B, 0);
}
I915_WRITE(ADPA, adpa);
}
@@ -133,20 +146,39 @@ 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 temp;
u32 hotplug_en;
int i, tries = 0;
/*
* On 4 series desktop, CRT detect sequence need to be done twice
* to get a reliable result.
*/
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
if (IS_G4X(dev) && !IS_GM45(dev))
tries = 2;
else
tries = 1;
hotplug_en = I915_READ(PORT_HOTPLUG_EN);
hotplug_en &= CRT_FORCE_HOTPLUG_MASK;
hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
temp = I915_READ(PORT_HOTPLUG_EN);
if (IS_GM45(dev))
hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
I915_WRITE(PORT_HOTPLUG_EN,
temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5));
hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
do {
if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT))
break;
msleep(1);
} while (time_after(timeout, jiffies));
for (i = 0; i < tries ; i++) {
unsigned long timeout;
/* turn on the FORCE_DETECT */
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
timeout = jiffies + msecs_to_jiffies(1000);
/* wait for FORCE_DETECT to go off */
do {
if (!(I915_READ(PORT_HOTPLUG_EN) &
CRT_HOTPLUG_FORCE_DETECT))
break;
msleep(1);
} while (time_after(timeout, jiffies));
}
if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) ==
CRT_HOTPLUG_MONITOR_COLOR)

View File

@@ -56,11 +56,13 @@ typedef struct {
} intel_p2_t;
#define INTEL_P2_NUM 2
typedef struct {
typedef struct intel_limit intel_limit_t;
struct intel_limit {
intel_range_t dot, vco, n, m, m1, m2, p, p1;
intel_p2_t p2;
} intel_limit_t;
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
int, int, intel_clock_t *);
};
#define I8XX_DOT_MIN 25000
#define I8XX_DOT_MAX 350000
@@ -90,18 +92,32 @@ typedef struct {
#define I9XX_DOT_MAX 400000
#define I9XX_VCO_MIN 1400000
#define I9XX_VCO_MAX 2800000
#define IGD_VCO_MIN 1700000
#define IGD_VCO_MAX 3500000
#define I9XX_N_MIN 1
#define I9XX_N_MAX 6
/* IGD's Ncounter is a ring counter */
#define IGD_N_MIN 3
#define IGD_N_MAX 6
#define I9XX_M_MIN 70
#define I9XX_M_MAX 120
#define IGD_M_MIN 2
#define IGD_M_MAX 256
#define I9XX_M1_MIN 10
#define I9XX_M1_MAX 22
#define I9XX_M2_MIN 5
#define I9XX_M2_MAX 9
/* IGD M1 is reserved, and must be 0 */
#define IGD_M1_MIN 0
#define IGD_M1_MAX 0
#define IGD_M2_MIN 0
#define IGD_M2_MAX 254
#define I9XX_P_SDVO_DAC_MIN 5
#define I9XX_P_SDVO_DAC_MAX 80
#define I9XX_P_LVDS_MIN 7
#define I9XX_P_LVDS_MAX 98
#define IGD_P_LVDS_MIN 7
#define IGD_P_LVDS_MAX 112
#define I9XX_P1_MIN 1
#define I9XX_P1_MAX 8
#define I9XX_P2_SDVO_DAC_SLOW 10
@@ -115,6 +131,97 @@ typedef struct {
#define INTEL_LIMIT_I8XX_LVDS 1
#define INTEL_LIMIT_I9XX_SDVO_DAC 2
#define INTEL_LIMIT_I9XX_LVDS 3
#define INTEL_LIMIT_G4X_SDVO 4
#define INTEL_LIMIT_G4X_HDMI_DAC 5
#define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS 6
#define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7
#define INTEL_LIMIT_IGD_SDVO_DAC 8
#define INTEL_LIMIT_IGD_LVDS 9
/*The parameter is for SDVO on G4x platform*/
#define G4X_DOT_SDVO_MIN 25000
#define G4X_DOT_SDVO_MAX 270000
#define G4X_VCO_MIN 1750000
#define G4X_VCO_MAX 3500000
#define G4X_N_SDVO_MIN 1
#define G4X_N_SDVO_MAX 4
#define G4X_M_SDVO_MIN 104
#define G4X_M_SDVO_MAX 138
#define G4X_M1_SDVO_MIN 17
#define G4X_M1_SDVO_MAX 23
#define G4X_M2_SDVO_MIN 5
#define G4X_M2_SDVO_MAX 11
#define G4X_P_SDVO_MIN 10
#define G4X_P_SDVO_MAX 30
#define G4X_P1_SDVO_MIN 1
#define G4X_P1_SDVO_MAX 3
#define G4X_P2_SDVO_SLOW 10
#define G4X_P2_SDVO_FAST 10
#define G4X_P2_SDVO_LIMIT 270000
/*The parameter is for HDMI_DAC on G4x platform*/
#define G4X_DOT_HDMI_DAC_MIN 22000
#define G4X_DOT_HDMI_DAC_MAX 400000
#define G4X_N_HDMI_DAC_MIN 1
#define G4X_N_HDMI_DAC_MAX 4
#define G4X_M_HDMI_DAC_MIN 104
#define G4X_M_HDMI_DAC_MAX 138
#define G4X_M1_HDMI_DAC_MIN 16
#define G4X_M1_HDMI_DAC_MAX 23
#define G4X_M2_HDMI_DAC_MIN 5
#define G4X_M2_HDMI_DAC_MAX 11
#define G4X_P_HDMI_DAC_MIN 5
#define G4X_P_HDMI_DAC_MAX 80
#define G4X_P1_HDMI_DAC_MIN 1
#define G4X_P1_HDMI_DAC_MAX 8
#define G4X_P2_HDMI_DAC_SLOW 10
#define G4X_P2_HDMI_DAC_FAST 5
#define G4X_P2_HDMI_DAC_LIMIT 165000
/*The parameter is for SINGLE_CHANNEL_LVDS on G4x platform*/
#define G4X_DOT_SINGLE_CHANNEL_LVDS_MIN 20000
#define G4X_DOT_SINGLE_CHANNEL_LVDS_MAX 115000
#define G4X_N_SINGLE_CHANNEL_LVDS_MIN 1
#define G4X_N_SINGLE_CHANNEL_LVDS_MAX 3
#define G4X_M_SINGLE_CHANNEL_LVDS_MIN 104
#define G4X_M_SINGLE_CHANNEL_LVDS_MAX 138
#define G4X_M1_SINGLE_CHANNEL_LVDS_MIN 17
#define G4X_M1_SINGLE_CHANNEL_LVDS_MAX 23
#define G4X_M2_SINGLE_CHANNEL_LVDS_MIN 5
#define G4X_M2_SINGLE_CHANNEL_LVDS_MAX 11
#define G4X_P_SINGLE_CHANNEL_LVDS_MIN 28
#define G4X_P_SINGLE_CHANNEL_LVDS_MAX 112
#define G4X_P1_SINGLE_CHANNEL_LVDS_MIN 2
#define G4X_P1_SINGLE_CHANNEL_LVDS_MAX 8
#define G4X_P2_SINGLE_CHANNEL_LVDS_SLOW 14
#define G4X_P2_SINGLE_CHANNEL_LVDS_FAST 14
#define G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT 0
/*The parameter is for DUAL_CHANNEL_LVDS on G4x platform*/
#define G4X_DOT_DUAL_CHANNEL_LVDS_MIN 80000
#define G4X_DOT_DUAL_CHANNEL_LVDS_MAX 224000
#define G4X_N_DUAL_CHANNEL_LVDS_MIN 1
#define G4X_N_DUAL_CHANNEL_LVDS_MAX 3
#define G4X_M_DUAL_CHANNEL_LVDS_MIN 104
#define G4X_M_DUAL_CHANNEL_LVDS_MAX 138
#define G4X_M1_DUAL_CHANNEL_LVDS_MIN 17
#define G4X_M1_DUAL_CHANNEL_LVDS_MAX 23
#define G4X_M2_DUAL_CHANNEL_LVDS_MIN 5
#define G4X_M2_DUAL_CHANNEL_LVDS_MAX 11
#define G4X_P_DUAL_CHANNEL_LVDS_MIN 14
#define G4X_P_DUAL_CHANNEL_LVDS_MAX 42
#define G4X_P1_DUAL_CHANNEL_LVDS_MIN 2
#define G4X_P1_DUAL_CHANNEL_LVDS_MAX 6
#define G4X_P2_DUAL_CHANNEL_LVDS_SLOW 7
#define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7
#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
static const intel_limit_t intel_limits[] = {
{ /* INTEL_LIMIT_I8XX_DVO_DAC */
@@ -128,6 +235,7 @@ static const intel_limit_t intel_limits[] = {
.p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX },
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST },
.find_pll = intel_find_best_PLL,
},
{ /* INTEL_LIMIT_I8XX_LVDS */
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
@@ -140,6 +248,7 @@ static const intel_limit_t intel_limits[] = {
.p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX },
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
},
{ /* INTEL_LIMIT_I9XX_SDVO_DAC */
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
@@ -152,6 +261,7 @@ static const intel_limit_t intel_limits[] = {
.p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
},
{ /* INTEL_LIMIT_I9XX_LVDS */
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
@@ -167,19 +277,157 @@ static const intel_limit_t intel_limits[] = {
*/
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
},
/* below parameter and function is for G4X Chipset Family*/
{ /* INTEL_LIMIT_G4X_SDVO */
.dot = { .min = G4X_DOT_SDVO_MIN, .max = G4X_DOT_SDVO_MAX },
.vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX},
.n = { .min = G4X_N_SDVO_MIN, .max = G4X_N_SDVO_MAX },
.m = { .min = G4X_M_SDVO_MIN, .max = G4X_M_SDVO_MAX },
.m1 = { .min = G4X_M1_SDVO_MIN, .max = G4X_M1_SDVO_MAX },
.m2 = { .min = G4X_M2_SDVO_MIN, .max = G4X_M2_SDVO_MAX },
.p = { .min = G4X_P_SDVO_MIN, .max = G4X_P_SDVO_MAX },
.p1 = { .min = G4X_P1_SDVO_MIN, .max = G4X_P1_SDVO_MAX},
.p2 = { .dot_limit = G4X_P2_SDVO_LIMIT,
.p2_slow = G4X_P2_SDVO_SLOW,
.p2_fast = G4X_P2_SDVO_FAST
},
.find_pll = intel_g4x_find_best_PLL,
},
{ /* INTEL_LIMIT_G4X_HDMI_DAC */
.dot = { .min = G4X_DOT_HDMI_DAC_MIN, .max = G4X_DOT_HDMI_DAC_MAX },
.vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX},
.n = { .min = G4X_N_HDMI_DAC_MIN, .max = G4X_N_HDMI_DAC_MAX },
.m = { .min = G4X_M_HDMI_DAC_MIN, .max = G4X_M_HDMI_DAC_MAX },
.m1 = { .min = G4X_M1_HDMI_DAC_MIN, .max = G4X_M1_HDMI_DAC_MAX },
.m2 = { .min = G4X_M2_HDMI_DAC_MIN, .max = G4X_M2_HDMI_DAC_MAX },
.p = { .min = G4X_P_HDMI_DAC_MIN, .max = G4X_P_HDMI_DAC_MAX },
.p1 = { .min = G4X_P1_HDMI_DAC_MIN, .max = G4X_P1_HDMI_DAC_MAX},
.p2 = { .dot_limit = G4X_P2_HDMI_DAC_LIMIT,
.p2_slow = G4X_P2_HDMI_DAC_SLOW,
.p2_fast = G4X_P2_HDMI_DAC_FAST
},
.find_pll = intel_g4x_find_best_PLL,
},
{ /* INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS */
.dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN,
.max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX },
.vco = { .min = G4X_VCO_MIN,
.max = G4X_VCO_MAX },
.n = { .min = G4X_N_SINGLE_CHANNEL_LVDS_MIN,
.max = G4X_N_SINGLE_CHANNEL_LVDS_MAX },
.m = { .min = G4X_M_SINGLE_CHANNEL_LVDS_MIN,
.max = G4X_M_SINGLE_CHANNEL_LVDS_MAX },
.m1 = { .min = G4X_M1_SINGLE_CHANNEL_LVDS_MIN,
.max = G4X_M1_SINGLE_CHANNEL_LVDS_MAX },
.m2 = { .min = G4X_M2_SINGLE_CHANNEL_LVDS_MIN,
.max = G4X_M2_SINGLE_CHANNEL_LVDS_MAX },
.p = { .min = G4X_P_SINGLE_CHANNEL_LVDS_MIN,
.max = G4X_P_SINGLE_CHANNEL_LVDS_MAX },
.p1 = { .min = G4X_P1_SINGLE_CHANNEL_LVDS_MIN,
.max = G4X_P1_SINGLE_CHANNEL_LVDS_MAX },
.p2 = { .dot_limit = G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT,
.p2_slow = G4X_P2_SINGLE_CHANNEL_LVDS_SLOW,
.p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
},
{ /* INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS */
.dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN,
.max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX },
.vco = { .min = G4X_VCO_MIN,
.max = G4X_VCO_MAX },
.n = { .min = G4X_N_DUAL_CHANNEL_LVDS_MIN,
.max = G4X_N_DUAL_CHANNEL_LVDS_MAX },
.m = { .min = G4X_M_DUAL_CHANNEL_LVDS_MIN,
.max = G4X_M_DUAL_CHANNEL_LVDS_MAX },
.m1 = { .min = G4X_M1_DUAL_CHANNEL_LVDS_MIN,
.max = G4X_M1_DUAL_CHANNEL_LVDS_MAX },
.m2 = { .min = G4X_M2_DUAL_CHANNEL_LVDS_MIN,
.max = G4X_M2_DUAL_CHANNEL_LVDS_MAX },
.p = { .min = G4X_P_DUAL_CHANNEL_LVDS_MIN,
.max = G4X_P_DUAL_CHANNEL_LVDS_MAX },
.p1 = { .min = G4X_P1_DUAL_CHANNEL_LVDS_MIN,
.max = G4X_P1_DUAL_CHANNEL_LVDS_MAX },
.p2 = { .dot_limit = G4X_P2_DUAL_CHANNEL_LVDS_LIMIT,
.p2_slow = G4X_P2_DUAL_CHANNEL_LVDS_SLOW,
.p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
},
{ /* INTEL_LIMIT_IGD_SDVO */
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
.vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX },
.n = { .min = IGD_N_MIN, .max = IGD_N_MAX },
.m = { .min = IGD_M_MIN, .max = IGD_M_MAX },
.m1 = { .min = IGD_M1_MIN, .max = IGD_M1_MAX },
.m2 = { .min = IGD_M2_MIN, .max = IGD_M2_MAX },
.p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX },
.p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
},
{ /* INTEL_LIMIT_IGD_LVDS */
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
.vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX },
.n = { .min = IGD_N_MIN, .max = IGD_N_MAX },
.m = { .min = IGD_M_MIN, .max = IGD_M_MAX },
.m1 = { .min = IGD_M1_MIN, .max = IGD_M1_MAX },
.m2 = { .min = IGD_M2_MIN, .max = IGD_M2_MAX },
.p = { .min = IGD_P_LVDS_MIN, .max = IGD_P_LVDS_MAX },
.p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
/* IGD only supports single-channel mode. */
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
},
};
static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
const intel_limit_t *limit;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP)
/* LVDS with dual channel */
limit = &intel_limits
[INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS];
else
/* LVDS with dual channel */
limit = &intel_limits
[INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS];
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC];
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
limit = &intel_limits[INTEL_LIMIT_G4X_SDVO];
} else /* The option is for other outputs */
limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
return limit;
}
static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
const intel_limit_t *limit;
if (IS_I9XX(dev)) {
if (IS_G4X(dev)) {
limit = intel_g4x_limit(crtc);
} else if (IS_I9XX(dev) && !IS_IGD(dev)) {
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS];
else
limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
} else if (IS_IGD(dev)) {
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
limit = &intel_limits[INTEL_LIMIT_IGD_LVDS];
else
limit = &intel_limits[INTEL_LIMIT_IGD_SDVO_DAC];
} else {
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS];
@@ -189,8 +437,21 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
return limit;
}
static void intel_clock(int refclk, intel_clock_t *clock)
/* m1 is reserved as 0 in IGD, n is a ring counter */
static void igd_clock(int refclk, intel_clock_t *clock)
{
clock->m = clock->m2 + 2;
clock->p = clock->p1 * clock->p2;
clock->vco = refclk * clock->m / clock->n;
clock->dot = clock->vco / clock->p;
}
static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock)
{
if (IS_IGD(dev)) {
igd_clock(refclk, clock);
return;
}
clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
clock->p = clock->p1 * clock->p2;
clock->vco = refclk * clock->m / (clock->n + 2);
@@ -226,6 +487,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock)
{
const intel_limit_t *limit = intel_limit (crtc);
struct drm_device *dev = crtc->dev;
if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
INTELPllInvalid ("p1 out of range\n");
@@ -235,7 +497,7 @@ static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock)
INTELPllInvalid ("m2 out of range\n");
if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
INTELPllInvalid ("m1 out of range\n");
if (clock->m1 <= clock->m2)
if (clock->m1 <= clock->m2 && !IS_IGD(dev))
INTELPllInvalid ("m1 <= m2\n");
if (clock->m < limit->m.min || limit->m.max < clock->m)
INTELPllInvalid ("m out of range\n");
@@ -252,18 +514,14 @@ static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock)
return true;
}
/**
* Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation:
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
int refclk, intel_clock_t *best_clock)
static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
intel_clock_t clock;
const intel_limit_t *limit = intel_limit(crtc);
int err = target;
if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
@@ -289,15 +547,17 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
memset (best_clock, 0, sizeof (*best_clock));
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 &&
clock.m2 <= limit->m2.max; clock.m2++) {
for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
/* m1 is always 0 in IGD */
if (clock.m2 >= clock.m1 && !IS_IGD(dev))
break;
for (clock.n = limit->n.min; clock.n <= limit->n.max;
clock.n++) {
for (clock.p1 = limit->p1.min;
clock.p1 <= limit->p1.max; clock.p1++) {
int this_err;
intel_clock(refclk, &clock);
intel_clock(dev, refclk, &clock);
if (!intel_PLL_is_valid(crtc, &clock))
continue;
@@ -315,11 +575,68 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
return (err != target);
}
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
intel_clock_t clock;
int max_n;
bool found;
/* approximately equals target * 0.00488 */
int err_most = (target >> 8) + (target >> 10);
found = false;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP)
clock.p2 = limit->p2.p2_fast;
else
clock.p2 = limit->p2.p2_slow;
} else {
if (target < limit->p2.dot_limit)
clock.p2 = limit->p2.p2_slow;
else
clock.p2 = limit->p2.p2_fast;
}
memset(best_clock, 0, sizeof(*best_clock));
max_n = limit->n.max;
/* based on hardware requriment prefer smaller n to precision */
for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
/* based on hardware requirment prefere larger m1,m2, p1 */
for (clock.m1 = limit->m1.max;
clock.m1 >= limit->m1.min; clock.m1--) {
for (clock.m2 = limit->m2.max;
clock.m2 >= limit->m2.min; clock.m2--) {
for (clock.p1 = limit->p1.max;
clock.p1 >= limit->p1.min; clock.p1--) {
int this_err;
intel_clock(dev, refclk, &clock);
if (!intel_PLL_is_valid(crtc, &clock))
continue;
this_err = abs(clock.dot - target) ;
if (this_err < err_most) {
*best_clock = clock;
err_most = this_err;
max_n = clock.n;
found = true;
}
}
}
}
}
return found;
}
void
intel_wait_for_vblank(struct drm_device *dev)
{
/* Wait for 20ms, i.e. one cycle at 50hz. */
udelay(20000);
mdelay(20);
}
static int
@@ -634,7 +951,7 @@ static int intel_get_core_clock_speed(struct drm_device *dev)
return 400000;
else if (IS_I915G(dev))
return 333000;
else if (IS_I945GM(dev) || IS_845G(dev))
else if (IS_I945GM(dev) || IS_845G(dev) || IS_IGDGM(dev))
return 200000;
else if (IS_I915GM(dev)) {
u16 gcfgc = 0;
@@ -733,6 +1050,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
bool is_crt = false, is_lvds = false, is_tv = false;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
const intel_limit_t *limit;
int ret;
drm_vblank_pre_modeset(dev, pipe);
@@ -776,13 +1094,42 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
refclk = 48000;
}
ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock);
/*
* Returns a set of divisors for the desired target clock with the given
* refclk, or FALSE. The returned values represent the clock equation:
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
limit = intel_limit(crtc);
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
}
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
/* SDVO TV has fixed PLL values depend on its clock range,
this mirrors vbios setting. */
if (is_sdvo && is_tv) {
if (adjusted_mode->clock >= 100000
&& adjusted_mode->clock < 140500) {
clock.p1 = 2;
clock.p2 = 10;
clock.n = 3;
clock.m1 = 16;
clock.m2 = 8;
} else if (adjusted_mode->clock >= 140500
&& adjusted_mode->clock <= 200000) {
clock.p1 = 1;
clock.p2 = 10;
clock.n = 6;
clock.m1 = 12;
clock.m2 = 8;
}
}
if (IS_IGD(dev))
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
else
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
dpll = DPLL_VGA_MODE_DIS;
if (IS_I9XX(dev)) {
@@ -799,7 +1146,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
/* compute bitmask from p1 value */
dpll |= (1 << (clock.p1 - 1)) << 16;
if (IS_IGD(dev))
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_IGD;
else
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
switch (clock.p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
@@ -1279,10 +1629,20 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
fp = I915_READ((pipe == 0) ? FPA1 : FPB1);
clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
if (IS_IGD(dev)) {
clock.n = ffs((fp & FP_N_IGD_DIV_MASK) >> FP_N_DIV_SHIFT) - 1;
clock.m2 = (fp & FP_M2_IGD_DIV_MASK) >> FP_M2_DIV_SHIFT;
} else {
clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
}
if (IS_I9XX(dev)) {
clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
if (IS_IGD(dev))
clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_IGD) >>
DPLL_FPA01_P1_POST_DIV_SHIFT_IGD);
else
clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
DPLL_FPA01_P1_POST_DIV_SHIFT);
switch (dpll & DPLL_MODE_MASK) {
@@ -1301,7 +1661,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
}
/* XXX: Handle the 100Mhz refclk */
intel_clock(96000, &clock);
intel_clock(dev, 96000, &clock);
} else {
bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
@@ -1313,9 +1673,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
if ((dpll & PLL_REF_INPUT_MASK) ==
PLLB_REF_INPUT_SPREADSPECTRUMIN) {
/* XXX: might not be 66MHz */
intel_clock(66000, &clock);
intel_clock(dev, 66000, &clock);
} else
intel_clock(48000, &clock);
intel_clock(dev, 48000, &clock);
} else {
if (dpll & PLL_P1_DIVIDE_BY_TWO)
clock.p1 = 2;
@@ -1328,7 +1688,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
else
clock.p2 = 2;
intel_clock(48000, &clock);
intel_clock(dev, 48000, &clock);
}
}
@@ -1474,13 +1834,21 @@ static void intel_setup_outputs(struct drm_device *dev)
if (IS_I9XX(dev)) {
int found;
u32 reg;
if (I915_READ(SDVOB) & SDVO_DETECTED) {
found = intel_sdvo_init(dev, SDVOB);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
intel_hdmi_init(dev, SDVOB);
}
if (!IS_G4X(dev) || (I915_READ(SDVOB) & SDVO_DETECTED)) {
/* Before G4X SDVOC doesn't have its own detect register */
if (IS_G4X(dev))
reg = SDVOC;
else
reg = SDVOB;
if (I915_READ(reg) & SDVO_DETECTED) {
found = intel_sdvo_init(dev, SDVOC);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
intel_hdmi_init(dev, SDVOC);

View File

@@ -265,7 +265,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
pfit_control = 0;
if (!IS_I965G(dev)) {
if (dev_priv->panel_wants_dither)
if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
}
else

View File

@@ -76,6 +76,7 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
drm_mode_connector_update_edid_property(&intel_output->base,
edid);
ret = drm_add_edid_modes(&intel_output->base, edid);
intel_output->base.display_info.raw_edid = NULL;
kfree(edid);
}

View File

@@ -273,20 +273,20 @@ static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd,
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
int i;
DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
for (i = 0; i < args_len; i++)
printk("%02X ", ((u8 *)args)[i]);
printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]);
for (; i < 8; i++)
printk(" ");
printk(KERN_DEBUG " ");
for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
if (cmd == sdvo_cmd_names[i].cmd) {
printk("(%s)", sdvo_cmd_names[i].name);
printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name);
break;
}
}
if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
printk("(%02X)",cmd);
printk("\n");
printk(KERN_DEBUG "(%02X)", cmd);
printk(KERN_DEBUG "\n");
}
#else
#define intel_sdvo_debug_write(o, c, a, l)
@@ -323,17 +323,18 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output,
u8 status)
{
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
int i;
DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv));
printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv));
for (i = 0; i < response_len; i++)
printk("%02X ", ((u8 *)response)[i]);
printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]);
for (; i < 8; i++)
printk(" ");
printk(KERN_DEBUG " ");
if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
printk("(%s)", cmd_status_names[status]);
printk(KERN_DEBUG "(%s)", cmd_status_names[status]);
else
printk("(??? %d)", status);
printk("\n");
printk(KERN_DEBUG "(??? %d)", status);
printk(KERN_DEBUG "\n");
}
#else
#define intel_sdvo_debug_response(o, r, l, s)
@@ -588,9 +589,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
struct intel_sdvo_preferred_input_timing_args args;
uint8_t status;
memset(&args, 0, sizeof(args));
args.clock = clock;
args.width = width;
args.height = height;
args.interlace = 0;
args.scaled = 0;
intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
&args, sizeof(args));
status = intel_sdvo_read_response(output, NULL, 0);
@@ -683,7 +687,7 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |
((v_blank_len >> 8) & 0xf);
dtd->part2.h_sync_off = h_sync_offset;
dtd->part2.h_sync_off = h_sync_offset & 0xff;
dtd->part2.h_sync_width = h_sync_len & 0xff;
dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
(v_sync_len & 0xf);
@@ -705,27 +709,10 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
struct intel_sdvo_dtd *dtd)
{
uint16_t width, height;
uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;
uint16_t h_sync_offset, v_sync_offset;
width = mode->crtc_hdisplay;
height = mode->crtc_vdisplay;
/* do some mode translations */
h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
mode->hdisplay = dtd->part1.h_active;
mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
mode->hsync_start += (dtd->part2.sync_off_width_high & 0xa0) << 2;
mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
mode->htotal = mode->hdisplay + dtd->part1.h_blank;
@@ -735,7 +722,7 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
mode->vsync_start = mode->vdisplay;
mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0a) << 2;
mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
mode->vsync_end = mode->vsync_start +
(dtd->part2.v_sync_off_width & 0xf);
@@ -745,7 +732,7 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
mode->clock = dtd->part1.clock * 10;
mode->flags &= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
if (dtd->part2.dtd_flags & 0x2)
mode->flags |= DRM_MODE_FLAG_PHSYNC;
if (dtd->part2.dtd_flags & 0x4)
@@ -924,6 +911,27 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
SDVO_HBUF_TX_VSYNC);
}
static void intel_sdvo_set_tv_format(struct intel_output *output)
{
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
struct intel_sdvo_tv_format *format, unset;
u8 status;
format = &sdvo_priv->tv_format;
memset(&unset, 0, sizeof(unset));
if (memcmp(format, &unset, sizeof(*format))) {
DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
SDVO_NAME(sdvo_priv));
format->ntsc_m = 1;
intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, format,
sizeof(*format));
status = intel_sdvo_read_response(output, NULL, 0);
if (status != SDVO_CMD_STATUS_SUCCESS)
DRM_DEBUG("%s: Failed to set TV format\n",
SDVO_NAME(sdvo_priv));
}
}
static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -968,6 +976,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
&input_dtd);
intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
drm_mode_set_crtcinfo(adjusted_mode, 0);
mode->clock = adjusted_mode->clock;
adjusted_mode->clock *=
intel_sdvo_get_pixel_multiplier(mode);
} else {
return false;
}
@@ -1012,7 +1026,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
sdvox |= SDVO_AUDIO_ENABLE;
}
intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
/* We have tried to get input timing in mode_fixup, and filled into
adjusted_mode */
if (sdvo_priv->is_tv)
intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
else
intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
/* If it's a TV, we already set the output timing in mode_fixup.
* Otherwise, the output timing is equal to the input timing.
@@ -1027,6 +1046,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
/* Set the input timing to the screen. Assume always input 0. */
intel_sdvo_set_target_input(output, true, false);
if (sdvo_priv->is_tv)
intel_sdvo_set_tv_format(output);
/* We would like to use intel_sdvo_create_preferred_input_timing() to
* provide the device with a timing it can support, if it supports that
* feature. However, presumably we would need to adjust the CRTC to
@@ -1395,7 +1417,7 @@ static void
intel_sdvo_check_tv_format(struct intel_output *output)
{
struct intel_sdvo_priv *dev_priv = output->dev_priv;
struct intel_sdvo_tv_format format, unset;
struct intel_sdvo_tv_format format;
uint8_t status;
intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
@@ -1403,15 +1425,7 @@ intel_sdvo_check_tv_format(struct intel_output *output)
if (status != SDVO_CMD_STATUS_SUCCESS)
return;
memset(&unset, 0, sizeof(unset));
if (memcmp(&format, &unset, sizeof(format))) {
DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
SDVO_NAME(dev_priv));
format.ntsc_m = true;
intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, NULL, 0);
status = intel_sdvo_read_response(output, NULL, 0);
}
memcpy(&dev_priv->tv_format, &format, sizeof(format));
}
/*
@@ -1420,68 +1434,70 @@ intel_sdvo_check_tv_format(struct intel_output *output)
* XXX: all 60Hz refresh?
*/
struct drm_display_mode sdvo_tv_modes[] = {
{ DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815680, 321, 384, 416,
200, 0, 232, 201, 233, 4196112, 0,
{ DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384,
416, 0, 200, 201, 232, 233, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814080, 321, 384, 416,
240, 0, 272, 241, 273, 4196112, 0,
{ DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384,
416, 0, 240, 241, 272, 273, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910080, 401, 464, 496,
300, 0, 332, 301, 333, 4196112, 0,
{ DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464,
496, 0, 300, 301, 332, 333, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913280, 641, 704, 736,
350, 0, 382, 351, 383, 4196112, 0,
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704,
736, 0, 350, 351, 382, 383, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
400, 0, 432, 401, 433, 4196112, 0,
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704,
736, 0, 400, 401, 432, 433, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
400, 0, 432, 401, 433, 4196112, 0,
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704,
736, 0, 480, 481, 512, 513, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624000, 705, 768, 800,
480, 0, 512, 481, 513, 4196112, 0,
{ DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768,
800, 0, 480, 481, 512, 513, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232000, 705, 768, 800,
576, 0, 608, 577, 609, 4196112, 0,
{ DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768,
800, 0, 576, 577, 608, 609, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751680, 721, 784, 816,
350, 0, 382, 351, 383, 4196112, 0,
{ DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784,
816, 0, 350, 351, 382, 383, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199680, 721, 784, 816,
400, 0, 432, 401, 433, 4196112, 0,
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784,
816, 0, 400, 401, 432, 433, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116480, 721, 784, 816,
480, 0, 512, 481, 513, 4196112, 0,
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784,
816, 0, 480, 481, 512, 513, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054080, 721, 784, 816,
540, 0, 572, 541, 573, 4196112, 0,
{ DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784,
816, 0, 540, 541, 572, 573, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816640, 721, 784, 816,
576, 0, 608, 577, 609, 4196112, 0,
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784,
816, 0, 576, 577, 608, 609, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570560, 769, 832, 864,
576, 0, 608, 577, 609, 4196112, 0,
{ DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832,
864, 0, 576, 577, 608, 609, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030080, 801, 864, 896,
600, 0, 632, 601, 633, 4196112, 0,
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864,
896, 0, 600, 601, 632, 633, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581760, 833, 896, 928,
624, 0, 656, 625, 657, 4196112, 0,
{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896,
928, 0, 624, 625, 656, 657, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707040, 921, 984, 1016,
766, 0, 798, 767, 799, 4196112, 0,
{ DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984,
1016, 0, 766, 767, 798, 799, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827200, 1025, 1088, 1120,
768, 0, 800, 769, 801, 4196112, 0,
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088,
1120, 0, 768, 769, 800, 801, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265920, 1281, 1344, 1376,
1024, 0, 1056, 1025, 1057, 4196112, 0,
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344,
1376, 0, 1024, 1025, 1056, 1057, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
};
static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
{
struct intel_output *output = to_intel_output(connector);
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
struct intel_sdvo_sdtv_resolution_request tv_res;
uint32_t reply = 0;
uint8_t status;
int i = 0;
@@ -1491,15 +1507,22 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
/* Read the list of supported input resolutions for the selected TV
* format.
*/
memset(&tv_res, 0, sizeof(tv_res));
memcpy(&tv_res, &sdvo_priv->tv_format, sizeof(tv_res));
intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
NULL, 0);
&tv_res, sizeof(tv_res));
status = intel_sdvo_read_response(output, &reply, 3);
if (status != SDVO_CMD_STATUS_SUCCESS)
return;
for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)
if (reply & (1 << i))
drm_mode_probed_add(connector, &sdvo_tv_modes[i]);
if (reply & (1 << i)) {
struct drm_display_mode *nmode;
nmode = drm_mode_duplicate(connector->dev,
&sdvo_tv_modes[i]);
if (nmode)
drm_mode_probed_add(connector, nmode);
}
}
static int intel_sdvo_get_modes(struct drm_connector *connector)

View File

@@ -100,6 +100,9 @@ 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 */

View File

@@ -217,8 +217,8 @@ static const u32 filter_table[] = {
*/
static const struct color_conversion ntsc_m_csc_composite = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
};
static const struct video_levels ntsc_m_levels_composite = {
@@ -226,9 +226,9 @@ static const struct video_levels ntsc_m_levels_composite = {
};
static const struct color_conversion ntsc_m_csc_svideo = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
};
static const struct video_levels ntsc_m_levels_svideo = {
@@ -237,8 +237,8 @@ static const struct video_levels ntsc_m_levels_svideo = {
static const struct color_conversion ntsc_j_csc_composite = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
.ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00,
.rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00,
.ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
.rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
};
static const struct video_levels ntsc_j_levels_composite = {
@@ -247,8 +247,8 @@ static const struct video_levels ntsc_j_levels_composite = {
static const struct color_conversion ntsc_j_csc_svideo = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
.ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00,
.rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00,
.ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
.rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
};
static const struct video_levels ntsc_j_levels_svideo = {
@@ -257,8 +257,8 @@ static const struct video_levels ntsc_j_levels_svideo = {
static const struct color_conversion pal_csc_composite = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
.ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00,
.rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00,
.ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
.rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
};
static const struct video_levels pal_levels_composite = {
@@ -267,8 +267,8 @@ static const struct video_levels pal_levels_composite = {
static const struct color_conversion pal_csc_svideo = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
.ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00,
.rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00,
.ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
.rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
};
static const struct video_levels pal_levels_svideo = {
@@ -277,8 +277,8 @@ static const struct video_levels pal_levels_svideo = {
static const struct color_conversion pal_m_csc_composite = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
};
static const struct video_levels pal_m_levels_composite = {
@@ -286,9 +286,9 @@ static const struct video_levels pal_m_levels_composite = {
};
static const struct color_conversion pal_m_csc_svideo = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
};
static const struct video_levels pal_m_levels_svideo = {
@@ -297,8 +297,8 @@ static const struct video_levels pal_m_levels_svideo = {
static const struct color_conversion pal_n_csc_composite = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
};
static const struct video_levels pal_n_levels_composite = {
@@ -306,9 +306,9 @@ static const struct video_levels pal_n_levels_composite = {
};
static const struct color_conversion pal_n_csc_svideo = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
};
static const struct video_levels pal_n_levels_svideo = {
@@ -319,9 +319,9 @@ static const struct video_levels pal_n_levels_svideo = {
* Component connections
*/
static const struct color_conversion sdtv_csc_yprpb = {
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146,
.ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00,
.rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00,
.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
.ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
.rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
};
static const struct color_conversion sdtv_csc_rgb = {
@@ -331,9 +331,9 @@ static const struct color_conversion sdtv_csc_rgb = {
};
static const struct color_conversion hdtv_csc_yprpb = {
.ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146,
.ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00,
.rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00,
.ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
.ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
.rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
};
static const struct color_conversion hdtv_csc_rgb = {
@@ -414,7 +414,7 @@ struct tv_mode {
static const struct tv_mode tv_modes[] = {
{
.name = "NTSC-M",
.clock = 107520,
.clock = 108000,
.refresh = 29970,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -442,8 +442,8 @@ static const struct tv_mode tv_modes[] = {
.vburst_start_f4 = 10, .vburst_end_f4 = 240,
/* desired 3.5800000 actual 3.5800000 clock 107.52 */
.dda1_inc = 136,
.dda2_inc = 7624, .dda2_size = 20013,
.dda1_inc = 135,
.dda2_inc = 20800, .dda2_size = 27456,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_4,
.pal_burst = false,
@@ -457,7 +457,7 @@ static const struct tv_mode tv_modes[] = {
},
{
.name = "NTSC-443",
.clock = 107520,
.clock = 108000,
.refresh = 29970,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -485,10 +485,10 @@ static const struct tv_mode tv_modes[] = {
/* desired 4.4336180 actual 4.4336180 clock 107.52 */
.dda1_inc = 168,
.dda2_inc = 18557, .dda2_size = 20625,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = true,
.dda2_inc = 4093, .dda2_size = 27456,
.dda3_inc = 310, .dda3_size = 525,
.sc_reset = TV_SC_RESET_NEVER,
.pal_burst = false,
.composite_levels = &ntsc_m_levels_composite,
.composite_color = &ntsc_m_csc_composite,
@@ -499,7 +499,7 @@ static const struct tv_mode tv_modes[] = {
},
{
.name = "NTSC-J",
.clock = 107520,
.clock = 108000,
.refresh = 29970,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -527,8 +527,8 @@ static const struct tv_mode tv_modes[] = {
.vburst_start_f4 = 10, .vburst_end_f4 = 240,
/* desired 3.5800000 actual 3.5800000 clock 107.52 */
.dda1_inc = 136,
.dda2_inc = 7624, .dda2_size = 20013,
.dda1_inc = 135,
.dda2_inc = 20800, .dda2_size = 27456,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_4,
.pal_burst = false,
@@ -542,7 +542,7 @@ static const struct tv_mode tv_modes[] = {
},
{
.name = "PAL-M",
.clock = 107520,
.clock = 108000,
.refresh = 29970,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -570,11 +570,11 @@ static const struct tv_mode tv_modes[] = {
.vburst_start_f4 = 10, .vburst_end_f4 = 240,
/* desired 3.5800000 actual 3.5800000 clock 107.52 */
.dda1_inc = 136,
.dda2_inc = 7624, .dda2_size = 20013,
.dda1_inc = 135,
.dda2_inc = 16704, .dda2_size = 27456,
.dda3_inc = 0, .dda3_size = 0,
.sc_reset = TV_SC_RESET_EVERY_4,
.pal_burst = false,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = true,
.composite_levels = &pal_m_levels_composite,
.composite_color = &pal_m_csc_composite,
@@ -586,7 +586,7 @@ static const struct tv_mode tv_modes[] = {
{
/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
.name = "PAL-N",
.clock = 107520,
.clock = 108000,
.refresh = 25000,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
@@ -615,9 +615,9 @@ static const struct tv_mode tv_modes[] = {
/* desired 4.4336180 actual 4.4336180 clock 107.52 */
.dda1_inc = 168,
.dda2_inc = 18557, .dda2_size = 20625,
.dda3_inc = 0, .dda3_size = 0,
.dda1_inc = 135,
.dda2_inc = 23578, .dda2_size = 27648,
.dda3_inc = 134, .dda3_size = 625,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = true,
@@ -631,12 +631,12 @@ static const struct tv_mode tv_modes[] = {
{
/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
.name = "PAL",
.clock = 107520,
.clock = 108000,
.refresh = 25000,
.oversample = TV_OVERSAMPLE_8X,
.component_only = 0,
.hsync_end = 64, .hblank_end = 128,
.hsync_end = 64, .hblank_end = 142,
.hblank_start = 844, .htotal = 863,
.progressive = false, .trilevel_sync = false,
@@ -659,8 +659,8 @@ static const struct tv_mode tv_modes[] = {
/* desired 4.4336180 actual 4.4336180 clock 107.52 */
.dda1_inc = 168,
.dda2_inc = 18557, .dda2_size = 20625,
.dda3_inc = 0, .dda3_size = 0,
.dda2_inc = 4122, .dda2_size = 27648,
.dda3_inc = 67, .dda3_size = 625,
.sc_reset = TV_SC_RESET_EVERY_8,
.pal_burst = true,
@@ -689,7 +689,7 @@ static const struct tv_mode tv_modes[] = {
.veq_ena = false,
.vi_end_f1 = 44, .vi_end_f2 = 44,
.nbr_end = 496,
.nbr_end = 479,
.burst_ena = false,
@@ -713,7 +713,7 @@ static const struct tv_mode tv_modes[] = {
.veq_ena = false,
.vi_end_f1 = 44, .vi_end_f2 = 44,
.nbr_end = 496,
.nbr_end = 479,
.burst_ena = false,
@@ -876,7 +876,7 @@ static const struct tv_mode tv_modes[] = {
.component_only = 1,
.hsync_end = 88, .hblank_end = 235,
.hblank_start = 2155, .htotal = 2200,
.hblank_start = 2155, .htotal = 2201,
.progressive = false, .trilevel_sync = true,
@@ -1082,7 +1082,7 @@ intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mo
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
/* Ensure TV refresh is close to desired refresh */
if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1)
if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 10)
return MODE_OK;
return MODE_CLOCK_RANGE;
}
@@ -1135,7 +1135,8 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (!tv_mode)
return; /* can't happen (mode_prepare prevents this) */
tv_ctl = 0;
tv_ctl = I915_READ(TV_CTL);
tv_ctl &= TV_CTL_SAVE;
switch (tv_priv->type) {
default:
@@ -1215,7 +1216,6 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
/* dda1 implies valid video levels */
if (tv_mode->dda1_inc) {
scctl1 |= TV_SC_DDA1_EN;
scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
}
if (tv_mode->dda2_inc)
@@ -1225,6 +1225,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
scctl1 |= TV_SC_DDA3_EN;
scctl1 |= tv_mode->sc_reset;
scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
@@ -1266,7 +1267,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
color_conversion->av);
}
I915_WRITE(TV_CLR_KNOBS, 0x00606000);
if (IS_I965G(dev))
I915_WRITE(TV_CLR_KNOBS, 0x00404000);
else
I915_WRITE(TV_CLR_KNOBS, 0x00606000);
if (video_levels)
I915_WRITE(TV_CLR_LEVEL,
((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
@@ -1401,6 +1406,7 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
tv_dac = I915_READ(TV_DAC);
I915_WRITE(TV_DAC, save_tv_dac);
I915_WRITE(TV_CTL, save_tv_ctl);
intel_wait_for_vblank(dev);
}
/*
* A B C
@@ -1451,7 +1457,7 @@ intel_tv_detect(struct drm_connector *connector)
mode = reported_modes[0];
drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
if (encoder->crtc) {
if (encoder->crtc && encoder->crtc->enabled) {
type = intel_tv_detect_type(encoder->crtc, intel_output);
} else {
crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode);
@@ -1462,6 +1468,8 @@ intel_tv_detect(struct drm_connector *connector)
type = -1;
}
tv_priv->type = type;
if (type < 0)
return connector_status_disconnected;
@@ -1495,7 +1503,8 @@ intel_tv_get_modes(struct drm_connector *connector)
struct drm_display_mode *mode_ptr;
struct intel_output *intel_output = to_intel_output(connector);
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
int j;
int j, count = 0;
u64 tmp;
for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
j++) {
@@ -1510,8 +1519,9 @@ intel_tv_get_modes(struct drm_connector *connector)
&& !tv_mode->component_only))
continue;
mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
DRM_MEM_DRIVER);
mode_ptr = drm_mode_create(connector->dev);
if (!mode_ptr)
continue;
strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
mode_ptr->hdisplay = hactive_s;
@@ -1528,15 +1538,17 @@ intel_tv_get_modes(struct drm_connector *connector)
mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
mode_ptr->vtotal = vactive_s + 33;
mode_ptr->clock = (int) (tv_mode->refresh *
mode_ptr->vtotal *
mode_ptr->htotal / 1000) / 1000;
tmp = (u64) tv_mode->refresh * mode_ptr->vtotal;
tmp *= mode_ptr->htotal;
tmp = div_u64(tmp, 1000000);
mode_ptr->clock = (int) tmp;
mode_ptr->type = DRM_MODE_TYPE_DRIVER;
drm_mode_probed_add(connector, mode_ptr);
count++;
}
return 0;
return count;
}
static void
@@ -1558,33 +1570,49 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
struct drm_device *dev = connector->dev;
struct intel_output *intel_output = to_intel_output(connector);
struct intel_tv_priv *tv_priv = intel_output->dev_priv;
struct drm_encoder *encoder = &intel_output->enc;
struct drm_crtc *crtc = encoder->crtc;
int ret = 0;
bool changed = false;
ret = drm_connector_property_set_value(connector, property, val);
if (ret < 0)
goto out;
if (property == dev->mode_config.tv_left_margin_property)
if (property == dev->mode_config.tv_left_margin_property &&
tv_priv->margin[TV_MARGIN_LEFT] != val) {
tv_priv->margin[TV_MARGIN_LEFT] = val;
else if (property == dev->mode_config.tv_right_margin_property)
changed = true;
} else if (property == dev->mode_config.tv_right_margin_property &&
tv_priv->margin[TV_MARGIN_RIGHT] != val) {
tv_priv->margin[TV_MARGIN_RIGHT] = val;
else if (property == dev->mode_config.tv_top_margin_property)
changed = true;
} else if (property == dev->mode_config.tv_top_margin_property &&
tv_priv->margin[TV_MARGIN_TOP] != val) {
tv_priv->margin[TV_MARGIN_TOP] = val;
else if (property == dev->mode_config.tv_bottom_margin_property)
changed = true;
} else if (property == dev->mode_config.tv_bottom_margin_property &&
tv_priv->margin[TV_MARGIN_BOTTOM] != val) {
tv_priv->margin[TV_MARGIN_BOTTOM] = val;
else if (property == dev->mode_config.tv_mode_property) {
changed = true;
} else if (property == dev->mode_config.tv_mode_property) {
if (val >= NUM_TV_MODES) {
ret = -EINVAL;
goto out;
}
if (!strcmp(tv_priv->tv_format, tv_modes[val].name))
goto out;
tv_priv->tv_format = tv_modes[val].name;
intel_tv_mode_set(&intel_output->enc, NULL, NULL);
changed = true;
} else {
ret = -EINVAL;
goto out;
}
intel_tv_mode_set(&intel_output->enc, NULL, NULL);
if (changed && crtc)
drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
crtc->y, crtc->fb);
out:
return ret;
}

View File

@@ -148,8 +148,8 @@ void mga_do_dma_flush(drm_mga_private_t * dev_priv)
primary->space = head - tail;
}
DRM_DEBUG(" head = 0x%06lx\n", head - dev_priv->primary->offset);
DRM_DEBUG(" tail = 0x%06lx\n", tail - dev_priv->primary->offset);
DRM_DEBUG(" head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
DRM_DEBUG(" tail = 0x%06lx\n", (unsigned long)(tail - dev_priv->primary->offset));
DRM_DEBUG(" space = 0x%06x\n", primary->space);
mga_flush_write_combine();
@@ -187,7 +187,7 @@ void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv)
primary->space = head - dev_priv->primary->offset;
}
DRM_DEBUG(" head = 0x%06lx\n", head - dev_priv->primary->offset);
DRM_DEBUG(" head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset));
DRM_DEBUG(" tail = 0x%06x\n", primary->tail);
DRM_DEBUG(" wrap = %d\n", primary->last_wrap);
DRM_DEBUG(" space = 0x%06x\n", primary->space);
@@ -239,7 +239,7 @@ static void mga_freelist_print(struct drm_device * dev)
for (entry = dev_priv->head->next; entry; entry = entry->next) {
DRM_INFO(" %p idx=%2d age=0x%x 0x%06lx\n",
entry, entry->buf->idx, entry->age.head,
entry->age.head - dev_priv->primary->offset);
(unsigned long)(entry->age.head - dev_priv->primary->offset));
}
DRM_INFO("\n");
}
@@ -340,10 +340,10 @@ static struct drm_buf *mga_freelist_get(struct drm_device * dev)
DRM_DEBUG(" tail=0x%06lx %d\n",
tail->age.head ?
tail->age.head - dev_priv->primary->offset : 0,
(unsigned long)(tail->age.head - dev_priv->primary->offset) : 0,
tail->age.wrap);
DRM_DEBUG(" head=0x%06lx %d\n",
head - dev_priv->primary->offset, wrap);
(unsigned long)(head - dev_priv->primary->offset), wrap);
if (TEST_AGE(&tail->age, head, wrap)) {
prev = dev_priv->tail->prev;
@@ -366,8 +366,9 @@ int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf)
drm_mga_freelist_t *head, *entry, *prev;
DRM_DEBUG("age=0x%06lx wrap=%d\n",
buf_priv->list_entry->age.head -
dev_priv->primary->offset, buf_priv->list_entry->age.wrap);
(unsigned long)(buf_priv->list_entry->age.head -
dev_priv->primary->offset),
buf_priv->list_entry->age.wrap);
entry = buf_priv->list_entry;
head = dev_priv->head;

View File

@@ -113,8 +113,8 @@ typedef struct drm_mga_private {
* \sa drm_mga_private_t::mmio
*/
/*@{ */
u32 mmio_base; /**< Bus address of base of MMIO. */
u32 mmio_size; /**< Size of the MMIO region. */
resource_size_t mmio_base; /**< Bus address of base of MMIO. */
resource_size_t mmio_size; /**< Size of the MMIO region. */
/*@} */
u32 clear_cmd;
@@ -317,8 +317,8 @@ do { \
DRM_INFO( "\n" ); \
DRM_INFO( " tail=0x%06x head=0x%06lx\n", \
dev_priv->prim.tail, \
MGA_READ( MGA_PRIMADDRESS ) - \
dev_priv->primary->offset ); \
(unsigned long)(MGA_READ(MGA_PRIMADDRESS) - \
dev_priv->primary->offset)); \
} \
if ( !test_bit( 0, &dev_priv->prim.wrapped ) ) { \
if ( dev_priv->prim.space < \

View File

@@ -525,11 +525,12 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
} else
#endif
{
dev_priv->cce_ring->handle = (void *)dev_priv->cce_ring->offset;
dev_priv->cce_ring->handle =
(void *)(unsigned long)dev_priv->cce_ring->offset;
dev_priv->ring_rptr->handle =
(void *)dev_priv->ring_rptr->offset;
(void *)(unsigned long)dev_priv->ring_rptr->offset;
dev->agp_buffer_map->handle =
(void *)dev->agp_buffer_map->offset;
(void *)(unsigned long)dev->agp_buffer_map->offset;
}
#if __OS_HAS_AGP

View File

@@ -3,7 +3,7 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm
radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o r600_cp.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o

View File

@@ -37,6 +37,8 @@
#include "radeon_drv.h"
#include "r300_reg.h"
#include <asm/unaligned.h>
#define R300_SIMULTANEOUS_CLIPRECTS 4
/* Values for R300_RE_CLIPRECT_CNTL depending on the number of cliprects
@@ -205,6 +207,10 @@ void r300_init_reg_flags(struct drm_device *dev)
ADD_RANGE(0x42C0, 2);
ADD_RANGE(R300_RS_CNTL_0, 2);
ADD_RANGE(R300_SU_REG_DEST, 1);
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530)
ADD_RANGE(RV530_FG_ZBREG_DEST, 1);
ADD_RANGE(R300_SC_HYPERZ, 2);
ADD_RANGE(0x43E8, 1);
@@ -230,6 +236,7 @@ void r300_init_reg_flags(struct drm_device *dev)
ADD_RANGE(R300_ZB_DEPTHPITCH, 1);
ADD_RANGE(R300_ZB_DEPTHCLEARVALUE, 1);
ADD_RANGE(R300_ZB_ZMASK_OFFSET, 13);
ADD_RANGE(R300_ZB_ZPASS_DATA, 2); /* ZB_ZPASS_DATA, ZB_ZPASS_ADDR */
ADD_RANGE(R300_TX_FILTER_0, 16);
ADD_RANGE(R300_TX_FILTER1_0, 16);
@@ -917,6 +924,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
{
u32 *ref_age_base;
u32 i, buf_idx, h_pending;
u64 ptr_addr;
RING_LOCALS;
if (cmdbuf->bufsz <
@@ -930,7 +938,8 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
dev_priv->scratch_ages[header.scratch.reg]++;
ref_age_base = (u32 *)(unsigned long)*((uint64_t *)cmdbuf->buf);
ptr_addr = get_unaligned((u64 *)cmdbuf->buf);
ref_age_base = (u32 *)(unsigned long)ptr_addr;
cmdbuf->buf += sizeof(u64);
cmdbuf->bufsz -= sizeof(u64);

View File

@@ -1770,4 +1770,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#define R500_RB3D_COLOR_CLEAR_VALUE_AR 0x46c0
#define R500_RB3D_CONSTANT_COLOR_AR 0x4ef8
#define R300_SU_REG_DEST 0x42c8
#define RV530_FG_ZBREG_DEST 0x4be8
#define R300_ZB_ZPASS_DATA 0x4f58
#define R300_ZB_ZPASS_ADDR 0x4f5c
#endif /* _R300_REG_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -43,6 +43,78 @@
static int radeon_do_cleanup_cp(struct drm_device * dev);
static void radeon_do_cp_start(drm_radeon_private_t * dev_priv);
u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off)
{
u32 val;
if (dev_priv->flags & RADEON_IS_AGP) {
val = DRM_READ32(dev_priv->ring_rptr, off);
} else {
val = *(((volatile u32 *)
dev_priv->ring_rptr->handle) +
(off / sizeof(u32)));
val = le32_to_cpu(val);
}
return val;
}
u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv)
{
if (dev_priv->writeback_works)
return radeon_read_ring_rptr(dev_priv, 0);
else {
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return RADEON_READ(R600_CP_RB_RPTR);
else
return RADEON_READ(RADEON_CP_RB_RPTR);
}
}
void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val)
{
if (dev_priv->flags & RADEON_IS_AGP)
DRM_WRITE32(dev_priv->ring_rptr, off, val);
else
*(((volatile u32 *) dev_priv->ring_rptr->handle) +
(off / sizeof(u32))) = cpu_to_le32(val);
}
void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val)
{
radeon_write_ring_rptr(dev_priv, 0, val);
}
u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index)
{
if (dev_priv->writeback_works) {
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return radeon_read_ring_rptr(dev_priv,
R600_SCRATCHOFF(index));
else
return radeon_read_ring_rptr(dev_priv,
RADEON_SCRATCHOFF(index));
} else {
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return RADEON_READ(R600_SCRATCH_REG0 + 4*index);
else
return RADEON_READ(RADEON_SCRATCH_REG0 + 4*index);
}
}
u32 RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr)
{
u32 ret;
if (addr < 0x10000)
ret = DRM_READ32(dev_priv->mmio, addr);
else {
DRM_WRITE32(dev_priv->mmio, RADEON_MM_INDEX, addr);
ret = DRM_READ32(dev_priv->mmio, RADEON_MM_DATA);
}
return ret;
}
static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
u32 ret;
@@ -70,11 +142,22 @@ static u32 RS690_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
return ret;
}
static u32 RS600_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
u32 ret;
RADEON_WRITE(RS600_MC_INDEX, ((addr & RS600_MC_ADDR_MASK) |
RS600_MC_IND_CITF_ARB0));
ret = RADEON_READ(RS600_MC_DATA);
return ret;
}
static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
return RS690_READ_MCIND(dev_priv, addr);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
return RS600_READ_MCIND(dev_priv, addr);
else
return RS480_READ_MCIND(dev_priv, addr);
}
@@ -82,11 +165,17 @@ static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
return RADEON_READ(R700_MC_VM_FB_LOCATION);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return RADEON_READ(R600_MC_VM_FB_LOCATION);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION);
else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
return RS600_READ_MCIND(dev_priv, RS600_MC_FB_LOCATION);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION);
else
@@ -95,42 +184,66 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv)
static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
RADEON_WRITE(R700_MC_VM_FB_LOCATION, fb_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
RADEON_WRITE(R600_MC_VM_FB_LOCATION, fb_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc);
else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
RS600_WRITE_MCIND(RS600_MC_FB_LOCATION, fb_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc);
else
RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc);
}
static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc)
{
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
/*R6xx/R7xx: AGP_TOP and BOT are actually 18 bits each */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) {
RADEON_WRITE(R700_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */
RADEON_WRITE(R700_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff);
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
RADEON_WRITE(R600_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */
RADEON_WRITE(R600_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff);
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515)
R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc);
else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740))
RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
RS600_WRITE_MCIND(RS600_MC_AGP_LOCATION, agp_loc);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515)
R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc);
else
RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc);
}
static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
{
u32 agp_base_hi = upper_32_bits(agp_base);
u32 agp_base_lo = agp_base & 0xffffffff;
u32 r6xx_agp_base = (agp_base >> 22) & 0x3ffff;
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
/* R6xx/R7xx must be aligned to a 4MB boundry */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
RADEON_WRITE(R700_MC_VM_AGP_BASE, r6xx_agp_base);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
RADEON_WRITE(R600_MC_VM_AGP_BASE, r6xx_agp_base);
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) {
R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo);
R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi);
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo);
RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi);
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
RS600_WRITE_MCIND(RS600_AGP_BASE, agp_base_lo);
RS600_WRITE_MCIND(RS600_AGP_BASE_2, agp_base_hi);
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) {
R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo);
R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi);
@@ -145,6 +258,25 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base)
}
}
void radeon_enable_bm(struct drm_radeon_private *dev_priv)
{
u32 tmp;
/* Turn on bus mastering */
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
/* rs600/rs690/rs740 */
tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV350) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
/* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */
tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
} /* PCIE cards appears to not need this */
}
static int RADEON_READ_PLL(struct drm_device * dev, int addr)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -302,7 +434,7 @@ static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) {
RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4));
RADEON_WRITE(R500_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1));
RADEON_WRITE(R300_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1));
}
RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config);
radeon_do_wait_for_idle(dev_priv);
@@ -382,6 +514,14 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv)
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
RS690_cp_microcode[i][0]);
}
} else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
DRM_INFO("Loading RS600 Microcode\n");
for (i = 0; i < 256; i++) {
RADEON_WRITE(RADEON_CP_ME_RAM_DATAH,
RS600_cp_microcode[i][1]);
RADEON_WRITE(RADEON_CP_ME_RAM_DATAL,
RS600_cp_microcode[i][0]);
}
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) ||
@@ -562,7 +702,6 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
{
struct drm_radeon_master_private *master_priv;
u32 ring_start, cur_read_ptr;
u32 tmp;
/* Initialize the memory controller. With new memory map, the fb location
* is not changed, it should have been properly initialized already. Part
@@ -611,17 +750,10 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
} else
#endif
{
struct drm_sg_mem *entry = dev->sg;
unsigned long tmp_ofs, page_ofs;
tmp_ofs = dev_priv->ring_rptr->offset -
(unsigned long)dev->sg->virtual;
page_ofs = tmp_ofs >> PAGE_SHIFT;
RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, entry->busaddr[page_ofs]);
DRM_DEBUG("ring rptr: offset=0x%08lx handle=0x%08lx\n",
(unsigned long)entry->busaddr[page_ofs],
entry->handle + tmp_ofs);
RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
dev_priv->ring_rptr->offset
- ((unsigned long) dev->sg->virtual)
+ dev_priv->gart_vm_start);
}
/* Set ring buffer size */
@@ -649,34 +781,17 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR)
+ RADEON_SCRATCH_REG_OFFSET);
dev_priv->scratch = ((__volatile__ u32 *)
dev_priv->ring_rptr->handle +
(RADEON_SCRATCH_REG_OFFSET / sizeof(u32)));
RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7);
/* Turn on bus mastering */
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) {
/* rs600/rs690/rs740 */
tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV350) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) {
/* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */
tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
RADEON_WRITE(RADEON_BUS_CNTL, tmp);
} /* PCIE cards appears to not need this */
radeon_enable_bm(dev_priv);
dev_priv->scratch[0] = 0;
radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(0), 0);
RADEON_WRITE(RADEON_LAST_FRAME_REG, 0);
dev_priv->scratch[1] = 0;
radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1), 0);
RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0);
dev_priv->scratch[2] = 0;
radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(2), 0);
RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
/* reset sarea copies of these */
@@ -708,12 +823,15 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
/* Writeback doesn't seem to work everywhere, test it here and possibly
* enable it if it appears to work
*/
DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0);
radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1), 0);
RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef);
for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) ==
0xdeadbeef)
u32 val;
val = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
if (val == 0xdeadbeef)
break;
DRM_UDELAY(1);
}
@@ -809,6 +927,82 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
}
}
/* Enable or disable IGP GART on the chip */
static void rs600_set_igpgart(drm_radeon_private_t *dev_priv, int on)
{
u32 temp;
int i;
if (on) {
DRM_DEBUG("programming igp gart %08X %08lX %08X\n",
dev_priv->gart_vm_start,
(long)dev_priv->gart_info.bus_addr,
dev_priv->gart_size);
IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (RS600_EFFECTIVE_L2_CACHE_SIZE(6) |
RS600_EFFECTIVE_L2_QUEUE_SIZE(6)));
for (i = 0; i < 19; i++)
IGP_WRITE_MCIND(RS600_MC_PT0_CLIENT0_CNTL + i,
(RS600_ENABLE_TRANSLATION_MODE_OVERRIDE |
RS600_SYSTEM_ACCESS_MODE_IN_SYS |
RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH |
RS600_EFFECTIVE_L1_CACHE_SIZE(3) |
RS600_ENABLE_FRAGMENT_PROCESSING |
RS600_EFFECTIVE_L1_QUEUE_SIZE(3)));
IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL, (RS600_ENABLE_PAGE_TABLE |
RS600_PAGE_TABLE_TYPE_FLAT));
/* disable all other contexts */
for (i = 1; i < 8; i++)
IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL + i, 0);
/* setup the page table aperture */
IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR,
dev_priv->gart_info.bus_addr);
IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR,
dev_priv->gart_vm_start);
IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR,
(dev_priv->gart_vm_start + dev_priv->gart_size - 1));
IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0);
/* setup the system aperture */
IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR,
dev_priv->gart_vm_start);
IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR,
(dev_priv->gart_vm_start + dev_priv->gart_size - 1));
/* enable page tables */
temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (temp | RS600_ENABLE_PT));
temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1);
IGP_WRITE_MCIND(RS600_MC_CNTL1, (temp | RS600_ENABLE_PAGE_TABLES));
/* invalidate the cache */
temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
temp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE;
IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp);
temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL);
} else {
IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, 0);
temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1);
temp &= ~RS600_ENABLE_PAGE_TABLES;
IGP_WRITE_MCIND(RS600_MC_CNTL1, temp);
}
}
static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
@@ -850,6 +1044,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
return;
}
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) {
rs600_set_igpgart(dev_priv, on);
return;
}
if (dev_priv->flags & RADEON_IS_PCIE) {
radeon_set_pciegart(dev_priv, on);
return;
@@ -881,6 +1080,46 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
}
}
static int radeon_setup_pcigart_surface(drm_radeon_private_t *dev_priv)
{
struct drm_ati_pcigart_info *gart_info = &dev_priv->gart_info;
struct radeon_virt_surface *vp;
int i;
for (i = 0; i < RADEON_MAX_SURFACES * 2; i++) {
if (!dev_priv->virt_surfaces[i].file_priv ||
dev_priv->virt_surfaces[i].file_priv == PCIGART_FILE_PRIV)
break;
}
if (i >= 2 * RADEON_MAX_SURFACES)
return -ENOMEM;
vp = &dev_priv->virt_surfaces[i];
for (i = 0; i < RADEON_MAX_SURFACES; i++) {
struct radeon_surface *sp = &dev_priv->surfaces[i];
if (sp->refcount)
continue;
vp->surface_index = i;
vp->lower = gart_info->bus_addr;
vp->upper = vp->lower + gart_info->table_size;
vp->flags = 0;
vp->file_priv = PCIGART_FILE_PRIV;
sp->refcount = 1;
sp->lower = vp->lower;
sp->upper = vp->upper;
sp->flags = 0;
RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, sp->flags);
RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * i, sp->lower);
RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * i, sp->upper);
return 0;
}
return -ENOMEM;
}
static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
struct drm_file *file_priv)
{
@@ -1062,11 +1301,12 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
} else
#endif
{
dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset;
dev_priv->cp_ring->handle =
(void *)(unsigned long)dev_priv->cp_ring->offset;
dev_priv->ring_rptr->handle =
(void *)dev_priv->ring_rptr->offset;
(void *)(unsigned long)dev_priv->ring_rptr->offset;
dev->agp_buffer_map->handle =
(void *)dev->agp_buffer_map->offset;
(void *)(unsigned long)dev->agp_buffer_map->offset;
DRM_DEBUG("dev_priv->cp_ring->handle %p\n",
dev_priv->cp_ring->handle);
@@ -1173,11 +1413,14 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
} else
#endif
{
u32 sctrl;
int ret;
dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
/* if we have an offset set from userspace */
if (dev_priv->pcigart_offset_set) {
dev_priv->gart_info.bus_addr =
dev_priv->pcigart_offset + dev_priv->fb_location;
(resource_size_t)dev_priv->pcigart_offset + dev_priv->fb_location;
dev_priv->gart_info.mapping.offset =
dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
dev_priv->gart_info.mapping.size =
@@ -1214,12 +1457,31 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
}
}
if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
sctrl = RADEON_READ(RADEON_SURFACE_CNTL);
RADEON_WRITE(RADEON_SURFACE_CNTL, 0);
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
ret = r600_page_table_init(dev);
else
ret = drm_ati_pcigart_init(dev, &dev_priv->gart_info);
RADEON_WRITE(RADEON_SURFACE_CNTL, sctrl);
if (!ret) {
DRM_ERROR("failed to init PCI GART!\n");
radeon_do_cleanup_cp(dev);
return -ENOMEM;
}
ret = radeon_setup_pcigart_surface(dev_priv);
if (ret) {
DRM_ERROR("failed to setup GART surface!\n");
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
r600_page_table_cleanup(dev, &dev_priv->gart_info);
else
drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info);
radeon_do_cleanup_cp(dev);
return ret;
}
/* Turn on PCI GART */
radeon_set_pcigart(dev_priv, 1);
}
@@ -1268,14 +1530,18 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
if (dev_priv->gart_info.bus_addr) {
/* Turn off PCI GART */
radeon_set_pcigart(dev_priv, 0);
if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
DRM_ERROR("failed to cleanup PCI GART!\n");
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600)
r600_page_table_cleanup(dev, &dev_priv->gart_info);
else {
if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
DRM_ERROR("failed to cleanup PCI GART!\n");
}
}
if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
{
drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
dev_priv->gart_info.addr = 0;
dev_priv->gart_info.addr = NULL;
}
}
/* only clear to the start of flags */
@@ -1326,6 +1592,7 @@ static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_pri
int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_init_t *init = data;
LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -1338,8 +1605,13 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri
case RADEON_INIT_R200_CP:
case RADEON_INIT_R300_CP:
return radeon_do_init_cp(dev, init, file_priv);
case RADEON_INIT_R600_CP:
return r600_do_init_cp(dev, init, file_priv);
case RADEON_CLEANUP_CP:
return radeon_do_cleanup_cp(dev);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return r600_do_cleanup_cp(dev);
else
return radeon_do_cleanup_cp(dev);
}
return -EINVAL;
@@ -1362,7 +1634,10 @@ int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_pr
return 0;
}
radeon_do_cp_start(dev_priv);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
r600_do_cp_start(dev_priv);
else
radeon_do_cp_start(dev_priv);
return 0;
}
@@ -1393,7 +1668,10 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri
* code so that the DRM ioctl wrapper can try again.
*/
if (stop->idle) {
ret = radeon_do_cp_idle(dev_priv);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
ret = r600_do_cp_idle(dev_priv);
else
ret = radeon_do_cp_idle(dev_priv);
if (ret)
return ret;
}
@@ -1402,10 +1680,16 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri
* we will get some dropped triangles as they won't be fully
* rendered before the CP is shut down.
*/
radeon_do_cp_stop(dev_priv);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
r600_do_cp_stop(dev_priv);
else
radeon_do_cp_stop(dev_priv);
/* Reset the engine */
radeon_do_engine_reset(dev);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
r600_do_engine_reset(dev);
else
radeon_do_engine_reset(dev);
return 0;
}
@@ -1418,29 +1702,47 @@ void radeon_do_release(struct drm_device * dev)
if (dev_priv) {
if (dev_priv->cp_running) {
/* Stop the cp */
while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
while ((ret = r600_do_cp_idle(dev_priv)) != 0) {
DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
#ifdef __linux__
schedule();
schedule();
#else
tsleep(&ret, PZERO, "rdnrel", 1);
tsleep(&ret, PZERO, "rdnrel", 1);
#endif
}
} else {
while ((ret = radeon_do_cp_idle(dev_priv)) != 0) {
DRM_DEBUG("radeon_do_cp_idle %d\n", ret);
#ifdef __linux__
schedule();
#else
tsleep(&ret, PZERO, "rdnrel", 1);
#endif
}
}
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
r600_do_cp_stop(dev_priv);
r600_do_engine_reset(dev);
} else {
radeon_do_cp_stop(dev_priv);
radeon_do_engine_reset(dev);
}
radeon_do_cp_stop(dev_priv);
radeon_do_engine_reset(dev);
}
/* Disable *all* interrupts */
if (dev_priv->mmio) /* remove this after permanent addmaps */
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R600) {
/* Disable *all* interrupts */
if (dev_priv->mmio) /* remove this after permanent addmaps */
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
if (dev_priv->mmio) { /* remove all surfaces */
for (i = 0; i < RADEON_MAX_SURFACES; i++) {
RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, 0);
RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND +
16 * i, 0);
RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND +
16 * i, 0);
if (dev_priv->mmio) { /* remove all surfaces */
for (i = 0; i < RADEON_MAX_SURFACES; i++) {
RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * i, 0);
RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND +
16 * i, 0);
RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND +
16 * i, 0);
}
}
}
@@ -1449,7 +1751,10 @@ void radeon_do_release(struct drm_device * dev)
radeon_mem_takedown(&(dev_priv->fb_heap));
/* deallocate kernel resources */
radeon_do_cleanup_cp(dev);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
r600_do_cleanup_cp(dev);
else
radeon_do_cleanup_cp(dev);
}
}
@@ -1467,7 +1772,10 @@ int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_pr
return -EINVAL;
}
radeon_do_cp_reset(dev_priv);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
r600_do_cp_reset(dev_priv);
else
radeon_do_cp_reset(dev_priv);
/* The CP is no longer running after an engine reset */
dev_priv->cp_running = 0;
@@ -1482,23 +1790,36 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri
LOCK_TEST_WITH_RETURN(dev, file_priv);
return radeon_do_cp_idle(dev_priv);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return r600_do_cp_idle(dev_priv);
else
return radeon_do_cp_idle(dev_priv);
}
/* Added by Charl P. Botha to call radeon_do_resume_cp().
*/
int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
return radeon_do_resume_cp(dev, file_priv);
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return r600_do_resume_cp(dev, file_priv);
else
return radeon_do_resume_cp(dev, file_priv);
}
int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, file_priv);
return radeon_do_engine_reset(dev);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return r600_do_engine_reset(dev);
else
return radeon_do_engine_reset(dev);
}
/* ================================================================
@@ -1548,7 +1869,7 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
start = dev_priv->last_buf;
for (t = 0; t < dev_priv->usec_timeout; t++) {
u32 done_age = GET_SCRATCH(1);
u32 done_age = GET_SCRATCH(dev_priv, 1);
DRM_DEBUG("done_age = %d\n", done_age);
for (i = start; i < dma->buf_count; i++) {
buf = dma->buflist[i];
@@ -1582,8 +1903,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
struct drm_buf *buf;
int i, t;
int start;
u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1));
u32 done_age;
done_age = radeon_read_ring_rptr(dev_priv, RADEON_SCRATCHOFF(1));
if (++dev_priv->last_buf >= dma->buf_count)
dev_priv->last_buf = 0;
@@ -1854,3 +2176,41 @@ int radeon_driver_unload(struct drm_device *dev)
dev->dev_private = NULL;
return 0;
}
void radeon_commit_ring(drm_radeon_private_t *dev_priv)
{
int i;
u32 *ring;
int tail_aligned;
/* check if the ring is padded out to 16-dword alignment */
tail_aligned = dev_priv->ring.tail & 0xf;
if (tail_aligned) {
int num_p2 = 16 - tail_aligned;
ring = dev_priv->ring.start;
/* pad with some CP_PACKET2 */
for (i = 0; i < num_p2; i++)
ring[dev_priv->ring.tail + i] = CP_PACKET2();
dev_priv->ring.tail += i;
dev_priv->ring.space -= num_p2 * sizeof(u32);
}
dev_priv->ring.tail &= dev_priv->ring.tail_mask;
DRM_MEMORYBARRIER();
GET_RING_HEAD( dev_priv );
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
RADEON_WRITE(R600_CP_RB_WPTR, dev_priv->ring.tail);
/* read from PCI bus to ensure correct posting */
RADEON_READ(R600_CP_RB_RPTR);
} else {
RADEON_WRITE(RADEON_CP_RB_WPTR, dev_priv->ring.tail);
/* read from PCI bus to ensure correct posting */
RADEON_READ(RADEON_CP_RB_RPTR);
}
}

View File

@@ -41,23 +41,15 @@ int radeon_no_wb;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444);
static int dri_library_name(struct drm_device *dev, char *buf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
int family = dev_priv->flags & RADEON_FAMILY_MASK;
return snprintf(buf, PAGE_SIZE, "%s\n",
(family < CHIP_R200) ? "radeon" :
((family < CHIP_R300) ? "r200" :
"r300"));
}
static int radeon_suspend(struct drm_device *dev, pm_message_t state)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return 0;
/* Disable *all* interrupts */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
return 0;
@@ -67,8 +59,11 @@ static int radeon_resume(struct drm_device *dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return 0;
/* Restore interrupt registers */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg);
RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg);
return 0;
@@ -95,7 +90,6 @@ static struct drm_driver driver = {
.get_vblank_counter = radeon_get_vblank_counter,
.enable_vblank = radeon_enable_vblank,
.disable_vblank = radeon_disable_vblank,
.dri_library_name = dri_library_name,
.master_create = radeon_master_create,
.master_destroy = radeon_master_destroy,
.irq_preinstall = radeon_driver_irq_preinstall,

View File

@@ -126,6 +126,7 @@ enum radeon_family {
CHIP_RV410,
CHIP_RS400,
CHIP_RS480,
CHIP_RS600,
CHIP_RS690,
CHIP_RS740,
CHIP_RV515,
@@ -134,6 +135,16 @@ enum radeon_family {
CHIP_RV560,
CHIP_RV570,
CHIP_R580,
CHIP_R600,
CHIP_RV610,
CHIP_RV630,
CHIP_RV620,
CHIP_RV635,
CHIP_RV670,
CHIP_RS780,
CHIP_RV770,
CHIP_RV730,
CHIP_RV710,
CHIP_LAST,
};
@@ -160,10 +171,6 @@ enum radeon_chip_flags {
RADEON_IS_IGPGART = 0x01000000UL,
};
#define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \
DRM_READ32( (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR))
#define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) )
typedef struct drm_radeon_freelist {
unsigned int age;
struct drm_buf *buf;
@@ -221,10 +228,11 @@ struct radeon_virt_surface {
u32 upper;
u32 flags;
struct drm_file *file_priv;
#define PCIGART_FILE_PRIV ((void *) -1L)
};
#define RADEON_FLUSH_EMITED (1 < 0)
#define RADEON_PURGE_EMITED (1 < 1)
#define RADEON_FLUSH_EMITED (1 << 0)
#define RADEON_PURGE_EMITED (1 << 1)
struct drm_radeon_master_private {
drm_local_map_t *sarea;
@@ -248,7 +256,6 @@ typedef struct drm_radeon_private {
drm_radeon_freelist_t *head;
drm_radeon_freelist_t *tail;
int last_buf;
volatile u32 *scratch;
int writeback_works;
int usec_timeout;
@@ -316,11 +323,31 @@ typedef struct drm_radeon_private {
/* starting from here on, data is preserved accross an open */
uint32_t flags; /* see radeon_chip_flags */
unsigned long fb_aper_offset;
resource_size_t fb_aper_offset;
int num_gb_pipes;
int track_flush;
drm_local_map_t *mmio;
/* r6xx/r7xx pipe/shader config */
int r600_max_pipes;
int r600_max_tile_pipes;
int r600_max_simds;
int r600_max_backends;
int r600_max_gprs;
int r600_max_threads;
int r600_max_stack_entries;
int r600_max_hw_contexts;
int r600_max_gs_threads;
int r600_sx_max_export_size;
int r600_sx_max_export_pos_size;
int r600_sx_max_export_smx_size;
int r600_sq_num_cf_insts;
int r700_sx_num_of_sets;
int r700_sc_prim_fifo_size;
int r700_sc_hiz_tile_fifo_size;
int r700_sc_earlyz_tile_fifo_fize;
} drm_radeon_private_t;
typedef struct drm_radeon_buf_priv {
@@ -338,6 +365,12 @@ extern int radeon_no_wb;
extern struct drm_ioctl_desc radeon_ioctls[];
extern int radeon_max_ioctl;
extern u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv);
extern void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val);
#define GET_RING_HEAD(dev_priv) radeon_get_ring_head(dev_priv)
#define SET_RING_HEAD(dev_priv, val) radeon_set_ring_head(dev_priv, val)
/* Check whether the given hardware address is inside the framebuffer or the
* GART area.
*/
@@ -364,6 +397,9 @@ extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_fi
extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv);
extern void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc);
extern void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base);
extern u32 RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr);
extern void radeon_freelist_reset(struct drm_device * dev);
extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
@@ -383,6 +419,10 @@ extern void radeon_mem_takedown(struct mem_block **heap);
extern void radeon_mem_release(struct drm_file *file_priv,
struct mem_block *heap);
extern void radeon_enable_bm(struct drm_radeon_private *dev_priv);
extern u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off);
extern void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val);
/* radeon_irq.c */
extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state);
extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
@@ -423,6 +463,21 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *cmdbuf);
/* r600_cp.c */
extern int r600_do_engine_reset(struct drm_device *dev);
extern int r600_do_cleanup_cp(struct drm_device *dev);
extern int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
struct drm_file *file_priv);
extern int r600_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv);
extern int r600_do_cp_idle(drm_radeon_private_t *dev_priv);
extern void r600_do_cp_start(drm_radeon_private_t *dev_priv);
extern void r600_do_cp_reset(drm_radeon_private_t *dev_priv);
extern void r600_do_cp_stop(drm_radeon_private_t *dev_priv);
extern int r600_cp_dispatch_indirect(struct drm_device *dev,
struct drm_buf *buf, int start, int end);
extern int r600_page_table_init(struct drm_device *dev);
extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info);
/* Flags for stats.boxes
*/
#define RADEON_BOX_DMA_IDLE 0x1
@@ -434,6 +489,8 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
/* Register definitions, register access macros and drmAddMap constants
* for Radeon kernel driver.
*/
#define RADEON_MM_INDEX 0x0000
#define RADEON_MM_DATA 0x0004
#define RADEON_AGP_COMMAND 0x0f60
#define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config */
@@ -556,6 +613,56 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
#define RS690_MC_AGP_BASE 0x102
#define RS690_MC_AGP_BASE_2 0x103
#define RS600_MC_INDEX 0x70
# define RS600_MC_ADDR_MASK 0xffff
# define RS600_MC_IND_SEQ_RBS_0 (1 << 16)
# define RS600_MC_IND_SEQ_RBS_1 (1 << 17)
# define RS600_MC_IND_SEQ_RBS_2 (1 << 18)
# define RS600_MC_IND_SEQ_RBS_3 (1 << 19)
# define RS600_MC_IND_AIC_RBS (1 << 20)
# define RS600_MC_IND_CITF_ARB0 (1 << 21)
# define RS600_MC_IND_CITF_ARB1 (1 << 22)
# define RS600_MC_IND_WR_EN (1 << 23)
#define RS600_MC_DATA 0x74
#define RS600_MC_STATUS 0x0
# define RS600_MC_IDLE (1 << 1)
#define RS600_MC_FB_LOCATION 0x4
#define RS600_MC_AGP_LOCATION 0x5
#define RS600_AGP_BASE 0x6
#define RS600_AGP_BASE_2 0x7
#define RS600_MC_CNTL1 0x9
# define RS600_ENABLE_PAGE_TABLES (1 << 26)
#define RS600_MC_PT0_CNTL 0x100
# define RS600_ENABLE_PT (1 << 0)
# define RS600_EFFECTIVE_L2_CACHE_SIZE(x) ((x) << 15)
# define RS600_EFFECTIVE_L2_QUEUE_SIZE(x) ((x) << 21)
# define RS600_INVALIDATE_ALL_L1_TLBS (1 << 28)
# define RS600_INVALIDATE_L2_CACHE (1 << 29)
#define RS600_MC_PT0_CONTEXT0_CNTL 0x102
# define RS600_ENABLE_PAGE_TABLE (1 << 0)
# define RS600_PAGE_TABLE_TYPE_FLAT (0 << 1)
#define RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR 0x112
#define RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR 0x114
#define RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR 0x11c
#define RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR 0x12c
#define RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR 0x13c
#define RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR 0x14c
#define RS600_MC_PT0_CLIENT0_CNTL 0x16c
# define RS600_ENABLE_TRANSLATION_MODE_OVERRIDE (1 << 0)
# define RS600_TRANSLATION_MODE_OVERRIDE (1 << 1)
# define RS600_SYSTEM_ACCESS_MODE_MASK (3 << 8)
# define RS600_SYSTEM_ACCESS_MODE_PA_ONLY (0 << 8)
# define RS600_SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 8)
# define RS600_SYSTEM_ACCESS_MODE_IN_SYS (2 << 8)
# define RS600_SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 8)
# define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH (0 << 10)
# define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE (1 << 10)
# define RS600_EFFECTIVE_L1_CACHE_SIZE(x) ((x) << 11)
# define RS600_ENABLE_FRAGMENT_PROCESSING (1 << 14)
# define RS600_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 15)
# define RS600_INVALIDATE_L1_TLB (1 << 20)
#define R520_MC_IND_INDEX 0x70
#define R520_MC_IND_WR_EN (1 << 24)
#define R520_MC_IND_DATA 0x74
@@ -580,7 +687,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
/* pipe config regs */
#define R400_GB_PIPE_SELECT 0x402c
#define R500_DYN_SCLK_PWMEM_PIPE 0x000d /* PLL */
#define R500_SU_REG_DEST 0x42c8
#define R300_GB_TILE_CONFIG 0x4018
# define R300_ENABLE_TILING (1 << 0)
# define R300_PIPE_COUNT_RV350 (0 << 1)
@@ -639,9 +745,22 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
#define RADEON_SCRATCHOFF( x ) (RADEON_SCRATCH_REG_OFFSET + 4*(x))
#define GET_SCRATCH( x ) (dev_priv->writeback_works \
? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \
: RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) )
extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index);
#define GET_SCRATCH(dev_priv, x) radeon_get_scratch(dev_priv, x)
#define R600_SCRATCH_REG0 0x8500
#define R600_SCRATCH_REG1 0x8504
#define R600_SCRATCH_REG2 0x8508
#define R600_SCRATCH_REG3 0x850c
#define R600_SCRATCH_REG4 0x8510
#define R600_SCRATCH_REG5 0x8514
#define R600_SCRATCH_REG6 0x8518
#define R600_SCRATCH_REG7 0x851c
#define R600_SCRATCH_UMSK 0x8540
#define R600_SCRATCH_ADDR 0x8544
#define R600_SCRATCHOFF(x) (R600_SCRATCH_REG_OFFSET + 4*(x))
#define RADEON_GEN_INT_CNTL 0x0040
# define RADEON_CRTC_VBLANK_MASK (1 << 0)
@@ -922,6 +1041,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
#define RADEON_CP_RB_CNTL 0x0704
# define RADEON_BUF_SWAP_32BIT (2 << 16)
# define RADEON_RB_NO_UPDATE (1 << 27)
# define RADEON_RB_RPTR_WR_ENA (1 << 31)
#define RADEON_CP_RB_RPTR_ADDR 0x070c
#define RADEON_CP_RB_RPTR 0x0710
#define RADEON_CP_RB_WPTR 0x0714
@@ -983,6 +1103,14 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
# define RADEON_CNTL_BITBLT_MULTI 0x00009B00
# define RADEON_CNTL_SET_SCISSORS 0xC0001E00
# define R600_IT_INDIRECT_BUFFER 0x00003200
# define R600_IT_ME_INITIALIZE 0x00004400
# define R600_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
# define R600_IT_EVENT_WRITE 0x00004600
# define R600_IT_SET_CONFIG_REG 0x00006800
# define R600_SET_CONFIG_REG_OFFSET 0x00008000
# define R600_SET_CONFIG_REG_END 0x0000ac00
#define RADEON_CP_PACKET_MASK 0xC0000000
#define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000
#define RADEON_CP_PACKET0_REG_MASK 0x000007ff
@@ -1181,6 +1309,422 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
#define R500_D1_VBLANK_INTERRUPT (1 << 4)
#define R500_D2_VBLANK_INTERRUPT (1 << 5)
/* R6xx/R7xx registers */
#define R600_MC_VM_FB_LOCATION 0x2180
#define R600_MC_VM_AGP_TOP 0x2184
#define R600_MC_VM_AGP_BOT 0x2188
#define R600_MC_VM_AGP_BASE 0x218c
#define R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2190
#define R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194
#define R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198
#define R700_MC_VM_FB_LOCATION 0x2024
#define R700_MC_VM_AGP_TOP 0x2028
#define R700_MC_VM_AGP_BOT 0x202c
#define R700_MC_VM_AGP_BASE 0x2030
#define R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034
#define R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038
#define R700_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203c
#define R600_MCD_RD_A_CNTL 0x219c
#define R600_MCD_RD_B_CNTL 0x21a0
#define R600_MCD_WR_A_CNTL 0x21a4
#define R600_MCD_WR_B_CNTL 0x21a8
#define R600_MCD_RD_SYS_CNTL 0x2200
#define R600_MCD_WR_SYS_CNTL 0x2214
#define R600_MCD_RD_GFX_CNTL 0x21fc
#define R600_MCD_RD_HDP_CNTL 0x2204
#define R600_MCD_RD_PDMA_CNTL 0x2208
#define R600_MCD_RD_SEM_CNTL 0x220c
#define R600_MCD_WR_GFX_CNTL 0x2210
#define R600_MCD_WR_HDP_CNTL 0x2218
#define R600_MCD_WR_PDMA_CNTL 0x221c
#define R600_MCD_WR_SEM_CNTL 0x2220
# define R600_MCD_L1_TLB (1 << 0)
# define R600_MCD_L1_FRAG_PROC (1 << 1)
# define R600_MCD_L1_STRICT_ORDERING (1 << 2)
# define R600_MCD_SYSTEM_ACCESS_MODE_MASK (3 << 6)
# define R600_MCD_SYSTEM_ACCESS_MODE_PA_ONLY (0 << 6)
# define R600_MCD_SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 6)
# define R600_MCD_SYSTEM_ACCESS_MODE_IN_SYS (2 << 6)
# define R600_MCD_SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 6)
# define R600_MCD_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 8)
# define R600_MCD_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE (1 << 8)
# define R600_MCD_SEMAPHORE_MODE (1 << 10)
# define R600_MCD_WAIT_L2_QUERY (1 << 11)
# define R600_MCD_EFFECTIVE_L1_TLB_SIZE(x) ((x) << 12)
# define R600_MCD_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 15)
#define R700_MC_VM_MD_L1_TLB0_CNTL 0x2654
#define R700_MC_VM_MD_L1_TLB1_CNTL 0x2658
#define R700_MC_VM_MD_L1_TLB2_CNTL 0x265c
#define R700_MC_VM_MB_L1_TLB0_CNTL 0x2234
#define R700_MC_VM_MB_L1_TLB1_CNTL 0x2238
#define R700_MC_VM_MB_L1_TLB2_CNTL 0x223c
#define R700_MC_VM_MB_L1_TLB3_CNTL 0x2240
# define R700_ENABLE_L1_TLB (1 << 0)
# define R700_ENABLE_L1_FRAGMENT_PROCESSING (1 << 1)
# define R700_SYSTEM_ACCESS_MODE_IN_SYS (2 << 3)
# define R700_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 5)
# define R700_EFFECTIVE_L1_TLB_SIZE(x) ((x) << 15)
# define R700_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 18)
#define R700_MC_ARB_RAMCFG 0x2760
# define R700_NOOFBANK_SHIFT 0
# define R700_NOOFBANK_MASK 0x3
# define R700_NOOFRANK_SHIFT 2
# define R700_NOOFRANK_MASK 0x1
# define R700_NOOFROWS_SHIFT 3
# define R700_NOOFROWS_MASK 0x7
# define R700_NOOFCOLS_SHIFT 6
# define R700_NOOFCOLS_MASK 0x3
# define R700_CHANSIZE_SHIFT 8
# define R700_CHANSIZE_MASK 0x1
# define R700_BURSTLENGTH_SHIFT 9
# define R700_BURSTLENGTH_MASK 0x1
#define R600_RAMCFG 0x2408
# define R600_NOOFBANK_SHIFT 0
# define R600_NOOFBANK_MASK 0x1
# define R600_NOOFRANK_SHIFT 1
# define R600_NOOFRANK_MASK 0x1
# define R600_NOOFROWS_SHIFT 2
# define R600_NOOFROWS_MASK 0x7
# define R600_NOOFCOLS_SHIFT 5
# define R600_NOOFCOLS_MASK 0x3
# define R600_CHANSIZE_SHIFT 7
# define R600_CHANSIZE_MASK 0x1
# define R600_BURSTLENGTH_SHIFT 8
# define R600_BURSTLENGTH_MASK 0x1
#define R600_VM_L2_CNTL 0x1400
# define R600_VM_L2_CACHE_EN (1 << 0)
# define R600_VM_L2_FRAG_PROC (1 << 1)
# define R600_VM_ENABLE_PTE_CACHE_LRU_W (1 << 9)
# define R600_VM_L2_CNTL_QUEUE_SIZE(x) ((x) << 13)
# define R700_VM_L2_CNTL_QUEUE_SIZE(x) ((x) << 14)
#define R600_VM_L2_CNTL2 0x1404
# define R600_VM_L2_CNTL2_INVALIDATE_ALL_L1_TLBS (1 << 0)
# define R600_VM_L2_CNTL2_INVALIDATE_L2_CACHE (1 << 1)
#define R600_VM_L2_CNTL3 0x1408
# define R600_VM_L2_CNTL3_BANK_SELECT_0(x) ((x) << 0)
# define R600_VM_L2_CNTL3_BANK_SELECT_1(x) ((x) << 5)
# define R600_VM_L2_CNTL3_CACHE_UPDATE_MODE(x) ((x) << 10)
# define R700_VM_L2_CNTL3_BANK_SELECT(x) ((x) << 0)
# define R700_VM_L2_CNTL3_CACHE_UPDATE_MODE(x) ((x) << 6)
#define R600_VM_L2_STATUS 0x140c
#define R600_VM_CONTEXT0_CNTL 0x1410
# define R600_VM_ENABLE_CONTEXT (1 << 0)
# define R600_VM_PAGE_TABLE_DEPTH_FLAT (0 << 1)
#define R600_VM_CONTEXT0_CNTL2 0x1430
#define R600_VM_CONTEXT0_REQUEST_RESPONSE 0x1470
#define R600_VM_CONTEXT0_INVALIDATION_LOW_ADDR 0x1490
#define R600_VM_CONTEXT0_INVALIDATION_HIGH_ADDR 0x14b0
#define R600_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x1574
#define R600_VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x1594
#define R600_VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x15b4
#define R700_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153c
#define R700_VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x155c
#define R700_VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157c
#define R600_HDP_HOST_PATH_CNTL 0x2c00
#define R600_GRBM_CNTL 0x8000
# define R600_GRBM_READ_TIMEOUT(x) ((x) << 0)
#define R600_GRBM_STATUS 0x8010
# define R600_CMDFIFO_AVAIL_MASK 0x1f
# define R700_CMDFIFO_AVAIL_MASK 0xf
# define R600_GUI_ACTIVE (1 << 31)
#define R600_GRBM_STATUS2 0x8014
#define R600_GRBM_SOFT_RESET 0x8020
# define R600_SOFT_RESET_CP (1 << 0)
#define R600_WAIT_UNTIL 0x8040
#define R600_CP_SEM_WAIT_TIMER 0x85bc
#define R600_CP_ME_CNTL 0x86d8
# define R600_CP_ME_HALT (1 << 28)
#define R600_CP_QUEUE_THRESHOLDS 0x8760
# define R600_ROQ_IB1_START(x) ((x) << 0)
# define R600_ROQ_IB2_START(x) ((x) << 8)
#define R600_CP_MEQ_THRESHOLDS 0x8764
# define R700_STQ_SPLIT(x) ((x) << 0)
# define R600_MEQ_END(x) ((x) << 16)
# define R600_ROQ_END(x) ((x) << 24)
#define R600_CP_PERFMON_CNTL 0x87fc
#define R600_CP_RB_BASE 0xc100
#define R600_CP_RB_CNTL 0xc104
# define R600_RB_BUFSZ(x) ((x) << 0)
# define R600_RB_BLKSZ(x) ((x) << 8)
# define R600_RB_NO_UPDATE (1 << 27)
# define R600_RB_RPTR_WR_ENA (1 << 31)
#define R600_CP_RB_RPTR_WR 0xc108
#define R600_CP_RB_RPTR_ADDR 0xc10c
#define R600_CP_RB_RPTR_ADDR_HI 0xc110
#define R600_CP_RB_WPTR 0xc114
#define R600_CP_RB_WPTR_ADDR 0xc118
#define R600_CP_RB_WPTR_ADDR_HI 0xc11c
#define R600_CP_RB_RPTR 0x8700
#define R600_CP_RB_WPTR_DELAY 0x8704
#define R600_CP_PFP_UCODE_ADDR 0xc150
#define R600_CP_PFP_UCODE_DATA 0xc154
#define R600_CP_ME_RAM_RADDR 0xc158
#define R600_CP_ME_RAM_WADDR 0xc15c
#define R600_CP_ME_RAM_DATA 0xc160
#define R600_CP_DEBUG 0xc1fc
#define R600_PA_CL_ENHANCE 0x8a14
# define R600_CLIP_VTX_REORDER_ENA (1 << 0)
# define R600_NUM_CLIP_SEQ(x) ((x) << 1)
#define R600_PA_SC_LINE_STIPPLE_STATE 0x8b10
#define R600_PA_SC_MULTI_CHIP_CNTL 0x8b20
#define R700_PA_SC_FORCE_EOV_MAX_CNTS 0x8b24
# define R700_FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0)
# define R700_FORCE_EOV_MAX_REZ_CNT(x) ((x) << 16)
#define R600_PA_SC_AA_SAMPLE_LOCS_2S 0x8b40
#define R600_PA_SC_AA_SAMPLE_LOCS_4S 0x8b44
#define R600_PA_SC_AA_SAMPLE_LOCS_8S_WD0 0x8b48
#define R600_PA_SC_AA_SAMPLE_LOCS_8S_WD1 0x8b4c
# define R600_S0_X(x) ((x) << 0)
# define R600_S0_Y(x) ((x) << 4)
# define R600_S1_X(x) ((x) << 8)
# define R600_S1_Y(x) ((x) << 12)
# define R600_S2_X(x) ((x) << 16)
# define R600_S2_Y(x) ((x) << 20)
# define R600_S3_X(x) ((x) << 24)
# define R600_S3_Y(x) ((x) << 28)
# define R600_S4_X(x) ((x) << 0)
# define R600_S4_Y(x) ((x) << 4)
# define R600_S5_X(x) ((x) << 8)
# define R600_S5_Y(x) ((x) << 12)
# define R600_S6_X(x) ((x) << 16)
# define R600_S6_Y(x) ((x) << 20)
# define R600_S7_X(x) ((x) << 24)
# define R600_S7_Y(x) ((x) << 28)
#define R600_PA_SC_FIFO_SIZE 0x8bd0
# define R600_SC_PRIM_FIFO_SIZE(x) ((x) << 0)
# define R600_SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 8)
# define R600_SC_EARLYZ_TILE_FIFO_SIZE(x) ((x) << 16)
#define R700_PA_SC_FIFO_SIZE_R7XX 0x8bcc
# define R700_SC_PRIM_FIFO_SIZE(x) ((x) << 0)
# define R700_SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 12)
# define R700_SC_EARLYZ_TILE_FIFO_SIZE(x) ((x) << 20)
#define R600_PA_SC_ENHANCE 0x8bf0
# define R600_FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0)
# define R600_FORCE_EOV_MAX_TILE_CNT(x) ((x) << 12)
#define R600_PA_SC_CLIPRECT_RULE 0x2820c
#define R700_PA_SC_EDGERULE 0x28230
#define R600_PA_SC_LINE_STIPPLE 0x28a0c
#define R600_PA_SC_MODE_CNTL 0x28a4c
#define R600_PA_SC_AA_CONFIG 0x28c04
#define R600_SX_EXPORT_BUFFER_SIZES 0x900c
# define R600_COLOR_BUFFER_SIZE(x) ((x) << 0)
# define R600_POSITION_BUFFER_SIZE(x) ((x) << 8)
# define R600_SMX_BUFFER_SIZE(x) ((x) << 16)
#define R600_SX_DEBUG_1 0x9054
# define R600_SMX_EVENT_RELEASE (1 << 0)
# define R600_ENABLE_NEW_SMX_ADDRESS (1 << 16)
#define R700_SX_DEBUG_1 0x9058
# define R700_ENABLE_NEW_SMX_ADDRESS (1 << 16)
#define R600_SX_MISC 0x28350
#define R600_DB_DEBUG 0x9830
# define R600_PREZ_MUST_WAIT_FOR_POSTZ_DONE (1 << 31)
#define R600_DB_WATERMARKS 0x9838
# define R600_DEPTH_FREE(x) ((x) << 0)
# define R600_DEPTH_FLUSH(x) ((x) << 5)
# define R600_DEPTH_PENDING_FREE(x) ((x) << 15)
# define R600_DEPTH_CACHELINE_FREE(x) ((x) << 20)
#define R700_DB_DEBUG3 0x98b0
# define R700_DB_CLK_OFF_DELAY(x) ((x) << 11)
#define RV700_DB_DEBUG4 0x9b8c
# define RV700_DISABLE_TILE_COVERED_FOR_PS_ITER (1 << 6)
#define R600_VGT_CACHE_INVALIDATION 0x88c4
# define R600_CACHE_INVALIDATION(x) ((x) << 0)
# define R600_VC_ONLY 0
# define R600_TC_ONLY 1
# define R600_VC_AND_TC 2
# define R700_AUTO_INVLD_EN(x) ((x) << 6)
# define R700_NO_AUTO 0
# define R700_ES_AUTO 1
# define R700_GS_AUTO 2
# define R700_ES_AND_GS_AUTO 3
#define R600_VGT_GS_PER_ES 0x88c8
#define R600_VGT_ES_PER_GS 0x88cc
#define R600_VGT_GS_PER_VS 0x88e8
#define R600_VGT_GS_VERTEX_REUSE 0x88d4
#define R600_VGT_NUM_INSTANCES 0x8974
#define R600_VGT_STRMOUT_EN 0x28ab0
#define R600_VGT_EVENT_INITIATOR 0x28a90
# define R600_CACHE_FLUSH_AND_INV_EVENT (0x16 << 0)
#define R600_VGT_VERTEX_REUSE_BLOCK_CNTL 0x28c58
# define R600_VTX_REUSE_DEPTH_MASK 0xff
#define R600_VGT_OUT_DEALLOC_CNTL 0x28c5c
# define R600_DEALLOC_DIST_MASK 0x7f
#define R600_CB_COLOR0_BASE 0x28040
#define R600_CB_COLOR1_BASE 0x28044
#define R600_CB_COLOR2_BASE 0x28048
#define R600_CB_COLOR3_BASE 0x2804c
#define R600_CB_COLOR4_BASE 0x28050
#define R600_CB_COLOR5_BASE 0x28054
#define R600_CB_COLOR6_BASE 0x28058
#define R600_CB_COLOR7_BASE 0x2805c
#define R600_CB_COLOR7_FRAG 0x280fc
#define R600_TC_CNTL 0x9608
# define R600_TC_L2_SIZE(x) ((x) << 5)
# define R600_L2_DISABLE_LATE_HIT (1 << 9)
#define R600_ARB_POP 0x2418
# define R600_ENABLE_TC128 (1 << 30)
#define R600_ARB_GDEC_RD_CNTL 0x246c
#define R600_TA_CNTL_AUX 0x9508
# define R600_DISABLE_CUBE_WRAP (1 << 0)
# define R600_DISABLE_CUBE_ANISO (1 << 1)
# define R700_GETLOD_SELECT(x) ((x) << 2)
# define R600_SYNC_GRADIENT (1 << 24)
# define R600_SYNC_WALKER (1 << 25)
# define R600_SYNC_ALIGNER (1 << 26)
# define R600_BILINEAR_PRECISION_6_BIT (0 << 31)
# define R600_BILINEAR_PRECISION_8_BIT (1 << 31)
#define R700_TCP_CNTL 0x9610
#define R600_SMX_DC_CTL0 0xa020
# define R700_USE_HASH_FUNCTION (1 << 0)
# define R700_CACHE_DEPTH(x) ((x) << 1)
# define R700_FLUSH_ALL_ON_EVENT (1 << 10)
# define R700_STALL_ON_EVENT (1 << 11)
#define R700_SMX_EVENT_CTL 0xa02c
# define R700_ES_FLUSH_CTL(x) ((x) << 0)
# define R700_GS_FLUSH_CTL(x) ((x) << 3)
# define R700_ACK_FLUSH_CTL(x) ((x) << 6)
# define R700_SYNC_FLUSH_CTL (1 << 8)
#define R600_SQ_CONFIG 0x8c00
# define R600_VC_ENABLE (1 << 0)
# define R600_EXPORT_SRC_C (1 << 1)
# define R600_DX9_CONSTS (1 << 2)
# define R600_ALU_INST_PREFER_VECTOR (1 << 3)
# define R600_DX10_CLAMP (1 << 4)
# define R600_CLAUSE_SEQ_PRIO(x) ((x) << 8)
# define R600_PS_PRIO(x) ((x) << 24)
# define R600_VS_PRIO(x) ((x) << 26)
# define R600_GS_PRIO(x) ((x) << 28)
# define R600_ES_PRIO(x) ((x) << 30)
#define R600_SQ_GPR_RESOURCE_MGMT_1 0x8c04
# define R600_NUM_PS_GPRS(x) ((x) << 0)
# define R600_NUM_VS_GPRS(x) ((x) << 16)
# define R700_DYN_GPR_ENABLE (1 << 27)
# define R600_NUM_CLAUSE_TEMP_GPRS(x) ((x) << 28)
#define R600_SQ_GPR_RESOURCE_MGMT_2 0x8c08
# define R600_NUM_GS_GPRS(x) ((x) << 0)
# define R600_NUM_ES_GPRS(x) ((x) << 16)
#define R600_SQ_THREAD_RESOURCE_MGMT 0x8c0c
# define R600_NUM_PS_THREADS(x) ((x) << 0)
# define R600_NUM_VS_THREADS(x) ((x) << 8)
# define R600_NUM_GS_THREADS(x) ((x) << 16)
# define R600_NUM_ES_THREADS(x) ((x) << 24)
#define R600_SQ_STACK_RESOURCE_MGMT_1 0x8c10
# define R600_NUM_PS_STACK_ENTRIES(x) ((x) << 0)
# define R600_NUM_VS_STACK_ENTRIES(x) ((x) << 16)
#define R600_SQ_STACK_RESOURCE_MGMT_2 0x8c14
# define R600_NUM_GS_STACK_ENTRIES(x) ((x) << 0)
# define R600_NUM_ES_STACK_ENTRIES(x) ((x) << 16)
#define R600_SQ_MS_FIFO_SIZES 0x8cf0
# define R600_CACHE_FIFO_SIZE(x) ((x) << 0)
# define R600_FETCH_FIFO_HIWATER(x) ((x) << 8)
# define R600_DONE_FIFO_HIWATER(x) ((x) << 16)
# define R600_ALU_UPDATE_FIFO_HIWATER(x) ((x) << 24)
#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_0 0x8db0
# define R700_SIMDA_RING0(x) ((x) << 0)
# define R700_SIMDA_RING1(x) ((x) << 8)
# define R700_SIMDB_RING0(x) ((x) << 16)
# define R700_SIMDB_RING1(x) ((x) << 24)
#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_1 0x8db4
#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_2 0x8db8
#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_3 0x8dbc
#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_4 0x8dc0
#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_5 0x8dc4
#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_6 0x8dc8
#define R700_SQ_DYN_GPR_SIZE_SIMD_AB_7 0x8dcc
#define R600_SPI_PS_IN_CONTROL_0 0x286cc
# define R600_NUM_INTERP(x) ((x) << 0)
# define R600_POSITION_ENA (1 << 8)
# define R600_POSITION_CENTROID (1 << 9)
# define R600_POSITION_ADDR(x) ((x) << 10)
# define R600_PARAM_GEN(x) ((x) << 15)
# define R600_PARAM_GEN_ADDR(x) ((x) << 19)
# define R600_BARYC_SAMPLE_CNTL(x) ((x) << 26)
# define R600_PERSP_GRADIENT_ENA (1 << 28)
# define R600_LINEAR_GRADIENT_ENA (1 << 29)
# define R600_POSITION_SAMPLE (1 << 30)
# define R600_BARYC_AT_SAMPLE_ENA (1 << 31)
#define R600_SPI_PS_IN_CONTROL_1 0x286d0
# define R600_GEN_INDEX_PIX (1 << 0)
# define R600_GEN_INDEX_PIX_ADDR(x) ((x) << 1)
# define R600_FRONT_FACE_ENA (1 << 8)
# define R600_FRONT_FACE_CHAN(x) ((x) << 9)
# define R600_FRONT_FACE_ALL_BITS (1 << 11)
# define R600_FRONT_FACE_ADDR(x) ((x) << 12)
# define R600_FOG_ADDR(x) ((x) << 17)
# define R600_FIXED_PT_POSITION_ENA (1 << 24)
# define R600_FIXED_PT_POSITION_ADDR(x) ((x) << 25)
# define R700_POSITION_ULC (1 << 30)
#define R600_SPI_INPUT_Z 0x286d8
#define R600_SPI_CONFIG_CNTL 0x9100
# define R600_GPR_WRITE_PRIORITY(x) ((x) << 0)
# define R600_DISABLE_INTERP_1 (1 << 5)
#define R600_SPI_CONFIG_CNTL_1 0x913c
# define R600_VTX_DONE_DELAY(x) ((x) << 0)
# define R600_INTERP_ONE_PRIM_PER_ROW (1 << 4)
#define R600_GB_TILING_CONFIG 0x98f0
# define R600_PIPE_TILING(x) ((x) << 1)
# define R600_BANK_TILING(x) ((x) << 4)
# define R600_GROUP_SIZE(x) ((x) << 6)
# define R600_ROW_TILING(x) ((x) << 8)
# define R600_BANK_SWAPS(x) ((x) << 11)
# define R600_SAMPLE_SPLIT(x) ((x) << 14)
# define R600_BACKEND_MAP(x) ((x) << 16)
#define R600_DCP_TILING_CONFIG 0x6ca0
#define R600_HDP_TILING_CONFIG 0x2f3c
#define R600_CC_RB_BACKEND_DISABLE 0x98f4
#define R700_CC_SYS_RB_BACKEND_DISABLE 0x3f88
# define R600_BACKEND_DISABLE(x) ((x) << 16)
#define R600_CC_GC_SHADER_PIPE_CONFIG 0x8950
#define R600_GC_USER_SHADER_PIPE_CONFIG 0x8954
# define R600_INACTIVE_QD_PIPES(x) ((x) << 8)
# define R600_INACTIVE_QD_PIPES_MASK (0xff << 8)
# define R600_INACTIVE_SIMDS(x) ((x) << 16)
# define R600_INACTIVE_SIMDS_MASK (0xff << 16)
#define R700_CGTS_SYS_TCC_DISABLE 0x3f90
#define R700_CGTS_USER_SYS_TCC_DISABLE 0x3f94
#define R700_CGTS_TCC_DISABLE 0x9148
#define R700_CGTS_USER_TCC_DISABLE 0x914c
/* Constants */
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
@@ -1190,6 +1734,11 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
#define RADEON_LAST_SWI_REG RADEON_SCRATCH_REG3
#define RADEON_LAST_DISPATCH 1
#define R600_LAST_FRAME_REG R600_SCRATCH_REG0
#define R600_LAST_DISPATCH_REG R600_SCRATCH_REG1
#define R600_LAST_CLEAR_REG R600_SCRATCH_REG2
#define R600_LAST_SWI_REG R600_SCRATCH_REG3
#define RADEON_MAX_VB_AGE 0x7fffffff
#define RADEON_MAX_VB_VERTS (0xffff)
@@ -1198,7 +1747,15 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
#define RADEON_PCIGART_TABLE_SIZE (32*1024)
#define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) )
#define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) )
#define RADEON_WRITE(reg, val) \
do { \
if (reg < 0x10000) { \
DRM_WRITE32(dev_priv->mmio, (reg), (val)); \
} else { \
DRM_WRITE32(dev_priv->mmio, RADEON_MM_INDEX, (reg)); \
DRM_WRITE32(dev_priv->mmio, RADEON_MM_DATA, (val)); \
} \
} while (0)
#define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) )
#define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) )
@@ -1238,11 +1795,19 @@ do { \
RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); \
} while (0)
#define RS600_WRITE_MCIND(addr, val) \
do { \
RADEON_WRITE(RS600_MC_INDEX, RS600_MC_IND_WR_EN | RS600_MC_IND_CITF_ARB0 | ((addr) & RS600_MC_ADDR_MASK)); \
RADEON_WRITE(RS600_MC_DATA, val); \
} while (0)
#define IGP_WRITE_MCIND(addr, val) \
do { \
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || \
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) \
RS690_WRITE_MCIND(addr, val); \
else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) \
RS600_WRITE_MCIND(addr, val); \
else \
RS480_WRITE_MCIND(addr, val); \
} while (0)
@@ -1346,7 +1911,11 @@ do { \
struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \
drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \
if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \
int __ret = radeon_do_cp_idle( dev_priv ); \
int __ret; \
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) \
__ret = r600_do_cp_idle(dev_priv); \
else \
__ret = radeon_do_cp_idle(dev_priv); \
if ( __ret ) return __ret; \
sarea_priv->last_dispatch = 0; \
radeon_freelist_reset( dev ); \
@@ -1368,21 +1937,40 @@ do { \
OUT_RING( age ); \
} while (0)
#define R600_DISPATCH_AGE(age) do { \
OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1)); \
OUT_RING((R600_LAST_DISPATCH_REG - R600_SET_CONFIG_REG_OFFSET) >> 2); \
OUT_RING(age); \
} while (0)
#define R600_FRAME_AGE(age) do { \
OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1)); \
OUT_RING((R600_LAST_FRAME_REG - R600_SET_CONFIG_REG_OFFSET) >> 2); \
OUT_RING(age); \
} while (0)
#define R600_CLEAR_AGE(age) do { \
OUT_RING(CP_PACKET3(R600_IT_SET_CONFIG_REG, 1)); \
OUT_RING((R600_LAST_CLEAR_REG - R600_SET_CONFIG_REG_OFFSET) >> 2); \
OUT_RING(age); \
} while (0)
/* ================================================================
* Ring control
*/
#define RADEON_VERBOSE 0
#define RING_LOCALS int write, _nr; unsigned int mask; u32 *ring;
#define RING_LOCALS int write, _nr, _align_nr; unsigned int mask; u32 *ring;
#define BEGIN_RING( n ) do { \
if ( RADEON_VERBOSE ) { \
DRM_INFO( "BEGIN_RING( %d )\n", (n)); \
} \
if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \
_align_nr = (n + 0xf) & ~0xf; \
if (dev_priv->ring.space <= (_align_nr * sizeof(u32))) { \
COMMIT_RING(); \
radeon_wait_ring( dev_priv, (n) * sizeof(u32) ); \
radeon_wait_ring( dev_priv, _align_nr * sizeof(u32)); \
} \
_nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \
ring = dev_priv->ring.start; \
@@ -1399,19 +1987,16 @@ do { \
DRM_ERROR( \
"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \
((dev_priv->ring.tail + _nr) & mask), \
write, __LINE__); \
write, __LINE__); \
} else \
dev_priv->ring.tail = write; \
} while (0)
extern void radeon_commit_ring(drm_radeon_private_t *dev_priv);
#define COMMIT_RING() do { \
/* Flush writes to ring */ \
DRM_MEMORYBARRIER(); \
GET_RING_HEAD( dev_priv ); \
RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); \
/* read from PCI bus to ensure correct posting */ \
RADEON_READ( RADEON_CP_RB_RPTR ); \
} while (0)
radeon_commit_ring(dev_priv); \
} while(0)
#define OUT_RING( x ) do { \
if ( RADEON_VERBOSE ) { \

View File

@@ -65,7 +65,7 @@ int radeon_enable_vblank(struct drm_device *dev, int crtc)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
switch (crtc) {
case 0:
r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 1);
@@ -100,7 +100,7 @@ void radeon_disable_vblank(struct drm_device *dev, int crtc)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
switch (crtc) {
case 0:
r500_vbl_irq_set_state(dev, R500_D1MODE_INT_MASK, 0);
@@ -135,7 +135,7 @@ static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r
u32 irq_mask = RADEON_SW_INT_TEST;
*r500_disp_int = 0;
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
/* vbl interrupts in a different place */
if (irqs & R500_DISPLAY_INT_STATUS) {
@@ -202,7 +202,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
DRM_WAKEUP(&dev_priv->swi_queue);
/* VBLANK interrupt */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
if (r500_disp_int & R500_D1_VBLANK_INTERRUPT)
drm_handle_vblank(dev, 0);
if (r500_disp_int & R500_D2_VBLANK_INTERRUPT)
@@ -265,7 +265,7 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc)
return -EINVAL;
}
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) {
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
if (crtc == 0)
return RADEON_READ(R500_D1CRTC_FRAME_COUNT);
else
@@ -327,7 +327,7 @@ void radeon_driver_irq_preinstall(struct drm_device * dev)
u32 dummy;
/* Disable *all* interrupts */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
@@ -357,7 +357,7 @@ void radeon_driver_irq_uninstall(struct drm_device * dev)
if (!dev_priv)
return;
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690)
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600)
RADEON_WRITE(R500_DxMODE_INT_MASK, 0);
/* Disable *all* interrupts */
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);

View File

@@ -1556,9 +1556,15 @@ static void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *
buf_priv->age = ++master_priv->sarea_priv->last_dispatch;
/* Emit the vertex buffer age */
BEGIN_RING(2);
RADEON_DISPATCH_AGE(buf_priv->age);
ADVANCE_RING();
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
BEGIN_RING(3);
R600_DISPATCH_AGE(buf_priv->age);
ADVANCE_RING();
} else {
BEGIN_RING(2);
RADEON_DISPATCH_AGE(buf_priv->age);
ADVANCE_RING();
}
buf->pending = 1;
buf->used = 0;
@@ -1980,7 +1986,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
/* find a virtual surface */
for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
if (dev_priv->virt_surfaces[i].file_priv == 0)
if (dev_priv->virt_surfaces[i].file_priv == NULL)
break;
if (i == 2 * RADEON_MAX_SURFACES) {
return -1;
@@ -2473,24 +2479,25 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil
buf->used = indirect->end;
/* Wait for the 3D stream to idle before the indirect buffer
* containing 2D acceleration commands is processed.
*/
BEGIN_RING(2);
RADEON_WAIT_UNTIL_3D_IDLE();
ADVANCE_RING();
/* Dispatch the indirect buffer full of commands from the
* X server. This is insecure and is thus only available to
* privileged clients.
*/
radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
if (indirect->discard) {
radeon_cp_discard_buffer(dev, file_priv->master, buf);
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
r600_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
else {
/* Wait for the 3D stream to idle before the indirect buffer
* containing 2D acceleration commands is processed.
*/
BEGIN_RING(2);
RADEON_WAIT_UNTIL_3D_IDLE();
ADVANCE_RING();
radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
}
if (indirect->discard)
radeon_cp_discard_buffer(dev, file_priv->master, buf);
COMMIT_RING();
return 0;
}
@@ -3010,14 +3017,14 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
break;
case RADEON_PARAM_LAST_FRAME:
dev_priv->stats.last_frame_reads++;
value = GET_SCRATCH(0);
value = GET_SCRATCH(dev_priv, 0);
break;
case RADEON_PARAM_LAST_DISPATCH:
value = GET_SCRATCH(1);
value = GET_SCRATCH(dev_priv, 1);
break;
case RADEON_PARAM_LAST_CLEAR:
dev_priv->stats.last_clear_reads++;
value = GET_SCRATCH(2);
value = GET_SCRATCH(dev_priv, 2);
break;
case RADEON_PARAM_IRQ_NR:
value = drm_dev_to_irq(dev);
@@ -3052,7 +3059,10 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
case RADEON_PARAM_SCRATCH_OFFSET:
if (!dev_priv->writeback_works)
return -EINVAL;
value = RADEON_SCRATCH_REG_OFFSET;
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
value = R600_SCRATCH_REG_OFFSET;
else
value = RADEON_SCRATCH_REG_OFFSET;
break;
case RADEON_PARAM_CARD_TYPE:
if (dev_priv->flags & RADEON_IS_PCIE)
@@ -3155,6 +3165,7 @@ void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
void radeon_driver_lastclose(struct drm_device *dev)
{
radeon_surfaces_release(PCIGART_FILE_PRIV, dev->dev_private);
radeon_do_release(dev);
}

View File

@@ -599,8 +599,8 @@ int savage_driver_firstopen(struct drm_device *dev)
drm_mtrr_add(dev_priv->mtrr[2].base,
dev_priv->mtrr[2].size, DRM_MTRR_WC);
} else {
DRM_ERROR("strange pci_resource_len %08lx\n",
drm_get_resource_len(dev, 0));
DRM_ERROR("strange pci_resource_len %08llx\n",
(unsigned long long)drm_get_resource_len(dev, 0));
}
} else if (dev_priv->chipset != S3_SUPERSAVAGE &&
dev_priv->chipset != S3_SAVAGE2000) {
@@ -620,8 +620,8 @@ int savage_driver_firstopen(struct drm_device *dev)
drm_mtrr_add(dev_priv->mtrr[0].base,
dev_priv->mtrr[0].size, DRM_MTRR_WC);
} else {
DRM_ERROR("strange pci_resource_len %08lx\n",
drm_get_resource_len(dev, 1));
DRM_ERROR("strange pci_resource_len %08llx\n",
(unsigned long long)drm_get_resource_len(dev, 1));
}
} else {
mmio_base = drm_get_resource_start(dev, 0);

View File

@@ -28,11 +28,6 @@
#include "drm_pciids.h"
static int dri_library_name(struct drm_device *dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "unichrome");
}
static struct pci_device_id pciidlist[] = {
viadrv_PCI_IDS
};
@@ -52,7 +47,6 @@ static struct drm_driver driver = {
.irq_uninstall = via_driver_irq_uninstall,
.irq_handler = via_driver_irq_handler,
.dma_quiescent = via_driver_dma_quiescent,
.dri_library_name = dri_library_name,
.reclaim_buffers = drm_core_reclaim_buffers,
.reclaim_buffers_locked = NULL,
.reclaim_buffers_idlelocked = via_reclaim_buffers_locked,