Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (50 commits)
  drm: include kernel list header file in hashtab header
  drm: Export hash table functionality.
  drm: Split out the mm declarations in a separate header. Add atomic operations.
  drm/radeon: add support for RV790.
  drm/radeon: add rv740 drm support.
  drm_calloc_large: check right size, check integer overflow, use GFP_ZERO
  drm: Eliminate magic I2C frobbing when reading EDID
  drm/i915: duplicate desired mode for use by fbcon.
  drm/via: vfree() no need checking before calling it
  drm: Replace DRM_DEBUG with DRM_DEBUG_DRIVER in i915 driver
  drm: Replace DRM_DEBUG with DRM_DEBUG_MODE in drm_mode
  drm/i915: Replace DRM_DEBUG with DRM_DEBUG_KMS in intel_sdvo
  drm/i915: replace DRM_DEBUG with DRM_DEBUG_KMS in intel_lvds
  drm: add separate drm debugging levels
  radeon: remove _DRM_DRIVER from the preadded sarea map
  drm: don't associate _DRM_DRIVER maps with a master
  drm: simplify kcalloc() call to kzalloc().
  intelfb: fix spelling of "CLOCK"
  drm: fix LOCK_TEST_WITH_RETURN macro
  drm/i915: Hook connector to encoder during load detection (fixes tv/vga detect)
  ...
This commit is contained in:
Linus Torvalds 2009-06-12 18:09:18 -07:00
commit 6b702462cb
34 changed files with 2681 additions and 399 deletions

View file

@ -46,6 +46,10 @@
#define PCI_DEVICE_ID_INTEL_G45_IG 0x2E22
#define PCI_DEVICE_ID_INTEL_G41_HB 0x2E30
#define PCI_DEVICE_ID_INTEL_G41_IG 0x2E32
#define PCI_DEVICE_ID_INTEL_IGDNG_D_HB 0x0040
#define PCI_DEVICE_ID_INTEL_IGDNG_D_IG 0x0042
#define PCI_DEVICE_ID_INTEL_IGDNG_M_HB 0x0044
#define PCI_DEVICE_ID_INTEL_IGDNG_M_IG 0x0046
/* cover 915 and 945 variants */
#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
@ -75,7 +79,9 @@
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB)
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_D_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGDNG_M_HB)
extern int agp_memory_reserved;
@ -1211,6 +1217,8 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
case PCI_DEVICE_ID_INTEL_Q45_HB:
case PCI_DEVICE_ID_INTEL_G45_HB:
case PCI_DEVICE_ID_INTEL_G41_HB:
case PCI_DEVICE_ID_INTEL_IGDNG_D_HB:
case PCI_DEVICE_ID_INTEL_IGDNG_M_HB:
*gtt_offset = *gtt_size = MB(2);
break;
default:
@ -2186,6 +2194,10 @@ static const struct intel_driver_description {
"G45/G43", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
"G41", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IGDNG_D_HB, PCI_DEVICE_ID_INTEL_IGDNG_D_IG, 0,
"IGDNG/D", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IGDNG_M_HB, PCI_DEVICE_ID_INTEL_IGDNG_M_IG, 0,
"IGDNG/M", NULL, &intel_i965_driver },
{ 0, 0, 0, NULL, NULL, NULL }
};
@ -2387,6 +2399,8 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_Q45_HB),
ID(PCI_DEVICE_ID_INTEL_G45_HB),
ID(PCI_DEVICE_ID_INTEL_G41_HB),
ID(PCI_DEVICE_ID_INTEL_IGDNG_D_HB),
ID(PCI_DEVICE_ID_INTEL_IGDNG_M_HB),
{ }
};

View file

@ -371,7 +371,8 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
list->user_token = list->hash.key << PAGE_SHIFT;
mutex_unlock(&dev->struct_mutex);
list->master = dev->primary->master;
if (!(map->flags & _DRM_DRIVER))
list->master = dev->primary->master;
*maplist = list;
return 0;
}

View file

@ -589,85 +589,13 @@ int drm_do_probe_ddc_edid(struct i2c_adapter *adapter,
}
EXPORT_SYMBOL(drm_do_probe_ddc_edid);
/**
* 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;
int i, j;
int ret = -1;
algo_data->setscl(algo_data->data, 1);
for (i = 0; i < 1; i++) {
/* For some old monitors we need the
* following process to initialize/stop DDC
*/
algo_data->setsda(algo_data->data, 1);
msleep(13);
algo_data->setscl(algo_data->data, 1);
for (j = 0; j < 5; j++) {
msleep(10);
if (algo_data->getscl(algo_data->data))
break;
}
if (j == 5)
continue;
algo_data->setsda(algo_data->data, 0);
msleep(15);
algo_data->setscl(algo_data->data, 0);
msleep(15);
algo_data->setsda(algo_data->data, 1);
msleep(15);
/* Do the real work */
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);
algo_data->setscl(algo_data->data, 1);
for (j = 0; j < 10; j++) {
msleep(10);
if (algo_data->getscl(algo_data->data))
break;
}
algo_data->setsda(algo_data->data, 1);
msleep(15);
algo_data->setscl(algo_data->data, 0);
algo_data->setsda(algo_data->data, 0);
if (ret == 0)
break;
}
/* Release the DDC lines when done or the Apple Cinema HD display
* will switch off
*/
algo_data->setsda(algo_data->data, 1);
algo_data->setscl(algo_data->data, 1);
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);
ret = drm_do_probe_ddc_edid(adapter, buf, len);
if (ret != 0) {
dev_info(&connector->dev->pdev->dev, "%s: no EDID data\n",
drm_get_connector_name(connector));

View file

@ -133,7 +133,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
BUG_ON((size & (PAGE_SIZE - 1)) != 0);
obj = kcalloc(1, sizeof(*obj), GFP_KERNEL);
obj = kzalloc(sizeof(*obj), GFP_KERNEL);
obj->dev = dev;
obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);

View file

@ -62,6 +62,7 @@ int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
}
return 0;
}
EXPORT_SYMBOL(drm_ht_create);
void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
{
@ -156,6 +157,7 @@ int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *it
}
return 0;
}
EXPORT_SYMBOL(drm_ht_just_insert_please);
int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
struct drm_hash_item **item)
@ -169,6 +171,7 @@ int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
*item = hlist_entry(list, struct drm_hash_item, head);
return 0;
}
EXPORT_SYMBOL(drm_ht_find_item);
int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
{
@ -202,3 +205,4 @@ void drm_ht_remove(struct drm_open_hash *ht)
ht->table = NULL;
}
}
EXPORT_SYMBOL(drm_ht_remove);

View file

@ -42,8 +42,11 @@
*/
#include "drmP.h"
#include "drm_mm.h"
#include <linux/slab.h>
#define MM_UNUSED_TARGET 4
unsigned long drm_mm_tail_space(struct drm_mm *mm)
{
struct list_head *tail_node;
@ -74,16 +77,62 @@ int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size)
return 0;
}
static int drm_mm_create_tail_node(struct drm_mm *mm,
unsigned long start,
unsigned long size)
static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
{
struct drm_mm_node *child;
child = (struct drm_mm_node *)
drm_alloc(sizeof(*child), DRM_MEM_MM);
if (!child)
if (atomic)
child = kmalloc(sizeof(*child), GFP_ATOMIC);
else
child = kmalloc(sizeof(*child), GFP_KERNEL);
if (unlikely(child == NULL)) {
spin_lock(&mm->unused_lock);
if (list_empty(&mm->unused_nodes))
child = NULL;
else {
child =
list_entry(mm->unused_nodes.next,
struct drm_mm_node, fl_entry);
list_del(&child->fl_entry);
--mm->num_unused;
}
spin_unlock(&mm->unused_lock);
}
return child;
}
int drm_mm_pre_get(struct drm_mm *mm)
{
struct drm_mm_node *node;
spin_lock(&mm->unused_lock);
while (mm->num_unused < MM_UNUSED_TARGET) {
spin_unlock(&mm->unused_lock);
node = kmalloc(sizeof(*node), GFP_KERNEL);
spin_lock(&mm->unused_lock);
if (unlikely(node == NULL)) {
int ret = (mm->num_unused < 2) ? -ENOMEM : 0;
spin_unlock(&mm->unused_lock);
return ret;
}
++mm->num_unused;
list_add_tail(&node->fl_entry, &mm->unused_nodes);
}
spin_unlock(&mm->unused_lock);
return 0;
}
EXPORT_SYMBOL(drm_mm_pre_get);
static int drm_mm_create_tail_node(struct drm_mm *mm,
unsigned long start,
unsigned long size, int atomic)
{
struct drm_mm_node *child;
child = drm_mm_kmalloc(mm, atomic);
if (unlikely(child == NULL))
return -ENOMEM;
child->free = 1;
@ -97,8 +146,7 @@ static int drm_mm_create_tail_node(struct drm_mm *mm,
return 0;
}
int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size)
int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic)
{
struct list_head *tail_node;
struct drm_mm_node *entry;
@ -106,20 +154,21 @@ int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size)
tail_node = mm->ml_entry.prev;
entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
if (!entry->free) {
return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
return drm_mm_create_tail_node(mm, entry->start + entry->size,
size, atomic);
}
entry->size += size;
return 0;
}
static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
unsigned long size)
unsigned long size,
int atomic)
{
struct drm_mm_node *child;
child = (struct drm_mm_node *)
drm_alloc(sizeof(*child), DRM_MEM_MM);
if (!child)
child = drm_mm_kmalloc(parent->mm, atomic);
if (unlikely(child == NULL))
return NULL;
INIT_LIST_HEAD(&child->fl_entry);
@ -151,8 +200,9 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
tmp = parent->start % alignment;
if (tmp) {
align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
if (!align_splitoff)
align_splitoff =
drm_mm_split_at_start(parent, alignment - tmp, 0);
if (unlikely(align_splitoff == NULL))
return NULL;
}
@ -161,7 +211,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
parent->free = 0;
return parent;
} else {
child = drm_mm_split_at_start(parent, size);
child = drm_mm_split_at_start(parent, size, 0);
}
if (align_splitoff)
@ -169,14 +219,49 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
return child;
}
EXPORT_SYMBOL(drm_mm_get_block);
struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
unsigned long size,
unsigned alignment)
{
struct drm_mm_node *align_splitoff = NULL;
struct drm_mm_node *child;
unsigned tmp = 0;
if (alignment)
tmp = parent->start % alignment;
if (tmp) {
align_splitoff =
drm_mm_split_at_start(parent, alignment - tmp, 1);
if (unlikely(align_splitoff == NULL))
return NULL;
}
if (parent->size == size) {
list_del_init(&parent->fl_entry);
parent->free = 0;
return parent;
} else {
child = drm_mm_split_at_start(parent, size, 1);
}
if (align_splitoff)
drm_mm_put_block(align_splitoff);
return child;
}
EXPORT_SYMBOL(drm_mm_get_block_atomic);
/*
* Put a block. Merge with the previous and / or next block if they are free.
* Otherwise add to the free stack.
*/
void drm_mm_put_block(struct drm_mm_node * cur)
void drm_mm_put_block(struct drm_mm_node *cur)
{
struct drm_mm *mm = cur->mm;
@ -188,21 +273,27 @@ void drm_mm_put_block(struct drm_mm_node * cur)
int merged = 0;
if (cur_head->prev != root_head) {
prev_node = list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
prev_node =
list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
if (prev_node->free) {
prev_node->size += cur->size;
merged = 1;
}
}
if (cur_head->next != root_head) {
next_node = list_entry(cur_head->next, struct drm_mm_node, ml_entry);
next_node =
list_entry(cur_head->next, struct drm_mm_node, ml_entry);
if (next_node->free) {
if (merged) {
prev_node->size += next_node->size;
list_del(&next_node->ml_entry);
list_del(&next_node->fl_entry);
drm_free(next_node, sizeof(*next_node),
DRM_MEM_MM);
if (mm->num_unused < MM_UNUSED_TARGET) {
list_add(&next_node->fl_entry,
&mm->unused_nodes);
++mm->num_unused;
} else
kfree(next_node);
} else {
next_node->size += cur->size;
next_node->start = cur->start;
@ -215,14 +306,19 @@ void drm_mm_put_block(struct drm_mm_node * cur)
list_add(&cur->fl_entry, &mm->fl_entry);
} else {
list_del(&cur->ml_entry);
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
if (mm->num_unused < MM_UNUSED_TARGET) {
list_add(&cur->fl_entry, &mm->unused_nodes);
++mm->num_unused;
} else
kfree(cur);
}
}
EXPORT_SYMBOL(drm_mm_put_block);
struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
unsigned long size,
unsigned alignment, int best_match)
struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
unsigned long size,
unsigned alignment, int best_match)
{
struct list_head *list;
const struct list_head *free_stack = &mm->fl_entry;
@ -247,7 +343,6 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
wasted += alignment - tmp;
}
if (entry->size >= size + wasted) {
if (!best_match)
return entry;
@ -260,6 +355,7 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
return best;
}
EXPORT_SYMBOL(drm_mm_search_free);
int drm_mm_clean(struct drm_mm * mm)
{
@ -267,14 +363,17 @@ int drm_mm_clean(struct drm_mm * mm)
return (head->next->next == head);
}
EXPORT_SYMBOL(drm_mm_search_free);
EXPORT_SYMBOL(drm_mm_clean);
int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
{
INIT_LIST_HEAD(&mm->ml_entry);
INIT_LIST_HEAD(&mm->fl_entry);
INIT_LIST_HEAD(&mm->unused_nodes);
mm->num_unused = 0;
spin_lock_init(&mm->unused_lock);
return drm_mm_create_tail_node(mm, start, size);
return drm_mm_create_tail_node(mm, start, size, 0);
}
EXPORT_SYMBOL(drm_mm_init);
@ -282,6 +381,7 @@ void drm_mm_takedown(struct drm_mm * mm)
{
struct list_head *bnode = mm->fl_entry.next;
struct drm_mm_node *entry;
struct drm_mm_node *next;
entry = list_entry(bnode, struct drm_mm_node, fl_entry);
@ -293,7 +393,16 @@ void drm_mm_takedown(struct drm_mm * mm)
list_del(&entry->fl_entry);
list_del(&entry->ml_entry);
kfree(entry);
drm_free(entry, sizeof(*entry), DRM_MEM_MM);
spin_lock(&mm->unused_lock);
list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) {
list_del(&entry->fl_entry);
kfree(entry);
--mm->num_unused;
}
spin_unlock(&mm->unused_lock);
BUG_ON(mm->num_unused != 0);
}
EXPORT_SYMBOL(drm_mm_takedown);

View file

@ -38,6 +38,7 @@
#include "drm.h"
#include "drm_crtc.h"
#define DRM_MODESET_DEBUG "drm_mode"
/**
* drm_mode_debug_printmodeline - debug print a mode
* @dev: DRM device
@ -50,12 +51,13 @@
*/
void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
{
DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
mode->base.id, mode->name, mode->vrefresh, mode->clock,
mode->hdisplay, mode->hsync_start,
mode->hsync_end, mode->htotal,
mode->vdisplay, mode->vsync_start,
mode->vsync_end, mode->vtotal, mode->type, mode->flags);
DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
"Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
mode->base.id, mode->name, mode->vrefresh, mode->clock,
mode->hdisplay, mode->hsync_start,
mode->hsync_end, mode->htotal,
mode->vdisplay, mode->vsync_start,
mode->vsync_end, mode->vtotal, mode->type, mode->flags);
}
EXPORT_SYMBOL(drm_mode_debug_printmodeline);
@ -401,7 +403,9 @@ void drm_mode_prune_invalid(struct drm_device *dev,
list_del(&mode->head);
if (verbose) {
drm_mode_debug_printmodeline(mode);
DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
DRM_DEBUG_MODE(DRM_MODESET_DEBUG,
"Not using %s mode %d\n",
mode->name, mode->status);
}
drm_mode_destroy(dev, mode);
}

View file

@ -51,7 +51,22 @@ struct idr drm_minors_idr;
struct class *drm_class;
struct proc_dir_entry *drm_proc_root;
struct dentry *drm_debugfs_root;
void drm_ut_debug_printk(unsigned int request_level,
const char *prefix,
const char *function_name,
const char *format, ...)
{
va_list args;
if (drm_debug & request_level) {
if (function_name)
printk(KERN_DEBUG "[%s:%s], ", prefix, function_name);
va_start(args, format);
vprintk(format, args);
va_end(args);
}
}
EXPORT_SYMBOL(drm_ut_debug_printk);
static int drm_minor_get_id(struct drm_device *dev, int type)
{
int new_id;

View file

@ -33,6 +33,8 @@
#include "i915_drm.h"
#include "i915_drv.h"
#define I915_DRV "i915_drv"
/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
* the head pointer changes, so that EBUSY only happens if the ring
@ -99,7 +101,7 @@ static int i915_init_phys_hws(struct drm_device *dev)
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
return 0;
}
@ -185,7 +187,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
master_priv->sarea_priv = (drm_i915_sarea_t *)
((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
} else {
DRM_DEBUG("sarea not found assuming DRI2 userspace\n");
DRM_DEBUG_DRIVER(I915_DRV,
"sarea not found assuming DRI2 userspace\n");
}
if (init->ring_size != 0) {
@ -235,7 +238,7 @@ static int i915_dma_resume(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
DRM_DEBUG("%s\n", __func__);
DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
if (dev_priv->ring.map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
@ -248,13 +251,14 @@ static int i915_dma_resume(struct drm_device * dev)
DRM_ERROR("Can not find hardware status page\n");
return -EINVAL;
}
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
DRM_DEBUG_DRIVER(I915_DRV, "hw status page @ %p\n",
dev_priv->hw_status_page);
if (dev_priv->status_gfx_addr != 0)
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
else
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n");
return 0;
}
@ -548,10 +552,10 @@ static int i915_dispatch_flip(struct drm_device * dev)
if (!master_priv->sarea_priv)
return -EINVAL;
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
__func__,
dev_priv->current_page,
master_priv->sarea_priv->pf_current_page);
DRM_DEBUG_DRIVER(I915_DRV, "%s: page=%d pfCurrentPage=%d\n",
__func__,
dev_priv->current_page,
master_priv->sarea_priv->pf_current_page);
i915_kernel_lost_context(dev);
@ -629,8 +633,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
return -EINVAL;
}
DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
batch->start, batch->used, batch->num_cliprects);
DRM_DEBUG_DRIVER(I915_DRV,
"i915 batchbuffer, start %x used %d cliprects %d\n",
batch->start, batch->used, batch->num_cliprects);
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
@ -678,8 +683,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
void *batch_data;
int ret;
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
DRM_DEBUG_DRIVER(I915_DRV,
"i915 cmdbuffer, buf %p sz %d cliprects %d\n",
cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
@ -734,7 +740,7 @@ static int i915_flip_bufs(struct drm_device *dev, void *data,
{
int ret;
DRM_DEBUG("%s\n", __func__);
DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__);
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
@ -777,7 +783,8 @@ static int i915_getparam(struct drm_device *dev, void *data,
value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
break;
default:
DRM_DEBUG("Unknown parameter %d\n", param->param);
DRM_DEBUG_DRIVER(I915_DRV, "Unknown parameter %d\n",
param->param);
return -EINVAL;
}
@ -817,7 +824,8 @@ static int i915_setparam(struct drm_device *dev, void *data,
dev_priv->fence_reg_start = param->value;
break;
default:
DRM_DEBUG("unknown parameter %d\n", param->param);
DRM_DEBUG_DRIVER(I915_DRV, "unknown parameter %d\n",
param->param);
return -EINVAL;
}
@ -865,9 +873,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
dev_priv->status_gfx_addr);
DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
DRM_DEBUG_DRIVER(I915_DRV, "load hws HWS_PGA with gfx mem 0x%x\n",
dev_priv->status_gfx_addr);
DRM_DEBUG_DRIVER(I915_DRV, "load hws at %p\n",
dev_priv->hw_status_page);
return 0;
}
@ -922,7 +931,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) || IS_IGD(dev))
if (IS_G4X(dev) || IS_IGD(dev) || IS_IGDNG(dev))
overhead = 4096;
else
overhead = (*aperture_size / 1024) + 4096;
@ -1153,8 +1162,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
#endif
dev->driver->get_vblank_counter = i915_get_vblank_counter;
if (IS_GM45(dev))
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
if (IS_G4X(dev) || IS_IGDNG(dev)) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
}
i915_gem_load(dev);
@ -1198,7 +1210,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
}
/* Must be done after probing outputs */
intel_opregion_init(dev, 0);
/* FIXME: verify on IGDNG */
if (!IS_IGDNG(dev))
intel_opregion_init(dev, 0);
return 0;
@ -1232,7 +1246,8 @@ int i915_driver_unload(struct drm_device *dev)
if (dev_priv->regs != NULL)
iounmap(dev_priv->regs);
intel_opregion_free(dev, 0);
if (!IS_IGDNG(dev))
intel_opregion_free(dev, 0);
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
intel_modeset_cleanup(dev);
@ -1256,7 +1271,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_i915_file_private *i915_file_priv;
DRM_DEBUG("\n");
DRM_DEBUG_DRIVER(I915_DRV, "\n");
i915_file_priv = (struct drm_i915_file_private *)
drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES);
@ -1265,8 +1280,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
file_priv->driver_priv = i915_file_priv;
i915_file_priv->mm.last_gem_seqno = 0;
i915_file_priv->mm.last_gem_throttle_seqno = 0;
INIT_LIST_HEAD(&i915_file_priv->mm.request_list);
return 0;
}
@ -1303,6 +1317,7 @@ void i915_driver_lastclose(struct drm_device * dev)
void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = dev->dev_private;
i915_gem_release(dev, file_priv);
if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_mem_release(dev, file_priv, dev_priv->agp_heap);
}

View file

@ -126,6 +126,13 @@ struct drm_i915_fence_reg {
struct drm_gem_object *obj;
};
struct sdvo_device_mapping {
u8 dvo_port;
u8 slave_addr;
u8 dvo_wiring;
u8 initialized;
};
typedef struct drm_i915_private {
struct drm_device *dev;
@ -143,6 +150,8 @@ typedef struct drm_i915_private {
drm_local_map_t hws_map;
struct drm_gem_object *hws_obj;
struct resource mch_res;
unsigned int cpp;
int back_offset;
int front_offset;
@ -158,6 +167,11 @@ typedef struct drm_i915_private {
/** Cached value of IMR to avoid reads in updating the bitfield */
u32 irq_mask_reg;
u32 pipestat[2];
/** splitted irq regs for graphics and display engine on IGDNG,
irq_mask_reg is still used for display irq. */
u32 gt_irq_mask_reg;
u32 gt_irq_enable_reg;
u32 de_irq_enable_reg;
u32 hotplug_supported_mask;
struct work_struct hotplug_work;
@ -285,6 +299,13 @@ typedef struct drm_i915_private {
u8 saveDACMASK;
u8 saveCR[37];
uint64_t saveFENCE[16];
u32 saveCURACNTR;
u32 saveCURAPOS;
u32 saveCURABASE;
u32 saveCURBCNTR;
u32 saveCURBPOS;
u32 saveCURBBASE;
u32 saveCURSIZE;
struct {
struct drm_mm gtt_space;
@ -382,6 +403,7 @@ typedef struct drm_i915_private {
/* storage for physical objects */
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
} mm;
struct sdvo_device_mapping sdvo_mappings[2];
} drm_i915_private_t;
/** driver private structure attached to each drm_gem_object */
@ -491,13 +513,16 @@ struct drm_i915_gem_request {
/** Time at which this request was emitted, in jiffies. */
unsigned long emitted_jiffies;
/** global list entry for this request */
struct list_head list;
/** file_priv list entry for this request */
struct list_head client_list;
};
struct drm_i915_file_private {
struct {
uint32_t last_gem_seqno;
uint32_t last_gem_throttle_seqno;
struct list_head request_list;
} mm;
};
@ -642,6 +667,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev,
void i915_gem_free_all_phys_object(struct drm_device *dev);
int i915_gem_object_get_pages(struct drm_gem_object *obj);
void i915_gem_object_put_pages(struct drm_gem_object *obj);
void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
/* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
@ -785,7 +811,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
(dev)->pci_device == 0x2E02 || \
(dev)->pci_device == 0x2E12 || \
(dev)->pci_device == 0x2E22 || \
(dev)->pci_device == 0x2E32)
(dev)->pci_device == 0x2E32 || \
(dev)->pci_device == 0x0042 || \
(dev)->pci_device == 0x0046)
#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02 || \
(dev)->pci_device == 0x2A12)
@ -807,20 +835,26 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
(dev)->pci_device == 0x29D2 || \
(IS_IGD(dev)))
#define IS_IGDNG_D(dev) ((dev)->pci_device == 0x0042)
#define IS_IGDNG_M(dev) ((dev)->pci_device == 0x0046)
#define IS_IGDNG(dev) (IS_IGDNG_D(dev) || IS_IGDNG_M(dev))
#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \
IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev))
IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev) || \
IS_IGDNG(dev))
#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \
IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev) || \
IS_IGD(dev))
IS_IGD(dev) || IS_IGDNG_M(dev))
#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev))
#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev) || \
IS_IGDNG(dev))
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
* rows, which changed the alignment requirements and fence programming.
*/
#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 SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024)

View file

@ -989,10 +989,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
return -ENODEV;
/* Only handle setting domains to types used by the CPU. */
if (write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
if (write_domain & I915_GEM_GPU_DOMAINS)
return -EINVAL;
if (read_domains & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
if (read_domains & I915_GEM_GPU_DOMAINS)
return -EINVAL;
/* Having something in the write domain implies it's in the read
@ -1481,14 +1481,19 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
* Returned sequence numbers are nonzero on success.
*/
static uint32_t
i915_add_request(struct drm_device *dev, uint32_t flush_domains)
i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
uint32_t flush_domains)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_file_private *i915_file_priv = NULL;
struct drm_i915_gem_request *request;
uint32_t seqno;
int was_empty;
RING_LOCALS;
if (file_priv != NULL)
i915_file_priv = file_priv->driver_priv;
request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER);
if (request == NULL)
return 0;
@ -1515,6 +1520,12 @@ i915_add_request(struct drm_device *dev, uint32_t flush_domains)
request->emitted_jiffies = jiffies;
was_empty = list_empty(&dev_priv->mm.request_list);
list_add_tail(&request->list, &dev_priv->mm.request_list);
if (i915_file_priv) {
list_add_tail(&request->client_list,
&i915_file_priv->mm.request_list);
} else {
INIT_LIST_HEAD(&request->client_list);
}
/* Associate any objects on the flushing list matching the write
* domain we're flushing with our flush.
@ -1664,6 +1675,7 @@ i915_gem_retire_requests(struct drm_device *dev)
i915_gem_retire_request(dev, request);
list_del(&request->list);
list_del(&request->client_list);
drm_free(request, sizeof(*request), DRM_MEM_DRIVER);
} else
break;
@ -1702,7 +1714,10 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno)
BUG_ON(seqno == 0);
if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
ier = I915_READ(IER);
if (IS_IGDNG(dev))
ier = I915_READ(DEIER) | I915_READ(GTIER);
else
ier = I915_READ(IER);
if (!ier) {
DRM_ERROR("something (likely vbetool) disabled "
"interrupts, re-enabling\n");
@ -1754,8 +1769,7 @@ i915_gem_flush(struct drm_device *dev,
if (flush_domains & I915_GEM_DOMAIN_CPU)
drm_agp_chipset_flush(dev);
if ((invalidate_domains | flush_domains) & ~(I915_GEM_DOMAIN_CPU |
I915_GEM_DOMAIN_GTT)) {
if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) {
/*
* read/write caches:
*
@ -1977,7 +1991,7 @@ i915_gem_evict_something(struct drm_device *dev)
i915_gem_flush(dev,
obj->write_domain,
obj->write_domain);
i915_add_request(dev, obj->write_domain);
i915_add_request(dev, NULL, obj->write_domain);
obj = NULL;
continue;
@ -1991,7 +2005,7 @@ i915_gem_evict_something(struct drm_device *dev)
/* If we didn't do any of the above, there's nothing to be done
* and we just can't fit it in.
*/
return -ENOMEM;
return -ENOSPC;
}
return ret;
}
@ -2006,7 +2020,7 @@ i915_gem_evict_everything(struct drm_device *dev)
if (ret != 0)
break;
}
if (ret == -ENOMEM)
if (ret == -ENOSPC)
return 0;
return ret;
}
@ -2215,7 +2229,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write)
loff_t offset;
if (avail == 0)
return -ENOMEM;
return -ENOSPC;
for (i = dev_priv->fence_reg_start;
i < dev_priv->num_fence_regs; i++) {
@ -2248,7 +2262,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write)
i915_gem_flush(dev,
I915_GEM_GPU_DOMAINS,
I915_GEM_GPU_DOMAINS);
seqno = i915_add_request(dev,
seqno = i915_add_request(dev, NULL,
I915_GEM_GPU_DOMAINS);
if (seqno == 0)
return -ENOMEM;
@ -2364,7 +2378,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
spin_unlock(&dev_priv->mm.active_list_lock);
if (lists_empty) {
DRM_ERROR("GTT full, but LRU list empty\n");
return -ENOMEM;
return -ENOSPC;
}
ret = i915_gem_evict_something(dev);
@ -2409,8 +2423,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
* wasn't in the GTT, there shouldn't be any way it could have been in
* a GPU cache
*/
BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
return 0;
}
@ -2452,7 +2466,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
/* Queue the GPU write cache flushing we need. */
i915_gem_flush(dev, 0, obj->write_domain);
seqno = i915_add_request(dev, obj->write_domain);
seqno = i915_add_request(dev, NULL, obj->write_domain);
obj->write_domain = 0;
i915_gem_object_move_to_active(obj, seqno);
}
@ -3035,20 +3049,12 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev,
drm_i915_private_t *dev_priv = dev->dev_private;
int nbox = exec->num_cliprects;
int i = 0, count;
uint32_t exec_start, exec_len;
uint32_t exec_start, exec_len;
RING_LOCALS;
exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
exec_len = (uint32_t) exec->batch_len;
if ((exec_start | exec_len) & 0x7) {
DRM_ERROR("alignment\n");
return -EINVAL;
}
if (!exec_start)
return -EINVAL;
count = nbox ? nbox : 1;
for (i = 0; i < count; i++) {
@ -3089,6 +3095,10 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev,
/* Throttle our rendering by waiting until the ring has completed our requests
* emitted over 20 msec ago.
*
* Note that if we were to use the current jiffies each time around the loop,
* we wouldn't escape the function with any frames outstanding if the time to
* render a frame was over 20ms.
*
* This should get us reasonable parallelism between CPU and GPU but also
* relatively low latency when blocking on a particular request to finish.
*/
@ -3097,15 +3107,25 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
int ret = 0;
uint32_t seqno;
unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
mutex_lock(&dev->struct_mutex);
seqno = i915_file_priv->mm.last_gem_throttle_seqno;
i915_file_priv->mm.last_gem_throttle_seqno =
i915_file_priv->mm.last_gem_seqno;
if (seqno)
ret = i915_wait_request(dev, seqno);
while (!list_empty(&i915_file_priv->mm.request_list)) {
struct drm_i915_gem_request *request;
request = list_first_entry(&i915_file_priv->mm.request_list,
struct drm_i915_gem_request,
client_list);
if (time_after_eq(request->emitted_jiffies, recent_enough))
break;
ret = i915_wait_request(dev, request->seqno);
if (ret != 0)
break;
}
mutex_unlock(&dev->struct_mutex);
return ret;
}
@ -3182,12 +3202,29 @@ i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object *exec_list,
return ret;
}
static int
i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer *exec,
uint64_t exec_offset)
{
uint32_t exec_start, exec_len;
exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
exec_len = (uint32_t) exec->batch_len;
if ((exec_start | exec_len) & 0x7)
return -EINVAL;
if (!exec_start)
return -EINVAL;
return 0;
}
int
i915_gem_execbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
struct drm_i915_gem_execbuffer *args = data;
struct drm_i915_gem_exec_object *exec_list = NULL;
struct drm_gem_object **object_list = NULL;
@ -3312,7 +3349,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
break;
/* error other than GTT full, or we've already tried again */
if (ret != -ENOMEM || pin_tries >= 1) {
if (ret != -ENOSPC || pin_tries >= 1) {
if (ret != -ERESTARTSYS)
DRM_ERROR("Failed to pin buffers %d\n", ret);
goto err;
@ -3331,8 +3368,20 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
/* Set the pending read domains for the batch buffer to COMMAND */
batch_obj = object_list[args->buffer_count-1];
batch_obj->pending_read_domains = I915_GEM_DOMAIN_COMMAND;
batch_obj->pending_write_domain = 0;
if (batch_obj->pending_write_domain) {
DRM_ERROR("Attempting to use self-modifying batch buffer\n");
ret = -EINVAL;
goto err;
}
batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
/* Sanity check the batch buffer, prior to moving objects */
exec_offset = exec_list[args->buffer_count - 1].offset;
ret = i915_gem_check_execbuffer (args, exec_offset);
if (ret != 0) {
DRM_ERROR("execbuf with invalid offset/length\n");
goto err;
}
i915_verify_inactive(dev, __FILE__, __LINE__);
@ -3363,7 +3412,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
dev->invalidate_domains,
dev->flush_domains);
if (dev->flush_domains)
(void)i915_add_request(dev, dev->flush_domains);
(void)i915_add_request(dev, file_priv,
dev->flush_domains);
}
for (i = 0; i < args->buffer_count; i++) {
@ -3381,8 +3431,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
}
#endif
exec_offset = exec_list[args->buffer_count - 1].offset;
#if WATCH_EXEC
i915_gem_dump_object(batch_obj,
args->batch_len,
@ -3412,9 +3460,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
* *some* interrupts representing completion of buffers that we can
* wait on when trying to clear up gtt space).
*/
seqno = i915_add_request(dev, flush_domains);
seqno = i915_add_request(dev, file_priv, flush_domains);
BUG_ON(seqno == 0);
i915_file_priv->mm.last_gem_seqno = seqno;
for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i];
@ -3520,8 +3567,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
atomic_inc(&dev->pin_count);
atomic_add(obj->size, &dev->pin_memory);
if (!obj_priv->active &&
(obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
I915_GEM_DOMAIN_GTT)) == 0 &&
(obj->write_domain & I915_GEM_GPU_DOMAINS) == 0 &&
!list_empty(&obj_priv->list))
list_del_init(&obj_priv->list);
}
@ -3548,8 +3594,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj)
*/
if (obj_priv->pin_count == 0) {
if (!obj_priv->active &&
(obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
I915_GEM_DOMAIN_GTT)) == 0)
(obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
list_move_tail(&obj_priv->list,
&dev_priv->mm.inactive_list);
atomic_dec(&dev->pin_count);
@ -3653,15 +3698,14 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
mutex_lock(&dev->struct_mutex);
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) {
DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
args->handle);
mutex_unlock(&dev->struct_mutex);
return -EBADF;
}
mutex_lock(&dev->struct_mutex);
/* Update the active list for the hardware's current position.
* Otherwise this only updates on a delayed timer or when irqs are
* actually unmasked, and our working set ends up being larger than
@ -3800,9 +3844,8 @@ i915_gem_idle(struct drm_device *dev)
/* Flush the GPU along with all non-CPU write domains
*/
i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT),
~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU);
i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
if (seqno == 0) {
mutex_unlock(&dev->struct_mutex);
@ -4352,3 +4395,17 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
drm_agp_chipset_flush(dev);
return 0;
}
void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
{
struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
/* Clean up our request list when the client is going away, so that
* later retire_requests won't dereference our soon-to-be-gone
* file_priv.
*/
mutex_lock(&dev->struct_mutex);
while (!list_empty(&i915_file_priv->mm.request_list))
list_del_init(i915_file_priv->mm.request_list.next);
mutex_unlock(&dev->struct_mutex);
}

View file

@ -25,6 +25,8 @@
*
*/
#include <linux/acpi.h>
#include <linux/pnp.h>
#include "linux/string.h"
#include "linux/bitops.h"
#include "drmP.h"
@ -81,6 +83,143 @@
* to match what the GPU expects.
*/
#define MCHBAR_I915 0x44
#define MCHBAR_I965 0x48
#define MCHBAR_SIZE (4*4096)
#define DEVEN_REG 0x54
#define DEVEN_MCHBAR_EN (1 << 28)
/* Allocate space for the MCH regs if needed, return nonzero on error */
static int
intel_alloc_mchbar_resource(struct drm_device *dev)
{
struct pci_dev *bridge_dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
u32 temp_lo, temp_hi = 0;
u64 mchbar_addr;
int ret = 0;
bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
if (!bridge_dev) {
DRM_DEBUG("no bridge dev?!\n");
ret = -ENODEV;
goto out;
}
if (IS_I965G(dev))
pci_read_config_dword(bridge_dev, reg + 4, &temp_hi);
pci_read_config_dword(bridge_dev, reg, &temp_lo);
mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
/* If ACPI doesn't have it, assume we need to allocate it ourselves */
if (mchbar_addr &&
pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
ret = 0;
goto out_put;
}
/* Get some space for it */
ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
MCHBAR_SIZE, MCHBAR_SIZE,
PCIBIOS_MIN_MEM,
0, pcibios_align_resource,
bridge_dev);
if (ret) {
DRM_DEBUG("failed bus alloc: %d\n", ret);
dev_priv->mch_res.start = 0;
goto out_put;
}
if (IS_I965G(dev))
pci_write_config_dword(bridge_dev, reg + 4,
upper_32_bits(dev_priv->mch_res.start));
pci_write_config_dword(bridge_dev, reg,
lower_32_bits(dev_priv->mch_res.start));
out_put:
pci_dev_put(bridge_dev);
out:
return ret;
}
/* Setup MCHBAR if possible, return true if we should disable it again */
static bool
intel_setup_mchbar(struct drm_device *dev)
{
struct pci_dev *bridge_dev;
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
bool need_disable = false, enabled;
bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
if (!bridge_dev) {
DRM_DEBUG("no bridge dev?!\n");
goto out;
}
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
enabled = !!(temp & DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
enabled = temp & 1;
}
/* If it's already enabled, don't have to do anything */
if (enabled)
goto out_put;
if (intel_alloc_mchbar_resource(dev))
goto out_put;
need_disable = true;
/* Space is allocated or reserved, so enable it. */
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_write_config_dword(bridge_dev, DEVEN_REG,
temp | DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
pci_write_config_dword(bridge_dev, mchbar_reg, temp | 1);
}
out_put:
pci_dev_put(bridge_dev);
out:
return need_disable;
}
static void
intel_teardown_mchbar(struct drm_device *dev, bool disable)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct pci_dev *bridge_dev;
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
if (!bridge_dev) {
DRM_DEBUG("no bridge dev?!\n");
return;
}
if (disable) {
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_read_config_dword(bridge_dev, DEVEN_REG, &temp);
temp &= ~DEVEN_MCHBAR_EN;
pci_write_config_dword(bridge_dev, DEVEN_REG, temp);
} else {
pci_read_config_dword(bridge_dev, mchbar_reg, &temp);
temp &= ~1;
pci_write_config_dword(bridge_dev, mchbar_reg, temp);
}
}
if (dev_priv->mch_res.start)
release_resource(&dev_priv->mch_res);
}
/**
* Detects bit 6 swizzling of address lookup between IGD access and CPU
* access through main memory.
@ -91,6 +230,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
bool need_disable;
if (!IS_I9XX(dev)) {
/* As far as we know, the 865 doesn't have these bit 6
@ -101,6 +241,9 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
} else if (IS_MOBILE(dev)) {
uint32_t dcc;
/* Try to make sure MCHBAR is enabled before poking at it */
need_disable = intel_setup_mchbar(dev);
/* 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,
@ -140,6 +283,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
}
intel_teardown_mchbar(dev, need_disable);
} else {
/* The 965, G33, and newer, have a very flexible memory
* configuration. It will enable dual-channel mode
@ -170,6 +315,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
}
}
/* FIXME: check with memory config on IGDNG */
if (IS_IGDNG(dev)) {
DRM_ERROR("disable tiling on IGDNG...\n");
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
}
dev_priv->mm.bit_6_swizzle_x = swizzle_x;
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
}

View file

@ -57,6 +57,47 @@
#define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \
DRM_I915_VBLANK_PIPE_B)
void
igdng_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
{
if ((dev_priv->gt_irq_mask_reg & mask) != 0) {
dev_priv->gt_irq_mask_reg &= ~mask;
I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
(void) I915_READ(GTIMR);
}
}
static inline void
igdng_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
{
if ((dev_priv->gt_irq_mask_reg & mask) != mask) {
dev_priv->gt_irq_mask_reg |= mask;
I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
(void) I915_READ(GTIMR);
}
}
/* For display hotplug interrupt */
void
igdng_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{
if ((dev_priv->irq_mask_reg & mask) != 0) {
dev_priv->irq_mask_reg &= ~mask;
I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
(void) I915_READ(DEIMR);
}
}
static inline void
igdng_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{
if ((dev_priv->irq_mask_reg & mask) != mask) {
dev_priv->irq_mask_reg |= mask;
I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
(void) I915_READ(DEIMR);
}
}
void
i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
{
@ -196,6 +237,47 @@ static void i915_hotplug_work_func(struct work_struct *work)
drm_sysfs_hotplug_event(dev);
}
irqreturn_t igdng_irq_handler(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
u32 de_iir, gt_iir;
u32 new_de_iir, new_gt_iir;
struct drm_i915_master_private *master_priv;
de_iir = I915_READ(DEIIR);
gt_iir = I915_READ(GTIIR);
for (;;) {
if (de_iir == 0 && gt_iir == 0)
break;
ret = IRQ_HANDLED;
I915_WRITE(DEIIR, de_iir);
new_de_iir = I915_READ(DEIIR);
I915_WRITE(GTIIR, gt_iir);
new_gt_iir = I915_READ(GTIIR);
if (dev->primary->master) {
master_priv = dev->primary->master->driver_priv;
if (master_priv->sarea_priv)
master_priv->sarea_priv->last_dispatch =
READ_BREADCRUMB(dev_priv);
}
if (gt_iir & GT_USER_INTERRUPT) {
dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
DRM_WAKEUP(&dev_priv->irq_queue);
}
de_iir = new_de_iir;
gt_iir = new_gt_iir;
}
return ret;
}
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@ -212,6 +294,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
atomic_inc(&dev_priv->irq_received);
if (IS_IGDNG(dev))
return igdng_irq_handler(dev);
iir = I915_READ(IIR);
if (IS_I965G(dev)) {
@ -349,8 +434,12 @@ void i915_user_irq_get(struct drm_device *dev)
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
if (IS_IGDNG(dev))
igdng_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
else
i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
}
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
}
@ -361,8 +450,12 @@ void i915_user_irq_put(struct drm_device *dev)
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
if (IS_IGDNG(dev))
igdng_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
else
i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
}
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
}
@ -455,6 +548,9 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
if (!(pipeconf & PIPEACONF_ENABLE))
return -EINVAL;
if (IS_IGDNG(dev))
return 0;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (IS_I965G(dev))
i915_enable_pipestat(dev_priv, pipe,
@ -474,6 +570,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
if (IS_IGDNG(dev))
return;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
i915_disable_pipestat(dev_priv, pipe,
PIPE_VBLANK_INTERRUPT_ENABLE |
@ -484,7 +583,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
void i915_enable_interrupt (struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
opregion_enable_asle(dev);
if (!IS_IGDNG(dev))
opregion_enable_asle(dev);
dev_priv->irq_enabled = 1;
}
@ -545,12 +646,65 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
/* drm_dma.h hooks
*/
static void igdng_irq_preinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
I915_WRITE(HWSTAM, 0xeffe);
/* XXX hotplug from PCH */
I915_WRITE(DEIMR, 0xffffffff);
I915_WRITE(DEIER, 0x0);
(void) I915_READ(DEIER);
/* and GT */
I915_WRITE(GTIMR, 0xffffffff);
I915_WRITE(GTIER, 0x0);
(void) I915_READ(GTIER);
}
static int igdng_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */
u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */;
u32 render_mask = GT_USER_INTERRUPT;
dev_priv->irq_mask_reg = ~display_mask;
dev_priv->de_irq_enable_reg = display_mask;
/* should always can generate irq */
I915_WRITE(DEIIR, I915_READ(DEIIR));
I915_WRITE(DEIMR, dev_priv->irq_mask_reg);
I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
(void) I915_READ(DEIER);
/* user interrupt should be enabled, but masked initial */
dev_priv->gt_irq_mask_reg = 0xffffffff;
dev_priv->gt_irq_enable_reg = render_mask;
I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
(void) I915_READ(GTIER);
return 0;
}
void i915_driver_irq_preinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
atomic_set(&dev_priv->irq_received, 0);
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
if (IS_IGDNG(dev)) {
igdng_irq_preinstall(dev);
return;
}
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@ -562,7 +716,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
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)
@ -570,9 +723,12 @@ 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;
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
if (IS_IGDNG(dev))
return igdng_irq_postinstall(dev);
/* Unmask the interrupts that we always want on. */
dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX;
@ -613,11 +769,24 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
(void) I915_READ(IER);
opregion_enable_asle(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
return 0;
}
static void igdng_irq_uninstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
I915_WRITE(HWSTAM, 0xffffffff);
I915_WRITE(DEIMR, 0xffffffff);
I915_WRITE(DEIER, 0x0);
I915_WRITE(DEIIR, I915_READ(DEIIR));
I915_WRITE(GTIMR, 0xffffffff);
I915_WRITE(GTIER, 0x0);
I915_WRITE(GTIIR, I915_READ(GTIIR));
}
void i915_driver_irq_uninstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@ -627,6 +796,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
dev_priv->vblank_pipe = 0;
if (IS_IGDNG(dev)) {
igdng_irq_uninstall(dev);
return;
}
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));

View file

@ -450,6 +450,13 @@
#define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13)
#define PLL_REF_INPUT_MASK (3 << 13)
#define PLL_LOAD_PULSE_PHASE_SHIFT 9
/* IGDNG */
# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT 9
# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK (7 << 9)
# define PLL_REF_SDVO_HDMI_MULTIPLIER(x) (((x)-1) << 9)
# define DPLL_FPA1_P1_POST_DIV_SHIFT 0
# define DPLL_FPA1_P1_POST_DIV_MASK 0xff
/*
* Parallel to Serial Load Pulse phase selection.
* Selects the phase for the 10X DPLL clock for the PCIe
@ -631,8 +638,11 @@
/* Hotplug control (945+ only) */
#define PORT_HOTPLUG_EN 0x61110
#define HDMIB_HOTPLUG_INT_EN (1 << 29)
#define DPB_HOTPLUG_INT_EN (1 << 29)
#define HDMIC_HOTPLUG_INT_EN (1 << 28)
#define DPC_HOTPLUG_INT_EN (1 << 28)
#define HDMID_HOTPLUG_INT_EN (1 << 27)
#define DPD_HOTPLUG_INT_EN (1 << 27)
#define SDVOB_HOTPLUG_INT_EN (1 << 26)
#define SDVOC_HOTPLUG_INT_EN (1 << 25)
#define TV_HOTPLUG_INT_EN (1 << 18)
@ -665,8 +675,11 @@
#define PORT_HOTPLUG_STAT 0x61114
#define HDMIB_HOTPLUG_INT_STATUS (1 << 29)
#define DPB_HOTPLUG_INT_STATUS (1 << 29)
#define HDMIC_HOTPLUG_INT_STATUS (1 << 28)
#define DPC_HOTPLUG_INT_STATUS (1 << 28)
#define HDMID_HOTPLUG_INT_STATUS (1 << 27)
#define DPD_HOTPLUG_INT_STATUS (1 << 27)
#define CRT_HOTPLUG_INT_STATUS (1 << 11)
#define TV_HOTPLUG_INT_STATUS (1 << 10)
#define CRT_HOTPLUG_MONITOR_MASK (3 << 8)
@ -951,15 +964,15 @@
# define DAC_A_1_3_V (0 << 4)
# define DAC_A_1_1_V (1 << 4)
# define DAC_A_0_7_V (2 << 4)
# define DAC_A_OFF (3 << 4)
# define DAC_A_MASK (3 << 4)
# define DAC_B_1_3_V (0 << 2)
# define DAC_B_1_1_V (1 << 2)
# define DAC_B_0_7_V (2 << 2)
# define DAC_B_OFF (3 << 2)
# define DAC_B_MASK (3 << 2)
# define DAC_C_1_3_V (0 << 0)
# define DAC_C_1_1_V (1 << 0)
# define DAC_C_0_7_V (2 << 0)
# define DAC_C_OFF (3 << 0)
# define DAC_C_MASK (3 << 0)
/**
* CSC coefficients are stored in a floating point format with 9 bits of
@ -1328,6 +1341,163 @@
#define TV_V_CHROMA_0 0x68400
#define TV_V_CHROMA_42 0x684a8
/* Display Port */
#define DP_B 0x64100
#define DP_C 0x64200
#define DP_D 0x64300
#define DP_PORT_EN (1 << 31)
#define DP_PIPEB_SELECT (1 << 30)
/* Link training mode - select a suitable mode for each stage */
#define DP_LINK_TRAIN_PAT_1 (0 << 28)
#define DP_LINK_TRAIN_PAT_2 (1 << 28)
#define DP_LINK_TRAIN_PAT_IDLE (2 << 28)
#define DP_LINK_TRAIN_OFF (3 << 28)
#define DP_LINK_TRAIN_MASK (3 << 28)
#define DP_LINK_TRAIN_SHIFT 28
/* Signal voltages. These are mostly controlled by the other end */
#define DP_VOLTAGE_0_4 (0 << 25)
#define DP_VOLTAGE_0_6 (1 << 25)
#define DP_VOLTAGE_0_8 (2 << 25)
#define DP_VOLTAGE_1_2 (3 << 25)
#define DP_VOLTAGE_MASK (7 << 25)
#define DP_VOLTAGE_SHIFT 25
/* Signal pre-emphasis levels, like voltages, the other end tells us what
* they want
*/
#define DP_PRE_EMPHASIS_0 (0 << 22)
#define DP_PRE_EMPHASIS_3_5 (1 << 22)
#define DP_PRE_EMPHASIS_6 (2 << 22)
#define DP_PRE_EMPHASIS_9_5 (3 << 22)
#define DP_PRE_EMPHASIS_MASK (7 << 22)
#define DP_PRE_EMPHASIS_SHIFT 22
/* How many wires to use. I guess 3 was too hard */
#define DP_PORT_WIDTH_1 (0 << 19)
#define DP_PORT_WIDTH_2 (1 << 19)
#define DP_PORT_WIDTH_4 (3 << 19)
#define DP_PORT_WIDTH_MASK (7 << 19)
/* Mystic DPCD version 1.1 special mode */
#define DP_ENHANCED_FRAMING (1 << 18)
/** locked once port is enabled */
#define DP_PORT_REVERSAL (1 << 15)
/** sends the clock on lane 15 of the PEG for debug */
#define DP_CLOCK_OUTPUT_ENABLE (1 << 13)
#define DP_SCRAMBLING_DISABLE (1 << 12)
/** limit RGB values to avoid confusing TVs */
#define DP_COLOR_RANGE_16_235 (1 << 8)
/** Turn on the audio link */
#define DP_AUDIO_OUTPUT_ENABLE (1 << 6)
/** vs and hs sync polarity */
#define DP_SYNC_VS_HIGH (1 << 4)
#define DP_SYNC_HS_HIGH (1 << 3)
/** A fantasy */
#define DP_DETECTED (1 << 2)
/** The aux channel provides a way to talk to the
* signal sink for DDC etc. Max packet size supported
* is 20 bytes in each direction, hence the 5 fixed
* data registers
*/
#define DPB_AUX_CH_CTL 0x64110
#define DPB_AUX_CH_DATA1 0x64114
#define DPB_AUX_CH_DATA2 0x64118
#define DPB_AUX_CH_DATA3 0x6411c
#define DPB_AUX_CH_DATA4 0x64120
#define DPB_AUX_CH_DATA5 0x64124
#define DPC_AUX_CH_CTL 0x64210
#define DPC_AUX_CH_DATA1 0x64214
#define DPC_AUX_CH_DATA2 0x64218
#define DPC_AUX_CH_DATA3 0x6421c
#define DPC_AUX_CH_DATA4 0x64220
#define DPC_AUX_CH_DATA5 0x64224
#define DPD_AUX_CH_CTL 0x64310
#define DPD_AUX_CH_DATA1 0x64314
#define DPD_AUX_CH_DATA2 0x64318
#define DPD_AUX_CH_DATA3 0x6431c
#define DPD_AUX_CH_DATA4 0x64320
#define DPD_AUX_CH_DATA5 0x64324
#define DP_AUX_CH_CTL_SEND_BUSY (1 << 31)
#define DP_AUX_CH_CTL_DONE (1 << 30)
#define DP_AUX_CH_CTL_INTERRUPT (1 << 29)
#define DP_AUX_CH_CTL_TIME_OUT_ERROR (1 << 28)
#define DP_AUX_CH_CTL_TIME_OUT_400us (0 << 26)
#define DP_AUX_CH_CTL_TIME_OUT_600us (1 << 26)
#define DP_AUX_CH_CTL_TIME_OUT_800us (2 << 26)
#define DP_AUX_CH_CTL_TIME_OUT_1600us (3 << 26)
#define DP_AUX_CH_CTL_TIME_OUT_MASK (3 << 26)
#define DP_AUX_CH_CTL_RECEIVE_ERROR (1 << 25)
#define DP_AUX_CH_CTL_MESSAGE_SIZE_MASK (0x1f << 20)
#define DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT 20
#define DP_AUX_CH_CTL_PRECHARGE_2US_MASK (0xf << 16)
#define DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT 16
#define DP_AUX_CH_CTL_AUX_AKSV_SELECT (1 << 15)
#define DP_AUX_CH_CTL_MANCHESTER_TEST (1 << 14)
#define DP_AUX_CH_CTL_SYNC_TEST (1 << 13)
#define DP_AUX_CH_CTL_DEGLITCH_TEST (1 << 12)
#define DP_AUX_CH_CTL_PRECHARGE_TEST (1 << 11)
#define DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK (0x7ff)
#define DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT 0
/*
* Computing GMCH M and N values for the Display Port link
*
* GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes
*
* ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz)
*
* The GMCH value is used internally
*
* bytes_per_pixel is the number of bytes coming out of the plane,
* which is after the LUTs, so we want the bytes for our color format.
* For our current usage, this is always 3, one byte for R, G and B.
*/
#define PIPEA_GMCH_DATA_M 0x70050
#define PIPEB_GMCH_DATA_M 0x71050
/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25)
#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25
#define PIPE_GMCH_DATA_M_MASK (0xffffff)
#define PIPEA_GMCH_DATA_N 0x70054
#define PIPEB_GMCH_DATA_N 0x71054
#define PIPE_GMCH_DATA_N_MASK (0xffffff)
/*
* Computing Link M and N values for the Display Port link
*
* Link M / N = pixel_clock / ls_clk
*
* (the DP spec calls pixel_clock the 'strm_clk')
*
* The Link value is transmitted in the Main Stream
* Attributes and VB-ID.
*/
#define PIPEA_DP_LINK_M 0x70060
#define PIPEB_DP_LINK_M 0x71060
#define PIPEA_DP_LINK_M_MASK (0xffffff)
#define PIPEA_DP_LINK_N 0x70064
#define PIPEB_DP_LINK_N 0x71064
#define PIPEA_DP_LINK_N_MASK (0xffffff)
/* Display & cursor control */
/* Pipe A */
@ -1517,4 +1687,444 @@
# define VGA_2X_MODE (1 << 30)
# define VGA_PIPE_B_SELECT (1 << 29)
/* IGDNG */
#define CPU_VGACNTRL 0x41000
#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030
#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4)
#define DIGITAL_PORTA_SHORT_PULSE_2MS (0 << 2)
#define DIGITAL_PORTA_SHORT_PULSE_4_5MS (1 << 2)
#define DIGITAL_PORTA_SHORT_PULSE_6MS (2 << 2)
#define DIGITAL_PORTA_SHORT_PULSE_100MS (3 << 2)
#define DIGITAL_PORTA_NO_DETECT (0 << 0)
#define DIGITAL_PORTA_LONG_PULSE_DETECT_MASK (1 << 1)
#define DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK (1 << 0)
/* refresh rate hardware control */
#define RR_HW_CTL 0x45300
#define RR_HW_LOW_POWER_FRAMES_MASK 0xff
#define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00
#define FDI_PLL_BIOS_0 0x46000
#define FDI_PLL_BIOS_1 0x46004
#define FDI_PLL_BIOS_2 0x46008
#define DISPLAY_PORT_PLL_BIOS_0 0x4600c
#define DISPLAY_PORT_PLL_BIOS_1 0x46010
#define DISPLAY_PORT_PLL_BIOS_2 0x46014
#define FDI_PLL_FREQ_CTL 0x46030
#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24)
#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00
#define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff
#define PIPEA_DATA_M1 0x60030
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
#define TU_SIZE_MASK 0x7e000000
#define PIPEA_DATA_M1_OFFSET 0
#define PIPEA_DATA_N1 0x60034
#define PIPEA_DATA_N1_OFFSET 0
#define PIPEA_DATA_M2 0x60038
#define PIPEA_DATA_M2_OFFSET 0
#define PIPEA_DATA_N2 0x6003c
#define PIPEA_DATA_N2_OFFSET 0
#define PIPEA_LINK_M1 0x60040
#define PIPEA_LINK_M1_OFFSET 0
#define PIPEA_LINK_N1 0x60044
#define PIPEA_LINK_N1_OFFSET 0
#define PIPEA_LINK_M2 0x60048
#define PIPEA_LINK_M2_OFFSET 0
#define PIPEA_LINK_N2 0x6004c
#define PIPEA_LINK_N2_OFFSET 0
/* PIPEB timing regs are same start from 0x61000 */
#define PIPEB_DATA_M1 0x61030
#define PIPEB_DATA_M1_OFFSET 0
#define PIPEB_DATA_N1 0x61034
#define PIPEB_DATA_N1_OFFSET 0
#define PIPEB_DATA_M2 0x61038
#define PIPEB_DATA_M2_OFFSET 0
#define PIPEB_DATA_N2 0x6103c
#define PIPEB_DATA_N2_OFFSET 0
#define PIPEB_LINK_M1 0x61040
#define PIPEB_LINK_M1_OFFSET 0
#define PIPEB_LINK_N1 0x61044
#define PIPEB_LINK_N1_OFFSET 0
#define PIPEB_LINK_M2 0x61048
#define PIPEB_LINK_M2_OFFSET 0
#define PIPEB_LINK_N2 0x6104c
#define PIPEB_LINK_N2_OFFSET 0
/* CPU panel fitter */
#define PFA_CTL_1 0x68080
#define PFB_CTL_1 0x68880
#define PF_ENABLE (1<<31)
/* legacy palette */
#define LGC_PALETTE_A 0x4a000
#define LGC_PALETTE_B 0x4a800
/* interrupts */
#define DE_MASTER_IRQ_CONTROL (1 << 31)
#define DE_SPRITEB_FLIP_DONE (1 << 29)
#define DE_SPRITEA_FLIP_DONE (1 << 28)
#define DE_PLANEB_FLIP_DONE (1 << 27)
#define DE_PLANEA_FLIP_DONE (1 << 26)
#define DE_PCU_EVENT (1 << 25)
#define DE_GTT_FAULT (1 << 24)
#define DE_POISON (1 << 23)
#define DE_PERFORM_COUNTER (1 << 22)
#define DE_PCH_EVENT (1 << 21)
#define DE_AUX_CHANNEL_A (1 << 20)
#define DE_DP_A_HOTPLUG (1 << 19)
#define DE_GSE (1 << 18)
#define DE_PIPEB_VBLANK (1 << 15)
#define DE_PIPEB_EVEN_FIELD (1 << 14)
#define DE_PIPEB_ODD_FIELD (1 << 13)
#define DE_PIPEB_LINE_COMPARE (1 << 12)
#define DE_PIPEB_VSYNC (1 << 11)
#define DE_PIPEB_FIFO_UNDERRUN (1 << 8)
#define DE_PIPEA_VBLANK (1 << 7)
#define DE_PIPEA_EVEN_FIELD (1 << 6)
#define DE_PIPEA_ODD_FIELD (1 << 5)
#define DE_PIPEA_LINE_COMPARE (1 << 4)
#define DE_PIPEA_VSYNC (1 << 3)
#define DE_PIPEA_FIFO_UNDERRUN (1 << 0)
#define DEISR 0x44000
#define DEIMR 0x44004
#define DEIIR 0x44008
#define DEIER 0x4400c
/* GT interrupt */
#define GT_SYNC_STATUS (1 << 2)
#define GT_USER_INTERRUPT (1 << 0)
#define GTISR 0x44010
#define GTIMR 0x44014
#define GTIIR 0x44018
#define GTIER 0x4401c
/* PCH */
/* south display engine interrupt */
#define SDE_CRT_HOTPLUG (1 << 11)
#define SDE_PORTD_HOTPLUG (1 << 10)
#define SDE_PORTC_HOTPLUG (1 << 9)
#define SDE_PORTB_HOTPLUG (1 << 8)
#define SDE_SDVOB_HOTPLUG (1 << 6)
#define SDEISR 0xc4000
#define SDEIMR 0xc4004
#define SDEIIR 0xc4008
#define SDEIER 0xc400c
/* digital port hotplug */
#define PCH_PORT_HOTPLUG 0xc4030
#define PORTD_HOTPLUG_ENABLE (1 << 20)
#define PORTD_PULSE_DURATION_2ms (0)
#define PORTD_PULSE_DURATION_4_5ms (1 << 18)
#define PORTD_PULSE_DURATION_6ms (2 << 18)
#define PORTD_PULSE_DURATION_100ms (3 << 18)
#define PORTD_HOTPLUG_NO_DETECT (0)
#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16)
#define PORTD_HOTPLUG_LONG_DETECT (1 << 17)
#define PORTC_HOTPLUG_ENABLE (1 << 12)
#define PORTC_PULSE_DURATION_2ms (0)
#define PORTC_PULSE_DURATION_4_5ms (1 << 10)
#define PORTC_PULSE_DURATION_6ms (2 << 10)
#define PORTC_PULSE_DURATION_100ms (3 << 10)
#define PORTC_HOTPLUG_NO_DETECT (0)
#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8)
#define PORTC_HOTPLUG_LONG_DETECT (1 << 9)
#define PORTB_HOTPLUG_ENABLE (1 << 4)
#define PORTB_PULSE_DURATION_2ms (0)
#define PORTB_PULSE_DURATION_4_5ms (1 << 2)
#define PORTB_PULSE_DURATION_6ms (2 << 2)
#define PORTB_PULSE_DURATION_100ms (3 << 2)
#define PORTB_HOTPLUG_NO_DETECT (0)
#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0)
#define PORTB_HOTPLUG_LONG_DETECT (1 << 1)
#define PCH_GPIOA 0xc5010
#define PCH_GPIOB 0xc5014
#define PCH_GPIOC 0xc5018
#define PCH_GPIOD 0xc501c
#define PCH_GPIOE 0xc5020
#define PCH_GPIOF 0xc5024
#define PCH_DPLL_A 0xc6014
#define PCH_DPLL_B 0xc6018
#define PCH_FPA0 0xc6040
#define PCH_FPA1 0xc6044
#define PCH_FPB0 0xc6048
#define PCH_FPB1 0xc604c
#define PCH_DPLL_TEST 0xc606c
#define PCH_DREF_CONTROL 0xC6200
#define DREF_CONTROL_MASK 0x7fc3
#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13)
#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13)
#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13)
#define DREF_CPU_SOURCE_OUTPUT_MASK (3<<13)
#define DREF_SSC_SOURCE_DISABLE (0<<11)
#define DREF_SSC_SOURCE_ENABLE (2<<11)
#define DREF_SSC_SOURCE_MASK (2<<11)
#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9)
#define DREF_NONSPREAD_CK505_ENABLE (1<<9)
#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9)
#define DREF_NONSPREAD_SOURCE_MASK (2<<9)
#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7)
#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7)
#define DREF_SSC4_DOWNSPREAD (0<<6)
#define DREF_SSC4_CENTERSPREAD (1<<6)
#define DREF_SSC1_DISABLE (0<<1)
#define DREF_SSC1_ENABLE (1<<1)
#define DREF_SSC4_DISABLE (0)
#define DREF_SSC4_ENABLE (1)
#define PCH_RAWCLK_FREQ 0xc6204
#define FDL_TP1_TIMER_SHIFT 12
#define FDL_TP1_TIMER_MASK (3<<12)
#define FDL_TP2_TIMER_SHIFT 10
#define FDL_TP2_TIMER_MASK (3<<10)
#define RAWCLK_FREQ_MASK 0x3ff
#define PCH_DPLL_TMR_CFG 0xc6208
#define PCH_SSC4_PARMS 0xc6210
#define PCH_SSC4_AUX_PARMS 0xc6214
/* transcoder */
#define TRANS_HTOTAL_A 0xe0000
#define TRANS_HTOTAL_SHIFT 16
#define TRANS_HACTIVE_SHIFT 0
#define TRANS_HBLANK_A 0xe0004
#define TRANS_HBLANK_END_SHIFT 16
#define TRANS_HBLANK_START_SHIFT 0
#define TRANS_HSYNC_A 0xe0008
#define TRANS_HSYNC_END_SHIFT 16
#define TRANS_HSYNC_START_SHIFT 0
#define TRANS_VTOTAL_A 0xe000c
#define TRANS_VTOTAL_SHIFT 16
#define TRANS_VACTIVE_SHIFT 0
#define TRANS_VBLANK_A 0xe0010
#define TRANS_VBLANK_END_SHIFT 16
#define TRANS_VBLANK_START_SHIFT 0
#define TRANS_VSYNC_A 0xe0014
#define TRANS_VSYNC_END_SHIFT 16
#define TRANS_VSYNC_START_SHIFT 0
#define TRANSA_DATA_M1 0xe0030
#define TRANSA_DATA_N1 0xe0034
#define TRANSA_DATA_M2 0xe0038
#define TRANSA_DATA_N2 0xe003c
#define TRANSA_DP_LINK_M1 0xe0040
#define TRANSA_DP_LINK_N1 0xe0044
#define TRANSA_DP_LINK_M2 0xe0048
#define TRANSA_DP_LINK_N2 0xe004c
#define TRANS_HTOTAL_B 0xe1000
#define TRANS_HBLANK_B 0xe1004
#define TRANS_HSYNC_B 0xe1008
#define TRANS_VTOTAL_B 0xe100c
#define TRANS_VBLANK_B 0xe1010
#define TRANS_VSYNC_B 0xe1014
#define TRANSB_DATA_M1 0xe1030
#define TRANSB_DATA_N1 0xe1034
#define TRANSB_DATA_M2 0xe1038
#define TRANSB_DATA_N2 0xe103c
#define TRANSB_DP_LINK_M1 0xe1040
#define TRANSB_DP_LINK_N1 0xe1044
#define TRANSB_DP_LINK_M2 0xe1048
#define TRANSB_DP_LINK_N2 0xe104c
#define TRANSACONF 0xf0008
#define TRANSBCONF 0xf1008
#define TRANS_DISABLE (0<<31)
#define TRANS_ENABLE (1<<31)
#define TRANS_STATE_MASK (1<<30)
#define TRANS_STATE_DISABLE (0<<30)
#define TRANS_STATE_ENABLE (1<<30)
#define TRANS_FSYNC_DELAY_HB1 (0<<27)
#define TRANS_FSYNC_DELAY_HB2 (1<<27)
#define TRANS_FSYNC_DELAY_HB3 (2<<27)
#define TRANS_FSYNC_DELAY_HB4 (3<<27)
#define TRANS_DP_AUDIO_ONLY (1<<26)
#define TRANS_DP_VIDEO_AUDIO (0<<26)
#define TRANS_PROGRESSIVE (0<<21)
#define TRANS_8BPC (0<<5)
#define TRANS_10BPC (1<<5)
#define TRANS_6BPC (2<<5)
#define TRANS_12BPC (3<<5)
#define FDI_RXA_CHICKEN 0xc200c
#define FDI_RXB_CHICKEN 0xc2010
#define FDI_RX_PHASE_SYNC_POINTER_ENABLE (1)
/* CPU: FDI_TX */
#define FDI_TXA_CTL 0x60100
#define FDI_TXB_CTL 0x61100
#define FDI_TX_DISABLE (0<<31)
#define FDI_TX_ENABLE (1<<31)
#define FDI_LINK_TRAIN_PATTERN_1 (0<<28)
#define FDI_LINK_TRAIN_PATTERN_2 (1<<28)
#define FDI_LINK_TRAIN_PATTERN_IDLE (2<<28)
#define FDI_LINK_TRAIN_NONE (3<<28)
#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0<<25)
#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1<<25)
#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2<<25)
#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3<<25)
#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22)
#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22)
#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2<<22)
#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3<<22)
#define FDI_DP_PORT_WIDTH_X1 (0<<19)
#define FDI_DP_PORT_WIDTH_X2 (1<<19)
#define FDI_DP_PORT_WIDTH_X3 (2<<19)
#define FDI_DP_PORT_WIDTH_X4 (3<<19)
#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18)
/* IGDNG: hardwired to 1 */
#define FDI_TX_PLL_ENABLE (1<<14)
/* both Tx and Rx */
#define FDI_SCRAMBLING_ENABLE (0<<7)
#define FDI_SCRAMBLING_DISABLE (1<<7)
/* FDI_RX, FDI_X is hard-wired to Transcoder_X */
#define FDI_RXA_CTL 0xf000c
#define FDI_RXB_CTL 0xf100c
#define FDI_RX_ENABLE (1<<31)
#define FDI_RX_DISABLE (0<<31)
/* train, dp width same as FDI_TX */
#define FDI_DP_PORT_WIDTH_X8 (7<<19)
#define FDI_8BPC (0<<16)
#define FDI_10BPC (1<<16)
#define FDI_6BPC (2<<16)
#define FDI_12BPC (3<<16)
#define FDI_LINK_REVERSE_OVERWRITE (1<<15)
#define FDI_DMI_LINK_REVERSE_MASK (1<<14)
#define FDI_RX_PLL_ENABLE (1<<13)
#define FDI_FS_ERR_CORRECT_ENABLE (1<<11)
#define FDI_FE_ERR_CORRECT_ENABLE (1<<10)
#define FDI_FS_ERR_REPORT_ENABLE (1<<9)
#define FDI_FE_ERR_REPORT_ENABLE (1<<8)
#define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6)
#define FDI_SEL_RAWCLK (0<<4)
#define FDI_SEL_PCDCLK (1<<4)
#define FDI_RXA_MISC 0xf0010
#define FDI_RXB_MISC 0xf1010
#define FDI_RXA_TUSIZE1 0xf0030
#define FDI_RXA_TUSIZE2 0xf0038
#define FDI_RXB_TUSIZE1 0xf1030
#define FDI_RXB_TUSIZE2 0xf1038
/* FDI_RX interrupt register format */
#define FDI_RX_INTER_LANE_ALIGN (1<<10)
#define FDI_RX_SYMBOL_LOCK (1<<9) /* train 2 */
#define FDI_RX_BIT_LOCK (1<<8) /* train 1 */
#define FDI_RX_TRAIN_PATTERN_2_FAIL (1<<7)
#define FDI_RX_FS_CODE_ERR (1<<6)
#define FDI_RX_FE_CODE_ERR (1<<5)
#define FDI_RX_SYMBOL_ERR_RATE_ABOVE (1<<4)
#define FDI_RX_HDCP_LINK_FAIL (1<<3)
#define FDI_RX_PIXEL_FIFO_OVERFLOW (1<<2)
#define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1)
#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0)
#define FDI_RXA_IIR 0xf0014
#define FDI_RXA_IMR 0xf0018
#define FDI_RXB_IIR 0xf1014
#define FDI_RXB_IMR 0xf1018
#define FDI_PLL_CTL_1 0xfe000
#define FDI_PLL_CTL_2 0xfe004
/* CRT */
#define PCH_ADPA 0xe1100
#define ADPA_TRANS_SELECT_MASK (1<<30)
#define ADPA_TRANS_A_SELECT 0
#define ADPA_TRANS_B_SELECT (1<<30)
#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */
#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24)
#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24)
#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24)
#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24)
#define ADPA_CRT_HOTPLUG_ENABLE (1<<23)
#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22)
#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22)
#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21)
#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21)
#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20)
#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20)
#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18)
#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18)
#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18)
#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18)
#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17)
#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17)
#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
/* or SDVOB */
#define HDMIB 0xe1140
#define PORT_ENABLE (1 << 31)
#define TRANSCODER_A (0)
#define TRANSCODER_B (1 << 30)
#define COLOR_FORMAT_8bpc (0)
#define COLOR_FORMAT_12bpc (3 << 26)
#define SDVOB_HOTPLUG_ENABLE (1 << 23)
#define SDVO_ENCODING (0)
#define TMDS_ENCODING (2 << 10)
#define NULL_PACKET_VSYNC_ENABLE (1 << 9)
#define SDVOB_BORDER_ENABLE (1 << 7)
#define AUDIO_ENABLE (1 << 6)
#define VSYNC_ACTIVE_HIGH (1 << 4)
#define HSYNC_ACTIVE_HIGH (1 << 3)
#define PORT_DETECTED (1 << 2)
#define HDMIC 0xe1150
#define HDMID 0xe1160
#define PCH_LVDS 0xe1180
#define LVDS_DETECTED (1 << 1)
#define BLC_PWM_CPU_CTL2 0x48250
#define PWM_ENABLE (1 << 31)
#define PWM_PIPE_A (0 << 29)
#define PWM_PIPE_B (1 << 29)
#define BLC_PWM_CPU_CTL 0x48254
#define BLC_PWM_PCH_CTL1 0xc8250
#define PWM_PCH_ENABLE (1 << 31)
#define PWM_POLARITY_ACTIVE_LOW (1 << 29)
#define PWM_POLARITY_ACTIVE_HIGH (0 << 29)
#define PWM_POLARITY_ACTIVE_LOW2 (1 << 28)
#define PWM_POLARITY_ACTIVE_HIGH2 (0 << 28)
#define BLC_PWM_PCH_CTL2 0xc8254
#define PCH_PP_STATUS 0xc7200
#define PCH_PP_CONTROL 0xc7204
#define EDP_FORCE_VDD (1 << 3)
#define EDP_BLC_ENABLE (1 << 2)
#define PANEL_POWER_RESET (1 << 1)
#define PANEL_POWER_OFF (0 << 0)
#define PANEL_POWER_ON (1 << 0)
#define PCH_PP_ON_DELAYS 0xc7208
#define EDP_PANEL (1 << 30)
#define PCH_PP_OFF_DELAYS 0xc720c
#define PCH_PP_DIVISOR 0xc7210
#endif /* _I915_REG_H_ */

View file

@ -295,6 +295,16 @@ int i915_save_state(struct drm_device *dev)
i915_save_palette(dev, PIPE_B);
dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
/* Cursor state */
dev_priv->saveCURACNTR = I915_READ(CURACNTR);
dev_priv->saveCURAPOS = I915_READ(CURAPOS);
dev_priv->saveCURABASE = I915_READ(CURABASE);
dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
dev_priv->saveCURBPOS = I915_READ(CURBPOS);
dev_priv->saveCURBBASE = I915_READ(CURBBASE);
if (!IS_I9XX(dev))
dev_priv->saveCURSIZE = I915_READ(CURSIZE);
/* CRT state */
dev_priv->saveADPA = I915_READ(ADPA);
@ -480,6 +490,16 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
/* Cursor state */
I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
I915_WRITE(CURABASE, dev_priv->saveCURABASE);
I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
if (!IS_I9XX(dev))
I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
/* CRT state */
I915_WRITE(ADPA, dev_priv->saveADPA);

View file

@ -30,6 +30,8 @@
#include "i915_drv.h"
#include "intel_bios.h"
#define SLAVE_ADDR1 0x70
#define SLAVE_ADDR2 0x72
static void *
find_section(struct bdb_header *bdb, int section_id)
@ -193,6 +195,88 @@ parse_general_features(struct drm_i915_private *dev_priv,
}
}
static void
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
{
struct sdvo_device_mapping *p_mapping;
struct bdb_general_definitions *p_defs;
struct child_device_config *p_child;
int i, child_device_num, count;
u16 block_size, *block_ptr;
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (!p_defs) {
DRM_DEBUG("No general definition block is found\n");
return;
}
/* judge whether the size of child device meets the requirements.
* If the child device size obtained from general definition block
* is different with sizeof(struct child_device_config), skip the
* parsing of sdvo device info
*/
if (p_defs->child_dev_size != sizeof(*p_child)) {
/* different child dev size . Ignore it */
DRM_DEBUG("different child size is found. Invalid.\n");
return;
}
/* get the block size of general definitions */
block_ptr = (u16 *)((char *)p_defs - 2);
block_size = *block_ptr;
/* get the number of child device */
child_device_num = (block_size - sizeof(*p_defs)) /
sizeof(*p_child);
count = 0;
for (i = 0; i < child_device_num; i++) {
p_child = &(p_defs->devices[i]);
if (!p_child->device_type) {
/* skip the device block if device type is invalid */
continue;
}
if (p_child->slave_addr != SLAVE_ADDR1 &&
p_child->slave_addr != SLAVE_ADDR2) {
/*
* If the slave address is neither 0x70 nor 0x72,
* it is not a SDVO device. Skip it.
*/
continue;
}
if (p_child->dvo_port != DEVICE_PORT_DVOB &&
p_child->dvo_port != DEVICE_PORT_DVOC) {
/* skip the incorrect SDVO port */
DRM_DEBUG("Incorrect SDVO port. Skip it \n");
continue;
}
DRM_DEBUG("the SDVO device with slave addr %2x is found on "
"%s port\n",
p_child->slave_addr,
(p_child->dvo_port == DEVICE_PORT_DVOB) ?
"SDVOB" : "SDVOC");
p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]);
if (!p_mapping->initialized) {
p_mapping->dvo_port = p_child->dvo_port;
p_mapping->slave_addr = p_child->slave_addr;
p_mapping->dvo_wiring = p_child->dvo_wiring;
p_mapping->initialized = 1;
} else {
DRM_DEBUG("Maybe one SDVO port is shared by "
"two SDVO device.\n");
}
if (p_child->slave2_addr) {
/* Maybe this is a SDVO device with multiple inputs */
/* And the mapping info is not added */
DRM_DEBUG("there exists the slave2_addr. Maybe this "
"is a SDVO device with multiple inputs.\n");
}
count++;
}
if (!count) {
/* No SDVO device info is found */
DRM_DEBUG("No SDVO device info is found in VBT\n");
}
return;
}
/**
* intel_init_bios - initialize VBIOS settings & find VBT
* @dev: DRM device
@ -242,7 +326,7 @@ intel_init_bios(struct drm_device *dev)
parse_general_features(dev_priv, bdb);
parse_lfp_panel_data(dev_priv, bdb);
parse_sdvo_panel_data(dev_priv, bdb);
parse_sdvo_device_mapping(dev_priv, bdb);
pci_unmap_rom(pdev, bios);
return 0;

View file

@ -135,6 +135,86 @@ struct bdb_general_features {
u8 rsvd11:6; /* finish byte */
} __attribute__((packed));
/* pre-915 */
#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */
#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */
#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */
#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */
/* Pre 915 */
#define DEVICE_TYPE_NONE 0x00
#define DEVICE_TYPE_CRT 0x01
#define DEVICE_TYPE_TV 0x09
#define DEVICE_TYPE_EFP 0x12
#define DEVICE_TYPE_LFP 0x22
/* On 915+ */
#define DEVICE_TYPE_CRT_DPMS 0x6001
#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001
#define DEVICE_TYPE_TV_COMPOSITE 0x0209
#define DEVICE_TYPE_TV_MACROVISION 0x0289
#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c
#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609
#define DEVICE_TYPE_TV_SCART 0x0209
#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009
#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012
#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052
#define DEVICE_TYPE_EFP_DVI_I 0x6053
#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152
#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2
#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062
#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162
#define DEVICE_TYPE_LFP_PANELLINK 0x5012
#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042
#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062
#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162
#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2
#define DEVICE_CFG_NONE 0x00
#define DEVICE_CFG_12BIT_DVOB 0x01
#define DEVICE_CFG_12BIT_DVOC 0x02
#define DEVICE_CFG_24BIT_DVOBC 0x09
#define DEVICE_CFG_24BIT_DVOCB 0x0a
#define DEVICE_CFG_DUAL_DVOB 0x11
#define DEVICE_CFG_DUAL_DVOC 0x12
#define DEVICE_CFG_DUAL_DVOBC 0x13
#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19
#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a
#define DEVICE_WIRE_NONE 0x00
#define DEVICE_WIRE_DVOB 0x01
#define DEVICE_WIRE_DVOC 0x02
#define DEVICE_WIRE_DVOBC 0x03
#define DEVICE_WIRE_DVOBB 0x05
#define DEVICE_WIRE_DVOCC 0x06
#define DEVICE_WIRE_DVOB_MASTER 0x0d
#define DEVICE_WIRE_DVOC_MASTER 0x0e
#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */
#define DEVICE_PORT_DVOB 0x01
#define DEVICE_PORT_DVOC 0x02
struct child_device_config {
u16 handle;
u16 device_type;
u8 device_id[10]; /* See DEVICE_TYPE_* above */
u16 addin_offset;
u8 dvo_port; /* See Device_PORT_* above */
u8 i2c_pin;
u8 slave_addr;
u8 ddc_pin;
u16 edid_ptr;
u8 dvo_cfg; /* See DEVICE_CFG_* above */
u8 dvo2_port;
u8 i2c2_pin;
u8 slave2_addr;
u8 ddc2_pin;
u8 capabilities;
u8 dvo_wiring;/* See DEVICE_WIRE_* above */
u8 dvo2_wiring;
u16 extended_type;
u8 dvo_function;
} __attribute__((packed));
struct bdb_general_definitions {
/* DDC GPIO */
u8 crt_ddc_gmbus_pin;
@ -149,14 +229,19 @@ struct bdb_general_definitions {
u8 boot_display[2];
u8 child_dev_size;
/* device info */
u8 tv_or_lvds_info[33];
u8 dev1[33];
u8 dev2[33];
u8 dev3[33];
u8 dev4[33];
/* may be another device block here on some platforms */
};
/*
* Device info:
* If TV is present, it'll be at devices[0].
* LVDS will be next, either devices[0] or [1], if present.
* On some platforms the number of device is 6. But could be as few as
* 4 if both TV and LVDS are missing.
* And the device num is related with the size of general definition
* block. It is obtained by using the following formula:
* number = (block_size - sizeof(bdb_general_definitions))/
* sizeof(child_device_config);
*/
struct child_device_config devices[0];
} __attribute__((packed));
struct bdb_lvds_options {
u8 panel_type;

View file

@ -37,9 +37,14 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 temp;
u32 temp, reg;
temp = I915_READ(ADPA);
if (IS_IGDNG(dev))
reg = PCH_ADPA;
else
reg = ADPA;
temp = I915_READ(reg);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp |= ADPA_DAC_ENABLE;
@ -58,7 +63,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
break;
}
I915_WRITE(ADPA, temp);
I915_WRITE(reg, temp);
}
static int intel_crt_mode_valid(struct drm_connector *connector,
@ -101,17 +106,23 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private;
int dpll_md_reg;
u32 adpa, dpll_md;
u32 adpa_reg;
if (intel_crtc->pipe == 0)
dpll_md_reg = DPLL_A_MD;
else
dpll_md_reg = DPLL_B_MD;
if (IS_IGDNG(dev))
adpa_reg = PCH_ADPA;
else
adpa_reg = ADPA;
/*
* Disable separate mode multiplier used when cloning SDVO to CRT
* XXX this needs to be adjusted when we really are cloning
*/
if (IS_I965G(dev)) {
if (IS_I965G(dev) && !IS_IGDNG(dev)) {
dpll_md = I915_READ(dpll_md_reg);
I915_WRITE(dpll_md_reg,
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@ -125,13 +136,53 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
if (intel_crtc->pipe == 0) {
adpa |= ADPA_PIPE_A_SELECT;
I915_WRITE(BCLRPAT_A, 0);
if (!IS_IGDNG(dev))
I915_WRITE(BCLRPAT_A, 0);
} else {
adpa |= ADPA_PIPE_B_SELECT;
I915_WRITE(BCLRPAT_B, 0);
if (!IS_IGDNG(dev))
I915_WRITE(BCLRPAT_B, 0);
}
I915_WRITE(ADPA, adpa);
I915_WRITE(adpa_reg, adpa);
}
static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 adpa, temp;
bool ret;
temp = adpa = I915_READ(PCH_ADPA);
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
ADPA_CRT_HOTPLUG_WARMUP_10MS |
ADPA_CRT_HOTPLUG_SAMPLE_4S |
ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
ADPA_CRT_HOTPLUG_VOLREF_325MV |
ADPA_CRT_HOTPLUG_ENABLE |
ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
DRM_DEBUG("pch crt adpa 0x%x", adpa);
I915_WRITE(PCH_ADPA, adpa);
/* This might not be needed as not specified in spec...*/
udelay(1000);
/* Check the status to see if both blue and green are on now */
adpa = I915_READ(PCH_ADPA);
if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) ==
ADPA_CRT_HOTPLUG_MONITOR_COLOR)
ret = true;
else
ret = false;
/* restore origin register */
I915_WRITE(PCH_ADPA, temp);
return ret;
}
/**
@ -148,6 +199,10 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 hotplug_en;
int i, tries = 0;
if (IS_IGDNG(dev))
return intel_igdng_crt_detect_hotplug(connector);
/*
* On 4 series desktop, CRT detect sequence need to be done twice
* to get a reliable result.
@ -423,6 +478,7 @@ void intel_crt_init(struct drm_device *dev)
{
struct drm_connector *connector;
struct intel_output *intel_output;
u32 i2c_reg;
intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
if (!intel_output)
@ -439,7 +495,11 @@ void intel_crt_init(struct drm_device *dev)
&intel_output->enc);
/* Set up the DDC bus. */
intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
if (IS_IGDNG(dev))
i2c_reg = PCH_GPIOA;
else
i2c_reg = GPIOA;
intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
if (!intel_output->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
"failed.\n");

View file

@ -137,6 +137,8 @@ struct intel_limit {
#define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7
#define INTEL_LIMIT_IGD_SDVO_DAC 8
#define INTEL_LIMIT_IGD_LVDS 9
#define INTEL_LIMIT_IGDNG_SDVO_DAC 10
#define INTEL_LIMIT_IGDNG_LVDS 11
/*The parameter is for SDVO on G4x platform*/
#define G4X_DOT_SDVO_MIN 25000
@ -216,12 +218,43 @@ struct intel_limit {
#define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7
#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0
/* IGDNG */
/* as we calculate clock using (register_value + 2) for
N/M1/M2, so here the range value for them is (actual_value-2).
*/
#define IGDNG_DOT_MIN 25000
#define IGDNG_DOT_MAX 350000
#define IGDNG_VCO_MIN 1760000
#define IGDNG_VCO_MAX 3510000
#define IGDNG_N_MIN 1
#define IGDNG_N_MAX 5
#define IGDNG_M_MIN 79
#define IGDNG_M_MAX 118
#define IGDNG_M1_MIN 12
#define IGDNG_M1_MAX 23
#define IGDNG_M2_MIN 5
#define IGDNG_M2_MAX 9
#define IGDNG_P_SDVO_DAC_MIN 5
#define IGDNG_P_SDVO_DAC_MAX 80
#define IGDNG_P_LVDS_MIN 28
#define IGDNG_P_LVDS_MAX 112
#define IGDNG_P1_MIN 1
#define IGDNG_P1_MAX 8
#define IGDNG_P2_SDVO_DAC_SLOW 10
#define IGDNG_P2_SDVO_DAC_FAST 5
#define IGDNG_P2_LVDS_SLOW 14 /* single channel */
#define IGDNG_P2_LVDS_FAST 7 /* double channel */
#define IGDNG_P2_DOT_LIMIT 225000 /* 225Mhz */
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 bool
intel_igdng_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 */
@ -383,9 +416,47 @@ static const intel_limit_t intel_limits[] = {
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
.find_pll = intel_find_best_PLL,
},
{ /* INTEL_LIMIT_IGDNG_SDVO_DAC */
.dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX },
.vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX },
.n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX },
.m = { .min = IGDNG_M_MIN, .max = IGDNG_M_MAX },
.m1 = { .min = IGDNG_M1_MIN, .max = IGDNG_M1_MAX },
.m2 = { .min = IGDNG_M2_MIN, .max = IGDNG_M2_MAX },
.p = { .min = IGDNG_P_SDVO_DAC_MIN, .max = IGDNG_P_SDVO_DAC_MAX },
.p1 = { .min = IGDNG_P1_MIN, .max = IGDNG_P1_MAX },
.p2 = { .dot_limit = IGDNG_P2_DOT_LIMIT,
.p2_slow = IGDNG_P2_SDVO_DAC_SLOW,
.p2_fast = IGDNG_P2_SDVO_DAC_FAST },
.find_pll = intel_igdng_find_best_PLL,
},
{ /* INTEL_LIMIT_IGDNG_LVDS */
.dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX },
.vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX },
.n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX },
.m = { .min = IGDNG_M_MIN, .max = IGDNG_M_MAX },
.m1 = { .min = IGDNG_M1_MIN, .max = IGDNG_M1_MAX },
.m2 = { .min = IGDNG_M2_MIN, .max = IGDNG_M2_MAX },
.p = { .min = IGDNG_P_LVDS_MIN, .max = IGDNG_P_LVDS_MAX },
.p1 = { .min = IGDNG_P1_MIN, .max = IGDNG_P1_MAX },
.p2 = { .dot_limit = IGDNG_P2_DOT_LIMIT,
.p2_slow = IGDNG_P2_LVDS_SLOW,
.p2_fast = IGDNG_P2_LVDS_FAST },
.find_pll = intel_igdng_find_best_PLL,
},
};
static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc)
{
const intel_limit_t *limit;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS];
else
limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC];
return limit;
}
static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@ -418,7 +489,9 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
const intel_limit_t *limit;
if (IS_G4X(dev)) {
if (IS_IGDNG(dev))
limit = intel_igdng_limit(crtc);
else 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))
@ -630,7 +703,64 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
}
}
}
return found;
}
static bool
intel_igdng_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;
int err_most = 47;
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((10000 - (target*10000/clock.dot)));
if (this_err < err_most) {
*best_clock = clock;
err_most = this_err;
max_n = clock.n;
found = true;
/* found on first matching */
goto out;
}
}
}
}
}
out:
return found;
}
@ -785,18 +915,292 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
/**
* Sets the power management mode of the pipe and plane.
*
* This code should probably grow support for turning the cursor off and back
* on appropriately at the same time as we're turning the pipe off/on.
*/
static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
int plane = intel_crtc->pipe;
int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
u32 temp;
int tries = 5, j;
/* XXX: When our outputs are all unaware of DPMS modes other than off
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
*/
switch (mode) {
case DRM_MODE_DPMS_ON:
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
DRM_DEBUG("crtc %d dpms on\n", pipe);
/* enable PCH DPLL */
temp = I915_READ(pch_dpll_reg);
if ((temp & DPLL_VCO_ENABLE) == 0) {
I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
I915_READ(pch_dpll_reg);
}
/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
temp = I915_READ(fdi_rx_reg);
I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
FDI_SEL_PCDCLK |
FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
I915_READ(fdi_rx_reg);
udelay(200);
/* Enable CPU FDI TX PLL, always on for IGDNG */
temp = I915_READ(fdi_tx_reg);
if ((temp & FDI_TX_PLL_ENABLE) == 0) {
I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
I915_READ(fdi_tx_reg);
udelay(100);
}
/* Enable CPU pipe */
temp = I915_READ(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) == 0) {
I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
I915_READ(pipeconf_reg);
udelay(100);
}
/* configure and enable CPU plane */
temp = I915_READ(dspcntr_reg);
if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
}
/* enable CPU FDI TX and PCH FDI RX */
temp = I915_READ(fdi_tx_reg);
temp |= FDI_TX_ENABLE;
temp |= FDI_DP_PORT_WIDTH_X4; /* default */
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
I915_WRITE(fdi_tx_reg, temp);
I915_READ(fdi_tx_reg);
temp = I915_READ(fdi_rx_reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
I915_READ(fdi_rx_reg);
udelay(150);
/* Train FDI. */
/* umask FDI RX Interrupt symbol_lock and bit_lock bit
for train result */
temp = I915_READ(fdi_rx_imr_reg);
temp &= ~FDI_RX_SYMBOL_LOCK;
temp &= ~FDI_RX_BIT_LOCK;
I915_WRITE(fdi_rx_imr_reg, temp);
I915_READ(fdi_rx_imr_reg);
udelay(150);
temp = I915_READ(fdi_rx_iir_reg);
DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
if ((temp & FDI_RX_BIT_LOCK) == 0) {
for (j = 0; j < tries; j++) {
temp = I915_READ(fdi_rx_iir_reg);
DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
if (temp & FDI_RX_BIT_LOCK)
break;
udelay(200);
}
if (j != tries)
I915_WRITE(fdi_rx_iir_reg,
temp | FDI_RX_BIT_LOCK);
else
DRM_DEBUG("train 1 fail\n");
} else {
I915_WRITE(fdi_rx_iir_reg,
temp | FDI_RX_BIT_LOCK);
DRM_DEBUG("train 1 ok 2!\n");
}
temp = I915_READ(fdi_tx_reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_2;
I915_WRITE(fdi_tx_reg, temp);
temp = I915_READ(fdi_rx_reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_2;
I915_WRITE(fdi_rx_reg, temp);
udelay(150);
temp = I915_READ(fdi_rx_iir_reg);
DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
for (j = 0; j < tries; j++) {
temp = I915_READ(fdi_rx_iir_reg);
DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
if (temp & FDI_RX_SYMBOL_LOCK)
break;
udelay(200);
}
if (j != tries) {
I915_WRITE(fdi_rx_iir_reg,
temp | FDI_RX_SYMBOL_LOCK);
DRM_DEBUG("train 2 ok 1!\n");
} else
DRM_DEBUG("train 2 fail\n");
} else {
I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK);
DRM_DEBUG("train 2 ok 2!\n");
}
DRM_DEBUG("train done\n");
/* set transcoder timing */
I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
/* enable PCH transcoder */
temp = I915_READ(transconf_reg);
I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
I915_READ(transconf_reg);
while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
;
/* enable normal */
temp = I915_READ(fdi_tx_reg);
temp &= ~FDI_LINK_TRAIN_NONE;
I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
FDI_TX_ENHANCE_FRAME_ENABLE);
I915_READ(fdi_tx_reg);
temp = I915_READ(fdi_rx_reg);
temp &= ~FDI_LINK_TRAIN_NONE;
I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
FDI_RX_ENHANCE_FRAME_ENABLE);
I915_READ(fdi_rx_reg);
/* wait one idle pattern time */
udelay(100);
intel_crtc_load_lut(crtc);
break;
case DRM_MODE_DPMS_OFF:
DRM_DEBUG("crtc %d dpms off\n", pipe);
/* Disable the VGA plane that we never use */
I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE);
/* Disable display plane */
temp = I915_READ(dspcntr_reg);
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
I915_READ(dspbase_reg);
}
/* disable cpu pipe, disable after all planes disabled */
temp = I915_READ(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) != 0) {
I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
I915_READ(pipeconf_reg);
/* wait for cpu pipe off, pipe state */
while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0)
;
} else
DRM_DEBUG("crtc %d is disabled\n", pipe);
/* IGDNG-A : disable cpu panel fitter ? */
temp = I915_READ(pf_ctl_reg);
if ((temp & PF_ENABLE) != 0) {
I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
I915_READ(pf_ctl_reg);
}
/* disable CPU FDI tx and PCH FDI rx */
temp = I915_READ(fdi_tx_reg);
I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
I915_READ(fdi_tx_reg);
temp = I915_READ(fdi_rx_reg);
I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
I915_READ(fdi_rx_reg);
/* still set train pattern 1 */
temp = I915_READ(fdi_tx_reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
I915_WRITE(fdi_tx_reg, temp);
temp = I915_READ(fdi_rx_reg);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
I915_WRITE(fdi_rx_reg, temp);
/* disable PCH transcoder */
temp = I915_READ(transconf_reg);
if ((temp & TRANS_ENABLE) != 0) {
I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
I915_READ(transconf_reg);
/* wait for PCH transcoder off, transcoder state */
while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0)
;
}
/* disable PCH DPLL */
temp = I915_READ(pch_dpll_reg);
if ((temp & DPLL_VCO_ENABLE) != 0) {
I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
I915_READ(pch_dpll_reg);
}
temp = I915_READ(fdi_rx_reg);
if ((temp & FDI_RX_PLL_ENABLE) != 0) {
temp &= ~FDI_SEL_PCDCLK;
temp &= ~FDI_RX_PLL_ENABLE;
I915_WRITE(fdi_rx_reg, temp);
I915_READ(fdi_rx_reg);
}
/* Wait for the clocks to turn off. */
udelay(150);
break;
}
}
static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_master_private *master_priv;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
@ -805,7 +1209,6 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
u32 temp;
bool enabled;
/* XXX: When our outputs are all unaware of DPMS modes other than off
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@ -890,6 +1293,26 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
udelay(150);
break;
}
}
/**
* Sets the power management mode of the pipe and plane.
*
* This code should probably grow support for turning the cursor off and back
* on appropriately at the same time as we're turning the pipe off/on.
*/
static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_master_private *master_priv;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
bool enabled;
if (IS_IGDNG(dev))
igdng_crtc_dpms(crtc, mode);
else
i9xx_crtc_dpms(crtc, mode);
if (!dev->primary->master)
return;
@ -947,6 +1370,12 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = crtc->dev;
if (IS_IGDNG(dev)) {
/* FDI link clock is fixed at 2.7G */
if (mode->clock * 3 > 27000 * 4)
return MODE_CLOCK_HIGH;
}
return true;
}
@ -1030,6 +1459,48 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)
return 1;
}
struct fdi_m_n {
u32 tu;
u32 gmch_m;
u32 gmch_n;
u32 link_m;
u32 link_n;
};
static void
fdi_reduce_ratio(u32 *num, u32 *den)
{
while (*num > 0xffffff || *den > 0xffffff) {
*num >>= 1;
*den >>= 1;
}
}
#define DATA_N 0x800000
#define LINK_N 0x80000
static void
igdng_compute_m_n(int bytes_per_pixel, int nlanes,
int pixel_clock, int link_clock,
struct fdi_m_n *m_n)
{
u64 temp;
m_n->tu = 64; /* default size */
temp = (u64) DATA_N * pixel_clock;
temp = div_u64(temp, link_clock);
m_n->gmch_m = (temp * bytes_per_pixel) / nlanes;
m_n->gmch_n = DATA_N;
fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
temp = (u64) LINK_N * pixel_clock;
m_n->link_m = div_u64(temp, link_clock);
m_n->link_n = LINK_N;
fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
}
static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@ -1063,6 +1534,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_connector *connector;
const intel_limit_t *limit;
int ret;
struct fdi_m_n m_n = {0};
int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
int lvds_reg = LVDS;
u32 temp;
int sdvo_pixel_multiply;
drm_vblank_pre_modeset(dev, pipe);
@ -1101,6 +1583,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000);
} else if (IS_I9XX(dev)) {
refclk = 96000;
if (IS_IGDNG(dev))
refclk = 120000; /* 120Mhz refclk */
} else {
refclk = 48000;
}
@ -1114,6 +1598,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
drm_vblank_post_modeset(dev, pipe);
return -EINVAL;
}
@ -1137,12 +1622,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
}
/* FDI link */
if (IS_IGDNG(dev))
igdng_compute_m_n(3, 4, /* lane num 4 */
adjusted_mode->clock,
270000, /* lane clock */
&m_n);
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_IGDNG(dev))
dpll = DPLL_VGA_MODE_DIS;
if (IS_I9XX(dev)) {
if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
@ -1150,17 +1644,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= DPLLB_MODE_DAC_SERIAL;
if (is_sdvo) {
dpll |= DPLL_DVO_HIGH_SPEED;
if (IS_I945G(dev) || IS_I945GM(dev)) {
int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
if (IS_I945G(dev) || IS_I945GM(dev))
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
}
else if (IS_IGDNG(dev))
dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
}
/* compute bitmask from p1 value */
if (IS_IGD(dev))
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_IGD;
else
else {
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
/* also FPA1 */
if (IS_IGDNG(dev))
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
}
switch (clock.p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
@ -1175,7 +1674,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
}
if (IS_I965G(dev))
if (IS_I965G(dev) && !IS_IGDNG(dev))
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
} else {
if (is_lvds) {
@ -1207,10 +1706,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
if (pipe == 0)
dspcntr |= DISPPLANE_SEL_PIPE_A;
else
dspcntr |= DISPPLANE_SEL_PIPE_B;
/* IGDNG's plane is forced to pipe, bit 24 is to
enable color space conversion */
if (!IS_IGDNG(dev)) {
if (pipe == 0)
dspcntr |= DISPPLANE_SEL_PIPE_A;
else
dspcntr |= DISPPLANE_SEL_PIPE_B;
}
if (pipe == 0 && !IS_I965G(dev)) {
/* Enable pixel doubling when the dot clock is > 90% of the (display)
@ -1231,12 +1734,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Disable the panel fitter if it was on our pipe */
if (intel_panel_fitter_pipe(dev) == pipe)
if (!IS_IGDNG(dev) && intel_panel_fitter_pipe(dev) == pipe)
I915_WRITE(PFIT_CONTROL, 0);
DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
/* assign to IGDNG registers */
if (IS_IGDNG(dev)) {
fp_reg = pch_fp_reg;
dpll_reg = pch_dpll_reg;
}
if (dpll & DPLL_VCO_ENABLE) {
I915_WRITE(fp_reg, fp);
@ -1245,13 +1753,33 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
udelay(150);
}
if (IS_IGDNG(dev)) {
/* enable PCH clock reference source */
/* XXX need to change the setting for other outputs */
u32 temp;
temp = I915_READ(PCH_DREF_CONTROL);
temp &= ~DREF_NONSPREAD_SOURCE_MASK;
temp |= DREF_NONSPREAD_CK505_ENABLE;
temp &= ~DREF_SSC_SOURCE_MASK;
temp |= DREF_SSC_SOURCE_ENABLE;
temp &= ~DREF_SSC1_ENABLE;
/* if no eDP, disable source output to CPU */
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
}
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
* This is an exception to the general rule that mode_set doesn't turn
* things on.
*/
if (is_lvds) {
u32 lvds = I915_READ(LVDS);
u32 lvds;
if (IS_IGDNG(dev))
lvds_reg = PCH_LVDS;
lvds = I915_READ(lvds_reg);
lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
/* Set the B0-B3 data pairs corresponding to whether we're going to
* set the DPLLs for dual-channel mode or not.
@ -1266,8 +1794,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* panels behave in the two modes.
*/
I915_WRITE(LVDS, lvds);
I915_READ(LVDS);
I915_WRITE(lvds_reg, lvds);
I915_READ(lvds_reg);
}
I915_WRITE(fp_reg, fp);
@ -1276,8 +1804,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Wait for the clocks to stabilize. */
udelay(150);
if (IS_I965G(dev)) {
int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
if (IS_I965G(dev) && !IS_IGDNG(dev)) {
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
} else {
@ -1303,9 +1831,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* pipesrc and dspsize control the size that is scaled from, which should
* always be the user's requested size.
*/
I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
I915_WRITE(dsppos_reg, 0);
if (!IS_IGDNG(dev)) {
I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
(mode->hdisplay - 1));
I915_WRITE(dsppos_reg, 0);
}
I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
if (IS_IGDNG(dev)) {
I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
I915_WRITE(link_m1_reg, m_n.link_m);
I915_WRITE(link_n1_reg, m_n.link_n);
/* enable FDI RX PLL too */
temp = I915_READ(fdi_rx_reg);
I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
udelay(200);
}
I915_WRITE(pipeconf_reg, pipeconf);
I915_READ(pipeconf_reg);
@ -1315,12 +1859,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Flush the plane changes */
ret = intel_pipe_set_base(crtc, x, y, old_fb);
if (ret != 0)
return ret;
drm_vblank_post_modeset(dev, pipe);
return 0;
return ret;
}
/** Loads the palette/gamma unit for the CRTC with the prepared values */
@ -1336,6 +1877,11 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
if (!crtc->enabled)
return;
/* use legacy palette for IGDNG */
if (IS_IGDNG(dev))
palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A :
LGC_PALETTE_B;
for (i = 0; i < 256; i++) {
I915_WRITE(palreg + 4 * i,
(intel_crtc->lut_r[i] << 16) |
@ -1464,16 +2010,16 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
uint32_t adder;
if (x < 0) {
temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
x = -x;
}
if (y < 0) {
temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
y = -y;
}
temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
temp |= x << CURSOR_X_SHIFT;
temp |= y << CURSOR_Y_SHIFT;
adder = intel_crtc->cursor_addr;
I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
@ -1590,6 +2136,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
}
encoder->crtc = crtc;
intel_output->base.encoder = encoder;
intel_output->load_detect_temp = true;
intel_crtc = to_intel_crtc(crtc);
@ -1625,6 +2172,7 @@ void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_
if (intel_output->load_detect_temp) {
encoder->crtc = NULL;
intel_output->base.encoder = NULL;
intel_output->load_detect_temp = false;
crtc->enabled = drm_helper_crtc_in_use(crtc);
drm_helper_disable_unused_functions(dev);
@ -1762,6 +2310,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
if (intel_crtc->mode_set.mode)
drm_mode_destroy(crtc->dev, intel_crtc->mode_set.mode);
drm_crtc_cleanup(crtc);
kfree(intel_crtc);
}
@ -1888,7 +2438,24 @@ static void intel_setup_outputs(struct drm_device *dev)
if (IS_MOBILE(dev) && !IS_I830(dev))
intel_lvds_init(dev);
if (IS_I9XX(dev)) {
if (IS_IGDNG(dev)) {
int found;
if (I915_READ(HDMIB) & PORT_DETECTED) {
/* check SDVOB */
/* found = intel_sdvo_init(dev, HDMIB); */
found = 0;
if (!found)
intel_hdmi_init(dev, HDMIB);
}
if (I915_READ(HDMIC) & PORT_DETECTED)
intel_hdmi_init(dev, HDMIC);
if (I915_READ(HDMID) & PORT_DETECTED)
intel_hdmi_init(dev, HDMID);
} else if (IS_I9XX(dev)) {
int found;
u32 reg;
@ -1912,7 +2479,7 @@ static void intel_setup_outputs(struct drm_device *dev)
} else
intel_dvo_init(dev);
if (IS_I9XX(dev) && IS_MOBILE(dev))
if (IS_I9XX(dev) && IS_MOBILE(dev) && !IS_IGDNG(dev))
intel_tv_init(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {

View file

@ -207,7 +207,7 @@ static int intelfb_set_par(struct fb_info *info)
if (var->pixclock != -1) {
DRM_ERROR("PIXEL CLCOK SET\n");
DRM_ERROR("PIXEL CLOCK SET\n");
return -EINVAL;
} else {
struct drm_crtc *crtc;
@ -674,8 +674,12 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *
par->crtc_ids[0] = crtc->base.id;
modeset->num_connectors = conn_count;
if (modeset->mode != modeset->crtc->desired_mode)
modeset->mode = modeset->crtc->desired_mode;
if (modeset->crtc->desired_mode) {
if (modeset->mode)
drm_mode_destroy(dev, modeset->mode);
modeset->mode = drm_mode_duplicate(dev,
modeset->crtc->desired_mode);
}
par->crtc_count = 1;
@ -824,8 +828,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev)
par->crtc_ids[crtc_count++] = crtc->base.id;
modeset->num_connectors = conn_count;
if (modeset->mode != modeset->crtc->desired_mode)
modeset->mode = modeset->crtc->desired_mode;
if (modeset->crtc->desired_mode) {
if (modeset->mode)
drm_mode_destroy(dev, modeset->mode);
modeset->mode = drm_mode_duplicate(dev,
modeset->crtc->desired_mode);
}
}
par->crtc_count = crtc_count;
@ -857,9 +865,15 @@ void intelfb_restore(void)
drm_crtc_helper_set_config(&kernelfb_mode);
}
static void intelfb_restore_work_fn(struct work_struct *ignored)
{
intelfb_restore();
}
static DECLARE_WORK(intelfb_restore_work, intelfb_restore_work_fn);
static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3)
{
intelfb_restore();
schedule_work(&intelfb_restore_work);
}
static struct sysrq_key_op sysrq_intelfb_restore_op = {

View file

@ -56,7 +56,8 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
sdvox = SDVO_ENCODING_HDMI |
SDVO_BORDER_ENABLE |
SDVO_VSYNC_ACTIVE_HIGH |
SDVO_HSYNC_ACTIVE_HIGH;
SDVO_HSYNC_ACTIVE_HIGH |
SDVO_NULL_PACKETS_DURING_VSYNC;
if (hdmi_priv->has_hdmi_sink)
sdvox |= SDVO_AUDIO_ENABLE;
@ -144,6 +145,22 @@ intel_hdmi_sink_detect(struct drm_connector *connector)
}
}
static enum drm_connector_status
igdng_hdmi_detect(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
/* FIXME hotplug detect */
hdmi_priv->has_hdmi_sink = false;
intel_hdmi_sink_detect(connector);
if (hdmi_priv->has_hdmi_sink)
return connector_status_connected;
else
return connector_status_disconnected;
}
static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector)
{
@ -153,6 +170,9 @@ intel_hdmi_detect(struct drm_connector *connector)
struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
u32 temp, bit;
if (IS_IGDNG(dev))
return igdng_hdmi_detect(connector);
temp = I915_READ(PORT_HOTPLUG_EN);
switch (hdmi_priv->sdvox_reg) {
@ -269,8 +289,17 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
/* Set up the DDC bus. */
if (sdvox_reg == SDVOB)
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
else
else if (sdvox_reg == SDVOC)
intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
else if (sdvox_reg == HDMIB)
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
"HDMIB");
else if (sdvox_reg == HDMIC)
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
"HDMIC");
else if (sdvox_reg == HDMID)
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
"HDMID");
if (!intel_output->ddc_bus)
goto err_connector;

View file

@ -37,6 +37,8 @@
#include "i915_drm.h"
#include "i915_drv.h"
#define I915_LVDS "i915_lvds"
/**
* Sets the backlight level.
*
@ -45,10 +47,15 @@
static void intel_lvds_set_backlight(struct drm_device *dev, int level)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 blc_pwm_ctl;
u32 blc_pwm_ctl, reg;
blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl |
if (IS_IGDNG(dev))
reg = BLC_PWM_CPU_CTL;
else
reg = BLC_PWM_CTL;
blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
I915_WRITE(reg, (blc_pwm_ctl |
(level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
}
@ -58,8 +65,14 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level)
static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >>
if (IS_IGDNG(dev))
reg = BLC_PWM_PCH_CTL2;
else
reg = BLC_PWM_CTL;
return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
}
@ -69,23 +82,31 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
static void intel_lvds_set_power(struct drm_device *dev, bool on)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_status;
u32 pp_status, ctl_reg, status_reg;
if (IS_IGDNG(dev)) {
ctl_reg = PCH_PP_CONTROL;
status_reg = PCH_PP_STATUS;
} else {
ctl_reg = PP_CONTROL;
status_reg = PP_STATUS;
}
if (on) {
I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
POWER_TARGET_ON);
do {
pp_status = I915_READ(PP_STATUS);
pp_status = I915_READ(status_reg);
} while ((pp_status & PP_ON) == 0);
intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
} else {
intel_lvds_set_backlight(dev, 0);
I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) &
I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
~POWER_TARGET_ON);
do {
pp_status = I915_READ(PP_STATUS);
pp_status = I915_READ(status_reg);
} while (pp_status & PP_ON);
}
}
@ -106,12 +127,28 @@ static void intel_lvds_save(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg;
dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS);
dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS);
dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
if (IS_IGDNG(dev)) {
pp_on_reg = PCH_PP_ON_DELAYS;
pp_off_reg = PCH_PP_OFF_DELAYS;
pp_ctl_reg = PCH_PP_CONTROL;
pp_div_reg = PCH_PP_DIVISOR;
pwm_ctl_reg = BLC_PWM_CPU_CTL;
} else {
pp_on_reg = PP_ON_DELAYS;
pp_off_reg = PP_OFF_DELAYS;
pp_ctl_reg = PP_CONTROL;
pp_div_reg = PP_DIVISOR;
pwm_ctl_reg = BLC_PWM_CTL;
}
dev_priv->savePP_ON = I915_READ(pp_on_reg);
dev_priv->savePP_OFF = I915_READ(pp_off_reg);
dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg);
dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg);
dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg);
dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK);
@ -127,12 +164,28 @@ static void intel_lvds_restore(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg;
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON);
I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF);
I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
if (IS_IGDNG(dev)) {
pp_on_reg = PCH_PP_ON_DELAYS;
pp_off_reg = PCH_PP_OFF_DELAYS;
pp_ctl_reg = PCH_PP_CONTROL;
pp_div_reg = PCH_PP_DIVISOR;
pwm_ctl_reg = BLC_PWM_CPU_CTL;
} else {
pp_on_reg = PP_ON_DELAYS;
pp_off_reg = PP_OFF_DELAYS;
pp_ctl_reg = PP_CONTROL;
pp_div_reg = PP_DIVISOR;
pwm_ctl_reg = BLC_PWM_CTL;
}
I915_WRITE(pwm_ctl_reg, dev_priv->saveBLC_PWM_CTL);
I915_WRITE(pp_on_reg, dev_priv->savePP_ON);
I915_WRITE(pp_off_reg, dev_priv->savePP_OFF);
I915_WRITE(pp_div_reg, dev_priv->savePP_DIVISOR);
I915_WRITE(pp_ctl_reg, dev_priv->savePP_CONTROL);
if (dev_priv->savePP_CONTROL & POWER_TARGET_ON)
intel_lvds_set_power(dev, true);
else
@ -216,8 +269,14 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
if (IS_IGDNG(dev))
reg = BLC_PWM_CPU_CTL;
else
reg = BLC_PWM_CTL;
dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
BACKLIGHT_DUTY_CYCLE_MASK);
@ -251,6 +310,10 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
* settings.
*/
/* No panel fitting yet, fixme */
if (IS_IGDNG(dev))
return;
/*
* Enable automatic panel scaling so that non-native modes fill the
* screen. Should be enabled before the pipe is enabled, according to
@ -382,7 +445,8 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
{
DRM_DEBUG("Skipping LVDS initialization for %s\n", id->ident);
DRM_DEBUG_KMS(I915_LVDS,
"Skipping LVDS initialization for %s\n", id->ident);
return 1;
}
@ -420,8 +484,21 @@ static const struct dmi_system_id intel_no_lvds[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"),
},
},
/* FIXME: add a check for the Aopen Mini PC */
{
.callback = intel_no_lvds_dmi_callback,
.ident = "AOpen Mini PC",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "AOpen"),
DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"),
},
},
{
.callback = intel_no_lvds_dmi_callback,
.ident = "Aopen i945GTt-VFA",
.matches = {
DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
},
},
{ } /* terminating entry */
};
@ -442,12 +519,18 @@ void intel_lvds_init(struct drm_device *dev)
struct drm_display_mode *scan; /* *modes, *bios_mode; */
struct drm_crtc *crtc;
u32 lvds;
int pipe;
int pipe, gpio = GPIOC;
/* Skip init on machines we know falsely report LVDS */
if (dmi_check_system(intel_no_lvds))
return;
if (IS_IGDNG(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
return;
gpio = PCH_GPIOC;
}
intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
if (!intel_output) {
return;
@ -482,7 +565,7 @@ void intel_lvds_init(struct drm_device *dev)
*/
/* Set up the DDC bus. */
intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
intel_output->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
if (!intel_output->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
"failed.\n");
@ -524,6 +607,11 @@ void intel_lvds_init(struct drm_device *dev)
* on. If so, assume that whatever is currently programmed is the
* correct mode.
*/
/* IGDNG: FIXME if still fail, not try pipe mode now */
if (IS_IGDNG(dev))
goto failed;
lvds = I915_READ(LVDS);
pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
crtc = intel_get_crtc_from_pipe(dev, pipe);
@ -542,11 +630,22 @@ void intel_lvds_init(struct drm_device *dev)
goto failed;
out:
if (IS_IGDNG(dev)) {
u32 pwm;
/* make sure PWM is enabled */
pwm = I915_READ(BLC_PWM_CPU_CTL2);
pwm |= (PWM_ENABLE | PWM_PIPE_B);
I915_WRITE(BLC_PWM_CPU_CTL2, pwm);
pwm = I915_READ(BLC_PWM_PCH_CTL1);
pwm |= PWM_PCH_ENABLE;
I915_WRITE(BLC_PWM_PCH_CTL1, pwm);
}
drm_sysfs_connector_add(connector);
return;
failed:
DRM_DEBUG("No LVDS modes found, disabling.\n");
DRM_DEBUG_KMS(I915_LVDS, "No LVDS modes found, disabling.\n");
if (intel_output->ddc_bus)
intel_i2c_destroy(intel_output->ddc_bus);
drm_connector_cleanup(connector);

View file

@ -36,7 +36,7 @@
#include "intel_sdvo_regs.h"
#undef SDVO_DEBUG
#define I915_SDVO "i915_sdvo"
struct intel_sdvo_priv {
struct intel_i2c_chan *i2c_bus;
int slaveaddr;
@ -277,20 +277,21 @@ 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;
printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
DRM_DEBUG_KMS(I915_SDVO, "%s: W: %02X ",
SDVO_NAME(sdvo_priv), cmd);
for (i = 0; i < args_len; i++)
printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]);
DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);
for (; i < 8; i++)
printk(KERN_DEBUG " ");
DRM_LOG_KMS(" ");
for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
if (cmd == sdvo_cmd_names[i].cmd) {
printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name);
DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name);
break;
}
}
if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
printk(KERN_DEBUG "(%02X)", cmd);
printk(KERN_DEBUG "\n");
DRM_LOG_KMS("(%02X)", cmd);
DRM_LOG_KMS("\n");
}
#else
#define intel_sdvo_debug_write(o, c, a, l)
@ -329,16 +330,16 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output,
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
int i;
printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv));
DRM_DEBUG_KMS(I915_SDVO, "%s: R: ", SDVO_NAME(sdvo_priv));
for (i = 0; i < response_len; i++)
printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]);
DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
for (; i < 8; i++)
printk(KERN_DEBUG " ");
DRM_LOG_KMS(" ");
if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
printk(KERN_DEBUG "(%s)", cmd_status_names[status]);
DRM_LOG_KMS("(%s)", cmd_status_names[status]);
else
printk(KERN_DEBUG "(??? %d)", status);
printk(KERN_DEBUG "\n");
DRM_LOG_KMS("(??? %d)", status);
DRM_LOG_KMS("\n");
}
#else
#define intel_sdvo_debug_response(o, r, l, s)
@ -1742,6 +1743,43 @@ static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
.master_xfer = intel_sdvo_master_xfer,
};
static u8
intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct sdvo_device_mapping *my_mapping, *other_mapping;
if (output_device == SDVOB) {
my_mapping = &dev_priv->sdvo_mappings[0];
other_mapping = &dev_priv->sdvo_mappings[1];
} else {
my_mapping = &dev_priv->sdvo_mappings[1];
other_mapping = &dev_priv->sdvo_mappings[0];
}
/* If the BIOS described our SDVO device, take advantage of it. */
if (my_mapping->slave_addr)
return my_mapping->slave_addr;
/* If the BIOS only described a different SDVO device, use the
* address that it isn't using.
*/
if (other_mapping->slave_addr) {
if (other_mapping->slave_addr == 0x70)
return 0x72;
else
return 0x70;
}
/* No SDVO device info is found for another DVO port,
* so use mapping assumption we had before BIOS parsing.
*/
if (output_device == SDVOB)
return 0x70;
else
return 0x72;
}
bool intel_sdvo_init(struct drm_device *dev, int output_device)
{
struct drm_connector *connector;
@ -1753,6 +1791,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
u8 ch[0x40];
int i;
int encoder_type, output_id;
u8 slave_addr;
intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
if (!intel_output) {
@ -1771,16 +1810,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
if (!i2cbus)
goto err_inteloutput;
slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
sdvo_priv->i2c_bus = i2cbus;
if (output_device == SDVOB) {
output_id = 1;
sdvo_priv->i2c_bus->slave_addr = 0x38;
} else {
output_id = 2;
sdvo_priv->i2c_bus->slave_addr = 0x39;
}
sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1;
sdvo_priv->output_device = output_device;
intel_output->i2c_bus = i2cbus;
intel_output->dev_priv = sdvo_priv;
@ -1788,8 +1826,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) {
DRM_DEBUG("No SDVO device found on SDVO%c\n",
output_device == SDVOB ? 'B' : 'C');
DRM_DEBUG_KMS(I915_SDVO,
"No SDVO device found on SDVO%c\n",
output_device == SDVOB ? 'B' : 'C');
goto err_i2c;
}
}
@ -1873,9 +1912,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
sdvo_priv->controlled_output = 0;
memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
DRM_DEBUG("%s: Unknown SDVO output type (0x%02x%02x)\n",
SDVO_NAME(sdvo_priv),
bytes[0], bytes[1]);
DRM_DEBUG_KMS(I915_SDVO,
"%s: Unknown SDVO output type (0x%02x%02x)\n",
SDVO_NAME(sdvo_priv),
bytes[0], bytes[1]);
encoder_type = DRM_MODE_ENCODER_NONE;
connector_type = DRM_MODE_CONNECTOR_Unknown;
goto err_i2c;
@ -1905,21 +1945,21 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
&sdvo_priv->pixel_clock_max);
DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, "
"clock range %dMHz - %dMHz, "
"input 1: %c, input 2: %c, "
"output 1: %c, output 2: %c\n",
SDVO_NAME(sdvo_priv),
sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
sdvo_priv->caps.device_rev_id,
sdvo_priv->pixel_clock_min / 1000,
sdvo_priv->pixel_clock_max / 1000,
(sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
(sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
/* check currently supported outputs */
sdvo_priv->caps.output_flags &
DRM_DEBUG_KMS(I915_SDVO, "%s device VID/DID: %02X:%02X.%02X, "
"clock range %dMHz - %dMHz, "
"input 1: %c, input 2: %c, "
"output 1: %c, output 2: %c\n",
SDVO_NAME(sdvo_priv),
sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
sdvo_priv->caps.device_rev_id,
sdvo_priv->pixel_clock_min / 1000,
sdvo_priv->pixel_clock_max / 1000,
(sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
(sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
/* check currently supported outputs */
sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
sdvo_priv->caps.output_flags &
sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
return true;

View file

@ -1392,6 +1392,9 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
tv_ctl &= ~TV_TEST_MODE_MASK;
tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
tv_dac &= ~TVDAC_SENSE_MASK;
tv_dac &= ~DAC_A_MASK;
tv_dac &= ~DAC_B_MASK;
tv_dac &= ~DAC_C_MASK;
tv_dac |= (TVDAC_STATE_CHG_EN |
TVDAC_A_SENSE_CTL |
TVDAC_B_SENSE_CTL |

View file

@ -478,26 +478,27 @@ static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv)
if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770)) {
RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
DRM_INFO("Loading RV770 PFP Microcode\n");
DRM_INFO("Loading RV770/RV790 PFP Microcode\n");
for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV770_pfp_microcode[i]);
RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
DRM_INFO("Loading RV770 CP Microcode\n");
DRM_INFO("Loading RV770/RV790 CP Microcode\n");
for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
RADEON_WRITE(R600_CP_ME_RAM_DATA, RV770_cp_microcode[i]);
RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730)) {
} else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV730) ||
((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740)) {
RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
DRM_INFO("Loading RV730 PFP Microcode\n");
DRM_INFO("Loading RV730/RV740 PFP Microcode\n");
for (i = 0; i < R700_PFP_UCODE_SIZE; i++)
RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV730_pfp_microcode[i]);
RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0);
RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
DRM_INFO("Loading RV730 CP Microcode\n");
DRM_INFO("Loading RV730/RV740 CP Microcode\n");
for (i = 0; i < R700_PM4_UCODE_SIZE; i++)
RADEON_WRITE(R600_CP_ME_RAM_DATA, RV730_cp_microcode[i]);
RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0);
@ -1324,6 +1325,10 @@ static void r700_gfx_init(struct drm_device *dev,
dev_priv->r700_sc_prim_fifo_size = 0xf9;
dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
if (dev_priv->r600_sx_max_export_pos_size > 16) {
dev_priv->r600_sx_max_export_pos_size -= 16;
dev_priv->r600_sx_max_export_smx_size += 16;
}
break;
case CHIP_RV710:
dev_priv->r600_max_pipes = 2;
@ -1345,6 +1350,31 @@ static void r700_gfx_init(struct drm_device *dev,
dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
break;
case CHIP_RV740:
dev_priv->r600_max_pipes = 4;
dev_priv->r600_max_tile_pipes = 4;
dev_priv->r600_max_simds = 8;
dev_priv->r600_max_backends = 4;
dev_priv->r600_max_gprs = 256;
dev_priv->r600_max_threads = 248;
dev_priv->r600_max_stack_entries = 512;
dev_priv->r600_max_hw_contexts = 8;
dev_priv->r600_max_gs_threads = 16 * 2;
dev_priv->r600_sx_max_export_size = 256;
dev_priv->r600_sx_max_export_pos_size = 32;
dev_priv->r600_sx_max_export_smx_size = 224;
dev_priv->r600_sq_num_cf_insts = 2;
dev_priv->r700_sx_num_of_sets = 7;
dev_priv->r700_sc_prim_fifo_size = 0x100;
dev_priv->r700_sc_hiz_tile_fifo_size = 0x30;
dev_priv->r700_sc_earlyz_tile_fifo_fize = 0x130;
if (dev_priv->r600_sx_max_export_pos_size > 16) {
dev_priv->r600_sx_max_export_pos_size -= 16;
dev_priv->r600_sx_max_export_smx_size += 16;
}
break;
default:
break;
}
@ -1493,6 +1523,7 @@ static void r700_gfx_init(struct drm_device *dev,
break;
case CHIP_RV730:
case CHIP_RV710:
case CHIP_RV740:
default:
sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4);
break;
@ -1569,6 +1600,7 @@ static void r700_gfx_init(struct drm_device *dev,
switch (dev_priv->flags & RADEON_FAMILY_MASK) {
case CHIP_RV770:
case CHIP_RV730:
case CHIP_RV740:
gs_prim_buffer_depth = 384;
break;
case CHIP_RV710:

View file

@ -2109,7 +2109,7 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master)
/* prebuild the SAREA */
sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE);
ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER,
ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK,
&master_priv->sarea);
if (ret) {
DRM_ERROR("SAREA setup failed\n");

View file

@ -146,6 +146,7 @@ enum radeon_family {
CHIP_RV770,
CHIP_RV730,
CHIP_RV710,
CHIP_RV740,
CHIP_LAST,
};

View file

@ -195,10 +195,8 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
default:
vsg->state = dr_via_sg_init;
}
if (vsg->bounce_buffer) {
vfree(vsg->bounce_buffer);
vsg->bounce_buffer = NULL;
}
vfree(vsg->bounce_buffer);
vsg->bounce_buffer = NULL;
vsg->free_on_sequence = 0;
}

View file

@ -638,6 +638,24 @@ int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
}
EXPORT_SYMBOL(pnp_possible_config);
int pnp_range_reserved(resource_size_t start, resource_size_t end)
{
struct pnp_dev *dev;
struct pnp_resource *pnp_res;
resource_size_t *dev_start, *dev_end;
pnp_for_each_dev(dev) {
list_for_each_entry(pnp_res, &dev->resources, list) {
dev_start = &pnp_res->res.start;
dev_end = &pnp_res->res.end;
if (ranged_conflict(&start, &end, dev_start, dev_end))
return 1;
}
}
return 0;
}
EXPORT_SYMBOL(pnp_range_reserved);
/* format is: pnp_reserve_irq=irq1[,irq2] .... */
static int __init pnp_setup_reserve_irq(char *str)
{

View file

@ -86,7 +86,17 @@ struct drm_device;
#include "drm_os_linux.h"
#include "drm_hashtab.h"
#include "drm_mm.h"
#define DRM_UT_CORE 0x01
#define DRM_UT_DRIVER 0x02
#define DRM_UT_KMS 0x04
#define DRM_UT_MODE 0x08
extern void drm_ut_debug_printk(unsigned int request_level,
const char *prefix,
const char *function_name,
const char *format, ...);
/***********************************************************************/
/** \name DRM template customization defaults */
/*@{*/
@ -186,15 +196,57 @@ struct drm_device;
* \param arg arguments
*/
#if DRM_DEBUG_CODE
#define DRM_DEBUG(fmt, arg...) \
#define DRM_DEBUG(fmt, args...) \
do { \
if ( drm_debug ) \
printk(KERN_DEBUG \
"[" DRM_NAME ":%s] " fmt , \
__func__ , ##arg); \
drm_ut_debug_printk(DRM_UT_CORE, DRM_NAME, \
__func__, fmt, ##args); \
} while (0)
#define DRM_DEBUG_DRIVER(prefix, fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_DRIVER, prefix, \
__func__, fmt, ##args); \
} while (0)
#define DRM_DEBUG_KMS(prefix, fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_KMS, prefix, \
__func__, fmt, ##args); \
} while (0)
#define DRM_DEBUG_MODE(prefix, fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_MODE, prefix, \
__func__, fmt, ##args); \
} while (0)
#define DRM_LOG(fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_CORE, NULL, \
NULL, fmt, ##args); \
} while (0)
#define DRM_LOG_KMS(fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_KMS, NULL, \
NULL, fmt, ##args); \
} while (0)
#define DRM_LOG_MODE(fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_MODE, NULL, \
NULL, fmt, ##args); \
} while (0)
#define DRM_LOG_DRIVER(fmt, args...) \
do { \
drm_ut_debug_printk(DRM_UT_DRIVER, NULL, \
NULL, fmt, ##args); \
} while (0)
#else
#define DRM_DEBUG_DRIVER(prefix, fmt, args...) do { } while (0)
#define DRM_DEBUG_KMS(prefix, fmt, args...) do { } while (0)
#define DRM_DEBUG_MODE(prefix, fmt, args...) do { } while (0)
#define DRM_DEBUG(fmt, arg...) do { } while (0)
#define DRM_LOG(fmt, arg...) do { } while (0)
#define DRM_LOG_KMS(fmt, args...) do { } while (0)
#define DRM_LOG_MODE(fmt, arg...) do { } while (0)
#define DRM_LOG_DRIVER(fmt, arg...) do { } while (0)
#endif
#define DRM_PROC_LIMIT (PAGE_SIZE-80)
@ -237,15 +289,15 @@ struct drm_device;
* \param dev DRM device.
* \param filp file pointer of the caller.
*/
#define LOCK_TEST_WITH_RETURN( dev, file_priv ) \
do { \
if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock) || \
file_priv->master->lock.file_priv != file_priv) { \
#define LOCK_TEST_WITH_RETURN( dev, _file_priv ) \
do { \
if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) || \
_file_priv->master->lock.file_priv != _file_priv) { \
DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
__func__, _DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock),\
file_priv->master->lock.file_priv, file_priv); \
return -EINVAL; \
} \
__func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\
_file_priv->master->lock.file_priv, _file_priv); \
return -EINVAL; \
} \
} while (0)
/**
@ -502,26 +554,6 @@ struct drm_sigdata {
};
/*
* Generic memory manager structs
*/
struct drm_mm_node {
struct list_head fl_entry;
struct list_head ml_entry;
int free;
unsigned long start;
unsigned long size;
struct drm_mm *mm;
void *private;
};
struct drm_mm {
struct list_head fl_entry;
struct list_head ml_entry;
};
/**
* Kernel side of a mapping
*/
@ -1385,22 +1417,6 @@ extern char *drm_get_connector_status_name(enum drm_connector_status status);
extern int drm_sysfs_connector_add(struct drm_connector *connector);
extern void drm_sysfs_connector_remove(struct drm_connector *connector);
/*
* Basic memory manager support (drm_mm.c)
*/
extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
unsigned long size,
unsigned alignment);
extern void drm_mm_put_block(struct drm_mm_node * cur);
extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, unsigned long size,
unsigned alignment, int best_match);
extern int drm_mm_init(struct drm_mm *mm, unsigned long start, unsigned long size);
extern void drm_mm_takedown(struct drm_mm *mm);
extern int drm_mm_clean(struct drm_mm *mm);
extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);
extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
/* Graphics Execution Manager library functions (drm_gem.c) */
int drm_gem_init(struct drm_device *dev);
void drm_gem_destroy(struct drm_device *dev);
@ -1522,18 +1538,14 @@ static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area)
static __inline__ void *drm_calloc_large(size_t nmemb, size_t size)
{
u8 *addr;
if (size <= PAGE_SIZE)
if (size * nmemb <= PAGE_SIZE)
return kcalloc(nmemb, size, GFP_KERNEL);
addr = vmalloc(nmemb * size);
if (!addr)
if (size != 0 && nmemb > ULONG_MAX / size)
return NULL;
memset(addr, 0, nmemb * size);
return addr;
return __vmalloc(size * nmemb,
GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
}
static __inline void drm_free_large(void *ptr)

View file

@ -35,6 +35,8 @@
#ifndef DRM_HASHTAB_H
#define DRM_HASHTAB_H
#include <linux/list.h>
#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
struct drm_hash_item {

90
include/drm/drm_mm.h Normal file
View file

@ -0,0 +1,90 @@
/**************************************************************************
*
* Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. USA.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
**************************************************************************/
/*
* Authors:
* Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
*/
#ifndef _DRM_MM_H_
#define _DRM_MM_H_
/*
* Generic range manager structs
*/
#include <linux/list.h>
struct drm_mm_node {
struct list_head fl_entry;
struct list_head ml_entry;
int free;
unsigned long start;
unsigned long size;
struct drm_mm *mm;
void *private;
};
struct drm_mm {
struct list_head fl_entry;
struct list_head ml_entry;
struct list_head unused_nodes;
int num_unused;
spinlock_t unused_lock;
};
/*
* Basic range manager support (drm_mm.c)
*/
extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
unsigned long size,
unsigned alignment);
extern struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent,
unsigned long size,
unsigned alignment);
extern void drm_mm_put_block(struct drm_mm_node *cur);
extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
unsigned long size,
unsigned alignment,
int best_match);
extern int drm_mm_init(struct drm_mm *mm, unsigned long start,
unsigned long size);
extern void drm_mm_takedown(struct drm_mm *mm);
extern int drm_mm_clean(struct drm_mm *mm);
extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
extern int drm_mm_remove_space_from_tail(struct drm_mm *mm,
unsigned long size);
extern int drm_mm_add_space_to_tail(struct drm_mm *mm,
unsigned long size, int atomic);
extern int drm_mm_pre_get(struct drm_mm *mm);
static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
{
return block->mm;
}
#endif

View file

@ -254,6 +254,11 @@
{0x1002, 0x940A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
{0x1002, 0x940B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
{0x1002, 0x940F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
{0x1002, 0x94A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
{0x1002, 0x94A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
{0x1002, 0x94B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
{0x1002, 0x94B3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
{0x1002, 0x94B5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
@ -268,6 +273,8 @@
{0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
{0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x946B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x947A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
@ -536,4 +543,6 @@
{0x8086, 0xa001, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0xa011, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0x35e8, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0x0042, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0x8086, 0x0046, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \
{0, 0, 0}

View file

@ -446,6 +446,7 @@ int pnp_start_dev(struct pnp_dev *dev);
int pnp_stop_dev(struct pnp_dev *dev);
int pnp_activate_dev(struct pnp_dev *dev);
int pnp_disable_dev(struct pnp_dev *dev);
int pnp_range_reserved(resource_size_t start, resource_size_t end);
/* protocol helpers */
int pnp_is_active(struct pnp_dev *dev);
@ -476,6 +477,7 @@ static inline int pnp_start_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_range_reserved(resource_size_t start, resource_size_t end) { return 0;}
/* protocol helpers */
static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }