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: (151 commits)
  vga_switcheroo: disable default y by new rules.
  drm/nouveau: fix *staging* driver build with switcheroo off.
  drm/radeon: fix typo in Makefile
  vga_switcheroo: fix build on platforms with no ACPI
  drm/radeon: Fix printf type warning in 64bit system.
  drm/radeon/kms: bump the KMS version number for square tiling support.
  vga_switcheroo: initial implementation (v15)
  drm/radeon/kms: do not disable audio engine twice
  Revert "drm/radeon/kms: disable HDMI audio for now on rv710/rv730"
  drm/radeon/kms: do not preset audio stuff and start timer when not using audio
  drm/radeon: r100/r200 ums: block ability for userspace app to trash 0 page and beyond
  drm/ttm: fix function prototype to match implementation
  drm/radeon: use ALIGN instead of open coding it
  drm/radeon/kms: initialize set_surface_reg reg for rs600 asic
  drm/i915: Use a dmi quirk to skip a broken SDVO TV output.
  drm/i915: enable/disable LVDS port at DPMS time
  drm/i915: check for multiple write domains in pin_and_relocate
  drm/i915: clean-up i915_gem_flush_gpu_write_domain
  drm/i915: reuse i915_gpu_idle helper
  drm/i915: ensure lru ordering of fence_list
  ...

Fixed trivial conflicts in drivers/gpu/vga/Kconfig
This commit is contained in:
Linus Torvalds 2010-03-04 07:49:37 -08:00
commit 03a2c4d76c
146 changed files with 18032 additions and 6231 deletions

View File

@ -11,6 +11,9 @@
#include <asm/smp.h> #include <asm/smp.h>
#include "agp.h" #include "agp.h"
int intel_agp_enabled;
EXPORT_SYMBOL(intel_agp_enabled);
/* /*
* If we have Intel graphics, we're not going to have anything other than * If we have Intel graphics, we're not going to have anything other than
* an Intel IOMMU. So make the correct use of the PCI DMA API contingent * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
@ -65,6 +68,10 @@
#define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062 #define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062
#define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB 0x006a #define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB 0x006a
#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG 0x0046 #define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG 0x0046
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB 0x0100
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG 0x0102
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG 0x0106
/* cover 915 and 945 variants */ /* cover 915 and 945 variants */
#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
@ -99,7 +106,9 @@
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB) agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
extern int agp_memory_reserved; extern int agp_memory_reserved;
@ -148,6 +157,25 @@ extern int agp_memory_reserved;
#define INTEL_I7505_AGPCTRL 0x70 #define INTEL_I7505_AGPCTRL 0x70
#define INTEL_I7505_MCHCFG 0x50 #define INTEL_I7505_MCHCFG 0x50
#define SNB_GMCH_CTRL 0x50
#define SNB_GMCH_GMS_STOLEN_MASK 0xF8
#define SNB_GMCH_GMS_STOLEN_32M (1 << 3)
#define SNB_GMCH_GMS_STOLEN_64M (2 << 3)
#define SNB_GMCH_GMS_STOLEN_96M (3 << 3)
#define SNB_GMCH_GMS_STOLEN_128M (4 << 3)
#define SNB_GMCH_GMS_STOLEN_160M (5 << 3)
#define SNB_GMCH_GMS_STOLEN_192M (6 << 3)
#define SNB_GMCH_GMS_STOLEN_224M (7 << 3)
#define SNB_GMCH_GMS_STOLEN_256M (8 << 3)
#define SNB_GMCH_GMS_STOLEN_288M (9 << 3)
#define SNB_GMCH_GMS_STOLEN_320M (0xa << 3)
#define SNB_GMCH_GMS_STOLEN_352M (0xb << 3)
#define SNB_GMCH_GMS_STOLEN_384M (0xc << 3)
#define SNB_GMCH_GMS_STOLEN_416M (0xd << 3)
#define SNB_GMCH_GMS_STOLEN_448M (0xe << 3)
#define SNB_GMCH_GMS_STOLEN_480M (0xf << 3)
#define SNB_GMCH_GMS_STOLEN_512M (0x10 << 3)
static const struct aper_size_info_fixed intel_i810_sizes[] = static const struct aper_size_info_fixed intel_i810_sizes[] =
{ {
{64, 16384, 4}, {64, 16384, 4},
@ -294,6 +322,13 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem,
off_t pg_start, int mask_type) off_t pg_start, int mask_type)
{ {
int i, j; int i, j;
u32 cache_bits = 0;
if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
{
cache_bits = I830_PTE_SYSTEM_CACHED;
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge, writel(agp_bridge->driver->mask_memory(agp_bridge,
@ -614,7 +649,7 @@ static struct aper_size_info_fixed intel_i830_sizes[] =
static void intel_i830_init_gtt_entries(void) static void intel_i830_init_gtt_entries(void)
{ {
u16 gmch_ctrl; u16 gmch_ctrl;
int gtt_entries; int gtt_entries = 0;
u8 rdct; u8 rdct;
int local = 0; int local = 0;
static const int ddt[4] = { 0, 16, 32, 64 }; static const int ddt[4] = { 0, 16, 32, 64 };
@ -706,6 +741,63 @@ static void intel_i830_init_gtt_entries(void)
gtt_entries = 0; gtt_entries = 0;
break; break;
} }
} else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) {
/*
* SandyBridge has new memory control reg at 0x50.w
*/
u16 snb_gmch_ctl;
pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
case SNB_GMCH_GMS_STOLEN_32M:
gtt_entries = MB(32) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_64M:
gtt_entries = MB(64) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_96M:
gtt_entries = MB(96) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_128M:
gtt_entries = MB(128) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_160M:
gtt_entries = MB(160) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_192M:
gtt_entries = MB(192) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_224M:
gtt_entries = MB(224) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_256M:
gtt_entries = MB(256) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_288M:
gtt_entries = MB(288) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_320M:
gtt_entries = MB(320) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_352M:
gtt_entries = MB(352) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_384M:
gtt_entries = MB(384) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_416M:
gtt_entries = MB(416) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_448M:
gtt_entries = MB(448) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_480M:
gtt_entries = MB(480) - KB(size);
break;
case SNB_GMCH_GMS_STOLEN_512M:
gtt_entries = MB(512) - KB(size);
break;
}
} else { } else {
switch (gmch_ctrl & I855_GMCH_GMS_MASK) { switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
case I855_GMCH_GMS_STOLEN_1M: case I855_GMCH_GMS_STOLEN_1M:
@ -1357,6 +1449,8 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB: case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB: case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB: case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
*gtt_offset = *gtt_size = MB(2); *gtt_offset = *gtt_size = MB(2);
break; break;
default: default:
@ -2338,9 +2432,9 @@ static const struct intel_driver_description {
NULL, &intel_g33_driver }, NULL, &intel_g33_driver },
{ PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33", { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
NULL, &intel_g33_driver }, NULL, &intel_g33_driver },
{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "Pineview", { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "GMA3150",
NULL, &intel_g33_driver }, NULL, &intel_g33_driver },
{ PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "Pineview", { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "GMA3150",
NULL, &intel_g33_driver }, NULL, &intel_g33_driver },
{ PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0, { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
"GM45", NULL, &intel_i965_driver }, "GM45", NULL, &intel_i965_driver },
@ -2355,13 +2449,17 @@ static const struct intel_driver_description {
{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0, { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
"G41", NULL, &intel_i965_driver }, "G41", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0, { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0,
"Ironlake/D", NULL, &intel_i965_driver }, "HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0, { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
"Ironlake/M", NULL, &intel_i965_driver }, "HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0, { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
"Ironlake/MA", NULL, &intel_i965_driver }, "HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0, { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
"Ironlake/MC2", NULL, &intel_i965_driver }, "HD Graphics", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, 0,
"Sandybridge", NULL, &intel_i965_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, 0,
"Sandybridge", NULL, &intel_i965_driver },
{ 0, 0, 0, NULL, NULL, NULL } { 0, 0, 0, NULL, NULL, NULL }
}; };
@ -2371,7 +2469,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
struct agp_bridge_data *bridge; struct agp_bridge_data *bridge;
u8 cap_ptr = 0; u8 cap_ptr = 0;
struct resource *r; struct resource *r;
int i; int i, err;
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
@ -2463,7 +2561,10 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
} }
pci_set_drvdata(pdev, bridge); pci_set_drvdata(pdev, bridge);
return agp_add_bridge(bridge); err = agp_add_bridge(bridge);
if (!err)
intel_agp_enabled = 1;
return err;
} }
static void __devexit agp_intel_remove(struct pci_dev *pdev) static void __devexit agp_intel_remove(struct pci_dev *pdev)
@ -2568,6 +2669,8 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB), ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB),
ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB),
ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB),
{ } { }
}; };

View File

@ -4,7 +4,7 @@
ccflags-y := -Iinclude/drm ccflags-y := -Iinclude/drm
drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_context.o drm_dma.o drm_drawable.o \ drm_context.o drm_dma.o drm_drawable.o \
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \

View File

@ -0,0 +1,184 @@
/**************************************************************************
*
* Copyright 2010 Pauli Nieminen.
* 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.
*
*
**************************************************************************/
/*
* Multipart buffer for coping data which is larger than the page size.
*
* Authors:
* Pauli Nieminen <suokkos-at-gmail-dot-com>
*/
#include "drm_buffer.h"
/**
* Allocate the drm buffer object.
*
* buf: Pointer to a pointer where the object is stored.
* size: The number of bytes to allocate.
*/
int drm_buffer_alloc(struct drm_buffer **buf, int size)
{
int nr_pages = size / PAGE_SIZE + 1;
int idx;
/* Allocating pointer table to end of structure makes drm_buffer
* variable sized */
*buf = kzalloc(sizeof(struct drm_buffer) + nr_pages*sizeof(char *),
GFP_KERNEL);
if (*buf == NULL) {
DRM_ERROR("Failed to allocate drm buffer object to hold"
" %d bytes in %d pages.\n",
size, nr_pages);
return -ENOMEM;
}
(*buf)->size = size;
for (idx = 0; idx < nr_pages; ++idx) {
(*buf)->data[idx] =
kmalloc(min(PAGE_SIZE, size - idx * PAGE_SIZE),
GFP_KERNEL);
if ((*buf)->data[idx] == NULL) {
DRM_ERROR("Failed to allocate %dth page for drm"
" buffer with %d bytes and %d pages.\n",
idx + 1, size, nr_pages);
goto error_out;
}
}
return 0;
error_out:
/* Only last element can be null pointer so check for it first. */
if ((*buf)->data[idx])
kfree((*buf)->data[idx]);
for (--idx; idx >= 0; --idx)
kfree((*buf)->data[idx]);
kfree(*buf);
return -ENOMEM;
}
EXPORT_SYMBOL(drm_buffer_alloc);
/**
* Copy the user data to the begin of the buffer and reset the processing
* iterator.
*
* user_data: A pointer the data that is copied to the buffer.
* size: The Number of bytes to copy.
*/
extern int drm_buffer_copy_from_user(struct drm_buffer *buf,
void __user *user_data, int size)
{
int nr_pages = size / PAGE_SIZE + 1;
int idx;
if (size > buf->size) {
DRM_ERROR("Requesting to copy %d bytes to a drm buffer with"
" %d bytes space\n",
size, buf->size);
return -EFAULT;
}
for (idx = 0; idx < nr_pages; ++idx) {
if (DRM_COPY_FROM_USER(buf->data[idx],
user_data + idx * PAGE_SIZE,
min(PAGE_SIZE, size - idx * PAGE_SIZE))) {
DRM_ERROR("Failed to copy user data (%p) to drm buffer"
" (%p) %dth page.\n",
user_data, buf, idx);
return -EFAULT;
}
}
buf->iterator = 0;
return 0;
}
EXPORT_SYMBOL(drm_buffer_copy_from_user);
/**
* Free the drm buffer object
*/
void drm_buffer_free(struct drm_buffer *buf)
{
if (buf != NULL) {
int nr_pages = buf->size / PAGE_SIZE + 1;
int idx;
for (idx = 0; idx < nr_pages; ++idx)
kfree(buf->data[idx]);
kfree(buf);
}
}
EXPORT_SYMBOL(drm_buffer_free);
/**
* Read an object from buffer that may be split to multiple parts. If object
* is not split function just returns the pointer to object in buffer. But in
* case of split object data is copied to given stack object that is suplied
* by caller.
*
* The processing location of the buffer is also advanced to the next byte
* after the object.
*
* objsize: The size of the objet in bytes.
* stack_obj: A pointer to a memory location where object can be copied.
*/
void *drm_buffer_read_object(struct drm_buffer *buf,
int objsize, void *stack_obj)
{
int idx = drm_buffer_index(buf);
int page = drm_buffer_page(buf);
void *obj = 0;
if (idx + objsize <= PAGE_SIZE) {
obj = &buf->data[page][idx];
} else {
/* The object is split which forces copy to temporary object.*/
int beginsz = PAGE_SIZE - idx;
memcpy(stack_obj, &buf->data[page][idx], beginsz);
memcpy(stack_obj + beginsz, &buf->data[page + 1][0],
objsize - beginsz);
obj = stack_obj;
}
drm_buffer_advance(buf, objsize);
return obj;
}
EXPORT_SYMBOL(drm_buffer_read_object);

View File

@ -836,11 +836,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
mode_changed = true; mode_changed = true;
} else if (set->fb == NULL) { } else if (set->fb == NULL) {
mode_changed = true; mode_changed = true;
} else if ((set->fb->bits_per_pixel != } else
set->crtc->fb->bits_per_pixel) ||
set->fb->depth != set->crtc->fb->depth)
fb_changed = true;
else
fb_changed = true; fb_changed = true;
} }

View File

@ -125,28 +125,28 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW) DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
}; };
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )

View File

@ -60,8 +60,7 @@
#define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) #define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5)
/* use +hsync +vsync for detailed mode */ /* use +hsync +vsync for detailed mode */
#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6)
/* define the number of Extension EDID block */
#define MAX_EDID_EXT_NUM 4
#define LEVEL_DMT 0 #define LEVEL_DMT 0
#define LEVEL_GTF 1 #define LEVEL_GTF 1
@ -114,14 +113,14 @@ static const u8 edid_header[] = {
}; };
/** /**
* edid_is_valid - sanity check EDID data * drm_edid_is_valid - sanity check EDID data
* @edid: EDID data * @edid: EDID data
* *
* Sanity check the EDID block by looking at the header, the version number * Sanity check the EDID block by looking at the header, the version number
* and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's * and the checksum. Return 0 if the EDID doesn't check out, or 1 if it's
* valid. * valid.
*/ */
static bool edid_is_valid(struct edid *edid) bool drm_edid_is_valid(struct edid *edid)
{ {
int i, score = 0; int i, score = 0;
u8 csum = 0; u8 csum = 0;
@ -163,6 +162,7 @@ static bool edid_is_valid(struct edid *edid)
} }
return 0; return 0;
} }
EXPORT_SYMBOL(drm_edid_is_valid);
/** /**
* edid_vendor - match a string against EDID's obfuscated vendor field * edid_vendor - match a string against EDID's obfuscated vendor field
@ -1112,8 +1112,8 @@ static int add_detailed_info_eedid(struct drm_connector *connector,
} }
/* Chose real EDID extension number */ /* Chose real EDID extension number */
edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ? edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
MAX_EDID_EXT_NUM : edid->extensions; DRM_MAX_EDID_EXT_NUM : edid->extensions;
/* Find CEA extension */ /* Find CEA extension */
for (i = 0; i < edid_ext_num; i++) { for (i = 0; i < edid_ext_num; i++) {
@ -1195,7 +1195,7 @@ static int drm_ddc_read_edid(struct drm_connector *connector,
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (drm_do_probe_ddc_edid(adapter, buf, len)) if (drm_do_probe_ddc_edid(adapter, buf, len))
return -1; return -1;
if (edid_is_valid((struct edid *)buf)) if (drm_edid_is_valid((struct edid *)buf))
return 0; return 0;
} }
@ -1220,7 +1220,7 @@ struct edid *drm_get_edid(struct drm_connector *connector,
int ret; int ret;
struct edid *edid; struct edid *edid;
edid = kmalloc(EDID_LENGTH * (MAX_EDID_EXT_NUM + 1), edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
GFP_KERNEL); GFP_KERNEL);
if (edid == NULL) { if (edid == NULL) {
dev_warn(&connector->dev->pdev->dev, dev_warn(&connector->dev->pdev->dev,
@ -1238,14 +1238,14 @@ struct edid *drm_get_edid(struct drm_connector *connector,
if (edid->extensions != 0) { if (edid->extensions != 0) {
int edid_ext_num = edid->extensions; int edid_ext_num = edid->extensions;
if (edid_ext_num > MAX_EDID_EXT_NUM) { if (edid_ext_num > DRM_MAX_EDID_EXT_NUM) {
dev_warn(&connector->dev->pdev->dev, dev_warn(&connector->dev->pdev->dev,
"The number of extension(%d) is " "The number of extension(%d) is "
"over max (%d), actually read number (%d)\n", "over max (%d), actually read number (%d)\n",
edid_ext_num, MAX_EDID_EXT_NUM, edid_ext_num, DRM_MAX_EDID_EXT_NUM,
MAX_EDID_EXT_NUM); DRM_MAX_EDID_EXT_NUM);
/* Reset EDID extension number to be read */ /* Reset EDID extension number to be read */
edid_ext_num = MAX_EDID_EXT_NUM; edid_ext_num = DRM_MAX_EDID_EXT_NUM;
} }
/* Read EDID including extensions too */ /* Read EDID including extensions too */
ret = drm_ddc_read_edid(connector, adapter, (char *)edid, ret = drm_ddc_read_edid(connector, adapter, (char *)edid,
@ -1288,8 +1288,8 @@ bool drm_detect_hdmi_monitor(struct edid *edid)
goto end; goto end;
/* Chose real EDID extension number */ /* Chose real EDID extension number */
edid_ext_num = edid->extensions > MAX_EDID_EXT_NUM ? edid_ext_num = edid->extensions > DRM_MAX_EDID_EXT_NUM ?
MAX_EDID_EXT_NUM : edid->extensions; DRM_MAX_EDID_EXT_NUM : edid->extensions;
/* Find CEA extension */ /* Find CEA extension */
for (i = 0; i < edid_ext_num; i++) { for (i = 0; i < edid_ext_num; i++) {
@ -1346,7 +1346,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
if (edid == NULL) { if (edid == NULL) {
return 0; return 0;
} }
if (!edid_is_valid(edid)) { if (!drm_edid_is_valid(edid)) {
dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
drm_get_connector_name(connector)); drm_get_connector_name(connector));
return 0; return 0;

View File

@ -27,6 +27,7 @@
* Dave Airlie <airlied@linux.ie> * Dave Airlie <airlied@linux.ie>
* Jesse Barnes <jesse.barnes@intel.com> * Jesse Barnes <jesse.barnes@intel.com>
*/ */
#include <linux/kernel.h>
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/fb.h> #include <linux/fb.h>
#include "drmP.h" #include "drmP.h"
@ -50,21 +51,6 @@ int drm_fb_helper_add_connector(struct drm_connector *connector)
} }
EXPORT_SYMBOL(drm_fb_helper_add_connector); EXPORT_SYMBOL(drm_fb_helper_add_connector);
static int my_atoi(const char *name)
{
int val = 0;
for (;; name++) {
switch (*name) {
case '0' ... '9':
val = 10*val+(*name-'0');
break;
default:
return val;
}
}
}
/** /**
* drm_fb_helper_connector_parse_command_line - parse command line for connector * drm_fb_helper_connector_parse_command_line - parse command line for connector
* @connector - connector to parse line for * @connector - connector to parse line for
@ -111,7 +97,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
namelen = i; namelen = i;
if (!refresh_specified && !bpp_specified && if (!refresh_specified && !bpp_specified &&
!yres_specified) { !yres_specified) {
refresh = my_atoi(&name[i+1]); refresh = simple_strtol(&name[i+1], NULL, 10);
refresh_specified = 1; refresh_specified = 1;
if (cvt || rb) if (cvt || rb)
cvt = 0; cvt = 0;
@ -121,7 +107,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
case '-': case '-':
namelen = i; namelen = i;
if (!bpp_specified && !yres_specified) { if (!bpp_specified && !yres_specified) {
bpp = my_atoi(&name[i+1]); bpp = simple_strtol(&name[i+1], NULL, 10);
bpp_specified = 1; bpp_specified = 1;
if (cvt || rb) if (cvt || rb)
cvt = 0; cvt = 0;
@ -130,7 +116,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
break; break;
case 'x': case 'x':
if (!yres_specified) { if (!yres_specified) {
yres = my_atoi(&name[i+1]); yres = simple_strtol(&name[i+1], NULL, 10);
yres_specified = 1; yres_specified = 1;
} else } else
goto done; goto done;
@ -170,7 +156,7 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
} }
} }
if (i < 0 && yres_specified) { if (i < 0 && yres_specified) {
xres = my_atoi(name); xres = simple_strtol(name, NULL, 10);
res_specified = 1; res_specified = 1;
} }
done: done:
@ -694,7 +680,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
int i; int i;
if (var->pixclock != 0) { if (var->pixclock != 0) {
DRM_ERROR("PIXEL CLCOK SET\n"); DRM_ERROR("PIXEL CLOCK SET\n");
return -EINVAL; return -EINVAL;
} }

View File

@ -192,9 +192,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
idr_remove(&filp->object_idr, handle); idr_remove(&filp->object_idr, handle);
spin_unlock(&filp->table_lock); spin_unlock(&filp->table_lock);
mutex_lock(&dev->struct_mutex); drm_gem_object_handle_unreference_unlocked(obj);
drm_gem_object_handle_unreference(obj);
mutex_unlock(&dev->struct_mutex);
return 0; return 0;
} }
@ -325,9 +323,7 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
} }
err: err:
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(obj);
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
return ret; return ret;
} }
@ -358,9 +354,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
return -ENOENT; return -ENOENT;
ret = drm_gem_handle_create(file_priv, obj, &handle); ret = drm_gem_handle_create(file_priv, obj, &handle);
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(obj);
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
if (ret) if (ret)
return ret; return ret;
@ -390,7 +384,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
{ {
struct drm_gem_object *obj = ptr; struct drm_gem_object *obj = ptr;
drm_gem_object_handle_unreference(obj); drm_gem_object_handle_unreference_unlocked(obj);
return 0; return 0;
} }
@ -403,16 +397,25 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
void void
drm_gem_release(struct drm_device *dev, struct drm_file *file_private) drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
{ {
mutex_lock(&dev->struct_mutex);
idr_for_each(&file_private->object_idr, idr_for_each(&file_private->object_idr,
&drm_gem_object_release_handle, NULL); &drm_gem_object_release_handle, NULL);
idr_destroy(&file_private->object_idr); idr_destroy(&file_private->object_idr);
mutex_unlock(&dev->struct_mutex); }
static void
drm_gem_object_free_common(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
fput(obj->filp);
atomic_dec(&dev->object_count);
atomic_sub(obj->size, &dev->object_memory);
kfree(obj);
} }
/** /**
* Called after the last reference to the object has been lost. * Called after the last reference to the object has been lost.
* Must be called holding struct_ mutex
* *
* Frees the object * Frees the object
*/ */
@ -427,13 +430,39 @@ drm_gem_object_free(struct kref *kref)
if (dev->driver->gem_free_object != NULL) if (dev->driver->gem_free_object != NULL)
dev->driver->gem_free_object(obj); dev->driver->gem_free_object(obj);
fput(obj->filp); drm_gem_object_free_common(obj);
atomic_dec(&dev->object_count);
atomic_sub(obj->size, &dev->object_memory);
kfree(obj);
} }
EXPORT_SYMBOL(drm_gem_object_free); EXPORT_SYMBOL(drm_gem_object_free);
/**
* Called after the last reference to the object has been lost.
* Must be called without holding struct_mutex
*
* Frees the object
*/
void
drm_gem_object_free_unlocked(struct kref *kref)
{
struct drm_gem_object *obj = (struct drm_gem_object *) kref;
struct drm_device *dev = obj->dev;
if (dev->driver->gem_free_object_unlocked != NULL)
dev->driver->gem_free_object_unlocked(obj);
else if (dev->driver->gem_free_object != NULL) {
mutex_lock(&dev->struct_mutex);
dev->driver->gem_free_object(obj);
mutex_unlock(&dev->struct_mutex);
}
drm_gem_object_free_common(obj);
}
EXPORT_SYMBOL(drm_gem_object_free_unlocked);
static void drm_gem_object_ref_bug(struct kref *list_kref)
{
BUG();
}
/** /**
* Called after the last handle to the object has been closed * Called after the last handle to the object has been closed
* *
@ -458,8 +487,10 @@ drm_gem_object_handle_free(struct kref *kref)
/* /*
* The object name held a reference to this object, drop * The object name held a reference to this object, drop
* that now. * that now.
*
* This cannot be the last reference, since the handle holds one too.
*/ */
drm_gem_object_unreference(obj); kref_put(&obj->refcount, drm_gem_object_ref_bug);
} else } else
spin_unlock(&dev->object_name_lock); spin_unlock(&dev->object_name_lock);
@ -477,11 +508,8 @@ EXPORT_SYMBOL(drm_gem_vm_open);
void drm_gem_vm_close(struct vm_area_struct *vma) void drm_gem_vm_close(struct vm_area_struct *vma)
{ {
struct drm_gem_object *obj = vma->vm_private_data; struct drm_gem_object *obj = vma->vm_private_data;
struct drm_device *dev = obj->dev;
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(obj);
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
} }
EXPORT_SYMBOL(drm_gem_vm_close); EXPORT_SYMBOL(drm_gem_vm_close);

View File

@ -162,7 +162,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
if (!IS_IRONLAKE(dev)) { if (!HAS_PCH_SPLIT(dev)) {
seq_printf(m, "Interrupt enable: %08x\n", seq_printf(m, "Interrupt enable: %08x\n",
I915_READ(IER)); I915_READ(IER));
seq_printf(m, "Interrupt identity: %08x\n", seq_printf(m, "Interrupt identity: %08x\n",
@ -350,6 +350,36 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
return 0; return 0;
} }
static const char *pin_flag(int pinned)
{
if (pinned > 0)
return " P";
else if (pinned < 0)
return " p";
else
return "";
}
static const char *tiling_flag(int tiling)
{
switch (tiling) {
default:
case I915_TILING_NONE: return "";
case I915_TILING_X: return " X";
case I915_TILING_Y: return " Y";
}
}
static const char *dirty_flag(int dirty)
{
return dirty ? " dirty" : "";
}
static const char *purgeable_flag(int purgeable)
{
return purgeable ? " purgeable" : "";
}
static int i915_error_state(struct seq_file *m, void *unused) static int i915_error_state(struct seq_file *m, void *unused)
{ {
struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_info_node *node = (struct drm_info_node *) m->private;
@ -357,6 +387,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_error_state *error; struct drm_i915_error_state *error;
unsigned long flags; unsigned long flags;
int i, page, offset, elt;
spin_lock_irqsave(&dev_priv->error_lock, flags); spin_lock_irqsave(&dev_priv->error_lock, flags);
if (!dev_priv->first_error) { if (!dev_priv->first_error) {
@ -368,6 +399,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
error->time.tv_usec); error->time.tv_usec);
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
seq_printf(m, "EIR: 0x%08x\n", error->eir); seq_printf(m, "EIR: 0x%08x\n", error->eir);
seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er); seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm); seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
@ -379,6 +411,59 @@ static int i915_error_state(struct seq_file *m, void *unused)
seq_printf(m, " INSTPS: 0x%08x\n", error->instps); seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1); seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
} }
seq_printf(m, "seqno: 0x%08x\n", error->seqno);
if (error->active_bo_count) {
seq_printf(m, "Buffers [%d]:\n", error->active_bo_count);
for (i = 0; i < error->active_bo_count; i++) {
seq_printf(m, " %08x %8zd %08x %08x %08x%s%s%s%s",
error->active_bo[i].gtt_offset,
error->active_bo[i].size,
error->active_bo[i].read_domains,
error->active_bo[i].write_domain,
error->active_bo[i].seqno,
pin_flag(error->active_bo[i].pinned),
tiling_flag(error->active_bo[i].tiling),
dirty_flag(error->active_bo[i].dirty),
purgeable_flag(error->active_bo[i].purgeable));
if (error->active_bo[i].name)
seq_printf(m, " (name: %d)", error->active_bo[i].name);
if (error->active_bo[i].fence_reg != I915_FENCE_REG_NONE)
seq_printf(m, " (fence: %d)", error->active_bo[i].fence_reg);
seq_printf(m, "\n");
}
}
for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) {
if (error->batchbuffer[i]) {
struct drm_i915_error_object *obj = error->batchbuffer[i];
seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset);
offset = 0;
for (page = 0; page < obj->page_count; page++) {
for (elt = 0; elt < PAGE_SIZE/4; elt++) {
seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]);
offset += 4;
}
}
}
}
if (error->ringbuffer) {
struct drm_i915_error_object *obj = error->ringbuffer;
seq_printf(m, "--- ringbuffer = 0x%08x\n", obj->gtt_offset);
offset = 0;
for (page = 0; page < obj->page_count; page++) {
for (elt = 0; elt < PAGE_SIZE/4; elt++) {
seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]);
offset += 4;
}
}
}
out: out:
spin_unlock_irqrestore(&dev_priv->error_lock, flags); spin_unlock_irqrestore(&dev_priv->error_lock, flags);
@ -386,6 +471,165 @@ static int i915_error_state(struct seq_file *m, void *unused)
return 0; return 0;
} }
static int i915_rstdby_delays(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u16 crstanddelay = I915_READ16(CRSTANDVID);
seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f));
return 0;
}
static int i915_cur_delayinfo(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u16 rgvswctl = I915_READ16(MEMSWCTL);
seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3);
seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1);
seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf,
rgvswctl & 0x3f);
return 0;
}
static int i915_delayfreq_table(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u32 delayfreq;
int i;
for (i = 0; i < 16; i++) {
delayfreq = I915_READ(PXVFREQ_BASE + i * 4);
seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq);
}
return 0;
}
static inline int MAP_TO_MV(int map)
{
return 1250 - (map * 25);
}
static int i915_inttoext_table(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u32 inttoext;
int i;
for (i = 1; i <= 32; i++) {
inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4);
seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext);
}
return 0;
}
static int i915_drpc_info(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u32 rgvmodectl = I915_READ(MEMMODECTL);
seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
"yes" : "no");
seq_printf(m, "Boost freq: %d\n",
(rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >>
MEMMODE_BOOST_FREQ_SHIFT);
seq_printf(m, "HW control enabled: %s\n",
rgvmodectl & MEMMODE_HWIDLE_EN ? "yes" : "no");
seq_printf(m, "SW control enabled: %s\n",
rgvmodectl & MEMMODE_SWMODE_EN ? "yes" : "no");
seq_printf(m, "Gated voltage change: %s\n",
rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no");
seq_printf(m, "Starting frequency: P%d\n",
(rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
seq_printf(m, "Max frequency: P%d\n",
(rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT);
seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK));
return 0;
}
static int i915_fbc_status(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_crtc *crtc;
drm_i915_private_t *dev_priv = dev->dev_private;
bool fbc_enabled = false;
if (!dev_priv->display.fbc_enabled) {
seq_printf(m, "FBC unsupported on this chipset\n");
return 0;
}
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (!crtc->enabled)
continue;
if (dev_priv->display.fbc_enabled(crtc))
fbc_enabled = true;
}
if (fbc_enabled) {
seq_printf(m, "FBC enabled\n");
} else {
seq_printf(m, "FBC disabled: ");
switch (dev_priv->no_fbc_reason) {
case FBC_STOLEN_TOO_SMALL:
seq_printf(m, "not enough stolen memory");
break;
case FBC_UNSUPPORTED_MODE:
seq_printf(m, "mode not supported");
break;
case FBC_MODE_TOO_LARGE:
seq_printf(m, "mode too large");
break;
case FBC_BAD_PLANE:
seq_printf(m, "FBC unsupported on plane");
break;
case FBC_NOT_TILED:
seq_printf(m, "scanout buffer not tiled");
break;
default:
seq_printf(m, "unknown reason");
}
seq_printf(m, "\n");
}
return 0;
}
static int i915_sr_status(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
bool sr_enabled = false;
if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev))
sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
else if (IS_I915GM(dev))
sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
else if (IS_PINEVIEW(dev))
sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" :
"disabled");
return 0;
}
static int static int
i915_wedged_open(struct inode *inode, i915_wedged_open(struct inode *inode,
struct file *filp) struct file *filp)
@ -503,6 +747,13 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_ringbuffer_info", i915_ringbuffer_info, 0}, {"i915_ringbuffer_info", i915_ringbuffer_info, 0},
{"i915_batchbuffers", i915_batchbuffer_info, 0}, {"i915_batchbuffers", i915_batchbuffer_info, 0},
{"i915_error_state", i915_error_state, 0}, {"i915_error_state", i915_error_state, 0},
{"i915_rstdby_delays", i915_rstdby_delays, 0},
{"i915_cur_delayinfo", i915_cur_delayinfo, 0},
{"i915_delayfreq_table", i915_delayfreq_table, 0},
{"i915_inttoext_table", i915_inttoext_table, 0},
{"i915_drpc_info", i915_drpc_info, 0},
{"i915_fbc_status", i915_fbc_status, 0},
{"i915_sr_status", i915_sr_status, 0},
}; };
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)

View File

@ -35,6 +35,9 @@
#include "i915_drv.h" #include "i915_drv.h"
#include "i915_trace.h" #include "i915_trace.h"
#include <linux/vgaarb.h> #include <linux/vgaarb.h>
#include <linux/acpi.h>
#include <linux/pnp.h>
#include <linux/vga_switcheroo.h>
/* Really want an OS-independent resettable timer. Would like to have /* 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 * this loop run for (eg) 3 sec, but have the timer reset every time
@ -933,6 +936,120 @@ static int i915_get_bridge_dev(struct drm_device *dev)
return 0; return 0;
} }
#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)
{
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;
if (IS_I965G(dev))
pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
pci_read_config_dword(dev_priv->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 */
#ifdef CONFIG_PNP
if (mchbar_addr &&
pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
ret = 0;
goto out;
}
#endif
/* Get some space for it */
ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
MCHBAR_SIZE, MCHBAR_SIZE,
PCIBIOS_MIN_MEM,
0, pcibios_align_resource,
dev_priv->bridge_dev);
if (ret) {
DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret);
dev_priv->mch_res.start = 0;
goto out;
}
if (IS_I965G(dev))
pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
upper_32_bits(dev_priv->mch_res.start));
pci_write_config_dword(dev_priv->bridge_dev, reg,
lower_32_bits(dev_priv->mch_res.start));
out:
return ret;
}
/* Setup MCHBAR if possible, return true if we should disable it again */
static void
intel_setup_mchbar(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
bool enabled;
dev_priv->mchbar_need_disable = false;
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
enabled = !!(temp & DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
enabled = temp & 1;
}
/* If it's already enabled, don't have to do anything */
if (enabled)
return;
if (intel_alloc_mchbar_resource(dev))
return;
dev_priv->mchbar_need_disable = true;
/* Space is allocated or reserved, so enable it. */
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
temp | DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
}
}
static void
intel_teardown_mchbar(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
if (dev_priv->mchbar_need_disable) {
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
temp &= ~DEVEN_MCHBAR_EN;
pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
} else {
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
temp &= ~1;
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
}
}
if (dev_priv->mch_res.start)
release_resource(&dev_priv->mch_res);
}
/** /**
* i915_probe_agp - get AGP bootup configuration * i915_probe_agp - get AGP bootup configuration
* @pdev: PCI device * @pdev: PCI device
@ -978,59 +1095,123 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
* Some of the preallocated space is taken by the GTT * Some of the preallocated space is taken by the GTT
* and popup. GTT is 1K per MB of aperture size, and popup is 4K. * and popup. GTT is 1K per MB of aperture size, and popup is 4K.
*/ */
if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev)) if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev))
overhead = 4096; overhead = 4096;
else else
overhead = (*aperture_size / 1024) + 4096; overhead = (*aperture_size / 1024) + 4096;
switch (tmp & INTEL_GMCH_GMS_MASK) { if (IS_GEN6(dev)) {
case INTEL_855_GMCH_GMS_DISABLED: /* SNB has memory control reg at 0x50.w */
DRM_ERROR("video memory is disabled\n"); pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &tmp);
return -1;
case INTEL_855_GMCH_GMS_STOLEN_1M: switch (tmp & SNB_GMCH_GMS_STOLEN_MASK) {
stolen = 1 * 1024 * 1024; case INTEL_855_GMCH_GMS_DISABLED:
break; DRM_ERROR("video memory is disabled\n");
case INTEL_855_GMCH_GMS_STOLEN_4M: return -1;
stolen = 4 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_32M:
break; stolen = 32 * 1024 * 1024;
case INTEL_855_GMCH_GMS_STOLEN_8M: break;
stolen = 8 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_64M:
break; stolen = 64 * 1024 * 1024;
case INTEL_855_GMCH_GMS_STOLEN_16M: break;
stolen = 16 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_96M:
break; stolen = 96 * 1024 * 1024;
case INTEL_855_GMCH_GMS_STOLEN_32M: break;
stolen = 32 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_128M:
break; stolen = 128 * 1024 * 1024;
case INTEL_915G_GMCH_GMS_STOLEN_48M: break;
stolen = 48 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_160M:
break; stolen = 160 * 1024 * 1024;
case INTEL_915G_GMCH_GMS_STOLEN_64M: break;
stolen = 64 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_192M:
break; stolen = 192 * 1024 * 1024;
case INTEL_GMCH_GMS_STOLEN_128M: break;
stolen = 128 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_224M:
break; stolen = 224 * 1024 * 1024;
case INTEL_GMCH_GMS_STOLEN_256M: break;
stolen = 256 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_256M:
break; stolen = 256 * 1024 * 1024;
case INTEL_GMCH_GMS_STOLEN_96M: break;
stolen = 96 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_288M:
break; stolen = 288 * 1024 * 1024;
case INTEL_GMCH_GMS_STOLEN_160M: break;
stolen = 160 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_320M:
break; stolen = 320 * 1024 * 1024;
case INTEL_GMCH_GMS_STOLEN_224M: break;
stolen = 224 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_352M:
break; stolen = 352 * 1024 * 1024;
case INTEL_GMCH_GMS_STOLEN_352M: break;
stolen = 352 * 1024 * 1024; case SNB_GMCH_GMS_STOLEN_384M:
break; stolen = 384 * 1024 * 1024;
default: break;
DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", case SNB_GMCH_GMS_STOLEN_416M:
tmp & INTEL_GMCH_GMS_MASK); stolen = 416 * 1024 * 1024;
return -1; break;
case SNB_GMCH_GMS_STOLEN_448M:
stolen = 448 * 1024 * 1024;
break;
case SNB_GMCH_GMS_STOLEN_480M:
stolen = 480 * 1024 * 1024;
break;
case SNB_GMCH_GMS_STOLEN_512M:
stolen = 512 * 1024 * 1024;
break;
default:
DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
tmp & SNB_GMCH_GMS_STOLEN_MASK);
return -1;
}
} else {
switch (tmp & INTEL_GMCH_GMS_MASK) {
case INTEL_855_GMCH_GMS_DISABLED:
DRM_ERROR("video memory is disabled\n");
return -1;
case INTEL_855_GMCH_GMS_STOLEN_1M:
stolen = 1 * 1024 * 1024;
break;
case INTEL_855_GMCH_GMS_STOLEN_4M:
stolen = 4 * 1024 * 1024;
break;
case INTEL_855_GMCH_GMS_STOLEN_8M:
stolen = 8 * 1024 * 1024;
break;
case INTEL_855_GMCH_GMS_STOLEN_16M:
stolen = 16 * 1024 * 1024;
break;
case INTEL_855_GMCH_GMS_STOLEN_32M:
stolen = 32 * 1024 * 1024;
break;
case INTEL_915G_GMCH_GMS_STOLEN_48M:
stolen = 48 * 1024 * 1024;
break;
case INTEL_915G_GMCH_GMS_STOLEN_64M:
stolen = 64 * 1024 * 1024;
break;
case INTEL_GMCH_GMS_STOLEN_128M:
stolen = 128 * 1024 * 1024;
break;
case INTEL_GMCH_GMS_STOLEN_256M:
stolen = 256 * 1024 * 1024;
break;
case INTEL_GMCH_GMS_STOLEN_96M:
stolen = 96 * 1024 * 1024;
break;
case INTEL_GMCH_GMS_STOLEN_160M:
stolen = 160 * 1024 * 1024;
break;
case INTEL_GMCH_GMS_STOLEN_224M:
stolen = 224 * 1024 * 1024;
break;
case INTEL_GMCH_GMS_STOLEN_352M:
stolen = 352 * 1024 * 1024;
break;
default:
DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
tmp & INTEL_GMCH_GMS_MASK);
return -1;
}
} }
*preallocated_size = stolen - overhead; *preallocated_size = stolen - overhead;
*start = overhead; *start = overhead;
@ -1064,7 +1245,7 @@ static unsigned long i915_gtt_to_phys(struct drm_device *dev,
int gtt_offset, gtt_size; int gtt_offset, gtt_size;
if (IS_I965G(dev)) { if (IS_I965G(dev)) {
if (IS_G4X(dev) || IS_IRONLAKE(dev)) { if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
gtt_offset = 2*1024*1024; gtt_offset = 2*1024*1024;
gtt_size = 2*1024*1024; gtt_size = 2*1024*1024;
} else { } else {
@ -1133,6 +1314,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
/* Leave 1M for line length buffer & misc. */ /* Leave 1M for line length buffer & misc. */
compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0); compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
if (!compressed_fb) { if (!compressed_fb) {
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
i915_warn_stolen(dev); i915_warn_stolen(dev);
return; return;
} }
@ -1140,6 +1322,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
compressed_fb = drm_mm_get_block(compressed_fb, size, 4096); compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
if (!compressed_fb) { if (!compressed_fb) {
i915_warn_stolen(dev); i915_warn_stolen(dev);
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
return; return;
} }
@ -1199,6 +1382,32 @@ static unsigned int i915_vga_set_decode(void *cookie, bool state)
return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
} }
static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_INFO "i915: switched off\n");
/* i915 resume handler doesn't set to D0 */
pci_set_power_state(dev->pdev, PCI_D0);
i915_resume(dev);
} else {
printk(KERN_ERR "i915: switched off\n");
i915_suspend(dev, pmm);
}
}
static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
bool can_switch;
spin_lock(&dev->count_lock);
can_switch = (dev->open_count == 0);
spin_unlock(&dev->count_lock);
return can_switch;
}
static int i915_load_modeset_init(struct drm_device *dev, static int i915_load_modeset_init(struct drm_device *dev,
unsigned long prealloc_start, unsigned long prealloc_start,
unsigned long prealloc_size, unsigned long prealloc_size,
@ -1260,6 +1469,12 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (ret) if (ret)
goto destroy_ringbuffer; goto destroy_ringbuffer;
ret = vga_switcheroo_register_client(dev->pdev,
i915_switcheroo_set_state,
i915_switcheroo_can_switch);
if (ret)
goto destroy_ringbuffer;
intel_modeset_init(dev); intel_modeset_init(dev);
ret = drm_irq_install(dev); ret = drm_irq_install(dev);
@ -1281,7 +1496,9 @@ static int i915_load_modeset_init(struct drm_device *dev,
return 0; return 0;
destroy_ringbuffer: destroy_ringbuffer:
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev); i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
out: out:
return ret; return ret;
} }
@ -1445,11 +1662,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
if (IS_G4X(dev) || IS_IRONLAKE(dev)) { if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter; dev->driver->get_vblank_counter = gm45_get_vblank_counter;
} }
/* Try to make sure MCHBAR is enabled before poking at it */
intel_setup_mchbar(dev);
i915_gem_load(dev); i915_gem_load(dev);
/* Init HWS */ /* Init HWS */
@ -1523,6 +1743,8 @@ int i915_driver_unload(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
i915_destroy_error_state(dev);
destroy_workqueue(dev_priv->wq); destroy_workqueue(dev_priv->wq);
del_timer_sync(&dev_priv->hangcheck_timer); del_timer_sync(&dev_priv->hangcheck_timer);
@ -1544,6 +1766,7 @@ int i915_driver_unload(struct drm_device *dev)
dev_priv->child_dev_num = 0; dev_priv->child_dev_num = 0;
} }
drm_irq_uninstall(dev); drm_irq_uninstall(dev);
vga_switcheroo_unregister_client(dev->pdev);
vga_client_register(dev->pdev, NULL, NULL, NULL); vga_client_register(dev->pdev, NULL, NULL, NULL);
} }
@ -1569,6 +1792,8 @@ int i915_driver_unload(struct drm_device *dev)
intel_cleanup_overlay(dev); intel_cleanup_overlay(dev);
} }
intel_teardown_mchbar(dev);
pci_dev_put(dev_priv->bridge_dev); pci_dev_put(dev_priv->bridge_dev);
kfree(dev->dev_private); kfree(dev->dev_private);
@ -1611,6 +1836,7 @@ void i915_driver_lastclose(struct drm_device * dev)
if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
drm_fb_helper_restore(); drm_fb_helper_restore();
vga_switcheroo_process_delayed_switch();
return; return;
} }

View File

@ -49,6 +49,7 @@ unsigned int i915_lvds_downclock = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
static struct drm_driver driver; static struct drm_driver driver;
extern int intel_agp_enabled;
#define INTEL_VGA_DEVICE(id, info) { \ #define INTEL_VGA_DEVICE(id, info) { \
.class = PCI_CLASS_DISPLAY_VGA << 8, \ .class = PCI_CLASS_DISPLAY_VGA << 8, \
@ -136,6 +137,16 @@ const static struct intel_device_info intel_ironlake_m_info = {
.has_hotplug = 1, .has_hotplug = 1,
}; };
const static struct intel_device_info intel_sandybridge_d_info = {
.is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1,
.has_hotplug = 1,
};
const static struct intel_device_info intel_sandybridge_m_info = {
.is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1,
.has_hotplug = 1,
};
const static struct pci_device_id pciidlist[] = { const static struct pci_device_id pciidlist[] = {
INTEL_VGA_DEVICE(0x3577, &intel_i830_info), INTEL_VGA_DEVICE(0x3577, &intel_i830_info),
INTEL_VGA_DEVICE(0x2562, &intel_845g_info), INTEL_VGA_DEVICE(0x2562, &intel_845g_info),
@ -167,6 +178,8 @@ const static struct pci_device_id pciidlist[] = {
INTEL_VGA_DEVICE(0xa011, &intel_pineview_info), INTEL_VGA_DEVICE(0xa011, &intel_pineview_info),
INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info), INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info),
INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info), INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info),
INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info),
INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info),
{0, 0, 0} {0, 0, 0}
}; };
@ -201,7 +214,7 @@ static int i915_drm_freeze(struct drm_device *dev)
return 0; return 0;
} }
static int i915_suspend(struct drm_device *dev, pm_message_t state) int i915_suspend(struct drm_device *dev, pm_message_t state)
{ {
int error; int error;
@ -255,7 +268,7 @@ static int i915_drm_thaw(struct drm_device *dev)
return error; return error;
} }
static int i915_resume(struct drm_device *dev) int i915_resume(struct drm_device *dev)
{ {
if (pci_enable_device(dev->pdev)) if (pci_enable_device(dev->pdev))
return -EIO; return -EIO;
@ -546,6 +559,11 @@ static struct drm_driver driver = {
static int __init i915_init(void) static int __init i915_init(void)
{ {
if (!intel_agp_enabled) {
DRM_ERROR("drm/i915 can't work without intel_agp module!\n");
return -ENODEV;
}
driver.num_ioctls = i915_max_ioctl; driver.num_ioctls = i915_max_ioctl;
i915_gem_shrinker_init(); i915_gem_shrinker_init();
@ -571,6 +589,11 @@ static int __init i915_init(void)
driver.driver_features &= ~DRIVER_MODESET; driver.driver_features &= ~DRIVER_MODESET;
#endif #endif
if (!(driver.driver_features & DRIVER_MODESET)) {
driver.suspend = i915_suspend;
driver.resume = i915_resume;
}
return drm_init(&driver); return drm_init(&driver);
} }

View File

@ -150,7 +150,27 @@ struct drm_i915_error_state {
u32 instps; u32 instps;
u32 instdone1; u32 instdone1;
u32 seqno; u32 seqno;
u64 bbaddr;
struct timeval time; struct timeval time;
struct drm_i915_error_object {
int page_count;
u32 gtt_offset;
u32 *pages[0];
} *ringbuffer, *batchbuffer[2];
struct drm_i915_error_buffer {
size_t size;
u32 name;
u32 seqno;
u32 gtt_offset;
u32 read_domains;
u32 write_domain;
u32 fence_reg;
s32 pinned:2;
u32 tiling:2;
u32 dirty:1;
u32 purgeable:1;
} *active_bo;
u32 active_bo_count;
}; };
struct drm_i915_display_funcs { struct drm_i915_display_funcs {
@ -192,6 +212,14 @@ struct intel_device_info {
u8 cursor_needs_physical : 1; u8 cursor_needs_physical : 1;
}; };
enum no_fbc_reason {
FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
FBC_MODE_TOO_LARGE, /* mode too large for compression */
FBC_BAD_PLANE, /* fbc not supported on plane */
FBC_NOT_TILED, /* buffer not tiled */
};
typedef struct drm_i915_private { typedef struct drm_i915_private {
struct drm_device *dev; struct drm_device *dev;
@ -452,6 +480,7 @@ typedef struct drm_i915_private {
u32 savePIPEB_DATA_N1; u32 savePIPEB_DATA_N1;
u32 savePIPEB_LINK_M1; u32 savePIPEB_LINK_M1;
u32 savePIPEB_LINK_N1; u32 savePIPEB_LINK_N1;
u32 saveMCHBAR_RENDER_STANDBY;
struct { struct {
struct drm_mm gtt_space; struct drm_mm gtt_space;
@ -590,6 +619,14 @@ typedef struct drm_i915_private {
int child_dev_num; int child_dev_num;
struct child_device_config *child_dev; struct child_device_config *child_dev;
struct drm_connector *int_lvds_connector; struct drm_connector *int_lvds_connector;
bool mchbar_need_disable;
u8 cur_delay;
u8 min_delay;
u8 max_delay;
enum no_fbc_reason no_fbc_reason;
} drm_i915_private_t; } drm_i915_private_t;
/** driver private structure attached to each drm_gem_object */ /** driver private structure attached to each drm_gem_object */
@ -736,6 +773,8 @@ extern unsigned int i915_fbpercrtc;
extern unsigned int i915_powersave; extern unsigned int i915_powersave;
extern unsigned int i915_lvds_downclock; extern unsigned int i915_lvds_downclock;
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
extern void i915_save_display(struct drm_device *dev); extern void i915_save_display(struct drm_device *dev);
extern void i915_restore_display(struct drm_device *dev); extern void i915_restore_display(struct drm_device *dev);
extern int i915_master_create(struct drm_device *dev, struct drm_master *master); extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
@ -761,6 +800,7 @@ extern int i965_reset(struct drm_device *dev, u8 flags);
/* i915_irq.c */ /* i915_irq.c */
void i915_hangcheck_elapsed(unsigned long data); void i915_hangcheck_elapsed(unsigned long data);
void i915_destroy_error_state(struct drm_device *dev);
extern int i915_irq_emit(struct drm_device *dev, void *data, extern int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int i915_irq_wait(struct drm_device *dev, void *data, extern int i915_irq_wait(struct drm_device *dev, void *data,
@ -897,7 +937,8 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj);
void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj); void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj);
bool i915_tiling_ok(struct drm_device *dev, int stride, int size, bool i915_tiling_ok(struct drm_device *dev, int stride, int size,
int tiling_mode); int tiling_mode);
bool i915_obj_fenceable(struct drm_device *dev, struct drm_gem_object *obj); bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj,
int tiling_mode);
/* i915_gem_debug.c */ /* i915_gem_debug.c */
void i915_gem_dump_object(struct drm_gem_object *obj, int len, void i915_gem_dump_object(struct drm_gem_object *obj, int len,
@ -1026,7 +1067,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_845G(dev) ((dev)->pci_device == 0x2562) #define IS_845G(dev) ((dev)->pci_device == 0x2562)
#define IS_I85X(dev) ((dev)->pci_device == 0x3582) #define IS_I85X(dev) ((dev)->pci_device == 0x3582)
#define IS_I865G(dev) ((dev)->pci_device == 0x2572) #define IS_I865G(dev) ((dev)->pci_device == 0x2572)
#define IS_I8XX(dev) (INTEL_INFO(dev)->is_i8xx) #define IS_GEN2(dev) (INTEL_INFO(dev)->is_i8xx)
#define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g) #define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g)
#define IS_I915GM(dev) ((dev)->pci_device == 0x2592) #define IS_I915GM(dev) ((dev)->pci_device == 0x2592)
#define IS_I945G(dev) ((dev)->pci_device == 0x2772) #define IS_I945G(dev) ((dev)->pci_device == 0x2772)
@ -1045,8 +1086,29 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define IS_I9XX(dev) (INTEL_INFO(dev)->is_i9xx) #define IS_I9XX(dev) (INTEL_INFO(dev)->is_i9xx)
#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
#define IS_GEN3(dev) (IS_I915G(dev) || \
IS_I915GM(dev) || \
IS_I945G(dev) || \
IS_I945GM(dev) || \
IS_G33(dev) || \
IS_PINEVIEW(dev))
#define IS_GEN4(dev) ((dev)->pci_device == 0x2972 || \
(dev)->pci_device == 0x2982 || \
(dev)->pci_device == 0x2992 || \
(dev)->pci_device == 0x29A2 || \
(dev)->pci_device == 0x2A02 || \
(dev)->pci_device == 0x2A12 || \
(dev)->pci_device == 0x2E02 || \
(dev)->pci_device == 0x2E12 || \
(dev)->pci_device == 0x2E22 || \
(dev)->pci_device == 0x2E32 || \
(dev)->pci_device == 0x2A42 || \
(dev)->pci_device == 0x2E42)
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws) #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
#define IS_GEN6(dev) ((dev)->pci_device == 0x0102)
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte /* 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. * rows, which changed the alignment requirements and fence programming.
*/ */
@ -1067,6 +1129,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc) #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
#define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6) #define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
#define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) || \
IS_GEN6(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024) #define PRIMARY_RINGBUFFER_SIZE (128*1024)
#endif #endif

View File

@ -128,9 +128,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
return -ENOMEM; return -ENOMEM;
ret = drm_gem_handle_create(file_priv, obj, &handle); ret = drm_gem_handle_create(file_priv, obj, &handle);
mutex_lock(&dev->struct_mutex); drm_gem_object_handle_unreference_unlocked(obj);
drm_gem_object_handle_unreference(obj);
mutex_unlock(&dev->struct_mutex);
if (ret) if (ret)
return ret; return ret;
@ -488,7 +486,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
*/ */
if (args->offset > obj->size || args->size > obj->size || if (args->offset > obj->size || args->size > obj->size ||
args->offset + args->size > obj->size) { args->offset + args->size > obj->size) {
drm_gem_object_unreference(obj); drm_gem_object_unreference_unlocked(obj);
return -EINVAL; return -EINVAL;
} }
@ -501,7 +499,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
file_priv); file_priv);
} }
drm_gem_object_unreference(obj); drm_gem_object_unreference_unlocked(obj);
return ret; return ret;
} }
@ -961,7 +959,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
*/ */
if (args->offset > obj->size || args->size > obj->size || if (args->offset > obj->size || args->size > obj->size ||
args->offset + args->size > obj->size) { args->offset + args->size > obj->size) {
drm_gem_object_unreference(obj); drm_gem_object_unreference_unlocked(obj);
return -EINVAL; return -EINVAL;
} }
@ -995,7 +993,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
DRM_INFO("pwrite failed %d\n", ret); DRM_INFO("pwrite failed %d\n", ret);
#endif #endif
drm_gem_object_unreference(obj); drm_gem_object_unreference_unlocked(obj);
return ret; return ret;
} }
@ -1138,9 +1136,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
PROT_READ | PROT_WRITE, MAP_SHARED, PROT_READ | PROT_WRITE, MAP_SHARED,
args->offset); args->offset);
up_write(&current->mm->mmap_sem); up_write(&current->mm->mmap_sem);
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(obj);
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
if (IS_ERR((void *)addr)) if (IS_ERR((void *)addr))
return addr; return addr;
@ -1562,6 +1558,38 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
i915_verify_inactive(dev, __FILE__, __LINE__); i915_verify_inactive(dev, __FILE__, __LINE__);
} }
static void
i915_gem_process_flushing_list(struct drm_device *dev,
uint32_t flush_domains, uint32_t seqno)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv, *next;
list_for_each_entry_safe(obj_priv, next,
&dev_priv->mm.gpu_write_list,
gpu_write_list) {
struct drm_gem_object *obj = obj_priv->obj;
if ((obj->write_domain & flush_domains) ==
obj->write_domain) {
uint32_t old_write_domain = obj->write_domain;
obj->write_domain = 0;
list_del_init(&obj_priv->gpu_write_list);
i915_gem_object_move_to_active(obj, seqno);
/* update the fence lru list */
if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
list_move_tail(&obj_priv->fence_list,
&dev_priv->mm.fence_list);
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
old_write_domain);
}
}
}
/** /**
* Creates a new sequence number, emitting a write of it to the status page * Creates a new sequence number, emitting a write of it to the status page
* plus an interrupt, which will trigger i915_user_interrupt_handler. * plus an interrupt, which will trigger i915_user_interrupt_handler.
@ -1620,29 +1648,8 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
/* Associate any objects on the flushing list matching the write /* Associate any objects on the flushing list matching the write
* domain we're flushing with our flush. * domain we're flushing with our flush.
*/ */
if (flush_domains != 0) { if (flush_domains != 0)
struct drm_i915_gem_object *obj_priv, *next; i915_gem_process_flushing_list(dev, flush_domains, seqno);
list_for_each_entry_safe(obj_priv, next,
&dev_priv->mm.gpu_write_list,
gpu_write_list) {
struct drm_gem_object *obj = obj_priv->obj;
if ((obj->write_domain & flush_domains) ==
obj->write_domain) {
uint32_t old_write_domain = obj->write_domain;
obj->write_domain = 0;
list_del_init(&obj_priv->gpu_write_list);
i915_gem_object_move_to_active(obj, seqno);
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
old_write_domain);
}
}
}
if (!dev_priv->mm.suspended) { if (!dev_priv->mm.suspended) {
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
@ -1822,7 +1829,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible)
return -EIO; return -EIO;
if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) { if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
ier = I915_READ(DEIER) | I915_READ(GTIER); ier = I915_READ(DEIER) | I915_READ(GTIER);
else else
ier = I915_READ(IER); ier = I915_READ(IER);
@ -1991,6 +1998,7 @@ int
i915_gem_object_unbind(struct drm_gem_object *obj) i915_gem_object_unbind(struct drm_gem_object *obj)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private; struct drm_i915_gem_object *obj_priv = obj->driver_private;
int ret = 0; int ret = 0;
@ -2046,8 +2054,10 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
} }
/* Remove ourselves from the LRU list if present. */ /* Remove ourselves from the LRU list if present. */
spin_lock(&dev_priv->mm.active_list_lock);
if (!list_empty(&obj_priv->list)) if (!list_empty(&obj_priv->list))
list_del_init(&obj_priv->list); list_del_init(&obj_priv->list);
spin_unlock(&dev_priv->mm.active_list_lock);
if (i915_gem_object_is_purgeable(obj_priv)) if (i915_gem_object_is_purgeable(obj_priv))
i915_gem_object_truncate(obj); i915_gem_object_truncate(obj);
@ -2084,12 +2094,35 @@ i915_gem_find_inactive_object(struct drm_device *dev, int min_size)
return best ? best : first; return best ? best : first;
} }
static int
i915_gpu_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
bool lists_empty;
uint32_t seqno;
spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
list_empty(&dev_priv->mm.active_list);
spin_unlock(&dev_priv->mm.active_list_lock);
if (lists_empty)
return 0;
/* Flush everything onto the inactive list. */
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)
return -ENOMEM;
return i915_wait_request(dev, seqno);
}
static int static int
i915_gem_evict_everything(struct drm_device *dev) i915_gem_evict_everything(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
int ret; int ret;
uint32_t seqno;
bool lists_empty; bool lists_empty;
spin_lock(&dev_priv->mm.active_list_lock); spin_lock(&dev_priv->mm.active_list_lock);
@ -2102,12 +2135,7 @@ i915_gem_evict_everything(struct drm_device *dev)
return -ENOSPC; return -ENOSPC;
/* Flush everything (on to the inactive lists) and evict */ /* Flush everything (on to the inactive lists) and evict */
i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); ret = i915_gpu_idle(dev);
seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
if (seqno == 0)
return -ENOMEM;
ret = i915_wait_request(dev, seqno);
if (ret) if (ret)
return ret; return ret;
@ -2265,6 +2293,28 @@ i915_gem_object_get_pages(struct drm_gem_object *obj,
return 0; return 0;
} }
static void sandybridge_write_fence_reg(struct drm_i915_fence_reg *reg)
{
struct drm_gem_object *obj = reg->obj;
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int regnum = obj_priv->fence_reg;
uint64_t val;
val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) &
0xfffff000) << 32;
val |= obj_priv->gtt_offset & 0xfffff000;
val |= (uint64_t)((obj_priv->stride / 128) - 1) <<
SANDYBRIDGE_FENCE_PITCH_SHIFT;
if (obj_priv->tiling_mode == I915_TILING_Y)
val |= 1 << I965_FENCE_TILING_Y_SHIFT;
val |= I965_FENCE_REG_VALID;
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (regnum * 8), val);
}
static void i965_write_fence_reg(struct drm_i915_fence_reg *reg) static void i965_write_fence_reg(struct drm_i915_fence_reg *reg)
{ {
struct drm_gem_object *obj = reg->obj; struct drm_gem_object *obj = reg->obj;
@ -2361,6 +2411,58 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
} }
static int i915_find_fence_reg(struct drm_device *dev)
{
struct drm_i915_fence_reg *reg = NULL;
struct drm_i915_gem_object *obj_priv = NULL;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_gem_object *obj = NULL;
int i, avail, ret;
/* First try to find a free reg */
avail = 0;
for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
reg = &dev_priv->fence_regs[i];
if (!reg->obj)
return i;
obj_priv = reg->obj->driver_private;
if (!obj_priv->pin_count)
avail++;
}
if (avail == 0)
return -ENOSPC;
/* None available, try to steal one or wait for a user to finish */
i = I915_FENCE_REG_NONE;
list_for_each_entry(obj_priv, &dev_priv->mm.fence_list,
fence_list) {
obj = obj_priv->obj;
if (obj_priv->pin_count)
continue;
/* found one! */
i = obj_priv->fence_reg;
break;
}
BUG_ON(i == I915_FENCE_REG_NONE);
/* We only have a reference on obj from the active list. put_fence_reg
* might drop that one, causing a use-after-free in it. So hold a
* private reference to obj like the other callers of put_fence_reg
* (set_tiling ioctl) do. */
drm_gem_object_reference(obj);
ret = i915_gem_object_put_fence_reg(obj);
drm_gem_object_unreference(obj);
if (ret != 0)
return ret;
return i;
}
/** /**
* i915_gem_object_get_fence_reg - set up a fence reg for an object * i915_gem_object_get_fence_reg - set up a fence reg for an object
* @obj: object to map through a fence reg * @obj: object to map through a fence reg
@ -2381,8 +2483,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private; struct drm_i915_gem_object *obj_priv = obj->driver_private;
struct drm_i915_fence_reg *reg = NULL; struct drm_i915_fence_reg *reg = NULL;
struct drm_i915_gem_object *old_obj_priv = NULL; int ret;
int i, ret, avail;
/* Just update our place in the LRU if our fence is getting used. */ /* Just update our place in the LRU if our fence is getting used. */
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) { if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
@ -2410,86 +2511,27 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
break; break;
} }
/* First try to find a free reg */ ret = i915_find_fence_reg(dev);
avail = 0; if (ret < 0)
for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { return ret;
reg = &dev_priv->fence_regs[i];
if (!reg->obj)
break;
old_obj_priv = reg->obj->driver_private; obj_priv->fence_reg = ret;
if (!old_obj_priv->pin_count) reg = &dev_priv->fence_regs[obj_priv->fence_reg];
avail++;
}
/* None available, try to steal one or wait for a user to finish */
if (i == dev_priv->num_fence_regs) {
struct drm_gem_object *old_obj = NULL;
if (avail == 0)
return -ENOSPC;
list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list,
fence_list) {
old_obj = old_obj_priv->obj;
if (old_obj_priv->pin_count)
continue;
/* Take a reference, as otherwise the wait_rendering
* below may cause the object to get freed out from
* under us.
*/
drm_gem_object_reference(old_obj);
/* i915 uses fences for GPU access to tiled buffers */
if (IS_I965G(dev) || !old_obj_priv->active)
break;
/* This brings the object to the head of the LRU if it
* had been written to. The only way this should
* result in us waiting longer than the expected
* optimal amount of time is if there was a
* fence-using buffer later that was read-only.
*/
i915_gem_object_flush_gpu_write_domain(old_obj);
ret = i915_gem_object_wait_rendering(old_obj);
if (ret != 0) {
drm_gem_object_unreference(old_obj);
return ret;
}
break;
}
/*
* Zap this virtual mapping so we can set up a fence again
* for this object next time we need it.
*/
i915_gem_release_mmap(old_obj);
i = old_obj_priv->fence_reg;
reg = &dev_priv->fence_regs[i];
old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
list_del_init(&old_obj_priv->fence_list);
drm_gem_object_unreference(old_obj);
}
obj_priv->fence_reg = i;
list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list); list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);
reg->obj = obj; reg->obj = obj;
if (IS_I965G(dev)) if (IS_GEN6(dev))
sandybridge_write_fence_reg(reg);
else if (IS_I965G(dev))
i965_write_fence_reg(reg); i965_write_fence_reg(reg);
else if (IS_I9XX(dev)) else if (IS_I9XX(dev))
i915_write_fence_reg(reg); i915_write_fence_reg(reg);
else else
i830_write_fence_reg(reg); i830_write_fence_reg(reg);
trace_i915_gem_object_get_fence(obj, i, obj_priv->tiling_mode); trace_i915_gem_object_get_fence(obj, obj_priv->fence_reg,
obj_priv->tiling_mode);
return 0; return 0;
} }
@ -2508,9 +2550,12 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = obj->driver_private; struct drm_i915_gem_object *obj_priv = obj->driver_private;
if (IS_I965G(dev)) if (IS_GEN6(dev)) {
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 +
(obj_priv->fence_reg * 8), 0);
} else if (IS_I965G(dev)) {
I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0); I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
else { } else {
uint32_t fence_reg; uint32_t fence_reg;
if (obj_priv->fence_reg < 8) if (obj_priv->fence_reg < 8)
@ -2544,6 +2589,12 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
if (obj_priv->fence_reg == I915_FENCE_REG_NONE) if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
return 0; return 0;
/* If we've changed tiling, GTT-mappings of the object
* need to re-fault to ensure that the correct fence register
* setup is in place.
*/
i915_gem_release_mmap(obj);
/* On the i915, GPU access to tiled buffers is via a fence, /* On the i915, GPU access to tiled buffers is via a fence,
* therefore we must wait for any outstanding access to complete * therefore we must wait for any outstanding access to complete
* before clearing the fence. * before clearing the fence.
@ -2552,12 +2603,12 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
int ret; int ret;
i915_gem_object_flush_gpu_write_domain(obj); i915_gem_object_flush_gpu_write_domain(obj);
i915_gem_object_flush_gtt_write_domain(obj);
ret = i915_gem_object_wait_rendering(obj); ret = i915_gem_object_wait_rendering(obj);
if (ret != 0) if (ret != 0)
return ret; return ret;
} }
i915_gem_object_flush_gtt_write_domain(obj);
i915_gem_clear_fence_reg (obj); i915_gem_clear_fence_reg (obj);
return 0; return 0;
@ -2697,7 +2748,6 @@ static void
i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
uint32_t seqno;
uint32_t old_write_domain; uint32_t old_write_domain;
if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
@ -2706,9 +2756,8 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
/* Queue the GPU write cache flushing we need. */ /* Queue the GPU write cache flushing we need. */
old_write_domain = obj->write_domain; old_write_domain = obj->write_domain;
i915_gem_flush(dev, 0, obj->write_domain); i915_gem_flush(dev, 0, obj->write_domain);
seqno = i915_add_request(dev, NULL, obj->write_domain); (void) i915_add_request(dev, NULL, obj->write_domain);
BUG_ON(obj->write_domain); BUG_ON(obj->write_domain);
i915_gem_object_move_to_active(obj, seqno);
trace_i915_gem_object_change_domain(obj, trace_i915_gem_object_change_domain(obj,
obj->read_domains, obj->read_domains,
@ -3247,7 +3296,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
obj_priv->tiling_mode != I915_TILING_NONE; obj_priv->tiling_mode != I915_TILING_NONE;
/* Check fence reg constraints and rebind if necessary */ /* Check fence reg constraints and rebind if necessary */
if (need_fence && !i915_obj_fenceable(dev, obj)) if (need_fence && !i915_gem_object_fence_offset_ok(obj,
obj_priv->tiling_mode))
i915_gem_object_unbind(obj); i915_gem_object_unbind(obj);
/* Choose the GTT offset for our buffer and put it there. */ /* Choose the GTT offset for our buffer and put it there. */
@ -3317,6 +3367,16 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
} }
/* Validate that the target is in a valid r/w GPU domain */ /* Validate that the target is in a valid r/w GPU domain */
if (reloc->write_domain & (reloc->write_domain - 1)) {
DRM_ERROR("reloc with multiple write domains: "
"obj %p target %d offset %d "
"read %08x write %08x",
obj, reloc->target_handle,
(int) reloc->offset,
reloc->read_domains,
reloc->write_domain);
return -EINVAL;
}
if (reloc->write_domain & I915_GEM_DOMAIN_CPU || if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
reloc->read_domains & I915_GEM_DOMAIN_CPU) { reloc->read_domains & I915_GEM_DOMAIN_CPU) {
DRM_ERROR("reloc with read/write CPU domains: " DRM_ERROR("reloc with read/write CPU domains: "
@ -4445,8 +4505,7 @@ int
i915_gem_idle(struct drm_device *dev) i915_gem_idle(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno, cur_seqno, last_seqno; int ret;
int stuck, ret;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
@ -4455,115 +4514,36 @@ i915_gem_idle(struct drm_device *dev)
return 0; return 0;
} }
/* Hack! Don't let anybody do execbuf while we don't control the chip. ret = i915_gpu_idle(dev);
* We need to replace this with a semaphore, or something.
*/
dev_priv->mm.suspended = 1;
del_timer(&dev_priv->hangcheck_timer);
/* Cancel the retire work handler, wait for it to finish if running
*/
mutex_unlock(&dev->struct_mutex);
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
mutex_lock(&dev->struct_mutex);
i915_kernel_lost_context(dev);
/* Flush the GPU along with all non-CPU write domains
*/
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);
return -ENOMEM;
}
dev_priv->mm.waiting_gem_seqno = seqno;
last_seqno = 0;
stuck = 0;
for (;;) {
cur_seqno = i915_get_gem_seqno(dev);
if (i915_seqno_passed(cur_seqno, seqno))
break;
if (last_seqno == cur_seqno) {
if (stuck++ > 100) {
DRM_ERROR("hardware wedged\n");
atomic_set(&dev_priv->mm.wedged, 1);
DRM_WAKEUP(&dev_priv->irq_queue);
break;
}
}
msleep(10);
last_seqno = cur_seqno;
}
dev_priv->mm.waiting_gem_seqno = 0;
i915_gem_retire_requests(dev);
spin_lock(&dev_priv->mm.active_list_lock);
if (!atomic_read(&dev_priv->mm.wedged)) {
/* Active and flushing should now be empty as we've
* waited for a sequence higher than any pending execbuffer
*/
WARN_ON(!list_empty(&dev_priv->mm.active_list));
WARN_ON(!list_empty(&dev_priv->mm.flushing_list));
/* Request should now be empty as we've also waited
* for the last request in the list
*/
WARN_ON(!list_empty(&dev_priv->mm.request_list));
}
/* Empty the active and flushing lists to inactive. If there's
* anything left at this point, it means that we're wedged and
* nothing good's going to happen by leaving them there. So strip
* the GPU domains and just stuff them onto inactive.
*/
while (!list_empty(&dev_priv->mm.active_list)) {
struct drm_gem_object *obj;
uint32_t old_write_domain;
obj = list_first_entry(&dev_priv->mm.active_list,
struct drm_i915_gem_object,
list)->obj;
old_write_domain = obj->write_domain;
obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
i915_gem_object_move_to_inactive(obj);
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
old_write_domain);
}
spin_unlock(&dev_priv->mm.active_list_lock);
while (!list_empty(&dev_priv->mm.flushing_list)) {
struct drm_gem_object *obj;
uint32_t old_write_domain;
obj = list_first_entry(&dev_priv->mm.flushing_list,
struct drm_i915_gem_object,
list)->obj;
old_write_domain = obj->write_domain;
obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
i915_gem_object_move_to_inactive(obj);
trace_i915_gem_object_change_domain(obj,
obj->read_domains,
old_write_domain);
}
/* Move all inactive buffers out of the GTT. */
ret = i915_gem_evict_from_inactive_list(dev);
WARN_ON(!list_empty(&dev_priv->mm.inactive_list));
if (ret) { if (ret) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return ret; return ret;
} }
/* Under UMS, be paranoid and evict. */
if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = i915_gem_evict_from_inactive_list(dev);
if (ret) {
mutex_unlock(&dev->struct_mutex);
return ret;
}
}
/* Hack! Don't let anybody do execbuf while we don't control the chip.
* We need to replace this with a semaphore, or something.
* And not confound mm.suspended!
*/
dev_priv->mm.suspended = 1;
del_timer(&dev_priv->hangcheck_timer);
i915_kernel_lost_context(dev);
i915_gem_cleanup_ringbuffer(dev); i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
/* Cancel the retire work handler, which should be idle now. */
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
return 0; return 0;
} }
@ -4607,8 +4587,13 @@ i915_gem_init_hws(struct drm_device *dev)
} }
dev_priv->hws_obj = obj; dev_priv->hws_obj = obj;
memset(dev_priv->hw_status_page, 0, PAGE_SIZE); memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); if (IS_GEN6(dev)) {
I915_READ(HWS_PGA); /* posting read */ I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr);
I915_READ(HWS_PGA_GEN6); /* posting read */
} else {
I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
I915_READ(HWS_PGA); /* posting read */
}
DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
return 0; return 0;
@ -4850,7 +4835,8 @@ i915_gem_load(struct drm_device *dev)
spin_unlock(&shrink_list_lock); spin_unlock(&shrink_list_lock);
/* Old X drivers will take 0-2 for front, back, depth buffers */ /* Old X drivers will take 0-2 for front, back, depth buffers */
dev_priv->fence_reg_start = 3; if (!drm_core_check_feature(dev, DRIVER_MODESET))
dev_priv->fence_reg_start = 3;
if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
dev_priv->num_fence_regs = 16; dev_priv->num_fence_regs = 16;

View File

@ -25,8 +25,6 @@
* *
*/ */
#include <linux/acpi.h>
#include <linux/pnp.h>
#include "linux/string.h" #include "linux/string.h"
#include "linux/bitops.h" #include "linux/bitops.h"
#include "drmP.h" #include "drmP.h"
@ -83,120 +81,6 @@
* to match what the GPU expects. * 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)
{
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;
if (IS_I965G(dev))
pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
pci_read_config_dword(dev_priv->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 */
#ifdef CONFIG_PNP
if (mchbar_addr &&
pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
ret = 0;
goto out;
}
#endif
/* Get some space for it */
ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
MCHBAR_SIZE, MCHBAR_SIZE,
PCIBIOS_MIN_MEM,
0, pcibios_align_resource,
dev_priv->bridge_dev);
if (ret) {
DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret);
dev_priv->mch_res.start = 0;
goto out;
}
if (IS_I965G(dev))
pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
upper_32_bits(dev_priv->mch_res.start));
pci_write_config_dword(dev_priv->bridge_dev, reg,
lower_32_bits(dev_priv->mch_res.start));
out:
return ret;
}
/* Setup MCHBAR if possible, return true if we should disable it again */
static bool
intel_setup_mchbar(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
bool need_disable = false, enabled;
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
enabled = !!(temp & DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
enabled = temp & 1;
}
/* If it's already enabled, don't have to do anything */
if (enabled)
goto out;
if (intel_alloc_mchbar_resource(dev))
goto out;
need_disable = true;
/* Space is allocated or reserved, so enable it. */
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
temp | DEVEN_MCHBAR_EN);
} else {
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
}
out:
return need_disable;
}
static void
intel_teardown_mchbar(struct drm_device *dev, bool disable)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
u32 temp;
if (disable) {
if (IS_I915G(dev) || IS_I915GM(dev)) {
pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
temp &= ~DEVEN_MCHBAR_EN;
pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
} else {
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
temp &= ~1;
pci_write_config_dword(dev_priv->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 * Detects bit 6 swizzling of address lookup between IGD access and CPU
* access through main memory. * access through main memory.
@ -207,9 +91,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
bool need_disable;
if (IS_IRONLAKE(dev)) { if (IS_IRONLAKE(dev) || IS_GEN6(dev)) {
/* On Ironlake whatever DRAM config, GPU always do /* On Ironlake whatever DRAM config, GPU always do
* same swizzling setup. * same swizzling setup.
*/ */
@ -224,9 +107,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
} else if (IS_MOBILE(dev)) { } else if (IS_MOBILE(dev)) {
uint32_t dcc; 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 /* On mobile 9xx chipsets, channel interleave by the CPU is
* determined by DCC. For single-channel, neither the CPU * determined by DCC. For single-channel, neither the CPU
* nor the GPU do swizzling. For dual channel interleaved, * nor the GPU do swizzling. For dual channel interleaved,
@ -266,8 +146,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
} }
intel_teardown_mchbar(dev, need_disable);
} else { } else {
/* The 965, G33, and newer, have a very flexible memory /* The 965, G33, and newer, have a very flexible memory
* configuration. It will enable dual-channel mode * configuration. It will enable dual-channel mode
@ -302,39 +180,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
dev_priv->mm.bit_6_swizzle_y = swizzle_y; dev_priv->mm.bit_6_swizzle_y = swizzle_y;
} }
/**
* Returns whether an object is currently fenceable. If not, it may need
* to be unbound and have its pitch adjusted.
*/
bool
i915_obj_fenceable(struct drm_device *dev, struct drm_gem_object *obj)
{
struct drm_i915_gem_object *obj_priv = obj->driver_private;
if (IS_I965G(dev)) {
/* The 965 can have fences at any page boundary. */
if (obj->size & 4095)
return false;
return true;
} else if (IS_I9XX(dev)) {
if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
return false;
} else {
if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
return false;
}
/* Power of two sized... */
if (obj->size & (obj->size - 1))
return false;
/* Objects must be size aligned as well */
if (obj_priv->gtt_offset & (obj->size - 1))
return false;
return true;
}
/* Check pitch constriants for all chips & tiling formats */ /* Check pitch constriants for all chips & tiling formats */
bool bool
i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
@ -391,7 +236,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
return true; return true;
} }
static bool bool
i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
@ -438,9 +283,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
obj_priv = obj->driver_private; obj_priv = obj->driver_private;
if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) { if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) {
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(obj);
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
return -EINVAL; return -EINVAL;
} }
@ -493,12 +336,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
goto err; goto err;
} }
/* If we've changed tiling, GTT-mappings of the object
* need to re-fault to ensure that the correct fence register
* setup is in place.
*/
i915_gem_release_mmap(obj);
obj_priv->tiling_mode = args->tiling_mode; obj_priv->tiling_mode = args->tiling_mode;
obj_priv->stride = args->stride; obj_priv->stride = args->stride;
} }

View File

@ -166,7 +166,7 @@ void intel_enable_asle (struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
ironlake_enable_display_irq(dev_priv, DE_GSE); ironlake_enable_display_irq(dev_priv, DE_GSE);
else else
i915_enable_pipestat(dev_priv, 1, i915_enable_pipestat(dev_priv, 1,
@ -269,6 +269,57 @@ static void i915_hotplug_work_func(struct work_struct *work)
drm_sysfs_hotplug_event(dev); drm_sysfs_hotplug_event(dev);
} }
static void i915_handle_rps_change(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 busy_up, busy_down, max_avg, min_avg;
u16 rgvswctl;
u8 new_delay = dev_priv->cur_delay;
I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG);
busy_up = I915_READ(RCPREVBSYTUPAVG);
busy_down = I915_READ(RCPREVBSYTDNAVG);
max_avg = I915_READ(RCBMAXAVG);
min_avg = I915_READ(RCBMINAVG);
/* Handle RCS change request from hw */
if (busy_up > max_avg) {
if (dev_priv->cur_delay != dev_priv->max_delay)
new_delay = dev_priv->cur_delay - 1;
if (new_delay < dev_priv->max_delay)
new_delay = dev_priv->max_delay;
} else if (busy_down < min_avg) {
if (dev_priv->cur_delay != dev_priv->min_delay)
new_delay = dev_priv->cur_delay + 1;
if (new_delay > dev_priv->min_delay)
new_delay = dev_priv->min_delay;
}
DRM_DEBUG("rps change requested: %d -> %d\n",
dev_priv->cur_delay, new_delay);
rgvswctl = I915_READ(MEMSWCTL);
if (rgvswctl & MEMCTL_CMD_STS) {
DRM_ERROR("gpu busy, RCS change rejected\n");
return; /* still busy with another command */
}
/* Program the new state */
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
(new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
I915_WRITE(MEMSWCTL, rgvswctl);
POSTING_READ(MEMSWCTL);
rgvswctl |= MEMCTL_CMD_STS;
I915_WRITE(MEMSWCTL, rgvswctl);
dev_priv->cur_delay = new_delay;
DRM_DEBUG("rps changed\n");
return;
}
irqreturn_t ironlake_irq_handler(struct drm_device *dev) irqreturn_t ironlake_irq_handler(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@ -331,6 +382,11 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
queue_work(dev_priv->wq, &dev_priv->hotplug_work); queue_work(dev_priv->wq, &dev_priv->hotplug_work);
} }
if (de_iir & DE_PCU_EVENT) {
I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS));
i915_handle_rps_change(dev);
}
/* should clear PCH hotplug event before clear CPU irq */ /* should clear PCH hotplug event before clear CPU irq */
I915_WRITE(SDEIIR, pch_iir); I915_WRITE(SDEIIR, pch_iir);
I915_WRITE(GTIIR, gt_iir); I915_WRITE(GTIIR, gt_iir);
@ -376,6 +432,121 @@ static void i915_error_work_func(struct work_struct *work)
} }
} }
static struct drm_i915_error_object *
i915_error_object_create(struct drm_device *dev,
struct drm_gem_object *src)
{
struct drm_i915_error_object *dst;
struct drm_i915_gem_object *src_priv;
int page, page_count;
if (src == NULL)
return NULL;
src_priv = src->driver_private;
if (src_priv->pages == NULL)
return NULL;
page_count = src->size / PAGE_SIZE;
dst = kmalloc(sizeof(*dst) + page_count * sizeof (u32 *), GFP_ATOMIC);
if (dst == NULL)
return NULL;
for (page = 0; page < page_count; page++) {
void *s, *d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
if (d == NULL)
goto unwind;
s = kmap_atomic(src_priv->pages[page], KM_USER0);
memcpy(d, s, PAGE_SIZE);
kunmap_atomic(s, KM_USER0);
dst->pages[page] = d;
}
dst->page_count = page_count;
dst->gtt_offset = src_priv->gtt_offset;
return dst;
unwind:
while (page--)
kfree(dst->pages[page]);
kfree(dst);
return NULL;
}
static void
i915_error_object_free(struct drm_i915_error_object *obj)
{
int page;
if (obj == NULL)
return;
for (page = 0; page < obj->page_count; page++)
kfree(obj->pages[page]);
kfree(obj);
}
static void
i915_error_state_free(struct drm_device *dev,
struct drm_i915_error_state *error)
{
i915_error_object_free(error->batchbuffer[0]);
i915_error_object_free(error->batchbuffer[1]);
i915_error_object_free(error->ringbuffer);
kfree(error->active_bo);
kfree(error);
}
static u32
i915_get_bbaddr(struct drm_device *dev, u32 *ring)
{
u32 cmd;
if (IS_I830(dev) || IS_845G(dev))
cmd = MI_BATCH_BUFFER;
else if (IS_I965G(dev))
cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
MI_BATCH_NON_SECURE_I965);
else
cmd = (MI_BATCH_BUFFER_START | (2 << 6));
return ring[0] == cmd ? ring[1] : 0;
}
static u32
i915_ringbuffer_last_batch(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 head, bbaddr;
u32 *ring;
/* Locate the current position in the ringbuffer and walk back
* to find the most recently dispatched batch buffer.
*/
bbaddr = 0;
head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
ring = (u32 *)(dev_priv->ring.virtual_start + head);
while (--ring >= (u32 *)dev_priv->ring.virtual_start) {
bbaddr = i915_get_bbaddr(dev, ring);
if (bbaddr)
break;
}
if (bbaddr == 0) {
ring = (u32 *)(dev_priv->ring.virtual_start + dev_priv->ring.Size);
while (--ring >= (u32 *)dev_priv->ring.virtual_start) {
bbaddr = i915_get_bbaddr(dev, ring);
if (bbaddr)
break;
}
}
return bbaddr;
}
/** /**
* i915_capture_error_state - capture an error record for later analysis * i915_capture_error_state - capture an error record for later analysis
* @dev: drm device * @dev: drm device
@ -388,19 +559,26 @@ static void i915_error_work_func(struct work_struct *work)
static void i915_capture_error_state(struct drm_device *dev) static void i915_capture_error_state(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
struct drm_i915_error_state *error; struct drm_i915_error_state *error;
struct drm_gem_object *batchbuffer[2];
unsigned long flags; unsigned long flags;
u32 bbaddr;
int count;
spin_lock_irqsave(&dev_priv->error_lock, flags); spin_lock_irqsave(&dev_priv->error_lock, flags);
if (dev_priv->first_error) error = dev_priv->first_error;
goto out; spin_unlock_irqrestore(&dev_priv->error_lock, flags);
if (error)
return;
error = kmalloc(sizeof(*error), GFP_ATOMIC); error = kmalloc(sizeof(*error), GFP_ATOMIC);
if (!error) { if (!error) {
DRM_DEBUG_DRIVER("out ot memory, not capturing error state\n"); DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
goto out; return;
} }
error->seqno = i915_get_gem_seqno(dev);
error->eir = I915_READ(EIR); error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER); error->pgtbl_er = I915_READ(PGTBL_ER);
error->pipeastat = I915_READ(PIPEASTAT); error->pipeastat = I915_READ(PIPEASTAT);
@ -411,6 +589,7 @@ static void i915_capture_error_state(struct drm_device *dev)
error->ipehr = I915_READ(IPEHR); error->ipehr = I915_READ(IPEHR);
error->instdone = I915_READ(INSTDONE); error->instdone = I915_READ(INSTDONE);
error->acthd = I915_READ(ACTHD); error->acthd = I915_READ(ACTHD);
error->bbaddr = 0;
} else { } else {
error->ipeir = I915_READ(IPEIR_I965); error->ipeir = I915_READ(IPEIR_I965);
error->ipehr = I915_READ(IPEHR_I965); error->ipehr = I915_READ(IPEHR_I965);
@ -418,14 +597,101 @@ static void i915_capture_error_state(struct drm_device *dev)
error->instps = I915_READ(INSTPS); error->instps = I915_READ(INSTPS);
error->instdone1 = I915_READ(INSTDONE1); error->instdone1 = I915_READ(INSTDONE1);
error->acthd = I915_READ(ACTHD_I965); error->acthd = I915_READ(ACTHD_I965);
error->bbaddr = I915_READ64(BB_ADDR);
}
bbaddr = i915_ringbuffer_last_batch(dev);
/* Grab the current batchbuffer, most likely to have crashed. */
batchbuffer[0] = NULL;
batchbuffer[1] = NULL;
count = 0;
list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
struct drm_gem_object *obj = obj_priv->obj;
if (batchbuffer[0] == NULL &&
bbaddr >= obj_priv->gtt_offset &&
bbaddr < obj_priv->gtt_offset + obj->size)
batchbuffer[0] = obj;
if (batchbuffer[1] == NULL &&
error->acthd >= obj_priv->gtt_offset &&
error->acthd < obj_priv->gtt_offset + obj->size &&
batchbuffer[0] != obj)
batchbuffer[1] = obj;
count++;
}
/* We need to copy these to an anonymous buffer as the simplest
* method to avoid being overwritten by userpace.
*/
error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]);
/* Record the ringbuffer */
error->ringbuffer = i915_error_object_create(dev, dev_priv->ring.ring_obj);
/* Record buffers on the active list. */
error->active_bo = NULL;
error->active_bo_count = 0;
if (count)
error->active_bo = kmalloc(sizeof(*error->active_bo)*count,
GFP_ATOMIC);
if (error->active_bo) {
int i = 0;
list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
struct drm_gem_object *obj = obj_priv->obj;
error->active_bo[i].size = obj->size;
error->active_bo[i].name = obj->name;
error->active_bo[i].seqno = obj_priv->last_rendering_seqno;
error->active_bo[i].gtt_offset = obj_priv->gtt_offset;
error->active_bo[i].read_domains = obj->read_domains;
error->active_bo[i].write_domain = obj->write_domain;
error->active_bo[i].fence_reg = obj_priv->fence_reg;
error->active_bo[i].pinned = 0;
if (obj_priv->pin_count > 0)
error->active_bo[i].pinned = 1;
if (obj_priv->user_pin_count > 0)
error->active_bo[i].pinned = -1;
error->active_bo[i].tiling = obj_priv->tiling_mode;
error->active_bo[i].dirty = obj_priv->dirty;
error->active_bo[i].purgeable = obj_priv->madv != I915_MADV_WILLNEED;
if (++i == count)
break;
}
error->active_bo_count = i;
} }
do_gettimeofday(&error->time); do_gettimeofday(&error->time);
dev_priv->first_error = error; spin_lock_irqsave(&dev_priv->error_lock, flags);
if (dev_priv->first_error == NULL) {
out: dev_priv->first_error = error;
error = NULL;
}
spin_unlock_irqrestore(&dev_priv->error_lock, flags); spin_unlock_irqrestore(&dev_priv->error_lock, flags);
if (error)
i915_error_state_free(dev, error);
}
void i915_destroy_error_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_error_state *error;
spin_lock(&dev_priv->error_lock);
error = dev_priv->first_error;
dev_priv->first_error = NULL;
spin_unlock(&dev_priv->error_lock);
if (error)
i915_error_state_free(dev, error);
} }
/** /**
@ -576,7 +842,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
atomic_inc(&dev_priv->irq_received); atomic_inc(&dev_priv->irq_received);
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
return ironlake_irq_handler(dev); return ironlake_irq_handler(dev);
iir = I915_READ(IIR); iir = I915_READ(IIR);
@ -737,7 +1003,7 @@ void i915_user_irq_get(struct drm_device *dev)
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT); ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
else else
i915_enable_irq(dev_priv, I915_USER_INTERRUPT); i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
@ -753,7 +1019,7 @@ void i915_user_irq_put(struct drm_device *dev)
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
ironlake_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT); ironlake_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
else else
i915_disable_irq(dev_priv, I915_USER_INTERRUPT); i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
@ -861,7 +1127,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
ironlake_enable_display_irq(dev_priv, (pipe == 0) ? ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
else if (IS_I965G(dev)) else if (IS_I965G(dev))
@ -883,7 +1149,7 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
unsigned long irqflags; unsigned long irqflags;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
ironlake_disable_display_irq(dev_priv, (pipe == 0) ? ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
else else
@ -897,7 +1163,7 @@ void i915_enable_interrupt (struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
if (!IS_IRONLAKE(dev)) if (!HAS_PCH_SPLIT(dev))
opregion_enable_asle(dev); opregion_enable_asle(dev);
dev_priv->irq_enabled = 1; dev_priv->irq_enabled = 1;
} }
@ -973,7 +1239,11 @@ void i915_hangcheck_elapsed(unsigned long data)
struct drm_device *dev = (struct drm_device *)data; struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t acthd; uint32_t acthd;
/* No reset support on this chip yet. */
if (IS_GEN6(dev))
return;
if (!IS_I965G(dev)) if (!IS_I965G(dev))
acthd = I915_READ(ACTHD); acthd = I915_READ(ACTHD);
else else
@ -1064,6 +1334,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg); I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg);
(void) I915_READ(SDEIER); (void) I915_READ(SDEIER);
if (IS_IRONLAKE_M(dev)) {
/* Clear & enable PCU event interrupts */
I915_WRITE(DEIIR, DE_PCU_EVENT);
I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
}
return 0; return 0;
} }
@ -1076,7 +1353,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->error_work, i915_error_work_func); INIT_WORK(&dev_priv->error_work, i915_error_work_func);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
ironlake_irq_preinstall(dev); ironlake_irq_preinstall(dev);
return; return;
} }
@ -1108,7 +1385,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
return ironlake_irq_postinstall(dev); return ironlake_irq_postinstall(dev);
/* Unmask the interrupts that we always want on. */ /* Unmask the interrupts that we always want on. */
@ -1196,7 +1473,7 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
dev_priv->vblank_pipe = 0; dev_priv->vblank_pipe = 0;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
ironlake_irq_uninstall(dev); ironlake_irq_uninstall(dev);
return; return;
} }

View File

@ -53,6 +53,25 @@
#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4) #define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4)
#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4) #define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4)
#define SNB_GMCH_CTRL 0x50
#define SNB_GMCH_GMS_STOLEN_MASK 0xF8
#define SNB_GMCH_GMS_STOLEN_32M (1 << 3)
#define SNB_GMCH_GMS_STOLEN_64M (2 << 3)
#define SNB_GMCH_GMS_STOLEN_96M (3 << 3)
#define SNB_GMCH_GMS_STOLEN_128M (4 << 3)
#define SNB_GMCH_GMS_STOLEN_160M (5 << 3)
#define SNB_GMCH_GMS_STOLEN_192M (6 << 3)
#define SNB_GMCH_GMS_STOLEN_224M (7 << 3)
#define SNB_GMCH_GMS_STOLEN_256M (8 << 3)
#define SNB_GMCH_GMS_STOLEN_288M (9 << 3)
#define SNB_GMCH_GMS_STOLEN_320M (0xa << 3)
#define SNB_GMCH_GMS_STOLEN_352M (0xb << 3)
#define SNB_GMCH_GMS_STOLEN_384M (0xc << 3)
#define SNB_GMCH_GMS_STOLEN_416M (0xd << 3)
#define SNB_GMCH_GMS_STOLEN_448M (0xe << 3)
#define SNB_GMCH_GMS_STOLEN_480M (0xf << 3)
#define SNB_GMCH_GMS_STOLEN_512M (0x10 << 3)
/* PCI config space */ /* PCI config space */
#define HPLLCC 0xc0 /* 855 only */ #define HPLLCC 0xc0 /* 855 only */
@ -61,6 +80,7 @@
#define GC_CLOCK_100_200 (1 << 0) #define GC_CLOCK_100_200 (1 << 0)
#define GC_CLOCK_100_133 (2 << 0) #define GC_CLOCK_100_133 (2 << 0)
#define GC_CLOCK_166_250 (3 << 0) #define GC_CLOCK_166_250 (3 << 0)
#define GCFGC2 0xda
#define GCFGC 0xf0 /* 915+ only */ #define GCFGC 0xf0 /* 915+ only */
#define GC_LOW_FREQUENCY_ENABLE (1 << 7) #define GC_LOW_FREQUENCY_ENABLE (1 << 7)
#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) #define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
@ -234,6 +254,9 @@
#define I965_FENCE_REG_VALID (1<<0) #define I965_FENCE_REG_VALID (1<<0)
#define I965_FENCE_MAX_PITCH_VAL 0x0400 #define I965_FENCE_MAX_PITCH_VAL 0x0400
#define FENCE_REG_SANDYBRIDGE_0 0x100000
#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32
/* /*
* Instruction and interrupt control regs * Instruction and interrupt control regs
*/ */
@ -265,6 +288,7 @@
#define INSTDONE1 0x0207c /* 965+ only */ #define INSTDONE1 0x0207c /* 965+ only */
#define ACTHD_I965 0x02074 #define ACTHD_I965 0x02074
#define HWS_PGA 0x02080 #define HWS_PGA 0x02080
#define HWS_PGA_GEN6 0x04080
#define HWS_ADDRESS_MASK 0xfffff000 #define HWS_ADDRESS_MASK 0xfffff000
#define HWS_START_ADDRESS_SHIFT 4 #define HWS_START_ADDRESS_SHIFT 4
#define PWRCTXA 0x2088 /* 965GM+ only */ #define PWRCTXA 0x2088 /* 965GM+ only */
@ -282,7 +306,7 @@
#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
#define I915_DISPLAY_PORT_INTERRUPT (1<<17) #define I915_DISPLAY_PORT_INTERRUPT (1<<17)
#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) #define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */
#define I915_HWB_OOM_INTERRUPT (1<<13) #define I915_HWB_OOM_INTERRUPT (1<<13)
#define I915_SYNC_STATUS_INTERRUPT (1<<12) #define I915_SYNC_STATUS_INTERRUPT (1<<12)
#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) #define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
@ -306,11 +330,14 @@
#define I915_ERROR_MEMORY_REFRESH (1<<1) #define I915_ERROR_MEMORY_REFRESH (1<<1)
#define I915_ERROR_INSTRUCTION (1<<0) #define I915_ERROR_INSTRUCTION (1<<0)
#define INSTPM 0x020c0 #define INSTPM 0x020c0
#define INSTPM_SELF_EN (1<<12) /* 915GM only */
#define ACTHD 0x020c8 #define ACTHD 0x020c8
#define FW_BLC 0x020d8 #define FW_BLC 0x020d8
#define FW_BLC2 0x020dc #define FW_BLC2 0x020dc
#define FW_BLC_SELF 0x020e0 /* 915+ only */ #define FW_BLC_SELF 0x020e0 /* 915+ only */
#define FW_BLC_SELF_EN (1<<15) #define FW_BLC_SELF_EN_MASK (1<<31)
#define FW_BLC_SELF_FIFO_MASK (1<<16) /* 945 only */
#define FW_BLC_SELF_EN (1<<15) /* 945 only */
#define MM_BURST_LENGTH 0x00700000 #define MM_BURST_LENGTH 0x00700000
#define MM_FIFO_WATERMARK 0x0001F000 #define MM_FIFO_WATERMARK 0x0001F000
#define LM_BURST_LENGTH 0x00000700 #define LM_BURST_LENGTH 0x00000700
@ -324,6 +351,7 @@
#define CM0_COLOR_EVICT_DISABLE (1<<3) #define CM0_COLOR_EVICT_DISABLE (1<<3)
#define CM0_DEPTH_WRITE_DISABLE (1<<1) #define CM0_DEPTH_WRITE_DISABLE (1<<1)
#define CM0_RC_OP_FLUSH_DISABLE (1<<0) #define CM0_RC_OP_FLUSH_DISABLE (1<<0)
#define BB_ADDR 0x02140 /* 8 bytes */
#define GFX_FLSH_CNTL 0x02170 /* 915+ only */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */
@ -784,10 +812,144 @@
#define CLKCFG_MEM_800 (3 << 4) #define CLKCFG_MEM_800 (3 << 4)
#define CLKCFG_MEM_MASK (7 << 4) #define CLKCFG_MEM_MASK (7 << 4)
/** GM965 GM45 render standby register */ #define CRSTANDVID 0x11100
#define MCHBAR_RENDER_STANDBY 0x111B8 #define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
#define PXVFREQ_PX_MASK 0x7f000000
#define PXVFREQ_PX_SHIFT 24
#define VIDFREQ_BASE 0x11110
#define VIDFREQ1 0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */
#define VIDFREQ2 0x11114
#define VIDFREQ3 0x11118
#define VIDFREQ4 0x1111c
#define VIDFREQ_P0_MASK 0x1f000000
#define VIDFREQ_P0_SHIFT 24
#define VIDFREQ_P0_CSCLK_MASK 0x00f00000
#define VIDFREQ_P0_CSCLK_SHIFT 20
#define VIDFREQ_P0_CRCLK_MASK 0x000f0000
#define VIDFREQ_P0_CRCLK_SHIFT 16
#define VIDFREQ_P1_MASK 0x00001f00
#define VIDFREQ_P1_SHIFT 8
#define VIDFREQ_P1_CSCLK_MASK 0x000000f0
#define VIDFREQ_P1_CSCLK_SHIFT 4
#define VIDFREQ_P1_CRCLK_MASK 0x0000000f
#define INTTOEXT_BASE_ILK 0x11300
#define INTTOEXT_BASE 0x11120 /* INTTOEXT1-8 (0x1113c) */
#define INTTOEXT_MAP3_SHIFT 24
#define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT)
#define INTTOEXT_MAP2_SHIFT 16
#define INTTOEXT_MAP2_MASK (0x1f << INTTOEXT_MAP2_SHIFT)
#define INTTOEXT_MAP1_SHIFT 8
#define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT)
#define INTTOEXT_MAP0_SHIFT 0
#define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT)
#define MEMSWCTL 0x11170 /* Ironlake only */
#define MEMCTL_CMD_MASK 0xe000
#define MEMCTL_CMD_SHIFT 13
#define MEMCTL_CMD_RCLK_OFF 0
#define MEMCTL_CMD_RCLK_ON 1
#define MEMCTL_CMD_CHFREQ 2
#define MEMCTL_CMD_CHVID 3
#define MEMCTL_CMD_VMMOFF 4
#define MEMCTL_CMD_VMMON 5
#define MEMCTL_CMD_STS (1<<12) /* write 1 triggers command, clears
when command complete */
#define MEMCTL_FREQ_MASK 0x0f00 /* jitter, from 0-15 */
#define MEMCTL_FREQ_SHIFT 8
#define MEMCTL_SFCAVM (1<<7)
#define MEMCTL_TGT_VID_MASK 0x007f
#define MEMIHYST 0x1117c
#define MEMINTREN 0x11180 /* 16 bits */
#define MEMINT_RSEXIT_EN (1<<8)
#define MEMINT_CX_SUPR_EN (1<<7)
#define MEMINT_CONT_BUSY_EN (1<<6)
#define MEMINT_AVG_BUSY_EN (1<<5)
#define MEMINT_EVAL_CHG_EN (1<<4)
#define MEMINT_MON_IDLE_EN (1<<3)
#define MEMINT_UP_EVAL_EN (1<<2)
#define MEMINT_DOWN_EVAL_EN (1<<1)
#define MEMINT_SW_CMD_EN (1<<0)
#define MEMINTRSTR 0x11182 /* 16 bits */
#define MEM_RSEXIT_MASK 0xc000
#define MEM_RSEXIT_SHIFT 14
#define MEM_CONT_BUSY_MASK 0x3000
#define MEM_CONT_BUSY_SHIFT 12
#define MEM_AVG_BUSY_MASK 0x0c00
#define MEM_AVG_BUSY_SHIFT 10
#define MEM_EVAL_CHG_MASK 0x0300
#define MEM_EVAL_BUSY_SHIFT 8
#define MEM_MON_IDLE_MASK 0x00c0
#define MEM_MON_IDLE_SHIFT 6
#define MEM_UP_EVAL_MASK 0x0030
#define MEM_UP_EVAL_SHIFT 4
#define MEM_DOWN_EVAL_MASK 0x000c
#define MEM_DOWN_EVAL_SHIFT 2
#define MEM_SW_CMD_MASK 0x0003
#define MEM_INT_STEER_GFX 0
#define MEM_INT_STEER_CMR 1
#define MEM_INT_STEER_SMI 2
#define MEM_INT_STEER_SCI 3
#define MEMINTRSTS 0x11184
#define MEMINT_RSEXIT (1<<7)
#define MEMINT_CONT_BUSY (1<<6)
#define MEMINT_AVG_BUSY (1<<5)
#define MEMINT_EVAL_CHG (1<<4)
#define MEMINT_MON_IDLE (1<<3)
#define MEMINT_UP_EVAL (1<<2)
#define MEMINT_DOWN_EVAL (1<<1)
#define MEMINT_SW_CMD (1<<0)
#define MEMMODECTL 0x11190
#define MEMMODE_BOOST_EN (1<<31)
#define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */
#define MEMMODE_BOOST_FREQ_SHIFT 24
#define MEMMODE_IDLE_MODE_MASK 0x00030000
#define MEMMODE_IDLE_MODE_SHIFT 16
#define MEMMODE_IDLE_MODE_EVAL 0
#define MEMMODE_IDLE_MODE_CONT 1
#define MEMMODE_HWIDLE_EN (1<<15)
#define MEMMODE_SWMODE_EN (1<<14)
#define MEMMODE_RCLK_GATE (1<<13)
#define MEMMODE_HW_UPDATE (1<<12)
#define MEMMODE_FSTART_MASK 0x00000f00 /* starting jitter, 0-15 */
#define MEMMODE_FSTART_SHIFT 8
#define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */
#define MEMMODE_FMAX_SHIFT 4
#define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */
#define RCBMAXAVG 0x1119c
#define MEMSWCTL2 0x1119e /* Cantiga only */
#define SWMEMCMD_RENDER_OFF (0 << 13)
#define SWMEMCMD_RENDER_ON (1 << 13)
#define SWMEMCMD_SWFREQ (2 << 13)
#define SWMEMCMD_TARVID (3 << 13)
#define SWMEMCMD_VRM_OFF (4 << 13)
#define SWMEMCMD_VRM_ON (5 << 13)
#define CMDSTS (1<<12)
#define SFCAVM (1<<11)
#define SWFREQ_MASK 0x0380 /* P0-7 */
#define SWFREQ_SHIFT 7
#define TARVID_MASK 0x001f
#define MEMSTAT_CTG 0x111a0
#define RCBMINAVG 0x111a0
#define RCUPEI 0x111b0
#define RCDNEI 0x111b4
#define MCHBAR_RENDER_STANDBY 0x111b8
#define RCX_SW_EXIT (1<<23) #define RCX_SW_EXIT (1<<23)
#define RSX_STATUS_MASK 0x00700000 #define RSX_STATUS_MASK 0x00700000
#define VIDCTL 0x111c0
#define VIDSTS 0x111c8
#define VIDSTART 0x111cc /* 8 bits */
#define MEMSTAT_ILK 0x111f8
#define MEMSTAT_VID_MASK 0x7f00
#define MEMSTAT_VID_SHIFT 8
#define MEMSTAT_PSTATE_MASK 0x00f8
#define MEMSTAT_PSTATE_SHIFT 3
#define MEMSTAT_MON_ACTV (1<<2)
#define MEMSTAT_SRC_CTL_MASK 0x0003
#define MEMSTAT_SRC_CTL_CORE 0
#define MEMSTAT_SRC_CTL_TRB 1
#define MEMSTAT_SRC_CTL_THM 2
#define MEMSTAT_SRC_CTL_STDBY 3
#define RCPREVBSYTUPAVG 0x113b8
#define RCPREVBSYTDNAVG 0x113bc
#define PEG_BAND_GAP_DATA 0x14d68 #define PEG_BAND_GAP_DATA 0x14d68
/* /*

View File

@ -682,6 +682,8 @@ void i915_restore_display(struct drm_device *dev)
I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR); I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL); I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
I915_WRITE(MCHBAR_RENDER_STANDBY,
dev_priv->saveMCHBAR_RENDER_STANDBY);
} else { } else {
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
@ -745,11 +747,16 @@ int i915_save_state(struct drm_device *dev)
dev_priv->saveGTIMR = I915_READ(GTIMR); dev_priv->saveGTIMR = I915_READ(GTIMR);
dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR); dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR);
dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR); dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
dev_priv->saveMCHBAR_RENDER_STANDBY =
I915_READ(MCHBAR_RENDER_STANDBY);
} else { } else {
dev_priv->saveIER = I915_READ(IER); dev_priv->saveIER = I915_READ(IER);
dev_priv->saveIMR = I915_READ(IMR); dev_priv->saveIMR = I915_READ(IMR);
} }
if (IS_IRONLAKE_M(dev))
ironlake_disable_drps(dev);
/* Cache mode state */ /* Cache mode state */
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
@ -820,6 +827,9 @@ int i915_restore_state(struct drm_device *dev)
/* Clock gating state */ /* Clock gating state */
intel_init_clock_gating(dev); intel_init_clock_gating(dev);
if (IS_IRONLAKE_M(dev))
ironlake_enable_drps(dev);
/* Cache mode state */ /* Cache mode state */
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);

View File

@ -247,6 +247,7 @@ static void
parse_general_features(struct drm_i915_private *dev_priv, parse_general_features(struct drm_i915_private *dev_priv,
struct bdb_header *bdb) struct bdb_header *bdb)
{ {
struct drm_device *dev = dev_priv->dev;
struct bdb_general_features *general; struct bdb_general_features *general;
/* Set sensible defaults in case we can't find the general block */ /* Set sensible defaults in case we can't find the general block */
@ -263,7 +264,7 @@ parse_general_features(struct drm_i915_private *dev_priv,
if (IS_I85X(dev_priv->dev)) if (IS_I85X(dev_priv->dev))
dev_priv->lvds_ssc_freq = dev_priv->lvds_ssc_freq =
general->ssc_freq ? 66 : 48; general->ssc_freq ? 66 : 48;
else if (IS_IRONLAKE(dev_priv->dev)) else if (IS_IRONLAKE(dev_priv->dev) || IS_GEN6(dev))
dev_priv->lvds_ssc_freq = dev_priv->lvds_ssc_freq =
general->ssc_freq ? 100 : 120; general->ssc_freq ? 100 : 120;
else else

View File

@ -39,7 +39,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 temp, reg; u32 temp, reg;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
reg = PCH_ADPA; reg = PCH_ADPA;
else else
reg = ADPA; reg = ADPA;
@ -113,7 +113,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
else else
dpll_md_reg = DPLL_B_MD; dpll_md_reg = DPLL_B_MD;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
adpa_reg = PCH_ADPA; adpa_reg = PCH_ADPA;
else else
adpa_reg = ADPA; adpa_reg = ADPA;
@ -122,7 +122,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
* Disable separate mode multiplier used when cloning SDVO to CRT * Disable separate mode multiplier used when cloning SDVO to CRT
* XXX this needs to be adjusted when we really are cloning * XXX this needs to be adjusted when we really are cloning
*/ */
if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
dpll_md = I915_READ(dpll_md_reg); dpll_md = I915_READ(dpll_md_reg);
I915_WRITE(dpll_md_reg, I915_WRITE(dpll_md_reg,
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@ -136,11 +136,11 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
if (intel_crtc->pipe == 0) { if (intel_crtc->pipe == 0) {
adpa |= ADPA_PIPE_A_SELECT; adpa |= ADPA_PIPE_A_SELECT;
if (!IS_IRONLAKE(dev)) if (!HAS_PCH_SPLIT(dev))
I915_WRITE(BCLRPAT_A, 0); I915_WRITE(BCLRPAT_A, 0);
} else { } else {
adpa |= ADPA_PIPE_B_SELECT; adpa |= ADPA_PIPE_B_SELECT;
if (!IS_IRONLAKE(dev)) if (!HAS_PCH_SPLIT(dev))
I915_WRITE(BCLRPAT_B, 0); I915_WRITE(BCLRPAT_B, 0);
} }
@ -202,7 +202,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
u32 hotplug_en; u32 hotplug_en;
int i, tries = 0; int i, tries = 0;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
return intel_ironlake_crt_detect_hotplug(connector); return intel_ironlake_crt_detect_hotplug(connector);
/* /*
@ -524,7 +524,7 @@ void intel_crt_init(struct drm_device *dev)
&intel_output->enc); &intel_output->enc);
/* Set up the DDC bus. */ /* Set up the DDC bus. */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
i2c_reg = PCH_GPIOA; i2c_reg = PCH_GPIOA;
else { else {
i2c_reg = GPIOA; i2c_reg = GPIOA;

View File

@ -232,7 +232,7 @@ struct intel_limit {
#define G4X_P2_DISPLAY_PORT_FAST 10 #define G4X_P2_DISPLAY_PORT_FAST 10
#define G4X_P2_DISPLAY_PORT_LIMIT 0 #define G4X_P2_DISPLAY_PORT_LIMIT 0
/* Ironlake */ /* Ironlake / Sandybridge */
/* as we calculate clock using (register_value + 2) for /* as we calculate clock using (register_value + 2) for
N/M1/M2, so here the range value for them is (actual_value-2). N/M1/M2, so here the range value for them is (actual_value-2).
*/ */
@ -690,7 +690,7 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
const intel_limit_t *limit; const intel_limit_t *limit;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
limit = intel_ironlake_limit(crtc); limit = intel_ironlake_limit(crtc);
else if (IS_G4X(dev)) { else if (IS_G4X(dev)) {
limit = intel_g4x_limit(crtc); limit = intel_g4x_limit(crtc);
@ -886,7 +886,7 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
int lvds_reg; int lvds_reg;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
lvds_reg = PCH_LVDS; lvds_reg = PCH_LVDS;
else else
lvds_reg = LVDS; lvds_reg = LVDS;
@ -1188,25 +1188,30 @@ static void intel_update_fbc(struct drm_crtc *crtc,
if (intel_fb->obj->size > dev_priv->cfb_size) { if (intel_fb->obj->size > dev_priv->cfb_size) {
DRM_DEBUG_KMS("framebuffer too large, disabling " DRM_DEBUG_KMS("framebuffer too large, disabling "
"compression\n"); "compression\n");
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
goto out_disable; goto out_disable;
} }
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) || if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
(mode->flags & DRM_MODE_FLAG_DBLSCAN)) { (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
DRM_DEBUG_KMS("mode incompatible with compression, " DRM_DEBUG_KMS("mode incompatible with compression, "
"disabling\n"); "disabling\n");
dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
goto out_disable; goto out_disable;
} }
if ((mode->hdisplay > 2048) || if ((mode->hdisplay > 2048) ||
(mode->vdisplay > 1536)) { (mode->vdisplay > 1536)) {
DRM_DEBUG_KMS("mode too large for compression, disabling\n"); DRM_DEBUG_KMS("mode too large for compression, disabling\n");
dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
goto out_disable; goto out_disable;
} }
if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) { if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
DRM_DEBUG_KMS("plane not 0, disabling compression\n"); DRM_DEBUG_KMS("plane not 0, disabling compression\n");
dev_priv->no_fbc_reason = FBC_BAD_PLANE;
goto out_disable; goto out_disable;
} }
if (obj_priv->tiling_mode != I915_TILING_X) { if (obj_priv->tiling_mode != I915_TILING_X) {
DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n"); DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n");
dev_priv->no_fbc_reason = FBC_NOT_TILED;
goto out_disable; goto out_disable;
} }
@ -1366,7 +1371,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
dspcntr &= ~DISPPLANE_TILED; dspcntr &= ~DISPPLANE_TILED;
} }
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
/* must disable */ /* must disable */
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
@ -1427,7 +1432,7 @@ static void i915_disable_vga (struct drm_device *dev)
u8 sr1; u8 sr1;
u32 vga_reg; u32 vga_reg;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
vga_reg = CPU_VGACNTRL; vga_reg = CPU_VGACNTRL;
else else
vga_reg = VGACNTRL; vga_reg = VGACNTRL;
@ -2111,7 +2116,7 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
/* FDI link clock is fixed at 2.7G */ /* FDI link clock is fixed at 2.7G */
if (mode->clock * 3 > 27000 * 4) if (mode->clock * 3 > 27000 * 4)
return MODE_CLOCK_HIGH; return MODE_CLOCK_HIGH;
@ -2757,11 +2762,22 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
srwm = total_size - sr_entries; srwm = total_size - sr_entries;
if (srwm < 0) if (srwm < 0)
srwm = 1; srwm = 1;
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
if (IS_I945G(dev) || IS_I945GM(dev))
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
else if (IS_I915GM(dev)) {
/* 915M has a smaller SRWM field */
I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
}
} else { } else {
/* Turn off self refresh if both pipes are enabled */ /* Turn off self refresh if both pipes are enabled */
I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) if (IS_I945G(dev) || IS_I945GM(dev)) {
& ~FW_BLC_SELF_EN); I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
& ~FW_BLC_SELF_EN);
} else if (IS_I915GM(dev)) {
I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
}
} }
DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
@ -2967,7 +2983,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
refclk / 1000); refclk / 1000);
} else if (IS_I9XX(dev)) { } else if (IS_I9XX(dev)) {
refclk = 96000; refclk = 96000;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
refclk = 120000; /* 120Mhz refclk */ refclk = 120000; /* 120Mhz refclk */
} else { } else {
refclk = 48000; refclk = 48000;
@ -3025,7 +3041,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
} }
/* FDI link */ /* FDI link */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
int lane, link_bw, bpp; int lane, link_bw, bpp;
/* eDP doesn't require FDI link, so just set DP M/N /* eDP doesn't require FDI link, so just set DP M/N
according to current link config */ according to current link config */
@ -3102,7 +3118,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* PCH B stepping, previous chipset stepping should be * PCH B stepping, previous chipset stepping should be
* ignoring this setting. * ignoring this setting.
*/ */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
temp = I915_READ(PCH_DREF_CONTROL); temp = I915_READ(PCH_DREF_CONTROL);
/* Always enable nonspread source */ /* Always enable nonspread source */
temp &= ~DREF_NONSPREAD_SOURCE_MASK; temp &= ~DREF_NONSPREAD_SOURCE_MASK;
@ -3149,7 +3165,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
reduced_clock.m2; reduced_clock.m2;
} }
if (!IS_IRONLAKE(dev)) if (!HAS_PCH_SPLIT(dev))
dpll = DPLL_VGA_MODE_DIS; dpll = DPLL_VGA_MODE_DIS;
if (IS_I9XX(dev)) { if (IS_I9XX(dev)) {
@ -3162,7 +3178,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
else if (IS_IRONLAKE(dev)) else if (HAS_PCH_SPLIT(dev))
dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
} }
if (is_dp) if (is_dp)
@ -3174,7 +3190,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
else { else {
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
/* also FPA1 */ /* also FPA1 */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
if (IS_G4X(dev) && has_reduced_clock) if (IS_G4X(dev) && has_reduced_clock)
dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
@ -3193,7 +3209,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break; break;
} }
if (IS_I965G(dev) && !IS_IRONLAKE(dev)) if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
} else { } else {
if (is_lvds) { if (is_lvds) {
@ -3227,7 +3243,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Ironlake's plane is forced to pipe, bit 24 is to /* Ironlake's plane is forced to pipe, bit 24 is to
enable color space conversion */ enable color space conversion */
if (!IS_IRONLAKE(dev)) { if (!HAS_PCH_SPLIT(dev)) {
if (pipe == 0) if (pipe == 0)
dspcntr &= ~DISPPLANE_SEL_PIPE_MASK; dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
else else
@ -3254,14 +3270,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Disable the panel fitter if it was on our pipe */ /* Disable the panel fitter if it was on our pipe */
if (!IS_IRONLAKE(dev) && intel_panel_fitter_pipe(dev) == pipe) if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
I915_WRITE(PFIT_CONTROL, 0); I915_WRITE(PFIT_CONTROL, 0);
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode); drm_mode_debug_printmodeline(mode);
/* assign to Ironlake registers */ /* assign to Ironlake registers */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
fp_reg = pch_fp_reg; fp_reg = pch_fp_reg;
dpll_reg = pch_dpll_reg; dpll_reg = pch_dpll_reg;
} }
@ -3282,7 +3298,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
if (is_lvds) { if (is_lvds) {
u32 lvds; u32 lvds;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
lvds_reg = PCH_LVDS; lvds_reg = PCH_LVDS;
lvds = I915_READ(lvds_reg); lvds = I915_READ(lvds_reg);
@ -3304,12 +3320,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* set the dithering flag */ /* set the dithering flag */
if (IS_I965G(dev)) { if (IS_I965G(dev)) {
if (dev_priv->lvds_dither) { if (dev_priv->lvds_dither) {
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
pipeconf |= PIPE_ENABLE_DITHER; pipeconf |= PIPE_ENABLE_DITHER;
else else
lvds |= LVDS_ENABLE_DITHER; lvds |= LVDS_ENABLE_DITHER;
} else { } else {
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
pipeconf &= ~PIPE_ENABLE_DITHER; pipeconf &= ~PIPE_ENABLE_DITHER;
else else
lvds &= ~LVDS_ENABLE_DITHER; lvds &= ~LVDS_ENABLE_DITHER;
@ -3328,7 +3344,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Wait for the clocks to stabilize. */ /* Wait for the clocks to stabilize. */
udelay(150); udelay(150);
if (IS_I965G(dev) && !IS_IRONLAKE(dev)) { if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
if (is_sdvo) { if (is_sdvo) {
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
@ -3375,14 +3391,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* pipesrc and dspsize control the size that is scaled from, which should /* pipesrc and dspsize control the size that is scaled from, which should
* always be the user's requested size. * always be the user's requested size.
*/ */
if (!IS_IRONLAKE(dev)) { if (!HAS_PCH_SPLIT(dev)) {
I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
(mode->hdisplay - 1)); (mode->hdisplay - 1));
I915_WRITE(dsppos_reg, 0); I915_WRITE(dsppos_reg, 0);
} }
I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m); 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(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
I915_WRITE(link_m1_reg, m_n.link_m); I915_WRITE(link_m1_reg, m_n.link_m);
@ -3438,7 +3454,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
return; return;
/* use legacy palette for Ironlake */ /* use legacy palette for Ironlake */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A : palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A :
LGC_PALETTE_B; LGC_PALETTE_B;
@ -3553,11 +3569,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
intel_crtc->cursor_bo = bo; intel_crtc->cursor_bo = bo;
return 0; return 0;
fail:
mutex_lock(&dev->struct_mutex);
fail_locked: fail_locked:
drm_gem_object_unreference(bo);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
fail:
drm_gem_object_unreference_unlocked(bo);
return ret; return ret;
} }
@ -3922,7 +3937,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
int dpll = I915_READ(dpll_reg); int dpll = I915_READ(dpll_reg);
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
return; return;
if (!dev_priv->lvds_downclock_avail) if (!dev_priv->lvds_downclock_avail)
@ -3961,7 +3976,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
int dpll = I915_READ(dpll_reg); int dpll = I915_READ(dpll_reg);
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
return; return;
if (!dev_priv->lvds_downclock_avail) if (!dev_priv->lvds_downclock_avail)
@ -4011,6 +4026,11 @@ static void intel_idle_update(struct work_struct *work)
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (IS_I945G(dev) || IS_I945GM(dev)) {
DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
}
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
/* Skip inactive CRTCs */ /* Skip inactive CRTCs */
if (!crtc->fb) if (!crtc->fb)
@ -4044,9 +4064,17 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
return; return;
if (!dev_priv->busy) if (!dev_priv->busy) {
if (IS_I945G(dev) || IS_I945GM(dev)) {
u32 fw_blc_self;
DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
fw_blc_self = I915_READ(FW_BLC_SELF);
fw_blc_self &= ~FW_BLC_SELF_EN;
I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
}
dev_priv->busy = true; dev_priv->busy = true;
else } else
mod_timer(&dev_priv->idle_timer, jiffies + mod_timer(&dev_priv->idle_timer, jiffies +
msecs_to_jiffies(GPU_IDLE_TIMEOUT)); msecs_to_jiffies(GPU_IDLE_TIMEOUT));
@ -4058,6 +4086,14 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
intel_fb = to_intel_framebuffer(crtc->fb); intel_fb = to_intel_framebuffer(crtc->fb);
if (intel_fb->obj == obj) { if (intel_fb->obj == obj) {
if (!intel_crtc->busy) { if (!intel_crtc->busy) {
if (IS_I945G(dev) || IS_I945GM(dev)) {
u32 fw_blc_self;
DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
fw_blc_self = I915_READ(FW_BLC_SELF);
fw_blc_self &= ~FW_BLC_SELF_EN;
I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
}
/* Non-busy -> busy, upclock */ /* Non-busy -> busy, upclock */
intel_increase_pllclock(crtc, true); intel_increase_pllclock(crtc, true);
intel_crtc->busy = true; intel_crtc->busy = true;
@ -4382,7 +4418,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (IS_MOBILE(dev) && !IS_I830(dev)) if (IS_MOBILE(dev) && !IS_I830(dev))
intel_lvds_init(dev); intel_lvds_init(dev);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
int found; int found;
if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED)) if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
@ -4451,7 +4487,7 @@ static void intel_setup_outputs(struct drm_device *dev)
DRM_DEBUG_KMS("probing DP_D\n"); DRM_DEBUG_KMS("probing DP_D\n");
intel_dp_init(dev, DP_D); intel_dp_init(dev, DP_D);
} }
} else if (IS_I8XX(dev)) } else if (IS_GEN2(dev))
intel_dvo_init(dev); intel_dvo_init(dev);
if (SUPPORTS_TV(dev)) if (SUPPORTS_TV(dev))
@ -4476,9 +4512,7 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
intelfb_remove(dev, fb); intelfb_remove(dev, fb);
drm_framebuffer_cleanup(fb); drm_framebuffer_cleanup(fb);
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(intel_fb->obj);
drm_gem_object_unreference(intel_fb->obj);
mutex_unlock(&dev->struct_mutex);
kfree(intel_fb); kfree(intel_fb);
} }
@ -4541,9 +4575,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj); ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);
if (ret) { if (ret) {
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(obj);
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
return NULL; return NULL;
} }
@ -4591,6 +4623,91 @@ intel_alloc_power_context(struct drm_device *dev)
return NULL; return NULL;
} }
void ironlake_enable_drps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl;
u8 fmax, fmin, fstart, vstart;
int i = 0;
/* 100ms RC evaluation intervals */
I915_WRITE(RCUPEI, 100000);
I915_WRITE(RCDNEI, 100000);
/* Set max/min thresholds to 90ms and 80ms respectively */
I915_WRITE(RCBMAXAVG, 90000);
I915_WRITE(RCBMINAVG, 80000);
I915_WRITE(MEMIHYST, 1);
/* Set up min, max, and cur for interrupt handling */
fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
MEMMODE_FSTART_SHIFT;
vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
PXVFREQ_PX_SHIFT;
dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */
dev_priv->min_delay = fmin;
dev_priv->cur_delay = fstart;
I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
/*
* Interrupts will be enabled in ironlake_irq_postinstall
*/
I915_WRITE(VIDSTART, vstart);
POSTING_READ(VIDSTART);
rgvmodectl |= MEMMODE_SWMODE_EN;
I915_WRITE(MEMMODECTL, rgvmodectl);
while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) {
if (i++ > 100) {
DRM_ERROR("stuck trying to change perf mode\n");
break;
}
msleep(1);
}
msleep(1);
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
(fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
I915_WRITE(MEMSWCTL, rgvswctl);
POSTING_READ(MEMSWCTL);
rgvswctl |= MEMCTL_CMD_STS;
I915_WRITE(MEMSWCTL, rgvswctl);
}
void ironlake_disable_drps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 rgvswctl;
u8 fstart;
/* Ack interrupts, disable EFC interrupt */
I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
I915_WRITE(DEIIR, DE_PCU_EVENT);
I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
/* Go back to the starting frequency */
fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >>
MEMMODE_FSTART_SHIFT;
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
(fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
I915_WRITE(MEMSWCTL, rgvswctl);
msleep(1);
rgvswctl |= MEMCTL_CMD_STS;
I915_WRITE(MEMSWCTL, rgvswctl);
msleep(1);
}
void intel_init_clock_gating(struct drm_device *dev) void intel_init_clock_gating(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
@ -4599,7 +4716,7 @@ void intel_init_clock_gating(struct drm_device *dev)
* Disable clock gating reported to work incorrectly according to the * Disable clock gating reported to work incorrectly according to the
* specs, but enable as much else as we can. * specs, but enable as much else as we can.
*/ */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
return; return;
} else if (IS_G4X(dev)) { } else if (IS_G4X(dev)) {
uint32_t dspclk_gate; uint32_t dspclk_gate;
@ -4672,7 +4789,7 @@ static void intel_init_display(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
/* We always want a DPMS function */ /* We always want a DPMS function */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
dev_priv->display.dpms = ironlake_crtc_dpms; dev_priv->display.dpms = ironlake_crtc_dpms;
else else
dev_priv->display.dpms = i9xx_crtc_dpms; dev_priv->display.dpms = i9xx_crtc_dpms;
@ -4715,7 +4832,7 @@ static void intel_init_display(struct drm_device *dev)
i830_get_display_clock_speed; i830_get_display_clock_speed;
/* For FIFO watermark updates */ /* For FIFO watermark updates */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
dev_priv->display.update_wm = NULL; dev_priv->display.update_wm = NULL;
else if (IS_G4X(dev)) else if (IS_G4X(dev))
dev_priv->display.update_wm = g4x_update_wm; dev_priv->display.update_wm = g4x_update_wm;
@ -4774,11 +4891,6 @@ void intel_modeset_init(struct drm_device *dev)
DRM_DEBUG_KMS("%d display pipe%s available.\n", DRM_DEBUG_KMS("%d display pipe%s available.\n",
num_pipe, num_pipe > 1 ? "s" : ""); num_pipe, num_pipe > 1 ? "s" : "");
if (IS_I85X(dev))
pci_read_config_word(dev->pdev, HPLLCC, &dev_priv->orig_clock);
else if (IS_I9XX(dev) || IS_G4X(dev))
pci_read_config_word(dev->pdev, GCFGC, &dev_priv->orig_clock);
for (i = 0; i < num_pipe; i++) { for (i = 0; i < num_pipe; i++) {
intel_crtc_init(dev, i); intel_crtc_init(dev, i);
} }
@ -4787,6 +4899,9 @@ void intel_modeset_init(struct drm_device *dev)
intel_init_clock_gating(dev); intel_init_clock_gating(dev);
if (IS_IRONLAKE_M(dev))
ironlake_enable_drps(dev);
INIT_WORK(&dev_priv->idle_work, intel_idle_update); INIT_WORK(&dev_priv->idle_work, intel_idle_update);
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
(unsigned long)dev); (unsigned long)dev);
@ -4834,6 +4949,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
drm_gem_object_unreference(dev_priv->pwrctx); drm_gem_object_unreference(dev_priv->pwrctx);
} }
if (IS_IRONLAKE_M(dev))
ironlake_disable_drps(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
drm_mode_config_cleanup(dev); drm_mode_config_cleanup(dev);

View File

@ -231,7 +231,7 @@ intel_dp_aux_ch(struct intel_output *intel_output,
*/ */
if (IS_eDP(intel_output)) if (IS_eDP(intel_output))
aux_clock_divider = 225; /* eDP input clock at 450Mhz */ aux_clock_divider = 225; /* eDP input clock at 450Mhz */
else if (IS_IRONLAKE(dev)) else if (HAS_PCH_SPLIT(dev))
aux_clock_divider = 62; /* IRL input clock fixed at 125Mhz */ aux_clock_divider = 62; /* IRL input clock fixed at 125Mhz */
else else
aux_clock_divider = intel_hrawclk(dev) / 2; aux_clock_divider = intel_hrawclk(dev) / 2;
@ -584,7 +584,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
intel_dp_compute_m_n(3, lane_count, intel_dp_compute_m_n(3, lane_count,
mode->clock, adjusted_mode->clock, &m_n); mode->clock, adjusted_mode->clock, &m_n);
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
if (intel_crtc->pipe == 0) { if (intel_crtc->pipe == 0) {
I915_WRITE(TRANSA_DATA_M1, I915_WRITE(TRANSA_DATA_M1,
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
@ -1176,7 +1176,7 @@ intel_dp_detect(struct drm_connector *connector)
dp_priv->has_audio = false; dp_priv->has_audio = false;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
return ironlake_dp_detect(connector); return ironlake_dp_detect(connector);
temp = I915_READ(PORT_HOTPLUG_EN); temp = I915_READ(PORT_HOTPLUG_EN);

View File

@ -209,6 +209,8 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno); u16 *blue, int regno);
extern void intel_init_clock_gating(struct drm_device *dev); extern void intel_init_clock_gating(struct drm_device *dev);
extern void ironlake_enable_drps(struct drm_device *dev);
extern void ironlake_disable_drps(struct drm_device *dev);
extern int intel_framebuffer_create(struct drm_device *dev, extern int intel_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd, struct drm_mode_fb_cmd *mode_cmd,

View File

@ -35,6 +35,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/vga_switcheroo.h>
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
@ -235,6 +236,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
obj_priv->gtt_offset, fbo); obj_priv->gtt_offset, fbo);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
vga_switcheroo_client_fb_set(dev->pdev, info);
return 0; return 0;
out_unpin: out_unpin:

View File

@ -82,7 +82,7 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
/* HW workaround, need to toggle enable bit off and on for 12bpc, but /* HW workaround, need to toggle enable bit off and on for 12bpc, but
* we do this anyway which shows more stable in testing. * we do this anyway which shows more stable in testing.
*/ */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE); I915_WRITE(hdmi_priv->sdvox_reg, temp & ~SDVO_ENABLE);
POSTING_READ(hdmi_priv->sdvox_reg); POSTING_READ(hdmi_priv->sdvox_reg);
} }
@ -99,7 +99,7 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
/* HW workaround, need to write this twice for issue that may result /* HW workaround, need to write this twice for issue that may result
* in first write getting masked. * in first write getting masked.
*/ */
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(hdmi_priv->sdvox_reg, temp); I915_WRITE(hdmi_priv->sdvox_reg, temp);
POSTING_READ(hdmi_priv->sdvox_reg); POSTING_READ(hdmi_priv->sdvox_reg);
} }

View File

@ -128,7 +128,7 @@ intel_i2c_reset_gmbus(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(PCH_GMBUS0, 0); I915_WRITE(PCH_GMBUS0, 0);
} else { } else {
I915_WRITE(GMBUS0, 0); I915_WRITE(GMBUS0, 0);

View File

@ -56,7 +56,7 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 blc_pwm_ctl, reg; u32 blc_pwm_ctl, reg;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
reg = BLC_PWM_CPU_CTL; reg = BLC_PWM_CPU_CTL;
else else
reg = BLC_PWM_CTL; reg = BLC_PWM_CTL;
@ -74,7 +74,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg; u32 reg;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
reg = BLC_PWM_PCH_CTL2; reg = BLC_PWM_PCH_CTL2;
else else
reg = BLC_PWM_CTL; reg = BLC_PWM_CTL;
@ -89,17 +89,22 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
static void intel_lvds_set_power(struct drm_device *dev, bool on) static void intel_lvds_set_power(struct drm_device *dev, bool on)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_status, ctl_reg, status_reg; u32 pp_status, ctl_reg, status_reg, lvds_reg;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
ctl_reg = PCH_PP_CONTROL; ctl_reg = PCH_PP_CONTROL;
status_reg = PCH_PP_STATUS; status_reg = PCH_PP_STATUS;
lvds_reg = PCH_LVDS;
} else { } else {
ctl_reg = PP_CONTROL; ctl_reg = PP_CONTROL;
status_reg = PP_STATUS; status_reg = PP_STATUS;
lvds_reg = LVDS;
} }
if (on) { if (on) {
I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
POSTING_READ(lvds_reg);
I915_WRITE(ctl_reg, I915_READ(ctl_reg) | I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
POWER_TARGET_ON); POWER_TARGET_ON);
do { do {
@ -115,6 +120,9 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
do { do {
pp_status = I915_READ(status_reg); pp_status = I915_READ(status_reg);
} while (pp_status & PP_ON); } while (pp_status & PP_ON);
I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
POSTING_READ(lvds_reg);
} }
} }
@ -137,7 +145,7 @@ static void intel_lvds_save(struct drm_connector *connector)
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg; u32 pwm_ctl_reg;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
pp_on_reg = PCH_PP_ON_DELAYS; pp_on_reg = PCH_PP_ON_DELAYS;
pp_off_reg = PCH_PP_OFF_DELAYS; pp_off_reg = PCH_PP_OFF_DELAYS;
pp_ctl_reg = PCH_PP_CONTROL; pp_ctl_reg = PCH_PP_CONTROL;
@ -174,7 +182,7 @@ static void intel_lvds_restore(struct drm_connector *connector)
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg; u32 pwm_ctl_reg;
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
pp_on_reg = PCH_PP_ON_DELAYS; pp_on_reg = PCH_PP_ON_DELAYS;
pp_off_reg = PCH_PP_OFF_DELAYS; pp_off_reg = PCH_PP_OFF_DELAYS;
pp_ctl_reg = PCH_PP_CONTROL; pp_ctl_reg = PCH_PP_CONTROL;
@ -297,7 +305,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
} }
/* full screen scale for now */ /* full screen scale for now */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
goto out; goto out;
/* 965+ wants fuzzy fitting */ /* 965+ wants fuzzy fitting */
@ -327,7 +335,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* to register description and PRM. * to register description and PRM.
* Change the value here to see the borders for debugging * Change the value here to see the borders for debugging
*/ */
if (!IS_IRONLAKE(dev)) { if (!HAS_PCH_SPLIT(dev)) {
I915_WRITE(BCLRPAT_A, 0); I915_WRITE(BCLRPAT_A, 0);
I915_WRITE(BCLRPAT_B, 0); I915_WRITE(BCLRPAT_B, 0);
} }
@ -548,7 +556,7 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg; u32 reg;
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
reg = BLC_PWM_CPU_CTL; reg = BLC_PWM_CPU_CTL;
else else
reg = BLC_PWM_CTL; reg = BLC_PWM_CTL;
@ -587,7 +595,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
* settings. * settings.
*/ */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
return; return;
/* /*
@ -655,8 +663,15 @@ static const struct dmi_system_id bad_lid_status[] = {
*/ */
static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector) static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
{ {
struct drm_device *dev = connector->dev;
enum drm_connector_status status = connector_status_connected; enum drm_connector_status status = connector_status_connected;
/* ACPI lid methods were generally unreliable in this generation, so
* don't even bother.
*/
if (IS_GEN2(dev))
return connector_status_connected;
if (!dmi_check_system(bad_lid_status) && !acpi_lid_open()) if (!dmi_check_system(bad_lid_status) && !acpi_lid_open())
status = connector_status_disconnected; status = connector_status_disconnected;
@ -1020,7 +1035,7 @@ void intel_lvds_init(struct drm_device *dev)
return; return;
} }
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
return; return;
if (dev_priv->edp_support) { if (dev_priv->edp_support) {
@ -1123,7 +1138,7 @@ void intel_lvds_init(struct drm_device *dev)
*/ */
/* Ironlake: FIXME if still fail, not try pipe mode now */ /* Ironlake: FIXME if still fail, not try pipe mode now */
if (IS_IRONLAKE(dev)) if (HAS_PCH_SPLIT(dev))
goto failed; goto failed;
lvds = I915_READ(LVDS); lvds = I915_READ(LVDS);
@ -1144,7 +1159,7 @@ void intel_lvds_init(struct drm_device *dev)
goto failed; goto failed;
out: out:
if (IS_IRONLAKE(dev)) { if (HAS_PCH_SPLIT(dev)) {
u32 pwm; u32 pwm;
/* make sure PWM is enabled */ /* make sure PWM is enabled */
pwm = I915_READ(BLC_PWM_CPU_CTL2); pwm = I915_READ(BLC_PWM_CPU_CTL2);

View File

@ -172,7 +172,7 @@ struct overlay_registers {
#define OFC_UPDATE 0x1 #define OFC_UPDATE 0x1
#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev)) #define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev)) #define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev))
static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay) static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
@ -199,16 +199,11 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over
static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
{ {
struct drm_device *dev = overlay->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
if (OVERLAY_NONPHYSICAL(overlay->dev)) if (OVERLAY_NONPHYSICAL(overlay->dev))
io_mapping_unmap_atomic(overlay->virt_addr); io_mapping_unmap_atomic(overlay->virt_addr);
overlay->virt_addr = NULL; overlay->virt_addr = NULL;
I915_READ(OVADD); /* flush wc cashes */
return; return;
} }
@ -225,9 +220,7 @@ static int intel_overlay_on(struct intel_overlay *overlay)
overlay->active = 1; overlay->active = 1;
overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP; overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
BEGIN_LP_RING(6); BEGIN_LP_RING(4);
OUT_RING(MI_FLUSH);
OUT_RING(MI_NOOP);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
OUT_RING(overlay->flip_addr | OFC_UPDATE); OUT_RING(overlay->flip_addr | OFC_UPDATE);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@ -267,9 +260,7 @@ static void intel_overlay_continue(struct intel_overlay *overlay,
if (tmp & (1 << 17)) if (tmp & (1 << 17))
DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
BEGIN_LP_RING(4); BEGIN_LP_RING(2);
OUT_RING(MI_FLUSH);
OUT_RING(MI_NOOP);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
OUT_RING(flip_addr); OUT_RING(flip_addr);
ADVANCE_LP_RING(); ADVANCE_LP_RING();
@ -338,9 +329,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
/* wait for overlay to go idle */ /* wait for overlay to go idle */
overlay->hw_wedged = SWITCH_OFF_STAGE_1; overlay->hw_wedged = SWITCH_OFF_STAGE_1;
BEGIN_LP_RING(6); BEGIN_LP_RING(4);
OUT_RING(MI_FLUSH);
OUT_RING(MI_NOOP);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
OUT_RING(flip_addr); OUT_RING(flip_addr);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@ -358,9 +347,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
/* turn overlay off */ /* turn overlay off */
overlay->hw_wedged = SWITCH_OFF_STAGE_2; overlay->hw_wedged = SWITCH_OFF_STAGE_2;
BEGIN_LP_RING(6); BEGIN_LP_RING(4);
OUT_RING(MI_FLUSH);
OUT_RING(MI_NOOP);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
OUT_RING(flip_addr); OUT_RING(flip_addr);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@ -435,9 +422,7 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
overlay->hw_wedged = SWITCH_OFF_STAGE_2; overlay->hw_wedged = SWITCH_OFF_STAGE_2;
BEGIN_LP_RING(6); BEGIN_LP_RING(4);
OUT_RING(MI_FLUSH);
OUT_RING(MI_NOOP);
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF); OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
OUT_RING(flip_addr); OUT_RING(flip_addr);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
@ -1179,7 +1164,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
out_unlock: out_unlock:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
drm_gem_object_unreference(new_bo); drm_gem_object_unreference_unlocked(new_bo);
kfree(params); kfree(params);
return ret; return ret;

View File

@ -35,6 +35,7 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
#include "intel_sdvo_regs.h" #include "intel_sdvo_regs.h"
#include <linux/dmi.h>
static char *tv_format_names[] = { static char *tv_format_names[] = {
"NTSC_M" , "NTSC_J" , "NTSC_443", "NTSC_M" , "NTSC_J" , "NTSC_443",
@ -2283,6 +2284,25 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
return 0x72; return 0x72;
} }
static int intel_sdvo_bad_tv_callback(const struct dmi_system_id *id)
{
DRM_DEBUG_KMS("Ignoring bad SDVO TV connector for %s\n", id->ident);
return 1;
}
static struct dmi_system_id intel_sdvo_bad_tv[] = {
{
.callback = intel_sdvo_bad_tv_callback,
.ident = "IntelG45/ICH10R/DME1737",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "IBM CORPORATION"),
DMI_MATCH(DMI_PRODUCT_NAME, "4800784"),
},
},
{ } /* terminating entry */
};
static bool static bool
intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags) intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
{ {
@ -2323,7 +2343,8 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
(1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT); (1 << INTEL_ANALOG_CLONE_BIT);
} }
} else if (flags & SDVO_OUTPUT_SVID0) { } else if ((flags & SDVO_OUTPUT_SVID0) &&
!dmi_check_system(intel_sdvo_bad_tv)) {
sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
encoder->encoder_type = DRM_MODE_ENCODER_TVDAC; encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;

View File

@ -16,7 +16,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \ nv04_graph.o nv10_graph.o nv20_graph.o \
nv40_graph.o nv50_graph.o \ nv40_graph.o nv50_graph.o \
nv40_grctx.o \ nv40_grctx.o nv50_grctx.o \
nv04_instmem.o nv50_instmem.o \ nv04_instmem.o nv50_instmem.o \
nv50_crtc.o nv50_dac.o nv50_sor.o \ nv50_crtc.o nv50_dac.o nv50_sor.o \
nv50_cursor.o nv50_display.o nv50_fbcon.o \ nv50_cursor.o nv50_display.o nv50_fbcon.o \

View File

@ -11,6 +11,8 @@
#include "nouveau_drm.h" #include "nouveau_drm.h"
#include "nv50_display.h" #include "nv50_display.h"
#include <linux/vga_switcheroo.h>
#define NOUVEAU_DSM_SUPPORTED 0x00 #define NOUVEAU_DSM_SUPPORTED 0x00
#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00 #define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
@ -28,31 +30,30 @@
#define NOUVEAU_DSM_POWER_SPEED 0x01 #define NOUVEAU_DSM_POWER_SPEED 0x01
#define NOUVEAU_DSM_POWER_STAMINA 0x02 #define NOUVEAU_DSM_POWER_STAMINA 0x02
static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result) static struct nouveau_dsm_priv {
{ bool dsm_detected;
static char muid[] = { acpi_handle dhandle;
0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D, acpi_handle dsm_handle;
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4, } nouveau_dsm_priv;
};
struct pci_dev *pdev = dev->pdev; static const char nouveau_dsm_muid[] = {
struct acpi_handle *handle; 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
};
static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input; struct acpi_object_list input;
union acpi_object params[4]; union acpi_object params[4];
union acpi_object *obj; union acpi_object *obj;
int err; int err;
handle = DEVICE_ACPI_HANDLE(&pdev->dev);
if (!handle)
return -ENODEV;
input.count = 4; input.count = 4;
input.pointer = params; input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER; params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = sizeof(muid); params[0].buffer.length = sizeof(nouveau_dsm_muid);
params[0].buffer.pointer = (char *)muid; params[0].buffer.pointer = (char *)nouveau_dsm_muid;
params[1].type = ACPI_TYPE_INTEGER; params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 0x00000102; params[1].integer.value = 0x00000102;
params[2].type = ACPI_TYPE_INTEGER; params[2].type = ACPI_TYPE_INTEGER;
@ -62,7 +63,7 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
err = acpi_evaluate_object(handle, "_DSM", &input, &output); err = acpi_evaluate_object(handle, "_DSM", &input, &output);
if (err) { if (err) {
NV_INFO(dev, "failed to evaluate _DSM: %d\n", err); printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
return err; return err;
} }
@ -86,40 +87,119 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
return 0; return 0;
} }
int nouveau_hybrid_setup(struct drm_device *dev) static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
{ {
int result; return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
}
if (nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STATE,
&result))
return -ENODEV;
NV_INFO(dev, "_DSM hardware status gave 0x%x\n", result);
if (result) { /* Ensure that the external GPU is enabled */
nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL);
nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED,
NULL);
} else { /* Stamina mode - disable the external GPU */
nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA,
NULL);
nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA,
NULL);
}
static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
{
int arg;
if (state == VGA_SWITCHEROO_ON)
arg = NOUVEAU_DSM_POWER_SPEED;
else
arg = NOUVEAU_DSM_POWER_STAMINA;
nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL);
return 0; return 0;
} }
bool nouveau_dsm_probe(struct drm_device *dev) static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
{ {
int support = 0; if (id == VGA_SWITCHEROO_IGD)
return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_STAMINA);
else
return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_SPEED);
}
if (nouveau_dsm(dev, NOUVEAU_DSM_SUPPORTED, static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &support)) enum vga_switcheroo_state state)
return false; {
if (id == VGA_SWITCHEROO_IGD)
if (!support) return 0;
return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dsm_handle, state);
}
static int nouveau_dsm_init(void)
{
return 0;
}
static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
{
if (nouveau_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
return VGA_SWITCHEROO_IGD;
else
return VGA_SWITCHEROO_DIS;
}
static struct vga_switcheroo_handler nouveau_dsm_handler = {
.switchto = nouveau_dsm_switchto,
.power_state = nouveau_dsm_power_state,
.init = nouveau_dsm_init,
.get_client_id = nouveau_dsm_get_client_id,
};
static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
{
acpi_handle dhandle, nvidia_handle;
acpi_status status;
int ret;
uint32_t result;
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
if (!dhandle)
return false;
status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle);
if (ACPI_FAILURE(status)) {
return false;
}
ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED,
NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
if (ret < 0)
return false; return false;
nouveau_dsm_priv.dhandle = dhandle;
nouveau_dsm_priv.dsm_handle = nvidia_handle;
return true; return true;
} }
static bool nouveau_dsm_detect(void)
{
char acpi_method_name[255] = { 0 };
struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
struct pci_dev *pdev = NULL;
int has_dsm = 0;
int vga_count = 0;
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
vga_count++;
has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
}
if (vga_count == 2 && has_dsm) {
acpi_get_name(nouveau_dsm_priv.dsm_handle, ACPI_FULL_PATHNAME, &buffer);
printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
acpi_method_name);
nouveau_dsm_priv.dsm_detected = true;
return true;
}
return false;
}
void nouveau_register_dsm_handler(void)
{
bool r;
r = nouveau_dsm_detect();
if (!r)
return;
vga_switcheroo_register_handler(&nouveau_dsm_handler);
}
void nouveau_unregister_dsm_handler(void)
{
vga_switcheroo_unregister_handler();
}

View File

@ -311,11 +311,11 @@ valid_reg(struct nvbios *bios, uint32_t reg)
/* C51 has misaligned regs on purpose. Marvellous */ /* C51 has misaligned regs on purpose. Marvellous */
if (reg & 0x2 || if (reg & 0x2 ||
(reg & 0x1 && dev_priv->VBIOS.pub.chip_version != 0x51)) (reg & 0x1 && dev_priv->vbios.chip_version != 0x51))
NV_ERROR(dev, "======= misaligned reg 0x%08X =======\n", reg); NV_ERROR(dev, "======= misaligned reg 0x%08X =======\n", reg);
/* warn on C51 regs that haven't been verified accessible in tracing */ /* warn on C51 regs that haven't been verified accessible in tracing */
if (reg & 0x1 && dev_priv->VBIOS.pub.chip_version == 0x51 && if (reg & 0x1 && dev_priv->vbios.chip_version == 0x51 &&
reg != 0x130d && reg != 0x1311 && reg != 0x60081d) reg != 0x130d && reg != 0x1311 && reg != 0x60081d)
NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n", NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n",
reg); reg);
@ -420,7 +420,7 @@ bios_wr32(struct nvbios *bios, uint32_t reg, uint32_t data)
LOG_OLD_VALUE(bios_rd32(bios, reg)); LOG_OLD_VALUE(bios_rd32(bios, reg));
BIOSLOG(bios, " Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data); BIOSLOG(bios, " Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
if (dev_priv->VBIOS.execute) { if (dev_priv->vbios.execute) {
still_alive(); still_alive();
nv_wr32(bios->dev, reg, data); nv_wr32(bios->dev, reg, data);
} }
@ -647,7 +647,7 @@ nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk)
reg0 = (reg0 & 0xfff8ffff) | (pll.log2P << 16); reg0 = (reg0 & 0xfff8ffff) | (pll.log2P << 16);
reg1 = (reg1 & 0xffff0000) | (pll.N1 << 8) | pll.M1; reg1 = (reg1 & 0xffff0000) | (pll.N1 << 8) | pll.M1;
if (dev_priv->VBIOS.execute) { if (dev_priv->vbios.execute) {
still_alive(); still_alive();
nv_wr32(dev, reg + 4, reg1); nv_wr32(dev, reg + 4, reg1);
nv_wr32(dev, reg + 0, reg0); nv_wr32(dev, reg + 0, reg0);
@ -689,7 +689,7 @@ setPLL(struct nvbios *bios, uint32_t reg, uint32_t clk)
static int dcb_entry_idx_from_crtchead(struct drm_device *dev) static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
/* /*
* For the results of this function to be correct, CR44 must have been * For the results of this function to be correct, CR44 must have been
@ -700,7 +700,7 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
uint8_t dcb_entry = NVReadVgaCrtc5758(dev, bios->state.crtchead, 0); uint8_t dcb_entry = NVReadVgaCrtc5758(dev, bios->state.crtchead, 0);
if (dcb_entry > bios->bdcb.dcb.entries) { if (dcb_entry > bios->dcb.entries) {
NV_ERROR(dev, "CR58 doesn't have a valid DCB entry currently " NV_ERROR(dev, "CR58 doesn't have a valid DCB entry currently "
"(%02X)\n", dcb_entry); "(%02X)\n", dcb_entry);
dcb_entry = 0x7f; /* unused / invalid marker */ dcb_entry = 0x7f; /* unused / invalid marker */
@ -713,25 +713,26 @@ static struct nouveau_i2c_chan *
init_i2c_device_find(struct drm_device *dev, int i2c_index) init_i2c_device_find(struct drm_device *dev, int i2c_index)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct bios_parsed_dcb *bdcb = &dev_priv->VBIOS.bdcb; struct dcb_table *dcb = &dev_priv->vbios.dcb;
if (i2c_index == 0xff) { if (i2c_index == 0xff) {
/* note: dcb_entry_idx_from_crtchead needs pre-script set-up */ /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
int idx = dcb_entry_idx_from_crtchead(dev), shift = 0; int idx = dcb_entry_idx_from_crtchead(dev), shift = 0;
int default_indices = bdcb->i2c_default_indices; int default_indices = dcb->i2c_default_indices;
if (idx != 0x7f && bdcb->dcb.entry[idx].i2c_upper_default) if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
shift = 4; shift = 4;
i2c_index = (default_indices >> shift) & 0xf; i2c_index = (default_indices >> shift) & 0xf;
} }
if (i2c_index == 0x80) /* g80+ */ if (i2c_index == 0x80) /* g80+ */
i2c_index = bdcb->i2c_default_indices & 0xf; i2c_index = dcb->i2c_default_indices & 0xf;
return nouveau_i2c_find(dev, i2c_index); return nouveau_i2c_find(dev, i2c_index);
} }
static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv) static uint32_t
get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
{ {
/* /*
* For mlv < 0x80, it is an index into a table of TMDS base addresses. * For mlv < 0x80, it is an index into a table of TMDS base addresses.
@ -744,6 +745,7 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios;
const int pramdac_offset[13] = { const int pramdac_offset[13] = {
0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 }; 0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
const uint32_t pramdac_table[4] = { const uint32_t pramdac_table[4] = {
@ -756,13 +758,12 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
dcb_entry = dcb_entry_idx_from_crtchead(dev); dcb_entry = dcb_entry_idx_from_crtchead(dev);
if (dcb_entry == 0x7f) if (dcb_entry == 0x7f)
return 0; return 0;
dacoffset = pramdac_offset[ dacoffset = pramdac_offset[bios->dcb.entry[dcb_entry].or];
dev_priv->VBIOS.bdcb.dcb.entry[dcb_entry].or];
if (mlv == 0x81) if (mlv == 0x81)
dacoffset ^= 8; dacoffset ^= 8;
return 0x6808b0 + dacoffset; return 0x6808b0 + dacoffset;
} else { } else {
if (mlv > ARRAY_SIZE(pramdac_table)) { if (mlv >= ARRAY_SIZE(pramdac_table)) {
NV_ERROR(dev, "Magic Lookup Value too big (%02X)\n", NV_ERROR(dev, "Magic Lookup Value too big (%02X)\n",
mlv); mlv);
return 0; return 0;
@ -2574,19 +2575,19 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
const uint8_t *gpio_table = &bios->data[bios->bdcb.gpio_table_ptr]; const uint8_t *gpio_table = &bios->data[bios->dcb.gpio_table_ptr];
const uint8_t *gpio_entry; const uint8_t *gpio_entry;
int i; int i;
if (!iexec->execute) if (!iexec->execute)
return 1; return 1;
if (bios->bdcb.version != 0x40) { if (bios->dcb.version != 0x40) {
NV_ERROR(bios->dev, "DCB table not version 4.0\n"); NV_ERROR(bios->dev, "DCB table not version 4.0\n");
return 0; return 0;
} }
if (!bios->bdcb.gpio_table_ptr) { if (!bios->dcb.gpio_table_ptr) {
NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n"); NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n");
return 0; return 0;
} }
@ -3123,7 +3124,7 @@ run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
struct dcb_entry *dcbent, int head, bool dl) struct dcb_entry *dcbent, int head, bool dl)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
struct init_exec iexec = {true, false}; struct init_exec iexec = {true, false};
NV_TRACE(dev, "0x%04X: Parsing digital output script table\n", NV_TRACE(dev, "0x%04X: Parsing digital output script table\n",
@ -3140,7 +3141,7 @@ run_digital_op_script(struct drm_device *dev, uint16_t scriptptr,
static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entry *dcbent, int head, enum LVDS_script script) static int call_lvds_manufacturer_script(struct drm_device *dev, struct dcb_entry *dcbent, int head, enum LVDS_script script)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
uint8_t sub = bios->data[bios->fp.xlated_entry + script] + (bios->fp.link_c_increment && dcbent->or & OUTPUT_C ? 1 : 0); uint8_t sub = bios->data[bios->fp.xlated_entry + script] + (bios->fp.link_c_increment && dcbent->or & OUTPUT_C ? 1 : 0);
uint16_t scriptofs = ROM16(bios->data[bios->init_script_tbls_ptr + sub * 2]); uint16_t scriptofs = ROM16(bios->data[bios->init_script_tbls_ptr + sub * 2]);
@ -3194,7 +3195,7 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int
* of a list of pxclks and script pointers. * of a list of pxclks and script pointers.
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
unsigned int outputset = (dcbent->or == 4) ? 1 : 0; unsigned int outputset = (dcbent->or == 4) ? 1 : 0;
uint16_t scriptptr = 0, clktable; uint16_t scriptptr = 0, clktable;
uint8_t clktableptr = 0; uint8_t clktableptr = 0;
@ -3261,7 +3262,7 @@ int call_lvds_script(struct drm_device *dev, struct dcb_entry *dcbent, int head,
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
uint8_t lvds_ver = bios->data[bios->fp.lvdsmanufacturerpointer]; uint8_t lvds_ver = bios->data[bios->fp.lvdsmanufacturerpointer];
uint32_t sel_clk_binding, sel_clk; uint32_t sel_clk_binding, sel_clk;
int ret; int ret;
@ -3395,7 +3396,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
#ifndef __powerpc__ #ifndef __powerpc__
NV_ERROR(dev, "Pointer to flat panel table invalid\n"); NV_ERROR(dev, "Pointer to flat panel table invalid\n");
#endif #endif
bios->pub.digital_min_front_porch = 0x4b; bios->digital_min_front_porch = 0x4b;
return 0; return 0;
} }
@ -3428,7 +3429,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
* fptable[4] is the minimum * fptable[4] is the minimum
* RAMDAC_FP_HCRTC -> RAMDAC_FP_HSYNC_START gap * RAMDAC_FP_HCRTC -> RAMDAC_FP_HSYNC_START gap
*/ */
bios->pub.digital_min_front_porch = fptable[4]; bios->digital_min_front_porch = fptable[4];
ofs = -7; ofs = -7;
break; break;
default: default:
@ -3467,7 +3468,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
/* nv4x cards need both a strap value and fpindex of 0xf to use DDC */ /* nv4x cards need both a strap value and fpindex of 0xf to use DDC */
if (lth.lvds_ver > 0x10) if (lth.lvds_ver > 0x10)
bios->pub.fp_no_ddc = fpstrapping != 0xf || fpindex != 0xf; bios->fp_no_ddc = fpstrapping != 0xf || fpindex != 0xf;
/* /*
* If either the strap or xlated fpindex value are 0xf there is no * If either the strap or xlated fpindex value are 0xf there is no
@ -3491,7 +3492,7 @@ static int parse_fp_mode_table(struct drm_device *dev, struct nvbios *bios)
bool nouveau_bios_fp_mode(struct drm_device *dev, struct drm_display_mode *mode) bool nouveau_bios_fp_mode(struct drm_device *dev, struct drm_display_mode *mode)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
uint8_t *mode_entry = &bios->data[bios->fp.mode_ptr]; uint8_t *mode_entry = &bios->data[bios->fp.mode_ptr];
if (!mode) /* just checking whether we can produce a mode */ if (!mode) /* just checking whether we can produce a mode */
@ -3562,11 +3563,11 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
* until later, when this function should be called with non-zero pxclk * until later, when this function should be called with non-zero pxclk
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
int fpstrapping = get_fp_strap(dev, bios), lvdsmanufacturerindex = 0; int fpstrapping = get_fp_strap(dev, bios), lvdsmanufacturerindex = 0;
struct lvdstableheader lth; struct lvdstableheader lth;
uint16_t lvdsofs; uint16_t lvdsofs;
int ret, chip_version = bios->pub.chip_version; int ret, chip_version = bios->chip_version;
ret = parse_lvds_manufacturer_table_header(dev, bios, &lth); ret = parse_lvds_manufacturer_table_header(dev, bios, &lth);
if (ret) if (ret)
@ -3682,7 +3683,7 @@ bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent,
uint16_t record, int record_len, int record_nr) uint16_t record, int record_len, int record_nr)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
uint32_t entry; uint32_t entry;
uint16_t table; uint16_t table;
int i, v; int i, v;
@ -3716,7 +3717,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
int *length) int *length)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
uint8_t *table; uint8_t *table;
if (!bios->display.dp_table_ptr) { if (!bios->display.dp_table_ptr) {
@ -3725,7 +3726,7 @@ nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent,
} }
table = &bios->data[bios->display.dp_table_ptr]; table = &bios->data[bios->display.dp_table_ptr];
if (table[0] != 0x21) { if (table[0] != 0x20 && table[0] != 0x21) {
NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n", NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n",
table[0]); table[0]);
return NULL; return NULL;
@ -3765,7 +3766,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
uint8_t *table = &bios->data[bios->display.script_table_ptr]; uint8_t *table = &bios->data[bios->display.script_table_ptr];
uint8_t *otable = NULL; uint8_t *otable = NULL;
uint16_t script; uint16_t script;
@ -3918,8 +3919,8 @@ int run_tmds_table(struct drm_device *dev, struct dcb_entry *dcbent, int head, i
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
int cv = bios->pub.chip_version; int cv = bios->chip_version;
uint16_t clktable = 0, scriptptr; uint16_t clktable = 0, scriptptr;
uint32_t sel_clk_binding, sel_clk; uint32_t sel_clk_binding, sel_clk;
@ -3978,8 +3979,8 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
int cv = bios->pub.chip_version, pllindex = 0; int cv = bios->chip_version, pllindex = 0;
uint8_t pll_lim_ver = 0, headerlen = 0, recordlen = 0, entries = 0; uint8_t pll_lim_ver = 0, headerlen = 0, recordlen = 0, entries = 0;
uint32_t crystal_strap_mask, crystal_straps; uint32_t crystal_strap_mask, crystal_straps;
@ -4332,7 +4333,7 @@ static void parse_bios_version(struct drm_device *dev, struct nvbios *bios, uint
*/ */
bios->major_version = bios->data[offset + 3]; bios->major_version = bios->data[offset + 3];
bios->pub.chip_version = bios->data[offset + 2]; bios->chip_version = bios->data[offset + 2];
NV_TRACE(dev, "Bios version %02x.%02x.%02x.%02x\n", NV_TRACE(dev, "Bios version %02x.%02x.%02x.%02x\n",
bios->data[offset + 3], bios->data[offset + 2], bios->data[offset + 3], bios->data[offset + 2],
bios->data[offset + 1], bios->data[offset]); bios->data[offset + 1], bios->data[offset]);
@ -4402,7 +4403,7 @@ static int parse_bit_A_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
} }
/* First entry is normal dac, 2nd tv-out perhaps? */ /* First entry is normal dac, 2nd tv-out perhaps? */
bios->pub.dactestval = ROM32(bios->data[load_table_ptr + headerlen]) & 0x3ff; bios->dactestval = ROM32(bios->data[load_table_ptr + headerlen]) & 0x3ff;
return 0; return 0;
} }
@ -4526,8 +4527,8 @@ static int parse_bit_i_tbl_entry(struct drm_device *dev, struct nvbios *bios, st
return -ENOSYS; return -ENOSYS;
} }
bios->pub.dactestval = ROM32(bios->data[daccmpoffset + dacheaderlen]); bios->dactestval = ROM32(bios->data[daccmpoffset + dacheaderlen]);
bios->pub.tvdactestval = ROM32(bios->data[daccmpoffset + dacheaderlen + 4]); bios->tvdactestval = ROM32(bios->data[daccmpoffset + dacheaderlen + 4]);
return 0; return 0;
} }
@ -4796,11 +4797,11 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
uint16_t legacy_scripts_offset, legacy_i2c_offset; uint16_t legacy_scripts_offset, legacy_i2c_offset;
/* load needed defaults in case we can't parse this info */ /* load needed defaults in case we can't parse this info */
bios->bdcb.dcb.i2c[0].write = NV_CIO_CRE_DDC_WR__INDEX; bios->dcb.i2c[0].write = NV_CIO_CRE_DDC_WR__INDEX;
bios->bdcb.dcb.i2c[0].read = NV_CIO_CRE_DDC_STATUS__INDEX; bios->dcb.i2c[0].read = NV_CIO_CRE_DDC_STATUS__INDEX;
bios->bdcb.dcb.i2c[1].write = NV_CIO_CRE_DDC0_WR__INDEX; bios->dcb.i2c[1].write = NV_CIO_CRE_DDC0_WR__INDEX;
bios->bdcb.dcb.i2c[1].read = NV_CIO_CRE_DDC0_STATUS__INDEX; bios->dcb.i2c[1].read = NV_CIO_CRE_DDC0_STATUS__INDEX;
bios->pub.digital_min_front_porch = 0x4b; bios->digital_min_front_porch = 0x4b;
bios->fmaxvco = 256000; bios->fmaxvco = 256000;
bios->fminvco = 128000; bios->fminvco = 128000;
bios->fp.duallink_transition_clk = 90000; bios->fp.duallink_transition_clk = 90000;
@ -4907,10 +4908,10 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset]; bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset];
bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1]; bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1];
bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2]; bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2];
bios->bdcb.dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4]; bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4];
bios->bdcb.dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5]; bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5];
bios->bdcb.dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6]; bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6];
bios->bdcb.dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7]; bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7];
if (bmplength > 74) { if (bmplength > 74) {
bios->fmaxvco = ROM32(bmp[67]); bios->fmaxvco = ROM32(bmp[67]);
@ -4984,7 +4985,8 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
else else
NV_WARN(dev, NV_WARN(dev,
"DCB I2C table has more entries than indexable " "DCB I2C table has more entries than indexable "
"(%d entries, max index 15)\n", i2ctable[2]); "(%d entries, max %d)\n", i2ctable[2],
DCB_MAX_NUM_I2C_ENTRIES);
entry_len = i2ctable[3]; entry_len = i2ctable[3];
/* [4] is i2c_default_indices, read in parse_dcb_table() */ /* [4] is i2c_default_indices, read in parse_dcb_table() */
} }
@ -5000,8 +5002,8 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
if (index == 0xf) if (index == 0xf)
return 0; return 0;
if (index > i2c_entries) { if (index >= i2c_entries) {
NV_ERROR(dev, "DCB I2C index too big (%d > %d)\n", NV_ERROR(dev, "DCB I2C index too big (%d >= %d)\n",
index, i2ctable[2]); index, i2ctable[2]);
return -ENOENT; return -ENOENT;
} }
@ -5036,7 +5038,7 @@ read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, i
static struct dcb_gpio_entry * static struct dcb_gpio_entry *
new_gpio_entry(struct nvbios *bios) new_gpio_entry(struct nvbios *bios)
{ {
struct parsed_dcb_gpio *gpio = &bios->bdcb.gpio; struct dcb_gpio_table *gpio = &bios->dcb.gpio;
return &gpio->entry[gpio->entries++]; return &gpio->entry[gpio->entries++];
} }
@ -5045,14 +5047,14 @@ struct dcb_gpio_entry *
nouveau_bios_gpio_entry(struct drm_device *dev, enum dcb_gpio_tag tag) nouveau_bios_gpio_entry(struct drm_device *dev, enum dcb_gpio_tag tag)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
int i; int i;
for (i = 0; i < bios->bdcb.gpio.entries; i++) { for (i = 0; i < bios->dcb.gpio.entries; i++) {
if (bios->bdcb.gpio.entry[i].tag != tag) if (bios->dcb.gpio.entry[i].tag != tag)
continue; continue;
return &bios->bdcb.gpio.entry[i]; return &bios->dcb.gpio.entry[i];
} }
return NULL; return NULL;
@ -5100,7 +5102,7 @@ static void
parse_dcb_gpio_table(struct nvbios *bios) parse_dcb_gpio_table(struct nvbios *bios)
{ {
struct drm_device *dev = bios->dev; struct drm_device *dev = bios->dev;
uint16_t gpio_table_ptr = bios->bdcb.gpio_table_ptr; uint16_t gpio_table_ptr = bios->dcb.gpio_table_ptr;
uint8_t *gpio_table = &bios->data[gpio_table_ptr]; uint8_t *gpio_table = &bios->data[gpio_table_ptr];
int header_len = gpio_table[1], int header_len = gpio_table[1],
entries = gpio_table[2], entries = gpio_table[2],
@ -5108,7 +5110,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
void (*parse_entry)(struct nvbios *, uint16_t) = NULL; void (*parse_entry)(struct nvbios *, uint16_t) = NULL;
int i; int i;
if (bios->bdcb.version >= 0x40) { if (bios->dcb.version >= 0x40) {
if (gpio_table_ptr && entry_len != 4) { if (gpio_table_ptr && entry_len != 4) {
NV_WARN(dev, "Invalid DCB GPIO table entry length.\n"); NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
return; return;
@ -5116,7 +5118,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
parse_entry = parse_dcb40_gpio_entry; parse_entry = parse_dcb40_gpio_entry;
} else if (bios->bdcb.version >= 0x30) { } else if (bios->dcb.version >= 0x30) {
if (gpio_table_ptr && entry_len != 2) { if (gpio_table_ptr && entry_len != 2) {
NV_WARN(dev, "Invalid DCB GPIO table entry length.\n"); NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
return; return;
@ -5124,7 +5126,7 @@ parse_dcb_gpio_table(struct nvbios *bios)
parse_entry = parse_dcb30_gpio_entry; parse_entry = parse_dcb30_gpio_entry;
} else if (bios->bdcb.version >= 0x22) { } else if (bios->dcb.version >= 0x22) {
/* /*
* DCBs older than v3.0 don't really have a GPIO * DCBs older than v3.0 don't really have a GPIO
* table, instead they keep some GPIO info at fixed * table, instead they keep some GPIO info at fixed
@ -5158,30 +5160,67 @@ struct dcb_connector_table_entry *
nouveau_bios_connector_entry(struct drm_device *dev, int index) nouveau_bios_connector_entry(struct drm_device *dev, int index)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
struct dcb_connector_table_entry *cte; struct dcb_connector_table_entry *cte;
if (index >= bios->bdcb.connector.entries) if (index >= bios->dcb.connector.entries)
return NULL; return NULL;
cte = &bios->bdcb.connector.entry[index]; cte = &bios->dcb.connector.entry[index];
if (cte->type == 0xff) if (cte->type == 0xff)
return NULL; return NULL;
return cte; return cte;
} }
static enum dcb_connector_type
divine_connector_type(struct nvbios *bios, int index)
{
struct dcb_table *dcb = &bios->dcb;
unsigned encoders = 0, type = DCB_CONNECTOR_NONE;
int i;
for (i = 0; i < dcb->entries; i++) {
if (dcb->entry[i].connector == index)
encoders |= (1 << dcb->entry[i].type);
}
if (encoders & (1 << OUTPUT_DP)) {
if (encoders & (1 << OUTPUT_TMDS))
type = DCB_CONNECTOR_DP;
else
type = DCB_CONNECTOR_eDP;
} else
if (encoders & (1 << OUTPUT_TMDS)) {
if (encoders & (1 << OUTPUT_ANALOG))
type = DCB_CONNECTOR_DVI_I;
else
type = DCB_CONNECTOR_DVI_D;
} else
if (encoders & (1 << OUTPUT_ANALOG)) {
type = DCB_CONNECTOR_VGA;
} else
if (encoders & (1 << OUTPUT_LVDS)) {
type = DCB_CONNECTOR_LVDS;
} else
if (encoders & (1 << OUTPUT_TV)) {
type = DCB_CONNECTOR_TV_0;
}
return type;
}
static void static void
parse_dcb_connector_table(struct nvbios *bios) parse_dcb_connector_table(struct nvbios *bios)
{ {
struct drm_device *dev = bios->dev; struct drm_device *dev = bios->dev;
struct dcb_connector_table *ct = &bios->bdcb.connector; struct dcb_connector_table *ct = &bios->dcb.connector;
struct dcb_connector_table_entry *cte; struct dcb_connector_table_entry *cte;
uint8_t *conntab = &bios->data[bios->bdcb.connector_table_ptr]; uint8_t *conntab = &bios->data[bios->dcb.connector_table_ptr];
uint8_t *entry; uint8_t *entry;
int i; int i;
if (!bios->bdcb.connector_table_ptr) { if (!bios->dcb.connector_table_ptr) {
NV_DEBUG_KMS(dev, "No DCB connector table present\n"); NV_DEBUG_KMS(dev, "No DCB connector table present\n");
return; return;
} }
@ -5203,6 +5242,7 @@ parse_dcb_connector_table(struct nvbios *bios)
cte->entry = ROM16(entry[0]); cte->entry = ROM16(entry[0]);
else else
cte->entry = ROM32(entry[0]); cte->entry = ROM32(entry[0]);
cte->type = (cte->entry & 0x000000ff) >> 0; cte->type = (cte->entry & 0x000000ff) >> 0;
cte->index = (cte->entry & 0x00000f00) >> 8; cte->index = (cte->entry & 0x00000f00) >> 8;
switch (cte->entry & 0x00033000) { switch (cte->entry & 0x00033000) {
@ -5228,10 +5268,33 @@ parse_dcb_connector_table(struct nvbios *bios)
NV_INFO(dev, " %d: 0x%08x: type 0x%02x idx %d tag 0x%02x\n", NV_INFO(dev, " %d: 0x%08x: type 0x%02x idx %d tag 0x%02x\n",
i, cte->entry, cte->type, cte->index, cte->gpio_tag); i, cte->entry, cte->type, cte->index, cte->gpio_tag);
/* check for known types, fallback to guessing the type
* from attached encoders if we hit an unknown.
*/
switch (cte->type) {
case DCB_CONNECTOR_VGA:
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
case DCB_CONNECTOR_TV_3:
case DCB_CONNECTOR_DVI_I:
case DCB_CONNECTOR_DVI_D:
case DCB_CONNECTOR_LVDS:
case DCB_CONNECTOR_DP:
case DCB_CONNECTOR_eDP:
case DCB_CONNECTOR_HDMI_0:
case DCB_CONNECTOR_HDMI_1:
break;
default:
cte->type = divine_connector_type(bios, cte->index);
NV_WARN(dev, "unknown type, using 0x%02x", cte->type);
break;
}
} }
} }
static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb) static struct dcb_entry *new_dcb_entry(struct dcb_table *dcb)
{ {
struct dcb_entry *entry = &dcb->entry[dcb->entries]; struct dcb_entry *entry = &dcb->entry[dcb->entries];
@ -5241,7 +5304,7 @@ static struct dcb_entry *new_dcb_entry(struct parsed_dcb *dcb)
return entry; return entry;
} }
static void fabricate_vga_output(struct parsed_dcb *dcb, int i2c, int heads) static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads)
{ {
struct dcb_entry *entry = new_dcb_entry(dcb); struct dcb_entry *entry = new_dcb_entry(dcb);
@ -5252,7 +5315,7 @@ static void fabricate_vga_output(struct parsed_dcb *dcb, int i2c, int heads)
/* "or" mostly unused in early gen crt modesetting, 0 is fine */ /* "or" mostly unused in early gen crt modesetting, 0 is fine */
} }
static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads) static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
{ {
struct dcb_entry *entry = new_dcb_entry(dcb); struct dcb_entry *entry = new_dcb_entry(dcb);
@ -5279,7 +5342,7 @@ static void fabricate_dvi_i_output(struct parsed_dcb *dcb, bool twoHeads)
#endif #endif
} }
static void fabricate_tv_output(struct parsed_dcb *dcb, bool twoHeads) static void fabricate_tv_output(struct dcb_table *dcb, bool twoHeads)
{ {
struct dcb_entry *entry = new_dcb_entry(dcb); struct dcb_entry *entry = new_dcb_entry(dcb);
@ -5290,13 +5353,13 @@ static void fabricate_tv_output(struct parsed_dcb *dcb, bool twoHeads)
} }
static bool static bool
parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb, parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
uint32_t conn, uint32_t conf, struct dcb_entry *entry) uint32_t conn, uint32_t conf, struct dcb_entry *entry)
{ {
entry->type = conn & 0xf; entry->type = conn & 0xf;
entry->i2c_index = (conn >> 4) & 0xf; entry->i2c_index = (conn >> 4) & 0xf;
entry->heads = (conn >> 8) & 0xf; entry->heads = (conn >> 8) & 0xf;
if (bdcb->version >= 0x40) if (dcb->version >= 0x40)
entry->connector = (conn >> 12) & 0xf; entry->connector = (conn >> 12) & 0xf;
entry->bus = (conn >> 16) & 0xf; entry->bus = (conn >> 16) & 0xf;
entry->location = (conn >> 20) & 0x3; entry->location = (conn >> 20) & 0x3;
@ -5314,7 +5377,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
* Although the rest of a CRT conf dword is usually * Although the rest of a CRT conf dword is usually
* zeros, mac biosen have stuff there so we must mask * zeros, mac biosen have stuff there so we must mask
*/ */
entry->crtconf.maxfreq = (bdcb->version < 0x30) ? entry->crtconf.maxfreq = (dcb->version < 0x30) ?
(conf & 0xffff) * 10 : (conf & 0xffff) * 10 :
(conf & 0xff) * 10000; (conf & 0xff) * 10000;
break; break;
@ -5323,7 +5386,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
uint32_t mask; uint32_t mask;
if (conf & 0x1) if (conf & 0x1)
entry->lvdsconf.use_straps_for_mode = true; entry->lvdsconf.use_straps_for_mode = true;
if (bdcb->version < 0x22) { if (dcb->version < 0x22) {
mask = ~0xd; mask = ~0xd;
/* /*
* The laptop in bug 14567 lies and claims to not use * The laptop in bug 14567 lies and claims to not use
@ -5347,7 +5410,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
* Until we even try to use these on G8x, it's * Until we even try to use these on G8x, it's
* useless reporting unknown bits. They all are. * useless reporting unknown bits. They all are.
*/ */
if (bdcb->version >= 0x40) if (dcb->version >= 0x40)
break; break;
NV_ERROR(dev, "Unknown LVDS configuration bits, " NV_ERROR(dev, "Unknown LVDS configuration bits, "
@ -5357,7 +5420,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
} }
case OUTPUT_TV: case OUTPUT_TV:
{ {
if (bdcb->version >= 0x30) if (dcb->version >= 0x30)
entry->tvconf.has_component_output = conf & (0x8 << 4); entry->tvconf.has_component_output = conf & (0x8 << 4);
else else
entry->tvconf.has_component_output = false; entry->tvconf.has_component_output = false;
@ -5384,8 +5447,10 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
break; break;
case 0xe: case 0xe:
/* weird g80 mobile type that "nv" treats as a terminator */ /* weird g80 mobile type that "nv" treats as a terminator */
bdcb->dcb.entries--; dcb->entries--;
return false; return false;
default:
break;
} }
/* unsure what DCB version introduces this, 3.0? */ /* unsure what DCB version introduces this, 3.0? */
@ -5396,7 +5461,7 @@ parse_dcb20_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb,
} }
static bool static bool
parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb, parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb,
uint32_t conn, uint32_t conf, struct dcb_entry *entry) uint32_t conn, uint32_t conf, struct dcb_entry *entry)
{ {
switch (conn & 0x0000000f) { switch (conn & 0x0000000f) {
@ -5462,27 +5527,27 @@ parse_dcb15_entry(struct drm_device *dev, struct parsed_dcb *dcb,
return true; return true;
} }
static bool parse_dcb_entry(struct drm_device *dev, struct bios_parsed_dcb *bdcb, static bool parse_dcb_entry(struct drm_device *dev, struct dcb_table *dcb,
uint32_t conn, uint32_t conf) uint32_t conn, uint32_t conf)
{ {
struct dcb_entry *entry = new_dcb_entry(&bdcb->dcb); struct dcb_entry *entry = new_dcb_entry(dcb);
bool ret; bool ret;
if (bdcb->version >= 0x20) if (dcb->version >= 0x20)
ret = parse_dcb20_entry(dev, bdcb, conn, conf, entry); ret = parse_dcb20_entry(dev, dcb, conn, conf, entry);
else else
ret = parse_dcb15_entry(dev, &bdcb->dcb, conn, conf, entry); ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
if (!ret) if (!ret)
return ret; return ret;
read_dcb_i2c_entry(dev, bdcb->version, bdcb->i2c_table, read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
entry->i2c_index, &bdcb->dcb.i2c[entry->i2c_index]); entry->i2c_index, &dcb->i2c[entry->i2c_index]);
return true; return true;
} }
static static
void merge_like_dcb_entries(struct drm_device *dev, struct parsed_dcb *dcb) void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb)
{ {
/* /*
* DCB v2.0 lists each output combination separately. * DCB v2.0 lists each output combination separately.
@ -5534,8 +5599,7 @@ static int
parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct bios_parsed_dcb *bdcb = &bios->bdcb; struct dcb_table *dcb = &bios->dcb;
struct parsed_dcb *dcb;
uint16_t dcbptr = 0, i2ctabptr = 0; uint16_t dcbptr = 0, i2ctabptr = 0;
uint8_t *dcbtable; uint8_t *dcbtable;
uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES; uint8_t headerlen = 0x4, entries = DCB_MAX_NUM_ENTRIES;
@ -5543,9 +5607,6 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
int recordlength = 8, confofs = 4; int recordlength = 8, confofs = 4;
int i; int i;
dcb = bios->pub.dcb = &bdcb->dcb;
dcb->entries = 0;
/* get the offset from 0x36 */ /* get the offset from 0x36 */
if (dev_priv->card_type > NV_04) { if (dev_priv->card_type > NV_04) {
dcbptr = ROM16(bios->data[0x36]); dcbptr = ROM16(bios->data[0x36]);
@ -5567,21 +5628,21 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
dcbtable = &bios->data[dcbptr]; dcbtable = &bios->data[dcbptr];
/* get DCB version */ /* get DCB version */
bdcb->version = dcbtable[0]; dcb->version = dcbtable[0];
NV_TRACE(dev, "Found Display Configuration Block version %d.%d\n", NV_TRACE(dev, "Found Display Configuration Block version %d.%d\n",
bdcb->version >> 4, bdcb->version & 0xf); dcb->version >> 4, dcb->version & 0xf);
if (bdcb->version >= 0x20) { /* NV17+ */ if (dcb->version >= 0x20) { /* NV17+ */
uint32_t sig; uint32_t sig;
if (bdcb->version >= 0x30) { /* NV40+ */ if (dcb->version >= 0x30) { /* NV40+ */
headerlen = dcbtable[1]; headerlen = dcbtable[1];
entries = dcbtable[2]; entries = dcbtable[2];
recordlength = dcbtable[3]; recordlength = dcbtable[3];
i2ctabptr = ROM16(dcbtable[4]); i2ctabptr = ROM16(dcbtable[4]);
sig = ROM32(dcbtable[6]); sig = ROM32(dcbtable[6]);
bdcb->gpio_table_ptr = ROM16(dcbtable[10]); dcb->gpio_table_ptr = ROM16(dcbtable[10]);
bdcb->connector_table_ptr = ROM16(dcbtable[20]); dcb->connector_table_ptr = ROM16(dcbtable[20]);
} else { } else {
i2ctabptr = ROM16(dcbtable[2]); i2ctabptr = ROM16(dcbtable[2]);
sig = ROM32(dcbtable[4]); sig = ROM32(dcbtable[4]);
@ -5593,7 +5654,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
"signature (%08X)\n", sig); "signature (%08X)\n", sig);
return -EINVAL; return -EINVAL;
} }
} else if (bdcb->version >= 0x15) { /* some NV11 and NV20 */ } else if (dcb->version >= 0x15) { /* some NV11 and NV20 */
char sig[8] = { 0 }; char sig[8] = { 0 };
strncpy(sig, (char *)&dcbtable[-7], 7); strncpy(sig, (char *)&dcbtable[-7], 7);
@ -5641,14 +5702,11 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
if (!i2ctabptr) if (!i2ctabptr)
NV_WARN(dev, "No pointer to DCB I2C port table\n"); NV_WARN(dev, "No pointer to DCB I2C port table\n");
else { else {
bdcb->i2c_table = &bios->data[i2ctabptr]; dcb->i2c_table = &bios->data[i2ctabptr];
if (bdcb->version >= 0x30) if (dcb->version >= 0x30)
bdcb->i2c_default_indices = bdcb->i2c_table[4]; dcb->i2c_default_indices = dcb->i2c_table[4];
} }
parse_dcb_gpio_table(bios);
parse_dcb_connector_table(bios);
if (entries > DCB_MAX_NUM_ENTRIES) if (entries > DCB_MAX_NUM_ENTRIES)
entries = DCB_MAX_NUM_ENTRIES; entries = DCB_MAX_NUM_ENTRIES;
@ -5673,7 +5731,7 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n", NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n",
dcb->entries, connection, config); dcb->entries, connection, config);
if (!parse_dcb_entry(dev, bdcb, connection, config)) if (!parse_dcb_entry(dev, dcb, connection, config))
break; break;
} }
@ -5681,18 +5739,22 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
* apart for v2.1+ not being known for requiring merging, this * apart for v2.1+ not being known for requiring merging, this
* guarantees dcbent->index is the index of the entry in the rom image * guarantees dcbent->index is the index of the entry in the rom image
*/ */
if (bdcb->version < 0x21) if (dcb->version < 0x21)
merge_like_dcb_entries(dev, dcb); merge_like_dcb_entries(dev, dcb);
return dcb->entries ? 0 : -ENXIO; if (!dcb->entries)
return -ENXIO;
parse_dcb_gpio_table(bios);
parse_dcb_connector_table(bios);
return 0;
} }
static void static void
fixup_legacy_connector(struct nvbios *bios) fixup_legacy_connector(struct nvbios *bios)
{ {
struct bios_parsed_dcb *bdcb = &bios->bdcb; struct dcb_table *dcb = &bios->dcb;
struct parsed_dcb *dcb = &bdcb->dcb; int i, i2c, i2c_conn[DCB_MAX_NUM_I2C_ENTRIES] = { };
int high = 0, i;
/* /*
* DCB 3.0 also has the table in most cases, but there are some cards * DCB 3.0 also has the table in most cases, but there are some cards
@ -5700,9 +5762,11 @@ fixup_legacy_connector(struct nvbios *bios)
* indices are all 0. We don't need the connector indices on pre-G80 * indices are all 0. We don't need the connector indices on pre-G80
* chips (yet?) so limit the use to DCB 4.0 and above. * chips (yet?) so limit the use to DCB 4.0 and above.
*/ */
if (bdcb->version >= 0x40) if (dcb->version >= 0x40)
return; return;
dcb->connector.entries = 0;
/* /*
* No known connector info before v3.0, so make it up. the rule here * No known connector info before v3.0, so make it up. the rule here
* is: anything on the same i2c bus is considered to be on the same * is: anything on the same i2c bus is considered to be on the same
@ -5710,37 +5774,38 @@ fixup_legacy_connector(struct nvbios *bios)
* its own unique connector index. * its own unique connector index.
*/ */
for (i = 0; i < dcb->entries; i++) { for (i = 0; i < dcb->entries; i++) {
if (dcb->entry[i].i2c_index == 0xf)
continue;
/* /*
* Ignore the I2C index for on-chip TV-out, as there * Ignore the I2C index for on-chip TV-out, as there
* are cards with bogus values (nv31m in bug 23212), * are cards with bogus values (nv31m in bug 23212),
* and it's otherwise useless. * and it's otherwise useless.
*/ */
if (dcb->entry[i].type == OUTPUT_TV && if (dcb->entry[i].type == OUTPUT_TV &&
dcb->entry[i].location == DCB_LOC_ON_CHIP) { dcb->entry[i].location == DCB_LOC_ON_CHIP)
dcb->entry[i].i2c_index = 0xf; dcb->entry[i].i2c_index = 0xf;
i2c = dcb->entry[i].i2c_index;
if (i2c_conn[i2c]) {
dcb->entry[i].connector = i2c_conn[i2c] - 1;
continue; continue;
} }
dcb->entry[i].connector = dcb->entry[i].i2c_index; dcb->entry[i].connector = dcb->connector.entries++;
if (dcb->entry[i].connector > high) if (i2c != 0xf)
high = dcb->entry[i].connector; i2c_conn[i2c] = dcb->connector.entries;
} }
for (i = 0; i < dcb->entries; i++) { /* Fake the connector table as well as just connector indices */
if (dcb->entry[i].i2c_index != 0xf) for (i = 0; i < dcb->connector.entries; i++) {
continue; dcb->connector.entry[i].index = i;
dcb->connector.entry[i].type = divine_connector_type(bios, i);
dcb->entry[i].connector = ++high; dcb->connector.entry[i].gpio_tag = 0xff;
} }
} }
static void static void
fixup_legacy_i2c(struct nvbios *bios) fixup_legacy_i2c(struct nvbios *bios)
{ {
struct parsed_dcb *dcb = &bios->bdcb.dcb; struct dcb_table *dcb = &bios->dcb;
int i; int i;
for (i = 0; i < dcb->entries; i++) { for (i = 0; i < dcb->entries; i++) {
@ -5826,7 +5891,7 @@ static int load_nv17_hw_sequencer_ucode(struct drm_device *dev,
uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev) uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
const uint8_t edid_sig[] = { const uint8_t edid_sig[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
uint16_t offset = 0; uint16_t offset = 0;
@ -5859,7 +5924,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
struct dcb_entry *dcbent) struct dcb_entry *dcbent)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
struct init_exec iexec = { true, false }; struct init_exec iexec = { true, false };
mutex_lock(&bios->lock); mutex_lock(&bios->lock);
@ -5872,7 +5937,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
static bool NVInitVBIOS(struct drm_device *dev) static bool NVInitVBIOS(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
memset(bios, 0, sizeof(struct nvbios)); memset(bios, 0, sizeof(struct nvbios));
mutex_init(&bios->lock); mutex_init(&bios->lock);
@ -5888,7 +5953,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
static int nouveau_parse_vbios_struct(struct drm_device *dev) static int nouveau_parse_vbios_struct(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' }; const uint8_t bit_signature[] = { 0xff, 0xb8, 'B', 'I', 'T' };
const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 }; const uint8_t bmp_signature[] = { 0xff, 0x7f, 'N', 'V', 0x0 };
int offset; int offset;
@ -5915,7 +5980,7 @@ int
nouveau_run_vbios_init(struct drm_device *dev) nouveau_run_vbios_init(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
int i, ret = 0; int i, ret = 0;
NVLockVgaCrtcs(dev, false); NVLockVgaCrtcs(dev, false);
@ -5946,9 +6011,9 @@ nouveau_run_vbios_init(struct drm_device *dev)
} }
if (dev_priv->card_type >= NV_50) { if (dev_priv->card_type >= NV_50) {
for (i = 0; i < bios->bdcb.dcb.entries; i++) { for (i = 0; i < bios->dcb.entries; i++) {
nouveau_bios_run_display_table(dev, nouveau_bios_run_display_table(dev,
&bios->bdcb.dcb.entry[i], &bios->dcb.entry[i],
0, 0); 0, 0);
} }
} }
@ -5962,11 +6027,11 @@ static void
nouveau_bios_i2c_devices_takedown(struct drm_device *dev) nouveau_bios_i2c_devices_takedown(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
struct dcb_i2c_entry *entry; struct dcb_i2c_entry *entry;
int i; int i;
entry = &bios->bdcb.dcb.i2c[0]; entry = &bios->dcb.i2c[0];
for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++) for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++)
nouveau_i2c_fini(dev, entry); nouveau_i2c_fini(dev, entry);
} }
@ -5975,13 +6040,11 @@ int
nouveau_bios_init(struct drm_device *dev) nouveau_bios_init(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
uint32_t saved_nv_pextdev_boot_0; uint32_t saved_nv_pextdev_boot_0;
bool was_locked; bool was_locked;
int ret; int ret;
dev_priv->vbios = &bios->pub;
if (!NVInitVBIOS(dev)) if (!NVInitVBIOS(dev))
return -ENODEV; return -ENODEV;
@ -6023,10 +6086,8 @@ nouveau_bios_init(struct drm_device *dev)
bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0); bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0);
ret = nouveau_run_vbios_init(dev); ret = nouveau_run_vbios_init(dev);
if (ret) { if (ret)
dev_priv->vbios = NULL;
return ret; return ret;
}
/* feature_byte on BMP is poor, but init always sets CR4B */ /* feature_byte on BMP is poor, but init always sets CR4B */
was_locked = NVLockVgaCrtcs(dev, false); was_locked = NVLockVgaCrtcs(dev, false);

View File

@ -34,9 +34,67 @@
#define DCB_LOC_ON_CHIP 0 #define DCB_LOC_ON_CHIP 0
struct dcb_i2c_entry {
uint8_t port_type;
uint8_t read, write;
struct nouveau_i2c_chan *chan;
};
enum dcb_gpio_tag {
DCB_GPIO_TVDAC0 = 0xc,
DCB_GPIO_TVDAC1 = 0x2d,
};
struct dcb_gpio_entry {
enum dcb_gpio_tag tag;
int line;
bool invert;
};
struct dcb_gpio_table {
int entries;
struct dcb_gpio_entry entry[DCB_MAX_NUM_GPIO_ENTRIES];
};
enum dcb_connector_type {
DCB_CONNECTOR_VGA = 0x00,
DCB_CONNECTOR_TV_0 = 0x10,
DCB_CONNECTOR_TV_1 = 0x11,
DCB_CONNECTOR_TV_3 = 0x13,
DCB_CONNECTOR_DVI_I = 0x30,
DCB_CONNECTOR_DVI_D = 0x31,
DCB_CONNECTOR_LVDS = 0x40,
DCB_CONNECTOR_DP = 0x46,
DCB_CONNECTOR_eDP = 0x47,
DCB_CONNECTOR_HDMI_0 = 0x60,
DCB_CONNECTOR_HDMI_1 = 0x61,
DCB_CONNECTOR_NONE = 0xff
};
struct dcb_connector_table_entry {
uint32_t entry;
enum dcb_connector_type type;
uint8_t index;
uint8_t gpio_tag;
};
struct dcb_connector_table {
int entries;
struct dcb_connector_table_entry entry[DCB_MAX_NUM_CONNECTOR_ENTRIES];
};
enum dcb_type {
OUTPUT_ANALOG = 0,
OUTPUT_TV = 1,
OUTPUT_TMDS = 2,
OUTPUT_LVDS = 3,
OUTPUT_DP = 6,
OUTPUT_ANY = -1
};
struct dcb_entry { struct dcb_entry {
int index; /* may not be raw dcb index if merging has happened */ int index; /* may not be raw dcb index if merging has happened */
uint8_t type; enum dcb_type type;
uint8_t i2c_index; uint8_t i2c_index;
uint8_t heads; uint8_t heads;
uint8_t connector; uint8_t connector;
@ -71,69 +129,22 @@ struct dcb_entry {
bool i2c_upper_default; bool i2c_upper_default;
}; };
struct dcb_i2c_entry { struct dcb_table {
uint8_t port_type;
uint8_t read, write;
struct nouveau_i2c_chan *chan;
};
struct parsed_dcb {
int entries;
struct dcb_entry entry[DCB_MAX_NUM_ENTRIES];
struct dcb_i2c_entry i2c[DCB_MAX_NUM_I2C_ENTRIES];
};
enum dcb_gpio_tag {
DCB_GPIO_TVDAC0 = 0xc,
DCB_GPIO_TVDAC1 = 0x2d,
};
struct dcb_gpio_entry {
enum dcb_gpio_tag tag;
int line;
bool invert;
};
struct parsed_dcb_gpio {
int entries;
struct dcb_gpio_entry entry[DCB_MAX_NUM_GPIO_ENTRIES];
};
struct dcb_connector_table_entry {
uint32_t entry;
uint8_t type;
uint8_t index;
uint8_t gpio_tag;
};
struct dcb_connector_table {
int entries;
struct dcb_connector_table_entry entry[DCB_MAX_NUM_CONNECTOR_ENTRIES];
};
struct bios_parsed_dcb {
uint8_t version; uint8_t version;
struct parsed_dcb dcb; int entries;
struct dcb_entry entry[DCB_MAX_NUM_ENTRIES];
uint8_t *i2c_table; uint8_t *i2c_table;
uint8_t i2c_default_indices; uint8_t i2c_default_indices;
struct dcb_i2c_entry i2c[DCB_MAX_NUM_I2C_ENTRIES];
uint16_t gpio_table_ptr; uint16_t gpio_table_ptr;
struct parsed_dcb_gpio gpio; struct dcb_gpio_table gpio;
uint16_t connector_table_ptr; uint16_t connector_table_ptr;
struct dcb_connector_table connector; struct dcb_connector_table connector;
}; };
enum nouveau_encoder_type {
OUTPUT_ANALOG = 0,
OUTPUT_TV = 1,
OUTPUT_TMDS = 2,
OUTPUT_LVDS = 3,
OUTPUT_DP = 6,
OUTPUT_ANY = -1
};
enum nouveau_or { enum nouveau_or {
OUTPUT_A = (1 << 0), OUTPUT_A = (1 << 0),
OUTPUT_B = (1 << 1), OUTPUT_B = (1 << 1),
@ -190,8 +201,8 @@ struct pll_lims {
int refclk; int refclk;
}; };
struct nouveau_bios_info { struct nvbios {
struct parsed_dcb *dcb; struct drm_device *dev;
uint8_t chip_version; uint8_t chip_version;
@ -199,11 +210,6 @@ struct nouveau_bios_info {
uint32_t tvdactestval; uint32_t tvdactestval;
uint8_t digital_min_front_porch; uint8_t digital_min_front_porch;
bool fp_no_ddc; bool fp_no_ddc;
};
struct nvbios {
struct drm_device *dev;
struct nouveau_bios_info pub;
struct mutex lock; struct mutex lock;
@ -234,7 +240,7 @@ struct nvbios {
uint16_t some_script_ptr; /* BIT I + 14 */ uint16_t some_script_ptr; /* BIT I + 14 */
uint16_t init96_tbl_ptr; /* BIT I + 16 */ uint16_t init96_tbl_ptr; /* BIT I + 16 */
struct bios_parsed_dcb bdcb; struct dcb_table dcb;
struct { struct {
int crtchead; int crtchead;

View File

@ -274,7 +274,7 @@ getMNP_single(struct drm_device *dev, struct pll_lims *pll_lim, int clk,
* returns calculated clock * returns calculated clock
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
int cv = dev_priv->vbios->chip_version; int cv = dev_priv->vbios.chip_version;
int minvco = pll_lim->vco1.minfreq, maxvco = pll_lim->vco1.maxfreq; int minvco = pll_lim->vco1.minfreq, maxvco = pll_lim->vco1.maxfreq;
int minM = pll_lim->vco1.min_m, maxM = pll_lim->vco1.max_m; int minM = pll_lim->vco1.min_m, maxM = pll_lim->vco1.max_m;
int minN = pll_lim->vco1.min_n, maxN = pll_lim->vco1.max_n; int minN = pll_lim->vco1.min_n, maxN = pll_lim->vco1.max_n;
@ -373,7 +373,7 @@ getMNP_double(struct drm_device *dev, struct pll_lims *pll_lim, int clk,
* returns calculated clock * returns calculated clock
*/ */
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
int chip_version = dev_priv->vbios->chip_version; int chip_version = dev_priv->vbios.chip_version;
int minvco1 = pll_lim->vco1.minfreq, maxvco1 = pll_lim->vco1.maxfreq; int minvco1 = pll_lim->vco1.minfreq, maxvco1 = pll_lim->vco1.maxfreq;
int minvco2 = pll_lim->vco2.minfreq, maxvco2 = pll_lim->vco2.maxfreq; int minvco2 = pll_lim->vco2.minfreq, maxvco2 = pll_lim->vco2.maxfreq;
int minU1 = pll_lim->vco1.min_inputfreq, minU2 = pll_lim->vco2.min_inputfreq; int minU1 = pll_lim->vco1.min_inputfreq, minU2 = pll_lim->vco2.min_inputfreq;

View File

@ -35,22 +35,27 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_bo *pb = chan->pushbuf_bo; struct nouveau_bo *pb = chan->pushbuf_bo;
struct nouveau_gpuobj *pushbuf = NULL; struct nouveau_gpuobj *pushbuf = NULL;
uint32_t start = pb->bo.mem.mm_node->start << PAGE_SHIFT;
int ret; int ret;
if (dev_priv->card_type >= NV_50) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
dev_priv->vm_end, NV_DMA_ACCESS_RO,
NV_DMA_TARGET_AGP, &pushbuf);
chan->pushbuf_base = pb->bo.offset;
} else
if (pb->bo.mem.mem_type == TTM_PL_TT) { if (pb->bo.mem.mem_type == TTM_PL_TT) {
ret = nouveau_gpuobj_gart_dma_new(chan, 0, ret = nouveau_gpuobj_gart_dma_new(chan, 0,
dev_priv->gart_info.aper_size, dev_priv->gart_info.aper_size,
NV_DMA_ACCESS_RO, &pushbuf, NV_DMA_ACCESS_RO, &pushbuf,
NULL); NULL);
chan->pushbuf_base = start; chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
} else } else
if (dev_priv->card_type != NV_04) { if (dev_priv->card_type != NV_04) {
ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
dev_priv->fb_available_size, dev_priv->fb_available_size,
NV_DMA_ACCESS_RO, NV_DMA_ACCESS_RO,
NV_DMA_TARGET_VIDMEM, &pushbuf); NV_DMA_TARGET_VIDMEM, &pushbuf);
chan->pushbuf_base = start; chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
} else { } else {
/* NV04 cmdbuf hack, from original ddx.. not sure of it's /* NV04 cmdbuf hack, from original ddx.. not sure of it's
* exact reason for existing :) PCI access to cmdbuf in * exact reason for existing :) PCI access to cmdbuf in
@ -61,7 +66,7 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan)
dev_priv->fb_available_size, dev_priv->fb_available_size,
NV_DMA_ACCESS_RO, NV_DMA_ACCESS_RO,
NV_DMA_TARGET_PCI, &pushbuf); NV_DMA_TARGET_PCI, &pushbuf);
chan->pushbuf_base = start; chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
} }
ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf); ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf);
@ -275,9 +280,18 @@ nouveau_channel_free(struct nouveau_channel *chan)
*/ */
nouveau_fence_fini(chan); nouveau_fence_fini(chan);
/* Ensure the channel is no longer active on the GPU */ /* This will prevent pfifo from switching channels. */
pfifo->reassign(dev, false); pfifo->reassign(dev, false);
/* We want to give pgraph a chance to idle and get rid of all potential
* errors. We need to do this before the lock, otherwise the irq handler
* is unable to process them.
*/
if (pgraph->channel(dev) == chan)
nouveau_wait_for_idle(dev);
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
pgraph->fifo_access(dev, false); pgraph->fifo_access(dev, false);
if (pgraph->channel(dev) == chan) if (pgraph->channel(dev) == chan)
pgraph->unload_context(dev); pgraph->unload_context(dev);
@ -293,6 +307,8 @@ nouveau_channel_free(struct nouveau_channel *chan)
pfifo->reassign(dev, true); pfifo->reassign(dev, true);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* Release the channel's resources */ /* Release the channel's resources */
nouveau_gpuobj_ref_del(dev, &chan->pushbuf); nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
if (chan->pushbuf_bo) { if (chan->pushbuf_bo) {
@ -369,6 +385,14 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
return ret; return ret;
init->channel = chan->id; init->channel = chan->id;
if (chan->dma.ib_max)
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
NOUVEAU_GEM_DOMAIN_GART;
else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM)
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM;
else
init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART;
init->subchan[0].handle = NvM2MF; init->subchan[0].handle = NvM2MF;
if (dev_priv->card_type < NV_50) if (dev_priv->card_type < NV_50)
init->subchan[0].grclass = 0x0039; init->subchan[0].grclass = 0x0039;
@ -408,7 +432,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
***********************************/ ***********************************/
struct drm_ioctl_desc nouveau_ioctls[] = { struct drm_ioctl_desc nouveau_ioctls[] = {
DRM_IOCTL_DEF(DRM_NOUVEAU_CARD_INIT, nouveau_ioctl_card_init, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH),
@ -418,13 +441,9 @@ struct drm_ioctl_desc nouveau_ioctls[] = {
DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF_CALL, nouveau_gem_ioctl_pushbuf_call, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PIN, nouveau_gem_ioctl_pin, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_UNPIN, nouveau_gem_ioctl_unpin, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH),
DRM_IOCTL_DEF(DRM_NOUVEAU_GEM_PUSHBUF_CALL2, nouveau_gem_ioctl_pushbuf_call2, DRM_AUTH),
}; };
int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls);

View File

@ -218,7 +218,7 @@ nouveau_connector_set_encoder(struct drm_connector *connector,
connector->interlace_allowed = true; connector->interlace_allowed = true;
} }
if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) { if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {
drm_connector_property_set_value(connector, drm_connector_property_set_value(connector,
dev->mode_config.dvi_i_subconnector_property, dev->mode_config.dvi_i_subconnector_property,
nv_encoder->dcb->type == OUTPUT_TMDS ? nv_encoder->dcb->type == OUTPUT_TMDS ?
@ -236,15 +236,17 @@ nouveau_connector_detect(struct drm_connector *connector)
struct nouveau_i2c_chan *i2c; struct nouveau_i2c_chan *i2c;
int type, flags; int type, flags;
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS)
nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
if (nv_encoder && nv_connector->native_mode) { if (nv_encoder && nv_connector->native_mode) {
unsigned status = connector_status_connected;
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
if (!nouveau_ignorelid && !acpi_lid_open()) if (!nouveau_ignorelid && !acpi_lid_open())
return connector_status_disconnected; status = connector_status_unknown;
#endif #endif
nouveau_connector_set_encoder(connector, nv_encoder); nouveau_connector_set_encoder(connector, nv_encoder);
return connector_status_connected; return status;
} }
/* Cleanup the previous EDID block. */ /* Cleanup the previous EDID block. */
@ -279,7 +281,7 @@ nouveau_connector_detect(struct drm_connector *connector)
* same i2c channel so the value returned from ddc_detect * same i2c channel so the value returned from ddc_detect
* isn't necessarily correct. * isn't necessarily correct.
*/ */
if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) { if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {
if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL) if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)
type = OUTPUT_TMDS; type = OUTPUT_TMDS;
else else
@ -321,11 +323,11 @@ nouveau_connector_detect(struct drm_connector *connector)
static void static void
nouveau_connector_force(struct drm_connector *connector) nouveau_connector_force(struct drm_connector *connector)
{ {
struct drm_device *dev = connector->dev; struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder; struct nouveau_encoder *nv_encoder;
int type; int type;
if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) { if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {
if (connector->force == DRM_FORCE_ON_DIGITAL) if (connector->force == DRM_FORCE_ON_DIGITAL)
type = OUTPUT_TMDS; type = OUTPUT_TMDS;
else else
@ -335,7 +337,7 @@ nouveau_connector_force(struct drm_connector *connector)
nv_encoder = find_encoder_by_type(connector, type); nv_encoder = find_encoder_by_type(connector, type);
if (!nv_encoder) { if (!nv_encoder) {
NV_ERROR(dev, "can't find encoder to force %s on!\n", NV_ERROR(connector->dev, "can't find encoder to force %s on!\n",
drm_get_connector_name(connector)); drm_get_connector_name(connector));
connector->status = connector_status_disconnected; connector->status = connector_status_disconnected;
return; return;
@ -369,7 +371,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
} }
/* LVDS always needs gpu scaling */ /* LVDS always needs gpu scaling */
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS && if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS &&
value == DRM_MODE_SCALE_NONE) value == DRM_MODE_SCALE_NONE)
return -EINVAL; return -EINVAL;
@ -535,7 +537,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
/* If we're not LVDS, destroy the previous native mode, the attached /* If we're not LVDS, destroy the previous native mode, the attached
* monitor could have changed. * monitor could have changed.
*/ */
if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && if (nv_connector->dcb->type != DCB_CONNECTOR_LVDS &&
nv_connector->native_mode) { nv_connector->native_mode) {
drm_mode_destroy(dev, nv_connector->native_mode); drm_mode_destroy(dev, nv_connector->native_mode);
nv_connector->native_mode = NULL; nv_connector->native_mode = NULL;
@ -563,7 +565,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
ret = get_slave_funcs(nv_encoder)-> ret = get_slave_funcs(nv_encoder)->
get_modes(to_drm_encoder(nv_encoder), connector); get_modes(to_drm_encoder(nv_encoder), connector);
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) if (nv_encoder->dcb->type == OUTPUT_LVDS)
ret += nouveau_connector_scaler_modes_add(connector); ret += nouveau_connector_scaler_modes_add(connector);
return ret; return ret;
@ -613,6 +615,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
clock *= 3; clock *= 3;
break; break;
default:
BUG_ON(1);
return MODE_BAD;
} }
if (clock < min_clock) if (clock < min_clock)
@ -680,7 +685,7 @@ nouveau_connector_create_lvds(struct drm_device *dev,
/* Firstly try getting EDID over DDC, if allowed and I2C channel /* Firstly try getting EDID over DDC, if allowed and I2C channel
* is available. * is available.
*/ */
if (!dev_priv->VBIOS.pub.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf) if (!dev_priv->vbios.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf)
i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
if (i2c) { if (i2c) {
@ -695,7 +700,7 @@ nouveau_connector_create_lvds(struct drm_device *dev,
*/ */
if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) && if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) &&
(nv_encoder->dcb->lvdsconf.use_straps_for_mode || (nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
dev_priv->VBIOS.pub.fp_no_ddc)) { dev_priv->vbios.fp_no_ddc)) {
nv_connector->native_mode = drm_mode_duplicate(dev, &native); nv_connector->native_mode = drm_mode_duplicate(dev, &native);
goto out; goto out;
} }
@ -704,7 +709,7 @@ nouveau_connector_create_lvds(struct drm_device *dev,
* stored for the panel stored in them. * stored for the panel stored in them.
*/ */
if (!nv_connector->edid && !nv_connector->native_mode && if (!nv_connector->edid && !nv_connector->native_mode &&
!dev_priv->VBIOS.pub.fp_no_ddc) { !dev_priv->vbios.fp_no_ddc) {
struct edid *edid = struct edid *edid =
(struct edid *)nouveau_bios_embedded_edid(dev); (struct edid *)nouveau_bios_embedded_edid(dev);
if (edid) { if (edid) {
@ -739,46 +744,66 @@ nouveau_connector_create_lvds(struct drm_device *dev,
} }
int int
nouveau_connector_create(struct drm_device *dev, int index, int type) nouveau_connector_create(struct drm_device *dev,
struct dcb_connector_table_entry *dcb)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL; struct nouveau_connector *nv_connector = NULL;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_encoder *encoder; struct drm_encoder *encoder;
int ret; int ret, type;
NV_DEBUG_KMS(dev, "\n"); NV_DEBUG_KMS(dev, "\n");
switch (dcb->type) {
case DCB_CONNECTOR_NONE:
return 0;
case DCB_CONNECTOR_VGA:
NV_INFO(dev, "Detected a VGA connector\n");
type = DRM_MODE_CONNECTOR_VGA;
break;
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
case DCB_CONNECTOR_TV_3:
NV_INFO(dev, "Detected a TV connector\n");
type = DRM_MODE_CONNECTOR_TV;
break;
case DCB_CONNECTOR_DVI_I:
NV_INFO(dev, "Detected a DVI-I connector\n");
type = DRM_MODE_CONNECTOR_DVII;
break;
case DCB_CONNECTOR_DVI_D:
NV_INFO(dev, "Detected a DVI-D connector\n");
type = DRM_MODE_CONNECTOR_DVID;
break;
case DCB_CONNECTOR_HDMI_0:
case DCB_CONNECTOR_HDMI_1:
NV_INFO(dev, "Detected a HDMI connector\n");
type = DRM_MODE_CONNECTOR_HDMIA;
break;
case DCB_CONNECTOR_LVDS:
NV_INFO(dev, "Detected a LVDS connector\n");
type = DRM_MODE_CONNECTOR_LVDS;
break;
case DCB_CONNECTOR_DP:
NV_INFO(dev, "Detected a DisplayPort connector\n");
type = DRM_MODE_CONNECTOR_DisplayPort;
break;
case DCB_CONNECTOR_eDP:
NV_INFO(dev, "Detected an eDP connector\n");
type = DRM_MODE_CONNECTOR_eDP;
break;
default:
NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type);
return -EINVAL;
}
nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
if (!nv_connector) if (!nv_connector)
return -ENOMEM; return -ENOMEM;
nv_connector->dcb = nouveau_bios_connector_entry(dev, index); nv_connector->dcb = dcb;
connector = &nv_connector->base; connector = &nv_connector->base;
switch (type) {
case DRM_MODE_CONNECTOR_VGA:
NV_INFO(dev, "Detected a VGA connector\n");
break;
case DRM_MODE_CONNECTOR_DVID:
NV_INFO(dev, "Detected a DVI-D connector\n");
break;
case DRM_MODE_CONNECTOR_DVII:
NV_INFO(dev, "Detected a DVI-I connector\n");
break;
case DRM_MODE_CONNECTOR_LVDS:
NV_INFO(dev, "Detected a LVDS connector\n");
break;
case DRM_MODE_CONNECTOR_TV:
NV_INFO(dev, "Detected a TV connector\n");
break;
case DRM_MODE_CONNECTOR_DisplayPort:
NV_INFO(dev, "Detected a DisplayPort connector\n");
break;
default:
NV_ERROR(dev, "Unknown connector, this is not good.\n");
break;
}
/* defaults, will get overridden in detect() */ /* defaults, will get overridden in detect() */
connector->interlace_allowed = false; connector->interlace_allowed = false;
connector->doublescan_allowed = false; connector->doublescan_allowed = false;
@ -786,44 +811,11 @@ nouveau_connector_create(struct drm_device *dev, int index, int type)
drm_connector_init(dev, connector, &nouveau_connector_funcs, type); drm_connector_init(dev, connector, &nouveau_connector_funcs, type);
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
/* Init DVI-I specific properties */
if (type == DRM_MODE_CONNECTOR_DVII) {
drm_mode_create_dvi_i_properties(dev);
drm_connector_attach_property(connector, dev->mode_config.dvi_i_subconnector_property, 0);
drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
}
if (type != DRM_MODE_CONNECTOR_LVDS)
nv_connector->use_dithering = false;
if (type == DRM_MODE_CONNECTOR_DVID ||
type == DRM_MODE_CONNECTOR_DVII ||
type == DRM_MODE_CONNECTOR_LVDS ||
type == DRM_MODE_CONNECTOR_DisplayPort) {
nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
drm_connector_attach_property(connector, dev->mode_config.scaling_mode_property,
nv_connector->scaling_mode);
drm_connector_attach_property(connector, dev->mode_config.dithering_mode_property,
nv_connector->use_dithering ? DRM_MODE_DITHERING_ON
: DRM_MODE_DITHERING_OFF);
} else {
nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
if (type == DRM_MODE_CONNECTOR_VGA &&
dev_priv->card_type >= NV_50) {
drm_connector_attach_property(connector,
dev->mode_config.scaling_mode_property,
nv_connector->scaling_mode);
}
}
/* attach encoders */ /* attach encoders */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
if (nv_encoder->dcb->connector != index) if (nv_encoder->dcb->connector != dcb->index)
continue; continue;
if (get_slave_funcs(nv_encoder)) if (get_slave_funcs(nv_encoder))
@ -832,9 +824,52 @@ nouveau_connector_create(struct drm_device *dev, int index, int type)
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
} }
if (!connector->encoder_ids[0]) {
NV_WARN(dev, " no encoders, ignoring\n");
drm_connector_cleanup(connector);
kfree(connector);
return 0;
}
/* Init DVI-I specific properties */
if (dcb->type == DCB_CONNECTOR_DVI_I) {
drm_mode_create_dvi_i_properties(dev);
drm_connector_attach_property(connector, dev->mode_config.dvi_i_subconnector_property, 0);
drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
}
if (dcb->type != DCB_CONNECTOR_LVDS)
nv_connector->use_dithering = false;
switch (dcb->type) {
case DCB_CONNECTOR_VGA:
if (dev_priv->card_type >= NV_50) {
drm_connector_attach_property(connector,
dev->mode_config.scaling_mode_property,
nv_connector->scaling_mode);
}
/* fall-through */
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
case DCB_CONNECTOR_TV_3:
nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
break;
default:
nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
drm_connector_attach_property(connector,
dev->mode_config.scaling_mode_property,
nv_connector->scaling_mode);
drm_connector_attach_property(connector,
dev->mode_config.dithering_mode_property,
nv_connector->use_dithering ?
DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
break;
}
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) { if (dcb->type == DCB_CONNECTOR_LVDS) {
ret = nouveau_connector_create_lvds(dev, connector); ret = nouveau_connector_create_lvds(dev, connector);
if (ret) { if (ret) {
connector->funcs->destroy(connector); connector->funcs->destroy(connector);

View File

@ -49,6 +49,7 @@ static inline struct nouveau_connector *nouveau_connector(
return container_of(con, struct nouveau_connector, base); return container_of(con, struct nouveau_connector, base);
} }
int nouveau_connector_create(struct drm_device *dev, int i2c_index, int type); int nouveau_connector_create(struct drm_device *,
struct dcb_connector_table_entry *);
#endif /* __NOUVEAU_CONNECTOR_H__ */ #endif /* __NOUVEAU_CONNECTOR_H__ */

View File

@ -47,12 +47,23 @@ nouveau_debugfs_channel_info(struct seq_file *m, void *data)
seq_printf(m, " cur: 0x%08x\n", chan->dma.cur << 2); seq_printf(m, " cur: 0x%08x\n", chan->dma.cur << 2);
seq_printf(m, " put: 0x%08x\n", chan->dma.put << 2); seq_printf(m, " put: 0x%08x\n", chan->dma.put << 2);
seq_printf(m, " free: 0x%08x\n", chan->dma.free << 2); seq_printf(m, " free: 0x%08x\n", chan->dma.free << 2);
if (chan->dma.ib_max) {
seq_printf(m, " ib max: 0x%08x\n", chan->dma.ib_max);
seq_printf(m, " ib put: 0x%08x\n", chan->dma.ib_put);
seq_printf(m, " ib free: 0x%08x\n", chan->dma.ib_free);
}
seq_printf(m, "gpu fifo state:\n"); seq_printf(m, "gpu fifo state:\n");
seq_printf(m, " get: 0x%08x\n", seq_printf(m, " get: 0x%08x\n",
nvchan_rd32(chan, chan->user_get)); nvchan_rd32(chan, chan->user_get));
seq_printf(m, " put: 0x%08x\n", seq_printf(m, " put: 0x%08x\n",
nvchan_rd32(chan, chan->user_put)); nvchan_rd32(chan, chan->user_put));
if (chan->dma.ib_max) {
seq_printf(m, " ib get: 0x%08x\n",
nvchan_rd32(chan, 0x88));
seq_printf(m, " ib put: 0x%08x\n",
nvchan_rd32(chan, 0x8c));
}
seq_printf(m, "last fence : %d\n", chan->fence.sequence); seq_printf(m, "last fence : %d\n", chan->fence.sequence);
seq_printf(m, "last signalled: %d\n", chan->fence.sequence_ack); seq_printf(m, "last signalled: %d\n", chan->fence.sequence_ack);
@ -133,9 +144,22 @@ nouveau_debugfs_memory_info(struct seq_file *m, void *data)
return 0; return 0;
} }
static int
nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_nouveau_private *dev_priv = node->minor->dev->dev_private;
int i;
for (i = 0; i < dev_priv->vbios.length; i++)
seq_printf(m, "%c", dev_priv->vbios.data[i]);
return 0;
}
static struct drm_info_list nouveau_debugfs_list[] = { static struct drm_info_list nouveau_debugfs_list[] = {
{ "chipset", nouveau_debugfs_chipset_info, 0, NULL }, { "chipset", nouveau_debugfs_chipset_info, 0, NULL },
{ "memory", nouveau_debugfs_memory_info, 0, NULL }, { "memory", nouveau_debugfs_memory_info, 0, NULL },
{ "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
}; };
#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list) #define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)

View File

@ -39,11 +39,8 @@ nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
if (drm_fb->fbdev) if (drm_fb->fbdev)
nouveau_fbcon_remove(dev, drm_fb); nouveau_fbcon_remove(dev, drm_fb);
if (fb->nvbo) { if (fb->nvbo)
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(fb->nvbo->gem);
drm_gem_object_unreference(fb->nvbo->gem);
mutex_unlock(&dev->struct_mutex);
}
drm_framebuffer_cleanup(drm_fb); drm_framebuffer_cleanup(drm_fb);
kfree(fb); kfree(fb);

View File

@ -32,7 +32,22 @@
void void
nouveau_dma_pre_init(struct nouveau_channel *chan) nouveau_dma_pre_init(struct nouveau_channel *chan)
{ {
chan->dma.max = (chan->pushbuf_bo->bo.mem.size >> 2) - 2; struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_bo *pushbuf = chan->pushbuf_bo;
if (dev_priv->card_type == NV_50) {
const int ib_size = pushbuf->bo.mem.size / 2;
chan->dma.ib_base = (pushbuf->bo.mem.size - ib_size) >> 2;
chan->dma.ib_max = (ib_size / 8) - 1;
chan->dma.ib_put = 0;
chan->dma.ib_free = chan->dma.ib_max - chan->dma.ib_put;
chan->dma.max = (pushbuf->bo.mem.size - ib_size) >> 2;
} else {
chan->dma.max = (pushbuf->bo.mem.size >> 2) - 2;
}
chan->dma.put = 0; chan->dma.put = 0;
chan->dma.cur = chan->dma.put; chan->dma.cur = chan->dma.put;
chan->dma.free = chan->dma.max - chan->dma.cur; chan->dma.free = chan->dma.max - chan->dma.cur;
@ -162,12 +177,101 @@ READ_GET(struct nouveau_channel *chan, uint32_t *prev_get, uint32_t *timeout)
return (val - chan->pushbuf_base) >> 2; return (val - chan->pushbuf_base) >> 2;
} }
void
nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo,
int delta, int length)
{
struct nouveau_bo *pb = chan->pushbuf_bo;
uint64_t offset = bo->bo.offset + delta;
int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
BUG_ON(chan->dma.ib_free < 1);
nouveau_bo_wr32(pb, ip++, lower_32_bits(offset));
nouveau_bo_wr32(pb, ip++, upper_32_bits(offset) | length << 8);
chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max;
nvchan_wr32(chan, 0x8c, chan->dma.ib_put);
chan->dma.ib_free--;
}
static int
nv50_dma_push_wait(struct nouveau_channel *chan, int count)
{
uint32_t cnt = 0, prev_get = 0;
while (chan->dma.ib_free < count) {
uint32_t get = nvchan_rd32(chan, 0x88);
if (get != prev_get) {
prev_get = get;
cnt = 0;
}
if ((++cnt & 0xff) == 0) {
DRM_UDELAY(1);
if (cnt > 100000)
return -EBUSY;
}
chan->dma.ib_free = get - chan->dma.ib_put;
if (chan->dma.ib_free <= 0)
chan->dma.ib_free += chan->dma.ib_max + 1;
}
return 0;
}
static int
nv50_dma_wait(struct nouveau_channel *chan, int slots, int count)
{
uint32_t cnt = 0, prev_get = 0;
int ret;
ret = nv50_dma_push_wait(chan, slots + 1);
if (unlikely(ret))
return ret;
while (chan->dma.free < count) {
int get = READ_GET(chan, &prev_get, &cnt);
if (unlikely(get < 0)) {
if (get == -EINVAL)
continue;
return get;
}
if (get <= chan->dma.cur) {
chan->dma.free = chan->dma.max - chan->dma.cur;
if (chan->dma.free >= count)
break;
FIRE_RING(chan);
do {
get = READ_GET(chan, &prev_get, &cnt);
if (unlikely(get < 0)) {
if (get == -EINVAL)
continue;
return get;
}
} while (get == 0);
chan->dma.cur = 0;
chan->dma.put = 0;
}
chan->dma.free = get - chan->dma.cur - 1;
}
return 0;
}
int int
nouveau_dma_wait(struct nouveau_channel *chan, int size) nouveau_dma_wait(struct nouveau_channel *chan, int slots, int size)
{ {
uint32_t prev_get = 0, cnt = 0; uint32_t prev_get = 0, cnt = 0;
int get; int get;
if (chan->dma.ib_max)
return nv50_dma_wait(chan, slots, size);
while (chan->dma.free < size) { while (chan->dma.free < size) {
get = READ_GET(chan, &prev_get, &cnt); get = READ_GET(chan, &prev_get, &cnt);
if (unlikely(get == -EBUSY)) if (unlikely(get == -EBUSY))

View File

@ -31,6 +31,9 @@
#define NOUVEAU_DMA_DEBUG 0 #define NOUVEAU_DMA_DEBUG 0
#endif #endif
void nv50_dma_push(struct nouveau_channel *, struct nouveau_bo *,
int delta, int length);
/* /*
* There's a hw race condition where you can't jump to your PUT offset, * There's a hw race condition where you can't jump to your PUT offset,
* to avoid this we jump to offset + SKIPS and fill the difference with * to avoid this we jump to offset + SKIPS and fill the difference with
@ -96,13 +99,11 @@ enum {
static __must_check inline int static __must_check inline int
RING_SPACE(struct nouveau_channel *chan, int size) RING_SPACE(struct nouveau_channel *chan, int size)
{ {
if (chan->dma.free < size) { int ret;
int ret;
ret = nouveau_dma_wait(chan, size); ret = nouveau_dma_wait(chan, 1, size);
if (ret) if (ret)
return ret; return ret;
}
chan->dma.free -= size; chan->dma.free -= size;
return 0; return 0;
@ -146,7 +147,13 @@ FIRE_RING(struct nouveau_channel *chan)
return; return;
chan->accel_done = true; chan->accel_done = true;
WRITE_PUT(chan->dma.cur); if (chan->dma.ib_max) {
nv50_dma_push(chan, chan->pushbuf_bo, chan->dma.put << 2,
(chan->dma.cur - chan->dma.put) << 2);
} else {
WRITE_PUT(chan->dma.cur);
}
chan->dma.put = chan->dma.cur; chan->dma.put = chan->dma.cur;
} }

View File

@ -75,11 +75,11 @@ MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
int nouveau_ignorelid = 0; int nouveau_ignorelid = 0;
module_param_named(ignorelid, nouveau_ignorelid, int, 0400); module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
MODULE_PARM_DESC(noagp, "Disable all acceleration"); MODULE_PARM_DESC(noaccel, "Disable all acceleration");
int nouveau_noaccel = 0; int nouveau_noaccel = 0;
module_param_named(noaccel, nouveau_noaccel, int, 0400); module_param_named(noaccel, nouveau_noaccel, int, 0400);
MODULE_PARM_DESC(noagp, "Disable fbcon acceleration"); MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration");
int nouveau_nofbaccel = 0; int nouveau_nofbaccel = 0;
module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400); module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
@ -135,7 +135,7 @@ nouveau_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev); drm_put_dev(dev);
} }
static int int
nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
{ {
struct drm_device *dev = pci_get_drvdata(pdev); struct drm_device *dev = pci_get_drvdata(pdev);
@ -233,7 +233,7 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
return ret; return ret;
} }
static int int
nouveau_pci_resume(struct pci_dev *pdev) nouveau_pci_resume(struct pci_dev *pdev)
{ {
struct drm_device *dev = pci_get_drvdata(pdev); struct drm_device *dev = pci_get_drvdata(pdev);
@ -402,8 +402,10 @@ static int __init nouveau_init(void)
nouveau_modeset = 1; nouveau_modeset = 1;
} }
if (nouveau_modeset == 1) if (nouveau_modeset == 1) {
driver.driver_features |= DRIVER_MODESET; driver.driver_features |= DRIVER_MODESET;
nouveau_register_dsm_handler();
}
return drm_init(&driver); return drm_init(&driver);
} }
@ -411,6 +413,7 @@ static int __init nouveau_init(void)
static void __exit nouveau_exit(void) static void __exit nouveau_exit(void)
{ {
drm_exit(&driver); drm_exit(&driver);
nouveau_unregister_dsm_handler();
} }
module_init(nouveau_init); module_init(nouveau_init);

View File

@ -34,7 +34,7 @@
#define DRIVER_MAJOR 0 #define DRIVER_MAJOR 0
#define DRIVER_MINOR 0 #define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 15 #define DRIVER_PATCHLEVEL 16
#define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FAMILY 0x0000FFFF
#define NOUVEAU_FLAGS 0xFFFF0000 #define NOUVEAU_FLAGS 0xFFFF0000
@ -83,6 +83,7 @@ struct nouveau_bo {
struct drm_file *reserved_by; struct drm_file *reserved_by;
struct list_head entry; struct list_head entry;
int pbbo_index; int pbbo_index;
bool validate_mapped;
struct nouveau_channel *channel; struct nouveau_channel *channel;
@ -239,6 +240,11 @@ struct nouveau_channel {
int cur; int cur;
int put; int put;
/* access via pushbuf_bo */ /* access via pushbuf_bo */
int ib_base;
int ib_max;
int ib_free;
int ib_put;
} dma; } dma;
uint32_t sw_subchannel[8]; uint32_t sw_subchannel[8];
@ -533,6 +539,9 @@ struct drm_nouveau_private {
struct nouveau_engine engine; struct nouveau_engine engine;
struct nouveau_channel *channel; struct nouveau_channel *channel;
/* For PFIFO and PGRAPH. */
spinlock_t context_switch_lock;
/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
struct nouveau_gpuobj *ramht; struct nouveau_gpuobj *ramht;
uint32_t ramin_rsvd_vram; uint32_t ramin_rsvd_vram;
@ -596,8 +605,7 @@ struct drm_nouveau_private {
struct list_head gpuobj_list; struct list_head gpuobj_list;
struct nvbios VBIOS; struct nvbios vbios;
struct nouveau_bios_info *vbios;
struct nv04_mode_state mode_reg; struct nv04_mode_state mode_reg;
struct nv04_mode_state saved_reg; struct nv04_mode_state saved_reg;
@ -614,7 +622,6 @@ struct drm_nouveau_private {
} susres; } susres;
struct backlight_device *backlight; struct backlight_device *backlight;
bool acpi_dsm;
struct nouveau_channel *evo; struct nouveau_channel *evo;
@ -682,6 +689,9 @@ extern int nouveau_ignorelid;
extern int nouveau_nofbaccel; extern int nouveau_nofbaccel;
extern int nouveau_noaccel; extern int nouveau_noaccel;
extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
extern int nouveau_pci_resume(struct pci_dev *pdev);
/* nouveau_state.c */ /* nouveau_state.c */
extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
extern int nouveau_load(struct drm_device *, unsigned long flags); extern int nouveau_load(struct drm_device *, unsigned long flags);
@ -696,12 +706,6 @@ extern bool nouveau_wait_until(struct drm_device *, uint64_t timeout,
uint32_t reg, uint32_t mask, uint32_t val); uint32_t reg, uint32_t mask, uint32_t val);
extern bool nouveau_wait_for_idle(struct drm_device *); extern bool nouveau_wait_for_idle(struct drm_device *);
extern int nouveau_card_init(struct drm_device *); extern int nouveau_card_init(struct drm_device *);
extern int nouveau_ioctl_card_init(struct drm_device *, void *data,
struct drm_file *);
extern int nouveau_ioctl_suspend(struct drm_device *, void *data,
struct drm_file *);
extern int nouveau_ioctl_resume(struct drm_device *, void *data,
struct drm_file *);
/* nouveau_mem.c */ /* nouveau_mem.c */
extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start, extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start,
@ -845,21 +849,15 @@ nouveau_debugfs_channel_fini(struct nouveau_channel *chan)
/* nouveau_dma.c */ /* nouveau_dma.c */
extern void nouveau_dma_pre_init(struct nouveau_channel *); extern void nouveau_dma_pre_init(struct nouveau_channel *);
extern int nouveau_dma_init(struct nouveau_channel *); extern int nouveau_dma_init(struct nouveau_channel *);
extern int nouveau_dma_wait(struct nouveau_channel *, int size); extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
/* nouveau_acpi.c */ /* nouveau_acpi.c */
#ifdef CONFIG_ACPI #if defined(CONFIG_ACPI)
extern int nouveau_hybrid_setup(struct drm_device *dev); void nouveau_register_dsm_handler(void);
extern bool nouveau_dsm_probe(struct drm_device *dev); void nouveau_unregister_dsm_handler(void);
#else #else
static inline int nouveau_hybrid_setup(struct drm_device *dev) static inline void nouveau_register_dsm_handler(void) {}
{ static inline void nouveau_unregister_dsm_handler(void) {}
return 0;
}
static inline bool nouveau_dsm_probe(struct drm_device *dev)
{
return false;
}
#endif #endif
/* nouveau_backlight.c */ /* nouveau_backlight.c */
@ -1027,6 +1025,7 @@ extern void nv50_graph_destroy_context(struct nouveau_channel *);
extern int nv50_graph_load_context(struct nouveau_channel *); extern int nv50_graph_load_context(struct nouveau_channel *);
extern int nv50_graph_unload_context(struct drm_device *); extern int nv50_graph_unload_context(struct drm_device *);
extern void nv50_graph_context_switch(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *);
/* nouveau_grctx.c */ /* nouveau_grctx.c */
extern int nouveau_grctx_prog_load(struct drm_device *); extern int nouveau_grctx_prog_load(struct drm_device *);
@ -1152,16 +1151,6 @@ extern int nouveau_gem_ioctl_new(struct drm_device *, void *,
struct drm_file *); struct drm_file *);
extern int nouveau_gem_ioctl_pushbuf(struct drm_device *, void *, extern int nouveau_gem_ioctl_pushbuf(struct drm_device *, void *,
struct drm_file *); struct drm_file *);
extern int nouveau_gem_ioctl_pushbuf_call(struct drm_device *, void *,
struct drm_file *);
extern int nouveau_gem_ioctl_pushbuf_call2(struct drm_device *, void *,
struct drm_file *);
extern int nouveau_gem_ioctl_pin(struct drm_device *, void *,
struct drm_file *);
extern int nouveau_gem_ioctl_unpin(struct drm_device *, void *,
struct drm_file *);
extern int nouveau_gem_ioctl_tile(struct drm_device *, void *,
struct drm_file *);
extern int nouveau_gem_ioctl_cpu_prep(struct drm_device *, void *, extern int nouveau_gem_ioctl_cpu_prep(struct drm_device *, void *,
struct drm_file *); struct drm_file *);
extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,

View File

@ -36,6 +36,7 @@
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/screen_info.h> #include <linux/screen_info.h>
#include <linux/vga_switcheroo.h>
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
@ -370,6 +371,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
nvbo->bo.offset, nvbo); nvbo->bo.offset, nvbo);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
vga_switcheroo_client_fb_set(dev->pdev, info);
return 0; return 0;
out_unref: out_unref:
@ -401,10 +403,8 @@ nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb)
unregister_framebuffer(info); unregister_framebuffer(info);
nouveau_bo_unmap(nouveau_fb->nvbo); nouveau_bo_unmap(nouveau_fb->nvbo);
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
drm_gem_object_unreference(nouveau_fb->nvbo->gem);
nouveau_fb->nvbo = NULL; nouveau_fb->nvbo = NULL;
mutex_unlock(&dev->struct_mutex);
if (par) if (par)
drm_fb_helper_free(&par->helper); drm_fb_helper_free(&par->helper);
framebuffer_release(info); framebuffer_release(info);

View File

@ -167,12 +167,10 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle); ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle);
out: out:
mutex_lock(&dev->struct_mutex); drm_gem_object_handle_unreference_unlocked(nvbo->gem);
drm_gem_object_handle_unreference(nvbo->gem);
mutex_unlock(&dev->struct_mutex);
if (ret) if (ret)
drm_gem_object_unreference(nvbo->gem); drm_gem_object_unreference_unlocked(nvbo->gem);
return ret; return ret;
} }
@ -243,6 +241,11 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
nouveau_fence_unref((void *)&prev_fence); nouveau_fence_unref((void *)&prev_fence);
} }
if (unlikely(nvbo->validate_mapped)) {
ttm_bo_kunmap(&nvbo->kmap);
nvbo->validate_mapped = false;
}
list_del(&nvbo->entry); list_del(&nvbo->entry);
nvbo->reserved_by = NULL; nvbo->reserved_by = NULL;
ttm_bo_unreserve(&nvbo->bo); ttm_bo_unreserve(&nvbo->bo);
@ -302,11 +305,14 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
if (ret == -EAGAIN) if (ret == -EAGAIN)
ret = ttm_bo_wait_unreserved(&nvbo->bo, false); ret = ttm_bo_wait_unreserved(&nvbo->bo, false);
drm_gem_object_unreference(gem); drm_gem_object_unreference(gem);
if (ret) if (ret) {
NV_ERROR(dev, "fail reserve\n");
return ret; return ret;
}
goto retry; goto retry;
} }
b->user_priv = (uint64_t)(unsigned long)nvbo;
nvbo->reserved_by = file_priv; nvbo->reserved_by = file_priv;
nvbo->pbbo_index = i; nvbo->pbbo_index = i;
if ((b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) && if ((b->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
@ -336,8 +342,10 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
} }
ret = ttm_bo_wait_cpu(&nvbo->bo, false); ret = ttm_bo_wait_cpu(&nvbo->bo, false);
if (ret) if (ret) {
NV_ERROR(dev, "fail wait_cpu\n");
return ret; return ret;
}
goto retry; goto retry;
} }
} }
@ -351,6 +359,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
{ {
struct drm_nouveau_gem_pushbuf_bo __user *upbbo = struct drm_nouveau_gem_pushbuf_bo __user *upbbo =
(void __force __user *)(uintptr_t)user_pbbo_ptr; (void __force __user *)(uintptr_t)user_pbbo_ptr;
struct drm_device *dev = chan->dev;
struct nouveau_bo *nvbo; struct nouveau_bo *nvbo;
int ret, relocs = 0; int ret, relocs = 0;
@ -362,39 +371,46 @@ validate_list(struct nouveau_channel *chan, struct list_head *list,
spin_lock(&nvbo->bo.lock); spin_lock(&nvbo->bo.lock);
ret = ttm_bo_wait(&nvbo->bo, false, false, false); ret = ttm_bo_wait(&nvbo->bo, false, false, false);
spin_unlock(&nvbo->bo.lock); spin_unlock(&nvbo->bo.lock);
if (unlikely(ret)) if (unlikely(ret)) {
NV_ERROR(dev, "fail wait other chan\n");
return ret; return ret;
}
} }
ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains, ret = nouveau_gem_set_domain(nvbo->gem, b->read_domains,
b->write_domains, b->write_domains,
b->valid_domains); b->valid_domains);
if (unlikely(ret)) if (unlikely(ret)) {
NV_ERROR(dev, "fail set_domain\n");
return ret; return ret;
}
nvbo->channel = chan; nvbo->channel = chan;
ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement,
false, false); false, false);
nvbo->channel = NULL; nvbo->channel = NULL;
if (unlikely(ret)) if (unlikely(ret)) {
NV_ERROR(dev, "fail ttm_validate\n");
return ret; return ret;
}
if (nvbo->bo.offset == b->presumed_offset && if (nvbo->bo.offset == b->presumed.offset &&
((nvbo->bo.mem.mem_type == TTM_PL_VRAM && ((nvbo->bo.mem.mem_type == TTM_PL_VRAM &&
b->presumed_domain & NOUVEAU_GEM_DOMAIN_VRAM) || b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) ||
(nvbo->bo.mem.mem_type == TTM_PL_TT && (nvbo->bo.mem.mem_type == TTM_PL_TT &&
b->presumed_domain & NOUVEAU_GEM_DOMAIN_GART))) b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART)))
continue; continue;
if (nvbo->bo.mem.mem_type == TTM_PL_TT) if (nvbo->bo.mem.mem_type == TTM_PL_TT)
b->presumed_domain = NOUVEAU_GEM_DOMAIN_GART; b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART;
else else
b->presumed_domain = NOUVEAU_GEM_DOMAIN_VRAM; b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM;
b->presumed_offset = nvbo->bo.offset; b->presumed.offset = nvbo->bo.offset;
b->presumed_ok = 0; b->presumed.valid = 0;
relocs++; relocs++;
if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index], b, sizeof(*b))) if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index].presumed,
&b->presumed, sizeof(b->presumed)))
return -EFAULT; return -EFAULT;
} }
@ -408,6 +424,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
uint64_t user_buffers, int nr_buffers, uint64_t user_buffers, int nr_buffers,
struct validate_op *op, int *apply_relocs) struct validate_op *op, int *apply_relocs)
{ {
struct drm_device *dev = chan->dev;
int ret, relocs = 0; int ret, relocs = 0;
INIT_LIST_HEAD(&op->vram_list); INIT_LIST_HEAD(&op->vram_list);
@ -418,11 +435,14 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
return 0; return 0;
ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); ret = validate_init(chan, file_priv, pbbo, nr_buffers, op);
if (unlikely(ret)) if (unlikely(ret)) {
NV_ERROR(dev, "validate_init\n");
return ret; return ret;
}
ret = validate_list(chan, &op->vram_list, pbbo, user_buffers); ret = validate_list(chan, &op->vram_list, pbbo, user_buffers);
if (unlikely(ret < 0)) { if (unlikely(ret < 0)) {
NV_ERROR(dev, "validate vram_list\n");
validate_fini(op, NULL); validate_fini(op, NULL);
return ret; return ret;
} }
@ -430,6 +450,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
ret = validate_list(chan, &op->gart_list, pbbo, user_buffers); ret = validate_list(chan, &op->gart_list, pbbo, user_buffers);
if (unlikely(ret < 0)) { if (unlikely(ret < 0)) {
NV_ERROR(dev, "validate gart_list\n");
validate_fini(op, NULL); validate_fini(op, NULL);
return ret; return ret;
} }
@ -437,6 +458,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan,
ret = validate_list(chan, &op->both_list, pbbo, user_buffers); ret = validate_list(chan, &op->both_list, pbbo, user_buffers);
if (unlikely(ret < 0)) { if (unlikely(ret < 0)) {
NV_ERROR(dev, "validate both_list\n");
validate_fini(op, NULL); validate_fini(op, NULL);
return ret; return ret;
} }
@ -465,59 +487,82 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
} }
static int static int
nouveau_gem_pushbuf_reloc_apply(struct nouveau_channel *chan, int nr_bo, nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev,
struct drm_nouveau_gem_pushbuf_bo *bo, struct drm_nouveau_gem_pushbuf *req,
unsigned nr_relocs, uint64_t ptr_relocs, struct drm_nouveau_gem_pushbuf_bo *bo)
unsigned nr_dwords, unsigned first_dword,
uint32_t *pushbuf, bool is_iomem)
{ {
struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL; struct drm_nouveau_gem_pushbuf_reloc *reloc = NULL;
struct drm_device *dev = chan->dev;
int ret = 0; int ret = 0;
unsigned i; unsigned i;
reloc = u_memcpya(ptr_relocs, nr_relocs, sizeof(*reloc)); reloc = u_memcpya(req->relocs, req->nr_relocs, sizeof(*reloc));
if (IS_ERR(reloc)) if (IS_ERR(reloc))
return PTR_ERR(reloc); return PTR_ERR(reloc);
for (i = 0; i < nr_relocs; i++) { for (i = 0; i < req->nr_relocs; i++) {
struct drm_nouveau_gem_pushbuf_reloc *r = &reloc[i]; struct drm_nouveau_gem_pushbuf_reloc *r = &reloc[i];
struct drm_nouveau_gem_pushbuf_bo *b; struct drm_nouveau_gem_pushbuf_bo *b;
struct nouveau_bo *nvbo;
uint32_t data; uint32_t data;
if (r->bo_index >= nr_bo || r->reloc_index < first_dword || if (unlikely(r->bo_index > req->nr_buffers)) {
r->reloc_index >= first_dword + nr_dwords) { NV_ERROR(dev, "reloc bo index invalid\n");
NV_ERROR(dev, "Bad relocation %d\n", i);
NV_ERROR(dev, " bo: %d max %d\n", r->bo_index, nr_bo);
NV_ERROR(dev, " id: %d max %d\n", r->reloc_index, nr_dwords);
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
b = &bo[r->bo_index]; b = &bo[r->bo_index];
if (b->presumed_ok) if (b->presumed.valid)
continue; continue;
if (unlikely(r->reloc_bo_index > req->nr_buffers)) {
NV_ERROR(dev, "reloc container bo index invalid\n");
ret = -EINVAL;
break;
}
nvbo = (void *)(unsigned long)bo[r->reloc_bo_index].user_priv;
if (unlikely(r->reloc_bo_offset + 4 >
nvbo->bo.mem.num_pages << PAGE_SHIFT)) {
NV_ERROR(dev, "reloc outside of bo\n");
ret = -EINVAL;
break;
}
if (!nvbo->kmap.virtual) {
ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages,
&nvbo->kmap);
if (ret) {
NV_ERROR(dev, "failed kmap for reloc\n");
break;
}
nvbo->validate_mapped = true;
}
if (r->flags & NOUVEAU_GEM_RELOC_LOW) if (r->flags & NOUVEAU_GEM_RELOC_LOW)
data = b->presumed_offset + r->data; data = b->presumed.offset + r->data;
else else
if (r->flags & NOUVEAU_GEM_RELOC_HIGH) if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
data = (b->presumed_offset + r->data) >> 32; data = (b->presumed.offset + r->data) >> 32;
else else
data = r->data; data = r->data;
if (r->flags & NOUVEAU_GEM_RELOC_OR) { if (r->flags & NOUVEAU_GEM_RELOC_OR) {
if (b->presumed_domain == NOUVEAU_GEM_DOMAIN_GART) if (b->presumed.domain == NOUVEAU_GEM_DOMAIN_GART)
data |= r->tor; data |= r->tor;
else else
data |= r->vor; data |= r->vor;
} }
if (is_iomem) spin_lock(&nvbo->bo.lock);
iowrite32_native(data, (void __force __iomem *) ret = ttm_bo_wait(&nvbo->bo, false, false, false);
&pushbuf[r->reloc_index]); spin_unlock(&nvbo->bo.lock);
else if (ret) {
pushbuf[r->reloc_index] = data; NV_ERROR(dev, "reloc wait_idle failed: %d\n", ret);
break;
}
nouveau_bo_wr32(nvbo, r->reloc_bo_offset >> 2, data);
} }
kfree(reloc); kfree(reloc);
@ -528,130 +573,53 @@ int
nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_gem_pushbuf *req = data; struct drm_nouveau_gem_pushbuf *req = data;
struct drm_nouveau_gem_pushbuf_bo *bo = NULL; struct drm_nouveau_gem_pushbuf_push *push;
struct drm_nouveau_gem_pushbuf_bo *bo;
struct nouveau_channel *chan; struct nouveau_channel *chan;
struct validate_op op; struct validate_op op;
struct nouveau_fence* fence = 0; struct nouveau_fence *fence = 0;
uint32_t *pushbuf = NULL; int i, j, ret = 0, do_reloc = 0;
int ret = 0, do_reloc = 0, i;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN; NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan); NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan);
if (req->nr_dwords >= chan->dma.max || req->vram_available = dev_priv->fb_aper_free;
req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS || req->gart_available = dev_priv->gart_info.aper_free;
req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS) { if (unlikely(req->nr_push == 0))
NV_ERROR(dev, "Pushbuf config exceeds limits:\n"); goto out_next;
NV_ERROR(dev, " dwords : %d max %d\n", req->nr_dwords,
chan->dma.max - 1); if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) {
NV_ERROR(dev, " buffers: %d max %d\n", req->nr_buffers, NV_ERROR(dev, "pushbuf push count exceeds limit: %d max %d\n",
NOUVEAU_GEM_MAX_BUFFERS); req->nr_push, NOUVEAU_GEM_MAX_PUSH);
NV_ERROR(dev, " relocs : %d max %d\n", req->nr_relocs,
NOUVEAU_GEM_MAX_RELOCS);
return -EINVAL; return -EINVAL;
} }
pushbuf = u_memcpya(req->dwords, req->nr_dwords, sizeof(uint32_t)); if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) {
if (IS_ERR(pushbuf)) NV_ERROR(dev, "pushbuf bo count exceeds limit: %d max %d\n",
return PTR_ERR(pushbuf); req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS);
return -EINVAL;
}
if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) {
NV_ERROR(dev, "pushbuf reloc count exceeds limit: %d max %d\n",
req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS);
return -EINVAL;
}
push = u_memcpya(req->push, req->nr_push, sizeof(*push));
if (IS_ERR(push))
return PTR_ERR(push);
bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
if (IS_ERR(bo)) { if (IS_ERR(bo)) {
kfree(pushbuf); kfree(push);
return PTR_ERR(bo); return PTR_ERR(bo);
} }
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
/* Validate buffer list */
ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers,
req->nr_buffers, &op, &do_reloc);
if (ret)
goto out;
/* Apply any relocations that are required */
if (do_reloc) {
ret = nouveau_gem_pushbuf_reloc_apply(chan, req->nr_buffers,
bo, req->nr_relocs,
req->relocs,
req->nr_dwords, 0,
pushbuf, false);
if (ret)
goto out;
}
/* Emit push buffer to the hw
*/
ret = RING_SPACE(chan, req->nr_dwords);
if (ret)
goto out;
OUT_RINGp(chan, pushbuf, req->nr_dwords);
ret = nouveau_fence_new(chan, &fence, true);
if (ret) {
NV_ERROR(dev, "error fencing pushbuf: %d\n", ret);
WIND_RING(chan);
goto out;
}
if (nouveau_gem_pushbuf_sync(chan)) {
ret = nouveau_fence_wait(fence, NULL, false, false);
if (ret) {
for (i = 0; i < req->nr_dwords; i++)
NV_ERROR(dev, "0x%08x\n", pushbuf[i]);
NV_ERROR(dev, "^^ above push buffer is fail :(\n");
}
}
out:
validate_fini(&op, fence);
nouveau_fence_unref((void**)&fence);
mutex_unlock(&dev->struct_mutex);
kfree(pushbuf);
kfree(bo);
return ret;
}
#define PUSHBUF_CAL (dev_priv->card_type >= NV_20)
int
nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_gem_pushbuf_call *req = data;
struct drm_nouveau_gem_pushbuf_bo *bo = NULL;
struct nouveau_channel *chan;
struct drm_gem_object *gem;
struct nouveau_bo *pbbo;
struct validate_op op;
struct nouveau_fence* fence = 0;
int i, ret = 0, do_reloc = 0;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan);
if (unlikely(req->handle == 0))
goto out_next;
if (req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS ||
req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS) {
NV_ERROR(dev, "Pushbuf config exceeds limits:\n");
NV_ERROR(dev, " buffers: %d max %d\n", req->nr_buffers,
NOUVEAU_GEM_MAX_BUFFERS);
NV_ERROR(dev, " relocs : %d max %d\n", req->nr_relocs,
NOUVEAU_GEM_MAX_RELOCS);
return -EINVAL;
}
bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo));
if (IS_ERR(bo))
return PTR_ERR(bo);
mutex_lock(&dev->struct_mutex);
/* Validate buffer list */ /* Validate buffer list */
ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers,
req->nr_buffers, &op, &do_reloc); req->nr_buffers, &op, &do_reloc);
@ -660,122 +628,84 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
goto out; goto out;
} }
/* Validate DMA push buffer */
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem) {
NV_ERROR(dev, "Unknown pb handle 0x%08x\n", req->handle);
ret = -EINVAL;
goto out;
}
pbbo = nouveau_gem_object(gem);
if ((req->offset & 3) || req->nr_dwords < 2 ||
(unsigned long)req->offset > (unsigned long)pbbo->bo.mem.size ||
(unsigned long)req->nr_dwords >
((unsigned long)(pbbo->bo.mem.size - req->offset ) >> 2)) {
NV_ERROR(dev, "pb call misaligned or out of bounds: "
"%d + %d * 4 > %ld\n",
req->offset, req->nr_dwords, pbbo->bo.mem.size);
ret = -EINVAL;
drm_gem_object_unreference(gem);
goto out;
}
ret = ttm_bo_reserve(&pbbo->bo, false, false, true,
chan->fence.sequence);
if (ret) {
NV_ERROR(dev, "resv pb: %d\n", ret);
drm_gem_object_unreference(gem);
goto out;
}
nouveau_bo_placement_set(pbbo, 1 << chan->pushbuf_bo->bo.mem.mem_type);
ret = ttm_bo_validate(&pbbo->bo, &pbbo->placement, false, false);
if (ret) {
NV_ERROR(dev, "validate pb: %d\n", ret);
ttm_bo_unreserve(&pbbo->bo);
drm_gem_object_unreference(gem);
goto out;
}
list_add_tail(&pbbo->entry, &op.both_list);
/* If presumed return address doesn't match, we need to map the
* push buffer and fix it..
*/
if (!PUSHBUF_CAL) {
uint32_t retaddy;
if (chan->dma.free < 4 + NOUVEAU_DMA_SKIPS) {
ret = nouveau_dma_wait(chan, 4 + NOUVEAU_DMA_SKIPS);
if (ret) {
NV_ERROR(dev, "jmp_space: %d\n", ret);
goto out;
}
}
retaddy = chan->pushbuf_base + ((chan->dma.cur + 2) << 2);
retaddy |= 0x20000000;
if (retaddy != req->suffix0) {
req->suffix0 = retaddy;
do_reloc = 1;
}
}
/* Apply any relocations that are required */ /* Apply any relocations that are required */
if (do_reloc) { if (do_reloc) {
void *pbvirt; ret = nouveau_gem_pushbuf_reloc_apply(dev, req, bo);
bool is_iomem;
ret = ttm_bo_kmap(&pbbo->bo, 0, pbbo->bo.mem.num_pages,
&pbbo->kmap);
if (ret) {
NV_ERROR(dev, "kmap pb: %d\n", ret);
goto out;
}
pbvirt = ttm_kmap_obj_virtual(&pbbo->kmap, &is_iomem);
ret = nouveau_gem_pushbuf_reloc_apply(chan, req->nr_buffers, bo,
req->nr_relocs,
req->relocs,
req->nr_dwords,
req->offset / 4,
pbvirt, is_iomem);
if (!PUSHBUF_CAL) {
nouveau_bo_wr32(pbbo,
req->offset / 4 + req->nr_dwords - 2,
req->suffix0);
}
ttm_bo_kunmap(&pbbo->kmap);
if (ret) { if (ret) {
NV_ERROR(dev, "reloc apply: %d\n", ret); NV_ERROR(dev, "reloc apply: %d\n", ret);
goto out; goto out;
} }
} }
if (PUSHBUF_CAL) { if (chan->dma.ib_max) {
ret = RING_SPACE(chan, 2); ret = nouveau_dma_wait(chan, req->nr_push + 1, 6);
if (ret) {
NV_INFO(dev, "nv50cal_space: %d\n", ret);
goto out;
}
for (i = 0; i < req->nr_push; i++) {
struct nouveau_bo *nvbo = (void *)(unsigned long)
bo[push[i].bo_index].user_priv;
nv50_dma_push(chan, nvbo, push[i].offset,
push[i].length);
}
} else
if (dev_priv->card_type >= NV_20) {
ret = RING_SPACE(chan, req->nr_push * 2);
if (ret) { if (ret) {
NV_ERROR(dev, "cal_space: %d\n", ret); NV_ERROR(dev, "cal_space: %d\n", ret);
goto out; goto out;
} }
OUT_RING(chan, ((pbbo->bo.mem.mm_node->start << PAGE_SHIFT) +
req->offset) | 2); for (i = 0; i < req->nr_push; i++) {
OUT_RING(chan, 0); struct nouveau_bo *nvbo = (void *)(unsigned long)
bo[push[i].bo_index].user_priv;
struct drm_mm_node *mem = nvbo->bo.mem.mm_node;
OUT_RING(chan, ((mem->start << PAGE_SHIFT) +
push[i].offset) | 2);
OUT_RING(chan, 0);
}
} else { } else {
ret = RING_SPACE(chan, 2 + NOUVEAU_DMA_SKIPS); ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS));
if (ret) { if (ret) {
NV_ERROR(dev, "jmp_space: %d\n", ret); NV_ERROR(dev, "jmp_space: %d\n", ret);
goto out; goto out;
} }
OUT_RING(chan, ((pbbo->bo.mem.mm_node->start << PAGE_SHIFT) +
req->offset) | 0x20000000);
OUT_RING(chan, 0);
/* Space the jumps apart with NOPs. */ for (i = 0; i < req->nr_push; i++) {
for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) struct nouveau_bo *nvbo = (void *)(unsigned long)
bo[push[i].bo_index].user_priv;
struct drm_mm_node *mem = nvbo->bo.mem.mm_node;
uint32_t cmd;
cmd = chan->pushbuf_base + ((chan->dma.cur + 2) << 2);
cmd |= 0x20000000;
if (unlikely(cmd != req->suffix0)) {
if (!nvbo->kmap.virtual) {
ret = ttm_bo_kmap(&nvbo->bo, 0,
nvbo->bo.mem.
num_pages,
&nvbo->kmap);
if (ret) {
WIND_RING(chan);
goto out;
}
nvbo->validate_mapped = true;
}
nouveau_bo_wr32(nvbo, (push[i].offset +
push[i].length - 8) / 4, cmd);
}
OUT_RING(chan, ((mem->start << PAGE_SHIFT) +
push[i].offset) | 0x20000000);
OUT_RING(chan, 0); OUT_RING(chan, 0);
for (j = 0; j < NOUVEAU_DMA_SKIPS; j++)
OUT_RING(chan, 0);
}
} }
ret = nouveau_fence_new(chan, &fence, true); ret = nouveau_fence_new(chan, &fence, true);
@ -790,9 +720,14 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
nouveau_fence_unref((void**)&fence); nouveau_fence_unref((void**)&fence);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
kfree(bo); kfree(bo);
kfree(push);
out_next: out_next:
if (PUSHBUF_CAL) { if (chan->dma.ib_max) {
req->suffix0 = 0x00000000;
req->suffix1 = 0x00000000;
} else
if (dev_priv->card_type >= NV_20) {
req->suffix0 = 0x00020000; req->suffix0 = 0x00020000;
req->suffix1 = 0x00000000; req->suffix1 = 0x00000000;
} else { } else {
@ -804,19 +739,6 @@ nouveau_gem_ioctl_pushbuf_call(struct drm_device *dev, void *data,
return ret; return ret;
} }
int
nouveau_gem_ioctl_pushbuf_call2(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_gem_pushbuf_call *req = data;
req->vram_available = dev_priv->fb_aper_free;
req->gart_available = dev_priv->gart_info.aper_free;
return nouveau_gem_ioctl_pushbuf_call(dev, data, file_priv);
}
static inline uint32_t static inline uint32_t
domain_to_ttm(struct nouveau_bo *nvbo, uint32_t domain) domain_to_ttm(struct nouveau_bo *nvbo, uint32_t domain)
{ {
@ -830,74 +752,6 @@ domain_to_ttm(struct nouveau_bo *nvbo, uint32_t domain)
return flags; return flags;
} }
int
nouveau_gem_ioctl_pin(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_nouveau_gem_pin *req = data;
struct drm_gem_object *gem;
struct nouveau_bo *nvbo;
int ret = 0;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
NV_ERROR(dev, "pin only allowed without kernel modesetting\n");
return -EINVAL;
}
if (!DRM_SUSER(DRM_CURPROC))
return -EPERM;
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem)
return -EINVAL;
nvbo = nouveau_gem_object(gem);
ret = nouveau_bo_pin(nvbo, domain_to_ttm(nvbo, req->domain));
if (ret)
goto out;
req->offset = nvbo->bo.offset;
if (nvbo->bo.mem.mem_type == TTM_PL_TT)
req->domain = NOUVEAU_GEM_DOMAIN_GART;
else
req->domain = NOUVEAU_GEM_DOMAIN_VRAM;
out:
mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(gem);
mutex_unlock(&dev->struct_mutex);
return ret;
}
int
nouveau_gem_ioctl_unpin(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_nouveau_gem_pin *req = data;
struct drm_gem_object *gem;
int ret;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem)
return -EINVAL;
ret = nouveau_bo_unpin(nouveau_gem_object(gem));
mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(gem);
mutex_unlock(&dev->struct_mutex);
return ret;
}
int int
nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
@ -935,9 +789,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
} }
out: out:
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(gem);
drm_gem_object_unreference(gem);
mutex_unlock(&dev->struct_mutex);
return ret; return ret;
} }
@ -965,9 +817,7 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
ret = 0; ret = 0;
out: out:
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(gem);
drm_gem_object_unreference(gem);
mutex_unlock(&dev->struct_mutex);
return ret; return ret;
} }
@ -986,9 +836,7 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data,
return -EINVAL; return -EINVAL;
ret = nouveau_gem_info(gem, req); ret = nouveau_gem_info(gem, req);
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(gem);
drm_gem_object_unreference(gem);
mutex_unlock(&dev->struct_mutex);
return ret; return ret;
} }

View File

@ -160,7 +160,7 @@ static void
setPLL_single(struct drm_device *dev, uint32_t reg, struct nouveau_pll_vals *pv) setPLL_single(struct drm_device *dev, uint32_t reg, struct nouveau_pll_vals *pv)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
int chip_version = dev_priv->vbios->chip_version; int chip_version = dev_priv->vbios.chip_version;
uint32_t oldpll = NVReadRAMDAC(dev, 0, reg); uint32_t oldpll = NVReadRAMDAC(dev, 0, reg);
int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff; int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1; uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
@ -216,7 +216,7 @@ setPLL_double_highregs(struct drm_device *dev, uint32_t reg1,
struct nouveau_pll_vals *pv) struct nouveau_pll_vals *pv)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
int chip_version = dev_priv->vbios->chip_version; int chip_version = dev_priv->vbios.chip_version;
bool nv3035 = chip_version == 0x30 || chip_version == 0x35; bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
uint32_t reg2 = reg1 + ((reg1 == NV_RAMDAC_VPLL2) ? 0x5c : 0x70); uint32_t reg2 = reg1 + ((reg1 == NV_RAMDAC_VPLL2) ? 0x5c : 0x70);
uint32_t oldpll1 = NVReadRAMDAC(dev, 0, reg1); uint32_t oldpll1 = NVReadRAMDAC(dev, 0, reg1);
@ -374,7 +374,7 @@ nouveau_hw_setpll(struct drm_device *dev, uint32_t reg1,
struct nouveau_pll_vals *pv) struct nouveau_pll_vals *pv)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
int cv = dev_priv->vbios->chip_version; int cv = dev_priv->vbios.chip_version;
if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 || if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
cv >= 0x40) { cv >= 0x40) {

View File

@ -254,16 +254,16 @@ struct nouveau_i2c_chan *
nouveau_i2c_find(struct drm_device *dev, int index) nouveau_i2c_find(struct drm_device *dev, int index)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
if (index > DCB_MAX_NUM_I2C_ENTRIES) if (index >= DCB_MAX_NUM_I2C_ENTRIES)
return NULL; return NULL;
if (!bios->bdcb.dcb.i2c[index].chan) { if (!bios->dcb.i2c[index].chan) {
if (nouveau_i2c_init(dev, &bios->bdcb.dcb.i2c[index], index)) if (nouveau_i2c_init(dev, &bios->dcb.i2c[index], index))
return NULL; return NULL;
} }
return bios->bdcb.dcb.i2c[index].chan; return bios->dcb.i2c[index].chan;
} }

View File

@ -691,11 +691,14 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
struct drm_device *dev = (struct drm_device *)arg; struct drm_device *dev = (struct drm_device *)arg;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t status, fbdev_flags = 0; uint32_t status, fbdev_flags = 0;
unsigned long flags;
status = nv_rd32(dev, NV03_PMC_INTR_0); status = nv_rd32(dev, NV03_PMC_INTR_0);
if (!status) if (!status)
return IRQ_NONE; return IRQ_NONE;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
if (dev_priv->fbdev_info) { if (dev_priv->fbdev_info) {
fbdev_flags = dev_priv->fbdev_info->flags; fbdev_flags = dev_priv->fbdev_info->flags;
dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED; dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
@ -733,5 +736,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
if (dev_priv->fbdev_info) if (dev_priv->fbdev_info)
dev_priv->fbdev_info->flags = fbdev_flags; dev_priv->fbdev_info->flags = fbdev_flags;
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }

View File

@ -61,11 +61,8 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
chan->notifier_bo = ntfy; chan->notifier_bo = ntfy;
out_err: out_err:
if (ret) { if (ret)
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(ntfy->gem);
drm_gem_object_unreference(ntfy->gem);
mutex_unlock(&dev->struct_mutex);
}
return ret; return ret;
} }
@ -81,8 +78,8 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
nouveau_bo_unmap(chan->notifier_bo); nouveau_bo_unmap(chan->notifier_bo);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
nouveau_bo_unpin(chan->notifier_bo); nouveau_bo_unpin(chan->notifier_bo);
drm_gem_object_unreference(chan->notifier_bo->gem);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
nouveau_mem_takedown(&chan->notifier_heap); nouveau_mem_takedown(&chan->notifier_heap);
} }

View File

@ -29,6 +29,7 @@
#include "drm_sarea.h" #include "drm_sarea.h"
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
#include <linux/vgaarb.h> #include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include "nouveau_drv.h" #include "nouveau_drv.h"
#include "nouveau_drm.h" #include "nouveau_drm.h"
@ -371,6 +372,30 @@ nouveau_card_init_channel(struct drm_device *dev)
return ret; return ret;
} }
static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
enum vga_switcheroo_state state)
{
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
nouveau_pci_resume(pdev);
} else {
printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
nouveau_pci_suspend(pdev, pmm);
}
}
static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
bool can_switch;
spin_lock(&dev->count_lock);
can_switch = (dev->open_count == 0);
spin_unlock(&dev->count_lock);
return can_switch;
}
int int
nouveau_card_init(struct drm_device *dev) nouveau_card_init(struct drm_device *dev)
{ {
@ -384,6 +409,8 @@ nouveau_card_init(struct drm_device *dev)
return 0; return 0;
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
nouveau_switcheroo_can_switch);
/* Initialise internal driver API hooks */ /* Initialise internal driver API hooks */
ret = nouveau_init_engine_ptrs(dev); ret = nouveau_init_engine_ptrs(dev);
@ -391,6 +418,7 @@ nouveau_card_init(struct drm_device *dev)
goto out; goto out;
engine = &dev_priv->engine; engine = &dev_priv->engine;
dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED; dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
spin_lock_init(&dev_priv->context_switch_lock);
/* Parse BIOS tables / Run init tables if card not POSTed */ /* Parse BIOS tables / Run init tables if card not POSTed */
if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@ -617,11 +645,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
dev->pci_vendor, dev->pci_device, dev->pdev->class); dev->pci_vendor, dev->pci_device, dev->pdev->class);
dev_priv->acpi_dsm = nouveau_dsm_probe(dev);
if (dev_priv->acpi_dsm)
nouveau_hybrid_setup(dev);
dev_priv->wq = create_workqueue("nouveau"); dev_priv->wq = create_workqueue("nouveau");
if (!dev_priv->wq) if (!dev_priv->wq)
return -EINVAL; return -EINVAL;
@ -776,13 +799,6 @@ int nouveau_unload(struct drm_device *dev)
return 0; return 0;
} }
int
nouveau_ioctl_card_init(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
return nouveau_card_init(dev);
}
int nouveau_ioctl_getparam(struct drm_device *dev, void *data, int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {

View File

@ -926,9 +926,7 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset); nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset);
nv_crtc->cursor.show(nv_crtc, true); nv_crtc->cursor.show(nv_crtc, true);
out: out:
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(gem);
drm_gem_object_unreference(gem);
mutex_unlock(&dev->struct_mutex);
return ret; return ret;
} }

View File

@ -230,13 +230,13 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
if (dcb->type == OUTPUT_TV) { if (dcb->type == OUTPUT_TV) {
testval = RGB_TEST_DATA(0xa0, 0xa0, 0xa0); testval = RGB_TEST_DATA(0xa0, 0xa0, 0xa0);
if (dev_priv->vbios->tvdactestval) if (dev_priv->vbios.tvdactestval)
testval = dev_priv->vbios->tvdactestval; testval = dev_priv->vbios.tvdactestval;
} else { } else {
testval = RGB_TEST_DATA(0x140, 0x140, 0x140); /* 0x94050140 */ testval = RGB_TEST_DATA(0x140, 0x140, 0x140); /* 0x94050140 */
if (dev_priv->vbios->dactestval) if (dev_priv->vbios.dactestval)
testval = dev_priv->vbios->dactestval; testval = dev_priv->vbios.dactestval;
} }
saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset); saved_rtest_ctrl = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);

View File

@ -269,10 +269,10 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
regp->fp_horiz_regs[FP_TOTAL] = output_mode->htotal - 1; regp->fp_horiz_regs[FP_TOTAL] = output_mode->htotal - 1;
if (!nv_gf4_disp_arch(dev) || if (!nv_gf4_disp_arch(dev) ||
(output_mode->hsync_start - output_mode->hdisplay) >= (output_mode->hsync_start - output_mode->hdisplay) >=
dev_priv->vbios->digital_min_front_porch) dev_priv->vbios.digital_min_front_porch)
regp->fp_horiz_regs[FP_CRTC] = output_mode->hdisplay; regp->fp_horiz_regs[FP_CRTC] = output_mode->hdisplay;
else else
regp->fp_horiz_regs[FP_CRTC] = output_mode->hsync_start - dev_priv->vbios->digital_min_front_porch - 1; regp->fp_horiz_regs[FP_CRTC] = output_mode->hsync_start - dev_priv->vbios.digital_min_front_porch - 1;
regp->fp_horiz_regs[FP_SYNC_START] = output_mode->hsync_start - 1; regp->fp_horiz_regs[FP_SYNC_START] = output_mode->hsync_start - 1;
regp->fp_horiz_regs[FP_SYNC_END] = output_mode->hsync_end - 1; regp->fp_horiz_regs[FP_SYNC_END] = output_mode->hsync_end - 1;
regp->fp_horiz_regs[FP_VALID_START] = output_mode->hskew; regp->fp_horiz_regs[FP_VALID_START] = output_mode->hskew;

View File

@ -93,10 +93,9 @@ int
nv04_display_create(struct drm_device *dev) nv04_display_create(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct parsed_dcb *dcb = dev_priv->vbios->dcb; struct dcb_table *dcb = &dev_priv->vbios.dcb;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_crtc *crtc; struct drm_crtc *crtc;
uint16_t connector[16] = { 0 };
int i, ret; int i, ret;
NV_DEBUG_KMS(dev, "\n"); NV_DEBUG_KMS(dev, "\n");
@ -154,52 +153,10 @@ nv04_display_create(struct drm_device *dev)
if (ret) if (ret)
continue; continue;
connector[dcbent->connector] |= (1 << dcbent->type);
} }
for (i = 0; i < dcb->entries; i++) { for (i = 0; i < dcb->connector.entries; i++)
struct dcb_entry *dcbent = &dcb->entry[i]; nouveau_connector_create(dev, &dcb->connector.entry[i]);
uint16_t encoders;
int type;
encoders = connector[dcbent->connector];
if (!(encoders & (1 << dcbent->type)))
continue;
connector[dcbent->connector] = 0;
switch (dcbent->type) {
case OUTPUT_ANALOG:
if (!MULTIPLE_ENCODERS(encoders))
type = DRM_MODE_CONNECTOR_VGA;
else
type = DRM_MODE_CONNECTOR_DVII;
break;
case OUTPUT_TMDS:
if (!MULTIPLE_ENCODERS(encoders))
type = DRM_MODE_CONNECTOR_DVID;
else
type = DRM_MODE_CONNECTOR_DVII;
break;
case OUTPUT_LVDS:
type = DRM_MODE_CONNECTOR_LVDS;
#if 0
/* don't create i2c adapter when lvds ddc not allowed */
if (dcbent->lvdsconf.use_straps_for_mode ||
dev_priv->vbios->fp_no_ddc)
i2c_index = 0xf;
#endif
break;
case OUTPUT_TV:
type = DRM_MODE_CONNECTOR_TV;
break;
default:
type = DRM_MODE_CONNECTOR_Unknown;
continue;
}
nouveau_connector_create(dev, dcbent->connector, type);
}
/* Save previous state */ /* Save previous state */
NVLockVgaCrtcs(dev, false); NVLockVgaCrtcs(dev, false);

View File

@ -118,7 +118,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
return; return;
} }
width = (image->width + 31) & ~31; width = ALIGN(image->width, 32);
dsize = (width * image->height) >> 5; dsize = (width * image->height) >> 5;
if (info->fix.visual == FB_VISUAL_TRUECOLOR || if (info->fix.visual == FB_VISUAL_TRUECOLOR ||

View File

@ -117,6 +117,7 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
{ {
struct drm_device *dev = chan->dev; struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
unsigned long flags;
int ret; int ret;
ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(chan->id), ~0, ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(chan->id), ~0,
@ -127,6 +128,8 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
if (ret) if (ret)
return ret; return ret;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
/* Setup initial state */ /* Setup initial state */
dev_priv->engine.instmem.prepare_access(dev, true); dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, chan->pushbuf_base); RAMFC_WR(DMA_PUT, chan->pushbuf_base);
@ -144,6 +147,8 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
/* enable the fifo dma operation */ /* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE, nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id)); nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0; return 0;
} }

View File

@ -262,7 +262,7 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->or = ffs(entry->or) - 1; nv_encoder->or = ffs(entry->or) - 1;
/* Run the slave-specific initialization */ /* Run the slave-specific initialization */
adap = &dev_priv->vbios->dcb->i2c[i2c_index].chan->adapter; adap = &dev_priv->vbios.dcb.i2c[i2c_index].chan->adapter;
was_locked = NVLockVgaCrtcs(dev, false); was_locked = NVLockVgaCrtcs(dev, false);

View File

@ -45,8 +45,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
#define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20) #define RGB_TEST_DATA(r, g, b) (r << 0 | g << 10 | b << 20)
testval = RGB_TEST_DATA(0x82, 0xeb, 0x82); testval = RGB_TEST_DATA(0x82, 0xeb, 0x82);
if (dev_priv->vbios->tvdactestval) if (dev_priv->vbios.tvdactestval)
testval = dev_priv->vbios->tvdactestval; testval = dev_priv->vbios.tvdactestval;
dacclk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); dacclk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
head = (dacclk & 0x100) >> 8; head = (dacclk & 0x100) >> 8;
@ -367,7 +367,7 @@ static void nv17_tv_prepare(struct drm_encoder *encoder)
!enc->crtc && !enc->crtc &&
nv04_dfp_get_bound_head(dev, dcb) == head) { nv04_dfp_get_bound_head(dev, dcb) == head) {
nv04_dfp_bind_head(dev, dcb, head ^ 1, nv04_dfp_bind_head(dev, dcb, head ^ 1,
dev_priv->VBIOS.fp.dual_link); dev_priv->vbios.fp.dual_link);
} }
} }

View File

@ -37,6 +37,7 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev; struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV40_RAMFC(chan->id); uint32_t fc = NV40_RAMFC(chan->id);
unsigned long flags;
int ret; int ret;
ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0, ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
@ -45,6 +46,8 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
if (ret) if (ret)
return ret; return ret;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
dev_priv->engine.instmem.prepare_access(dev, true); dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base); nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base); nv_wi32(dev, fc + 4, chan->pushbuf_base);
@ -63,6 +66,8 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
/* enable the fifo dma operation */ /* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE, nv_wr32(dev, NV04_PFIFO_MODE,
nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id)); nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0; return 0;
} }

View File

@ -358,9 +358,7 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
nv_crtc->cursor.show(nv_crtc, true); nv_crtc->cursor.show(nv_crtc, true);
out: out:
mutex_lock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(gem);
drm_gem_object_unreference(gem);
mutex_unlock(&dev->struct_mutex);
return ret; return ret;
} }

View File

@ -79,8 +79,8 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
} }
/* Use bios provided value if possible. */ /* Use bios provided value if possible. */
if (dev_priv->vbios->dactestval) { if (dev_priv->vbios.dactestval) {
load_pattern = dev_priv->vbios->dactestval; load_pattern = dev_priv->vbios.dactestval;
NV_DEBUG_KMS(dev, "Using bios provided load_pattern of %d\n", NV_DEBUG_KMS(dev, "Using bios provided load_pattern of %d\n",
load_pattern); load_pattern);
} else { } else {

View File

@ -370,9 +370,7 @@ nv50_display_init(struct drm_device *dev)
struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_connector *conn = nouveau_connector(connector);
struct dcb_gpio_entry *gpio; struct dcb_gpio_entry *gpio;
if (connector->connector_type != DRM_MODE_CONNECTOR_DVII && if (conn->dcb->gpio_tag == 0xff)
connector->connector_type != DRM_MODE_CONNECTOR_DVID &&
connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
continue; continue;
gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag); gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag);
@ -465,8 +463,7 @@ static int nv50_display_disable(struct drm_device *dev)
int nv50_display_create(struct drm_device *dev) int nv50_display_create(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct parsed_dcb *dcb = dev_priv->vbios->dcb; struct dcb_table *dcb = &dev_priv->vbios.dcb;
uint32_t connector[16] = {};
int ret, i; int ret, i;
NV_DEBUG_KMS(dev, "\n"); NV_DEBUG_KMS(dev, "\n");
@ -522,44 +519,13 @@ int nv50_display_create(struct drm_device *dev)
NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
continue; continue;
} }
connector[entry->connector] |= (1 << entry->type);
} }
/* It appears that DCB 3.0+ VBIOS has a connector table, however, for (i = 0 ; i < dcb->connector.entries; i++) {
* I'm not 100% certain how to decode it correctly yet so just if (i != 0 && dcb->connector.entry[i].index ==
* look at what encoders are present on each connector index and dcb->connector.entry[i - 1].index)
* attempt to derive the connector type from that.
*/
for (i = 0 ; i < dcb->entries; i++) {
struct dcb_entry *entry = &dcb->entry[i];
uint16_t encoders;
int type;
encoders = connector[entry->connector];
if (!(encoders & (1 << entry->type)))
continue; continue;
connector[entry->connector] = 0; nouveau_connector_create(dev, &dcb->connector.entry[i]);
if (encoders & (1 << OUTPUT_DP)) {
type = DRM_MODE_CONNECTOR_DisplayPort;
} else if (encoders & (1 << OUTPUT_TMDS)) {
if (encoders & (1 << OUTPUT_ANALOG))
type = DRM_MODE_CONNECTOR_DVII;
else
type = DRM_MODE_CONNECTOR_DVID;
} else if (encoders & (1 << OUTPUT_ANALOG)) {
type = DRM_MODE_CONNECTOR_VGA;
} else if (encoders & (1 << OUTPUT_LVDS)) {
type = DRM_MODE_CONNECTOR_LVDS;
} else {
type = DRM_MODE_CONNECTOR_Unknown;
}
if (type == DRM_MODE_CONNECTOR_Unknown)
continue;
nouveau_connector_create(dev, entry->connector, type);
} }
ret = nv50_display_init(dev); ret = nv50_display_init(dev);
@ -667,8 +633,8 @@ nv50_display_irq_head(struct drm_device *dev, int *phead,
return -1; return -1;
} }
for (i = 0; i < dev_priv->vbios->dcb->entries; i++) { for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
struct dcb_entry *dcbent = &dev_priv->vbios->dcb->entry[i]; struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i];
if (dcbent->type != type) if (dcbent->type != type)
continue; continue;
@ -692,7 +658,7 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent,
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL; struct nouveau_connector *nv_connector = NULL;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct nvbios *bios = &dev_priv->VBIOS; struct nvbios *bios = &dev_priv->vbios;
uint32_t mc, script = 0, or; uint32_t mc, script = 0, or;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@ -710,7 +676,7 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent,
switch (dcbent->type) { switch (dcbent->type) {
case OUTPUT_LVDS: case OUTPUT_LVDS:
script = (mc >> 8) & 0xf; script = (mc >> 8) & 0xf;
if (bios->pub.fp_no_ddc) { if (bios->fp_no_ddc) {
if (bios->fp.dual_link) if (bios->fp.dual_link)
script |= 0x0100; script |= 0x0100;
if (bios->fp.if_is_24bit) if (bios->fp.if_is_24bit)

View File

@ -109,7 +109,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
return; return;
} }
width = (image->width + 31) & ~31; width = ALIGN(image->width, 32);
dwords = (width * image->height) >> 5; dwords = (width * image->height) >> 5;
BEGIN_RING(chan, NvSub2D, 0x0814, 2); BEGIN_RING(chan, NvSub2D, 0x0814, 2);

View File

@ -243,6 +243,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev; struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramfc = NULL; struct nouveau_gpuobj *ramfc = NULL;
unsigned long flags;
int ret; int ret;
NV_DEBUG(dev, "ch%d\n", chan->id); NV_DEBUG(dev, "ch%d\n", chan->id);
@ -278,19 +279,21 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
return ret; return ret;
} }
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
dev_priv->engine.instmem.prepare_access(dev, true); dev_priv->engine.instmem.prepare_access(dev, true);
nv_wo32(dev, ramfc, 0x08/4, chan->pushbuf_base);
nv_wo32(dev, ramfc, 0x10/4, chan->pushbuf_base);
nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4); nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4)); nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4));
nv_wo32(dev, ramfc, 0x3c/4, 0x00086078);
nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff); nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff); nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
nv_wo32(dev, ramfc, 0x40/4, 0x00000000); nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
nv_wo32(dev, ramfc, 0x7c/4, 0x30000001); nv_wo32(dev, ramfc, 0x7c/4, 0x30000001);
nv_wo32(dev, ramfc, 0x78/4, 0x00000000); nv_wo32(dev, ramfc, 0x78/4, 0x00000000);
nv_wo32(dev, ramfc, 0x4c/4, 0xffffffff); nv_wo32(dev, ramfc, 0x3c/4, 0x403f6078);
nv_wo32(dev, ramfc, 0x50/4, chan->pushbuf_base +
chan->dma.ib_base * 4);
nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
if (!IS_G80) { if (!IS_G80) {
nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id); nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
@ -306,10 +309,12 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
ret = nv50_fifo_channel_enable(dev, chan->id, false); ret = nv50_fifo_channel_enable(dev, chan->id, false);
if (ret) { if (ret) {
NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret); NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
nouveau_gpuobj_ref_del(dev, &chan->ramfc); nouveau_gpuobj_ref_del(dev, &chan->ramfc);
return ret; return ret;
} }
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0; return 0;
} }

View File

@ -28,30 +28,7 @@
#include "drm.h" #include "drm.h"
#include "nouveau_drv.h" #include "nouveau_drv.h"
MODULE_FIRMWARE("nouveau/nv50.ctxprog"); #include "nouveau_grctx.h"
MODULE_FIRMWARE("nouveau/nv50.ctxvals");
MODULE_FIRMWARE("nouveau/nv84.ctxprog");
MODULE_FIRMWARE("nouveau/nv84.ctxvals");
MODULE_FIRMWARE("nouveau/nv86.ctxprog");
MODULE_FIRMWARE("nouveau/nv86.ctxvals");
MODULE_FIRMWARE("nouveau/nv92.ctxprog");
MODULE_FIRMWARE("nouveau/nv92.ctxvals");
MODULE_FIRMWARE("nouveau/nv94.ctxprog");
MODULE_FIRMWARE("nouveau/nv94.ctxvals");
MODULE_FIRMWARE("nouveau/nv96.ctxprog");
MODULE_FIRMWARE("nouveau/nv96.ctxvals");
MODULE_FIRMWARE("nouveau/nv98.ctxprog");
MODULE_FIRMWARE("nouveau/nv98.ctxvals");
MODULE_FIRMWARE("nouveau/nva0.ctxprog");
MODULE_FIRMWARE("nouveau/nva0.ctxvals");
MODULE_FIRMWARE("nouveau/nva5.ctxprog");
MODULE_FIRMWARE("nouveau/nva5.ctxvals");
MODULE_FIRMWARE("nouveau/nva8.ctxprog");
MODULE_FIRMWARE("nouveau/nva8.ctxvals");
MODULE_FIRMWARE("nouveau/nvaa.ctxprog");
MODULE_FIRMWARE("nouveau/nvaa.ctxvals");
MODULE_FIRMWARE("nouveau/nvac.ctxprog");
MODULE_FIRMWARE("nouveau/nvac.ctxvals");
#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) #define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
@ -111,9 +88,34 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
NV_DEBUG(dev, "\n"); NV_DEBUG(dev, "\n");
nouveau_grctx_prog_load(dev); if (nouveau_ctxfw) {
if (!dev_priv->engine.graph.ctxprog) nouveau_grctx_prog_load(dev);
dev_priv->engine.graph.accel_blocked = true; dev_priv->engine.graph.grctx_size = 0x70000;
}
if (!dev_priv->engine.graph.ctxprog) {
struct nouveau_grctx ctx = {};
uint32_t *cp = kmalloc(512 * 4, GFP_KERNEL);
int i;
if (!cp) {
NV_ERROR(dev, "Couldn't alloc ctxprog! Disabling acceleration.\n");
dev_priv->engine.graph.accel_blocked = true;
return 0;
}
ctx.dev = dev;
ctx.mode = NOUVEAU_GRCTX_PROG;
ctx.data = cp;
ctx.ctxprog_max = 512;
if (!nv50_grctx_init(&ctx)) {
dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
} else {
dev_priv->engine.graph.accel_blocked = true;
}
kfree(cp);
}
nv_wr32(dev, 0x400320, 4); nv_wr32(dev, 0x400320, 4);
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0); nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
@ -193,13 +195,13 @@ nv50_graph_create_context(struct nouveau_channel *chan)
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
struct nouveau_gpuobj *ctx; struct nouveau_gpuobj *ctx;
uint32_t grctx_size = 0x70000; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
int hdr, ret; int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id); NV_DEBUG(dev, "ch%d\n", chan->id);
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, grctx_size, 0x1000, ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
NVOBJ_FLAG_ZERO_ALLOC | 0x1000, NVOBJ_FLAG_ZERO_ALLOC |
NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
if (ret) if (ret)
return ret; return ret;
@ -209,7 +211,7 @@ nv50_graph_create_context(struct nouveau_channel *chan)
dev_priv->engine.instmem.prepare_access(dev, true); dev_priv->engine.instmem.prepare_access(dev, true);
nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002); nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance + nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
grctx_size - 1); pgraph->grctx_size - 1);
nv_wo32(dev, ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance); nv_wo32(dev, ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance);
nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0); nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
nv_wo32(dev, ramin, (hdr + 0x10)/4, 0); nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
@ -217,7 +219,15 @@ nv50_graph_create_context(struct nouveau_channel *chan)
dev_priv->engine.instmem.finish_access(dev); dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.prepare_access(dev, true); dev_priv->engine.instmem.prepare_access(dev, true);
nouveau_grctx_vals_load(dev, ctx); if (!pgraph->ctxprog) {
struct nouveau_grctx ctx = {};
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
ctx.data = chan->ramin_grctx->gpuobj;
nv50_grctx_init(&ctx);
} else {
nouveau_grctx_vals_load(dev, ctx);
}
nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12); nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
if ((dev_priv->chipset & 0xf0) == 0xa0) if ((dev_priv->chipset & 0xf0) == 0xa0)
nv_wo32(dev, ctx, 0x00004/4, 0x00000000); nv_wo32(dev, ctx, 0x00004/4, 0x00000000);

File diff suppressed because it is too large Load Diff

View File

@ -390,7 +390,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
if (gpuobj->im_backing) if (gpuobj->im_backing)
return -EINVAL; return -EINVAL;
*sz = (*sz + (NV50_INSTMEM_PAGE_SIZE-1)) & ~(NV50_INSTMEM_PAGE_SIZE-1); *sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE);
if (*sz == 0) if (*sz == 0)
return -EINVAL; return -EINVAL;

View File

@ -30,6 +30,9 @@ $(obj)/r420_reg_safe.h: $(src)/reg_srcs/r420 $(obj)/mkregtable
$(obj)/rs600_reg_safe.h: $(src)/reg_srcs/rs600 $(obj)/mkregtable $(obj)/rs600_reg_safe.h: $(src)/reg_srcs/rs600 $(obj)/mkregtable
$(call if_changed,mkregtable) $(call if_changed,mkregtable)
$(obj)/r600_reg_safe.h: $(src)/reg_srcs/r600 $(obj)/mkregtable
$(call if_changed,mkregtable)
$(obj)/r100.o: $(obj)/r100_reg_safe.h $(obj)/rn50_reg_safe.h $(obj)/r100.o: $(obj)/r100_reg_safe.h $(obj)/rn50_reg_safe.h
$(obj)/r200.o: $(obj)/r200_reg_safe.h $(obj)/r200.o: $(obj)/r200_reg_safe.h
@ -42,6 +45,8 @@ $(obj)/r420.o: $(obj)/r420_reg_safe.h
$(obj)/rs600.o: $(obj)/rs600_reg_safe.h $(obj)/rs600.o: $(obj)/rs600_reg_safe.h
$(obj)/r600_cs.o: $(obj)/r600_reg_safe.h
radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \ radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \
radeon_irq.o r300_cmdbuf.o r600_cp.o radeon_irq.o r300_cmdbuf.o r600_cp.o
# add KMS driver # add KMS driver
@ -54,8 +59,10 @@ radeon-y += radeon_device.o radeon_kms.o \
radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \ radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
evergreen.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
obj-$(CONFIG_DRM_RADEON)+= radeon.o obj-$(CONFIG_DRM_RADEON)+= radeon.o

View File

@ -881,8 +881,6 @@ static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
uint8_t attr = U8((*ptr)++), shift; uint8_t attr = U8((*ptr)++), shift;
uint32_t saved, dst; uint32_t saved, dst;
int dptr = *ptr; int dptr = *ptr;
attr &= 0x38;
attr |= atom_def_dst[attr >> 3] << 6;
SDEBUG(" dst: "); SDEBUG(" dst: ");
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
shift = atom_get_src(ctx, attr, ptr); shift = atom_get_src(ctx, attr, ptr);
@ -897,8 +895,6 @@ static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
uint8_t attr = U8((*ptr)++), shift; uint8_t attr = U8((*ptr)++), shift;
uint32_t saved, dst; uint32_t saved, dst;
int dptr = *ptr; int dptr = *ptr;
attr &= 0x38;
attr |= atom_def_dst[attr >> 3] << 6;
SDEBUG(" dst: "); SDEBUG(" dst: ");
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
shift = atom_get_src(ctx, attr, ptr); shift = atom_get_src(ctx, attr, ptr);

File diff suppressed because it is too large Load Diff

View File

@ -245,21 +245,25 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
switch (mode) { switch (mode) {
case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_ON:
atombios_enable_crtc(crtc, 1); atombios_enable_crtc(crtc, ATOM_ENABLE);
if (ASIC_IS_DCE3(rdev)) if (ASIC_IS_DCE3(rdev))
atombios_enable_crtc_memreq(crtc, 1); atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
atombios_blank_crtc(crtc, 0); atombios_blank_crtc(crtc, ATOM_DISABLE);
drm_vblank_post_modeset(dev, radeon_crtc->crtc_id); /* XXX re-enable when interrupt support is added */
if (!ASIC_IS_DCE4(rdev))
drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
radeon_crtc_load_lut(crtc); radeon_crtc_load_lut(crtc);
break; break;
case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF: case DRM_MODE_DPMS_OFF:
drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); /* XXX re-enable when interrupt support is added */
atombios_blank_crtc(crtc, 1); if (!ASIC_IS_DCE4(rdev))
drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
atombios_blank_crtc(crtc, ATOM_ENABLE);
if (ASIC_IS_DCE3(rdev)) if (ASIC_IS_DCE3(rdev))
atombios_enable_crtc_memreq(crtc, 0); atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
atombios_enable_crtc(crtc, 0); atombios_enable_crtc(crtc, ATOM_DISABLE);
break; break;
} }
} }
@ -349,6 +353,11 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc,
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
} }
union atom_enable_ss {
ENABLE_LVDS_SS_PARAMETERS legacy;
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
};
static void atombios_set_ss(struct drm_crtc *crtc, int enable) static void atombios_set_ss(struct drm_crtc *crtc, int enable)
{ {
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@ -358,11 +367,14 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable)
struct radeon_encoder *radeon_encoder = NULL; struct radeon_encoder *radeon_encoder = NULL;
struct radeon_encoder_atom_dig *dig = NULL; struct radeon_encoder_atom_dig *dig = NULL;
int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION args; union atom_enable_ss args;
ENABLE_LVDS_SS_PARAMETERS legacy_args;
uint16_t percentage = 0; uint16_t percentage = 0;
uint8_t type = 0, step = 0, delay = 0, range = 0; uint8_t type = 0, step = 0, delay = 0, range = 0;
/* XXX add ss support for DCE4 */
if (ASIC_IS_DCE4(rdev))
return;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) { if (encoder->crtc == crtc) {
radeon_encoder = to_radeon_encoder(encoder); radeon_encoder = to_radeon_encoder(encoder);
@ -386,29 +398,28 @@ static void atombios_set_ss(struct drm_crtc *crtc, int enable)
if (!radeon_encoder) if (!radeon_encoder)
return; return;
memset(&args, 0, sizeof(args));
if (ASIC_IS_AVIVO(rdev)) { if (ASIC_IS_AVIVO(rdev)) {
memset(&args, 0, sizeof(args)); args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
args.usSpreadSpectrumPercentage = cpu_to_le16(percentage); args.v1.ucSpreadSpectrumType = type;
args.ucSpreadSpectrumType = type; args.v1.ucSpreadSpectrumStep = step;
args.ucSpreadSpectrumStep = step; args.v1.ucSpreadSpectrumDelay = delay;
args.ucSpreadSpectrumDelay = delay; args.v1.ucSpreadSpectrumRange = range;
args.ucSpreadSpectrumRange = range; args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
args.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; args.v1.ucEnable = enable;
args.ucEnable = enable;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
} else { } else {
memset(&legacy_args, 0, sizeof(legacy_args)); args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
legacy_args.usSpreadSpectrumPercentage = cpu_to_le16(percentage); args.legacy.ucSpreadSpectrumType = type;
legacy_args.ucSpreadSpectrumType = type; args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2; args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4; args.legacy.ucEnable = enable;
legacy_args.ucEnable = enable;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&legacy_args);
} }
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
} }
union adjust_pixel_clock { union adjust_pixel_clock {
ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
}; };
static u32 atombios_adjust_pll(struct drm_crtc *crtc, static u32 atombios_adjust_pll(struct drm_crtc *crtc,
@ -420,10 +431,24 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
struct drm_encoder *encoder = NULL; struct drm_encoder *encoder = NULL;
struct radeon_encoder *radeon_encoder = NULL; struct radeon_encoder *radeon_encoder = NULL;
u32 adjusted_clock = mode->clock; u32 adjusted_clock = mode->clock;
int encoder_mode = 0;
/* reset the pll flags */ /* reset the pll flags */
pll->flags = 0; pll->flags = 0;
/* select the PLL algo */
if (ASIC_IS_AVIVO(rdev)) {
if (radeon_new_pll == 0)
pll->algo = PLL_ALGO_LEGACY;
else
pll->algo = PLL_ALGO_NEW;
} else {
if (radeon_new_pll == 1)
pll->algo = PLL_ALGO_NEW;
else
pll->algo = PLL_ALGO_LEGACY;
}
if (ASIC_IS_AVIVO(rdev)) { if (ASIC_IS_AVIVO(rdev)) {
if ((rdev->family == CHIP_RS600) || if ((rdev->family == CHIP_RS600) ||
(rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS690) ||
@ -448,10 +473,16 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) { if (encoder->crtc == crtc) {
radeon_encoder = to_radeon_encoder(encoder); radeon_encoder = to_radeon_encoder(encoder);
encoder_mode = atombios_get_encoder_mode(encoder);
if (ASIC_IS_AVIVO(rdev)) { if (ASIC_IS_AVIVO(rdev)) {
/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
adjusted_clock = mode->clock * 2; adjusted_clock = mode->clock * 2;
/* LVDS PLL quirks */
if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
pll->algo = dig->pll_algo;
}
} else { } else {
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
pll->flags |= RADEON_PLL_NO_ODD_POST_DIV; pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
@ -468,14 +499,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
*/ */
if (ASIC_IS_DCE3(rdev)) { if (ASIC_IS_DCE3(rdev)) {
union adjust_pixel_clock args; union adjust_pixel_clock args;
struct radeon_encoder_atom_dig *dig;
u8 frev, crev; u8 frev, crev;
int index; int index;
if (!radeon_encoder->enc_priv)
return adjusted_clock;
dig = radeon_encoder->enc_priv;
index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
&crev); &crev);
@ -489,12 +515,51 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
case 2: case 2:
args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
args.v1.ucTransmitterID = radeon_encoder->encoder_id; args.v1.ucTransmitterID = radeon_encoder->encoder_id;
args.v1.ucEncodeMode = atombios_get_encoder_mode(encoder); args.v1.ucEncodeMode = encoder_mode;
atom_execute_table(rdev->mode_info.atom_context, atom_execute_table(rdev->mode_info.atom_context,
index, (uint32_t *)&args); index, (uint32_t *)&args);
adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10; adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
break; break;
case 3:
args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10);
args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
args.v3.sInput.ucEncodeMode = encoder_mode;
args.v3.sInput.ucDispPllConfig = 0;
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (encoder_mode == ATOM_ENCODER_MODE_DP)
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_COHERENT_MODE;
else {
if (dig->coherent_mode)
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_COHERENT_MODE;
if (mode->clock > 165000)
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_DUAL_LINK;
}
} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
/* may want to enable SS on DP/eDP eventually */
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_SS_ENABLE;
if (mode->clock > 165000)
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_DUAL_LINK;
}
atom_execute_table(rdev->mode_info.atom_context,
index, (uint32_t *)&args);
adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
if (args.v3.sOutput.ucRefDiv) {
pll->flags |= RADEON_PLL_USE_REF_DIV;
pll->reference_div = args.v3.sOutput.ucRefDiv;
}
if (args.v3.sOutput.ucPostDiv) {
pll->flags |= RADEON_PLL_USE_POST_DIV;
pll->post_div = args.v3.sOutput.ucPostDiv;
}
break;
default: default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev); DRM_ERROR("Unknown table version %d %d\n", frev, crev);
return adjusted_clock; return adjusted_clock;
@ -513,9 +578,47 @@ union set_pixel_clock {
PIXEL_CLOCK_PARAMETERS v1; PIXEL_CLOCK_PARAMETERS v1;
PIXEL_CLOCK_PARAMETERS_V2 v2; PIXEL_CLOCK_PARAMETERS_V2 v2;
PIXEL_CLOCK_PARAMETERS_V3 v3; PIXEL_CLOCK_PARAMETERS_V3 v3;
PIXEL_CLOCK_PARAMETERS_V5 v5;
}; };
void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) static void atombios_crtc_set_dcpll(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
u8 frev, crev;
int index;
union set_pixel_clock args;
memset(&args, 0, sizeof(args));
index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
&crev);
switch (frev) {
case 1:
switch (crev) {
case 5:
/* if the default dcpll clock is specified,
* SetPixelClock provides the dividers
*/
args.v5.ucCRTC = ATOM_CRTC_INVALID;
args.v5.usPixelClock = rdev->clock.default_dispclk;
args.v5.ucPpll = ATOM_DCPLL;
break;
default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev);
return;
}
break;
default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev);
return;
}
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
{ {
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
@ -529,12 +632,14 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
struct radeon_pll *pll; struct radeon_pll *pll;
u32 adjusted_clock; u32 adjusted_clock;
int encoder_mode = 0;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) { if (encoder->crtc == crtc) {
radeon_encoder = to_radeon_encoder(encoder); radeon_encoder = to_radeon_encoder(encoder);
encoder_mode = atombios_get_encoder_mode(encoder);
break; break;
} }
} }
@ -542,26 +647,24 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
if (!radeon_encoder) if (!radeon_encoder)
return; return;
if (radeon_crtc->crtc_id == 0) switch (radeon_crtc->pll_id) {
case ATOM_PPLL1:
pll = &rdev->clock.p1pll; pll = &rdev->clock.p1pll;
else break;
case ATOM_PPLL2:
pll = &rdev->clock.p2pll; pll = &rdev->clock.p2pll;
break;
case ATOM_DCPLL:
case ATOM_PPLL_INVALID:
pll = &rdev->clock.dcpll;
break;
}
/* adjust pixel clock as needed */ /* adjust pixel clock as needed */
adjusted_clock = atombios_adjust_pll(crtc, mode, pll); adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
if (ASIC_IS_AVIVO(rdev)) { radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
if (radeon_new_pll) &ref_div, &post_div);
radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock,
&fb_div, &frac_fb_div,
&ref_div, &post_div);
else
radeon_compute_pll(pll, adjusted_clock, &pll_clock,
&fb_div, &frac_fb_div,
&ref_div, &post_div);
} else
radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
&ref_div, &post_div);
index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
@ -576,8 +679,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
args.v1.usFbDiv = cpu_to_le16(fb_div); args.v1.usFbDiv = cpu_to_le16(fb_div);
args.v1.ucFracFbDiv = frac_fb_div; args.v1.ucFracFbDiv = frac_fb_div;
args.v1.ucPostDiv = post_div; args.v1.ucPostDiv = post_div;
args.v1.ucPpll = args.v1.ucPpll = radeon_crtc->pll_id;
radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
args.v1.ucCRTC = radeon_crtc->crtc_id; args.v1.ucCRTC = radeon_crtc->crtc_id;
args.v1.ucRefDivSrc = 1; args.v1.ucRefDivSrc = 1;
break; break;
@ -587,8 +689,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
args.v2.usFbDiv = cpu_to_le16(fb_div); args.v2.usFbDiv = cpu_to_le16(fb_div);
args.v2.ucFracFbDiv = frac_fb_div; args.v2.ucFracFbDiv = frac_fb_div;
args.v2.ucPostDiv = post_div; args.v2.ucPostDiv = post_div;
args.v2.ucPpll = args.v2.ucPpll = radeon_crtc->pll_id;
radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
args.v2.ucCRTC = radeon_crtc->crtc_id; args.v2.ucCRTC = radeon_crtc->crtc_id;
args.v2.ucRefDivSrc = 1; args.v2.ucRefDivSrc = 1;
break; break;
@ -598,12 +699,22 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
args.v3.usFbDiv = cpu_to_le16(fb_div); args.v3.usFbDiv = cpu_to_le16(fb_div);
args.v3.ucFracFbDiv = frac_fb_div; args.v3.ucFracFbDiv = frac_fb_div;
args.v3.ucPostDiv = post_div; args.v3.ucPostDiv = post_div;
args.v3.ucPpll = args.v3.ucPpll = radeon_crtc->pll_id;
radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2);
args.v3.ucMiscInfo = (radeon_crtc->crtc_id << 2);
args.v3.ucTransmitterId = radeon_encoder->encoder_id; args.v3.ucTransmitterId = radeon_encoder->encoder_id;
args.v3.ucEncoderMode = args.v3.ucEncoderMode = encoder_mode;
atombios_get_encoder_mode(encoder); break;
case 5:
args.v5.ucCRTC = radeon_crtc->crtc_id;
args.v5.usPixelClock = cpu_to_le16(mode->clock / 10);
args.v5.ucRefDiv = ref_div;
args.v5.usFbDiv = cpu_to_le16(fb_div);
args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
args.v5.ucPostDiv = post_div;
args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
args.v5.ucTransmitterID = radeon_encoder->encoder_id;
args.v5.ucEncoderMode = encoder_mode;
args.v5.ucPpll = radeon_crtc->pll_id;
break; break;
default: default:
DRM_ERROR("Unknown table version %d %d\n", frev, crev); DRM_ERROR("Unknown table version %d %d\n", frev, crev);
@ -618,6 +729,140 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
} }
static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_framebuffer *radeon_fb;
struct drm_gem_object *obj;
struct radeon_bo *rbo;
uint64_t fb_location;
uint32_t fb_format, fb_pitch_pixels, tiling_flags;
int r;
/* no fb bound */
if (!crtc->fb) {
DRM_DEBUG("No FB bound\n");
return 0;
}
radeon_fb = to_radeon_framebuffer(crtc->fb);
/* Pin framebuffer & get tilling informations */
obj = radeon_fb->obj;
rbo = obj->driver_private;
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
return r;
r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
if (unlikely(r != 0)) {
radeon_bo_unreserve(rbo);
return -EINVAL;
}
radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
radeon_bo_unreserve(rbo);
switch (crtc->fb->bits_per_pixel) {
case 8:
fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
break;
case 15:
fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
break;
case 16:
fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
break;
case 24:
case 32:
fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
break;
default:
DRM_ERROR("Unsupported screen depth %d\n",
crtc->fb->bits_per_pixel);
return -EINVAL;
}
switch (radeon_crtc->crtc_id) {
case 0:
WREG32(AVIVO_D1VGA_CONTROL, 0);
break;
case 1:
WREG32(AVIVO_D2VGA_CONTROL, 0);
break;
case 2:
WREG32(EVERGREEN_D3VGA_CONTROL, 0);
break;
case 3:
WREG32(EVERGREEN_D4VGA_CONTROL, 0);
break;
case 4:
WREG32(EVERGREEN_D5VGA_CONTROL, 0);
break;
case 5:
WREG32(EVERGREEN_D6VGA_CONTROL, 0);
break;
default:
break;
}
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
upper_32_bits(fb_location));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
upper_32_bits(fb_location));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
(u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
(u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
crtc->mode.vdisplay);
x &= ~3;
y &= ~1;
WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
(x << 16) | y);
WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
(crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
EVERGREEN_INTERLEAVE_EN);
else
WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
if (old_fb && old_fb != crtc->fb) {
radeon_fb = to_radeon_framebuffer(old_fb);
rbo = radeon_fb->obj->driver_private;
r = radeon_bo_reserve(rbo, false);
if (unlikely(r != 0))
return r;
radeon_bo_unpin(rbo);
radeon_bo_unreserve(rbo);
}
/* Bytes per pixel may have changed */
radeon_bandwidth_update(rdev);
return 0;
}
static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y, static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb) struct drm_framebuffer *old_fb)
{ {
@ -755,7 +1000,9 @@ int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_device *dev = crtc->dev; struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
if (ASIC_IS_AVIVO(rdev)) if (ASIC_IS_DCE4(rdev))
return evergreen_crtc_set_base(crtc, x, y, old_fb);
else if (ASIC_IS_AVIVO(rdev))
return avivo_crtc_set_base(crtc, x, y, old_fb); return avivo_crtc_set_base(crtc, x, y, old_fb);
else else
return radeon_crtc_set_base(crtc, x, y, old_fb); return radeon_crtc_set_base(crtc, x, y, old_fb);
@ -785,6 +1032,46 @@ static void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
} }
} }
static int radeon_atom_pick_pll(struct drm_crtc *crtc)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *test_encoder;
struct drm_crtc *test_crtc;
uint32_t pll_in_use = 0;
if (ASIC_IS_DCE4(rdev)) {
/* if crtc is driving DP and we have an ext clock, use that */
list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) {
if (rdev->clock.dp_extclk)
return ATOM_PPLL_INVALID;
}
}
}
/* otherwise, pick one of the plls */
list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
struct radeon_crtc *radeon_test_crtc;
if (crtc == test_crtc)
continue;
radeon_test_crtc = to_radeon_crtc(test_crtc);
if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) &&
(radeon_test_crtc->pll_id <= ATOM_PPLL2))
pll_in_use |= (1 << radeon_test_crtc->pll_id);
}
if (!(pll_in_use & 1))
return ATOM_PPLL1;
return ATOM_PPLL2;
} else
return radeon_crtc->crtc_id;
}
int atombios_crtc_mode_set(struct drm_crtc *crtc, int atombios_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, struct drm_display_mode *adjusted_mode,
@ -796,19 +1083,27 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
/* TODO color tiling */ /* TODO color tiling */
/* pick pll */
radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
atombios_set_ss(crtc, 0); atombios_set_ss(crtc, 0);
/* always set DCPLL */
if (ASIC_IS_DCE4(rdev))
atombios_crtc_set_dcpll(crtc);
atombios_crtc_set_pll(crtc, adjusted_mode); atombios_crtc_set_pll(crtc, adjusted_mode);
atombios_set_ss(crtc, 1); atombios_set_ss(crtc, 1);
atombios_crtc_set_timing(crtc, adjusted_mode);
if (ASIC_IS_AVIVO(rdev)) if (ASIC_IS_DCE4(rdev))
atombios_crtc_set_base(crtc, x, y, old_fb); atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
else if (ASIC_IS_AVIVO(rdev))
atombios_crtc_set_timing(crtc, adjusted_mode);
else { else {
atombios_crtc_set_timing(crtc, adjusted_mode);
if (radeon_crtc->crtc_id == 0) if (radeon_crtc->crtc_id == 0)
atombios_set_crtc_dtd_timing(crtc, adjusted_mode); atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
atombios_crtc_set_base(crtc, x, y, old_fb);
radeon_legacy_atom_fixup(crtc); radeon_legacy_atom_fixup(crtc);
} }
atombios_crtc_set_base(crtc, x, y, old_fb);
atombios_overscan_setup(crtc, mode, adjusted_mode); atombios_overscan_setup(crtc, mode, adjusted_mode);
atombios_scaler_setup(crtc); atombios_scaler_setup(crtc);
return 0; return 0;
@ -825,14 +1120,14 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
static void atombios_crtc_prepare(struct drm_crtc *crtc) static void atombios_crtc_prepare(struct drm_crtc *crtc)
{ {
atombios_lock_crtc(crtc, 1); atombios_lock_crtc(crtc, ATOM_ENABLE);
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
} }
static void atombios_crtc_commit(struct drm_crtc *crtc) static void atombios_crtc_commit(struct drm_crtc *crtc)
{ {
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
atombios_lock_crtc(crtc, 0); atombios_lock_crtc(crtc, ATOM_DISABLE);
} }
static const struct drm_crtc_helper_funcs atombios_helper_funcs = { static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
@ -848,8 +1143,37 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
void radeon_atombios_init_crtc(struct drm_device *dev, void radeon_atombios_init_crtc(struct drm_device *dev,
struct radeon_crtc *radeon_crtc) struct radeon_crtc *radeon_crtc)
{ {
if (radeon_crtc->crtc_id == 1) struct radeon_device *rdev = dev->dev_private;
radeon_crtc->crtc_offset =
AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; if (ASIC_IS_DCE4(rdev)) {
switch (radeon_crtc->crtc_id) {
case 0:
default:
radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
break;
case 1:
radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
break;
case 2:
radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
break;
case 3:
radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
break;
case 4:
radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
break;
case 5:
radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
break;
}
} else {
if (radeon_crtc->crtc_id == 1)
radeon_crtc->crtc_offset =
AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
else
radeon_crtc->crtc_offset = 0;
}
radeon_crtc->pll_id = -1;
drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
} }

View File

@ -321,6 +321,10 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
train_set[lane] = v | p; train_set[lane] = v | p;
} }
union aux_channel_transaction {
PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
};
/* radeon aux chan functions */ /* radeon aux chan functions */
bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes, bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
@ -329,7 +333,7 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
{ {
struct drm_device *dev = chan->dev; struct drm_device *dev = chan->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args; union aux_channel_transaction args;
int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
unsigned char *base; unsigned char *base;
int retry_count = 0; int retry_count = 0;
@ -341,31 +345,33 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
retry: retry:
memcpy(base, req_bytes, num_bytes); memcpy(base, req_bytes, num_bytes);
args.lpAuxRequest = 0; args.v1.lpAuxRequest = 0;
args.lpDataOut = 16; args.v1.lpDataOut = 16;
args.ucDataOutLen = 0; args.v1.ucDataOutLen = 0;
args.ucChannelID = chan->rec.i2c_id; args.v1.ucChannelID = chan->rec.i2c_id;
args.ucDelay = delay / 10; args.v1.ucDelay = delay / 10;
if (ASIC_IS_DCE4(rdev))
args.v2.ucHPD_ID = chan->rec.hpd_id;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
if (args.ucReplyStatus && !args.ucDataOutLen) { if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) {
if (args.ucReplyStatus == 0x20 && retry_count++ < 10) if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10)
goto retry; goto retry;
DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n", DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n",
req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],
chan->rec.i2c_id, args.ucReplyStatus, retry_count); chan->rec.i2c_id, args.v1.ucReplyStatus, retry_count);
return false; return false;
} }
if (args.ucDataOutLen && read_byte && read_buf_len) { if (args.v1.ucDataOutLen && read_byte && read_buf_len) {
if (read_buf_len < args.ucDataOutLen) { if (read_buf_len < args.v1.ucDataOutLen) {
DRM_ERROR("Buffer to small for return answer %d %d\n", DRM_ERROR("Buffer to small for return answer %d %d\n",
read_buf_len, args.ucDataOutLen); read_buf_len, args.v1.ucDataOutLen);
return false; return false;
} }
{ {
int len = min(read_buf_len, args.ucDataOutLen); int len = min(read_buf_len, args.v1.ucDataOutLen);
memcpy(read_byte, base + 16, len); memcpy(read_byte, base + 16, len);
} }
} }
@ -626,12 +632,19 @@ void dp_link_train(struct drm_encoder *encoder,
dp_set_link_bw_lanes(radeon_connector, link_configuration); dp_set_link_bw_lanes(radeon_connector, link_configuration);
/* disable downspread on the sink */ /* disable downspread on the sink */
dp_set_downspread(radeon_connector, 0); dp_set_downspread(radeon_connector, 0);
/* start training on the source */ if (ASIC_IS_DCE4(rdev)) {
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_START, /* start training on the source */
dig_connector->dp_clock, enc_id, 0); atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
/* set training pattern 1 on the source */ /* set training pattern 1 on the source */
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1);
dig_connector->dp_clock, enc_id, 0); } else {
/* start training on the source */
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_START,
dig_connector->dp_clock, enc_id, 0);
/* set training pattern 1 on the source */
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
dig_connector->dp_clock, enc_id, 0);
}
/* set initial vs/emph */ /* set initial vs/emph */
memset(train_set, 0, 4); memset(train_set, 0, 4);
@ -691,8 +704,11 @@ void dp_link_train(struct drm_encoder *encoder,
/* set training pattern 2 on the sink */ /* set training pattern 2 on the sink */
dp_set_training(radeon_connector, DP_TRAINING_PATTERN_2); dp_set_training(radeon_connector, DP_TRAINING_PATTERN_2);
/* set training pattern 2 on the source */ /* set training pattern 2 on the source */
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL, if (ASIC_IS_DCE4(rdev))
dig_connector->dp_clock, enc_id, 1); atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2);
else
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
dig_connector->dp_clock, enc_id, 1);
/* channel equalization loop */ /* channel equalization loop */
tries = 0; tries = 0;
@ -729,7 +745,11 @@ void dp_link_train(struct drm_encoder *encoder,
>> DP_TRAIN_PRE_EMPHASIS_SHIFT); >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
/* disable the training pattern on the sink */ /* disable the training pattern on the sink */
dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE); if (ASIC_IS_DCE4(rdev))
atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
else
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
dig_connector->dp_clock, enc_id, 0);
radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE, radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
dig_connector->dp_clock, enc_id, 0); dig_connector->dp_clock, enc_id, 0);

View File

@ -30,11 +30,13 @@
#define D1CRTC_CONTROL 0x6080 #define D1CRTC_CONTROL 0x6080
#define CRTC_EN (1 << 0) #define CRTC_EN (1 << 0)
#define D1CRTC_STATUS 0x609c
#define D1CRTC_UPDATE_LOCK 0x60E8 #define D1CRTC_UPDATE_LOCK 0x60E8
#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 #define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110
#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 #define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118
#define D2CRTC_CONTROL 0x6880 #define D2CRTC_CONTROL 0x6880
#define D2CRTC_STATUS 0x689c
#define D2CRTC_UPDATE_LOCK 0x68E8 #define D2CRTC_UPDATE_LOCK 0x68E8
#define D2GRPH_PRIMARY_SURFACE_ADDRESS 0x6910 #define D2GRPH_PRIMARY_SURFACE_ADDRESS 0x6910
#define D2GRPH_SECONDARY_SURFACE_ADDRESS 0x6918 #define D2GRPH_SECONDARY_SURFACE_ADDRESS 0x6918

View File

@ -0,0 +1,767 @@
/*
* Copyright 2010 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Alex Deucher
*/
#include <linux/firmware.h>
#include <linux/platform_device.h>
#include "drmP.h"
#include "radeon.h"
#include "radeon_drm.h"
#include "rv770d.h"
#include "atom.h"
#include "avivod.h"
#include "evergreen_reg.h"
static void evergreen_gpu_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev);
bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
{
bool connected = false;
/* XXX */
return connected;
}
void evergreen_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd)
{
/* XXX */
}
void evergreen_hpd_init(struct radeon_device *rdev)
{
/* XXX */
}
void evergreen_bandwidth_update(struct radeon_device *rdev)
{
/* XXX */
}
void evergreen_hpd_fini(struct radeon_device *rdev)
{
/* XXX */
}
static int evergreen_mc_wait_for_idle(struct radeon_device *rdev)
{
unsigned i;
u32 tmp;
for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */
tmp = RREG32(SRBM_STATUS) & 0x1F00;
if (!tmp)
return 0;
udelay(1);
}
return -1;
}
/*
* GART
*/
int evergreen_pcie_gart_enable(struct radeon_device *rdev)
{
u32 tmp;
int r, i;
if (rdev->gart.table.vram.robj == NULL) {
dev_err(rdev->dev, "No VRAM object for PCIE GART.\n");
return -EINVAL;
}
r = radeon_gart_table_vram_pin(rdev);
if (r)
return r;
radeon_gart_restore(rdev);
/* Setup L2 cache */
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
EFFECTIVE_L2_QUEUE_SIZE(7));
WREG32(VM_L2_CNTL2, 0);
WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2));
/* Setup TLB control */
tmp = ENABLE_L1_TLB | ENABLE_L1_FRAGMENT_PROCESSING |
SYSTEM_ACCESS_MODE_NOT_IN_SYS |
SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU |
EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5);
WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp);
WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12);
WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
(u32)(rdev->dummy_page.addr >> 12));
for (i = 1; i < 7; i++)
WREG32(VM_CONTEXT0_CNTL + (i * 4), 0);
r600_pcie_gart_tlb_flush(rdev);
rdev->gart.ready = true;
return 0;
}
void evergreen_pcie_gart_disable(struct radeon_device *rdev)
{
u32 tmp;
int i, r;
/* Disable all tables */
for (i = 0; i < 7; i++)
WREG32(VM_CONTEXT0_CNTL + (i * 4), 0);
/* Setup L2 cache */
WREG32(VM_L2_CNTL, ENABLE_L2_FRAGMENT_PROCESSING |
EFFECTIVE_L2_QUEUE_SIZE(7));
WREG32(VM_L2_CNTL2, 0);
WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2));
/* Setup TLB control */
tmp = EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5);
WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp);
if (rdev->gart.table.vram.robj) {
r = radeon_bo_reserve(rdev->gart.table.vram.robj, false);
if (likely(r == 0)) {
radeon_bo_kunmap(rdev->gart.table.vram.robj);
radeon_bo_unpin(rdev->gart.table.vram.robj);
radeon_bo_unreserve(rdev->gart.table.vram.robj);
}
}
}
void evergreen_pcie_gart_fini(struct radeon_device *rdev)
{
evergreen_pcie_gart_disable(rdev);
radeon_gart_table_vram_free(rdev);
radeon_gart_fini(rdev);
}
void evergreen_agp_enable(struct radeon_device *rdev)
{
u32 tmp;
int i;
/* Setup L2 cache */
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
EFFECTIVE_L2_QUEUE_SIZE(7));
WREG32(VM_L2_CNTL2, 0);
WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2));
/* Setup TLB control */
tmp = ENABLE_L1_TLB | ENABLE_L1_FRAGMENT_PROCESSING |
SYSTEM_ACCESS_MODE_NOT_IN_SYS |
SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU |
EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5);
WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp);
for (i = 0; i < 7; i++)
WREG32(VM_CONTEXT0_CNTL + (i * 4), 0);
}
static void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
{
save->vga_control[0] = RREG32(D1VGA_CONTROL);
save->vga_control[1] = RREG32(D2VGA_CONTROL);
save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL);
save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL);
save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL);
save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL);
save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
/* Stop all video */
WREG32(VGA_RENDER_CONTROL, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
WREG32(D1VGA_CONTROL, 0);
WREG32(D2VGA_CONTROL, 0);
WREG32(EVERGREEN_D3VGA_CONTROL, 0);
WREG32(EVERGREEN_D4VGA_CONTROL, 0);
WREG32(EVERGREEN_D5VGA_CONTROL, 0);
WREG32(EVERGREEN_D6VGA_CONTROL, 0);
}
static void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
{
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC0_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC0_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC1_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET,
upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET,
(u32)rdev->mc.vram_start);
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
/* Unlock host access */
WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
mdelay(1);
/* Restore video state */
WREG32(D1VGA_CONTROL, save->vga_control[0]);
WREG32(D2VGA_CONTROL, save->vga_control[1]);
WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]);
WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]);
WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]);
WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
}
static void evergreen_mc_program(struct radeon_device *rdev)
{
struct evergreen_mc_save save;
u32 tmp;
int i, j;
/* Initialize HDP */
for (i = 0, j = 0; i < 32; i++, j += 0x18) {
WREG32((0x2c14 + j), 0x00000000);
WREG32((0x2c18 + j), 0x00000000);
WREG32((0x2c1c + j), 0x00000000);
WREG32((0x2c20 + j), 0x00000000);
WREG32((0x2c24 + j), 0x00000000);
}
WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
evergreen_mc_stop(rdev, &save);
if (evergreen_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
/* Lockout access through VGA aperture*/
WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
/* Update configuration */
if (rdev->flags & RADEON_IS_AGP) {
if (rdev->mc.vram_start < rdev->mc.gtt_start) {
/* VRAM before AGP */
WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
rdev->mc.vram_start >> 12);
WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
rdev->mc.gtt_end >> 12);
} else {
/* VRAM after AGP */
WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
rdev->mc.gtt_start >> 12);
WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
rdev->mc.vram_end >> 12);
}
} else {
WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
rdev->mc.vram_start >> 12);
WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
rdev->mc.vram_end >> 12);
}
WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
WREG32(MC_VM_FB_LOCATION, tmp);
WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
WREG32(HDP_NONSURFACE_INFO, (2 << 7));
WREG32(HDP_NONSURFACE_SIZE, (rdev->mc.mc_vram_size - 1) | 0x3FF);
if (rdev->flags & RADEON_IS_AGP) {
WREG32(MC_VM_AGP_TOP, rdev->mc.gtt_end >> 16);
WREG32(MC_VM_AGP_BOT, rdev->mc.gtt_start >> 16);
WREG32(MC_VM_AGP_BASE, rdev->mc.agp_base >> 22);
} else {
WREG32(MC_VM_AGP_BASE, 0);
WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
}
if (evergreen_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
evergreen_mc_resume(rdev, &save);
/* we need to own VRAM, so turn off the VGA renderer here
* to stop it overwriting our objects */
rv515_vga_render_disable(rdev);
}
#if 0
/*
* CP.
*/
static void evergreen_cp_stop(struct radeon_device *rdev)
{
/* XXX */
}
static int evergreen_cp_load_microcode(struct radeon_device *rdev)
{
/* XXX */
return 0;
}
/*
* Core functions
*/
static u32 evergreen_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
u32 num_backends,
u32 backend_disable_mask)
{
u32 backend_map = 0;
return backend_map;
}
#endif
static void evergreen_gpu_init(struct radeon_device *rdev)
{
/* XXX */
}
int evergreen_mc_init(struct radeon_device *rdev)
{
fixed20_12 a;
u32 tmp;
int chansize, numchan;
/* Get VRAM informations */
rdev->mc.vram_is_ddr = true;
tmp = RREG32(MC_ARB_RAMCFG);
if (tmp & CHANSIZE_OVERRIDE) {
chansize = 16;
} else if (tmp & CHANSIZE_MASK) {
chansize = 64;
} else {
chansize = 32;
}
tmp = RREG32(MC_SHARED_CHMAP);
switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
case 0:
default:
numchan = 1;
break;
case 1:
numchan = 2;
break;
case 2:
numchan = 4;
break;
case 3:
numchan = 8;
break;
}
rdev->mc.vram_width = numchan * chansize;
/* Could aper size report 0 ? */
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
/* Setup GPU memory space */
/* size in MB on evergreen */
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
rdev->mc.visible_vram_size = rdev->mc.aper_size;
/* FIXME remove this once we support unmappable VRAM */
if (rdev->mc.mc_vram_size > rdev->mc.aper_size) {
rdev->mc.mc_vram_size = rdev->mc.aper_size;
rdev->mc.real_vram_size = rdev->mc.aper_size;
}
r600_vram_gtt_location(rdev, &rdev->mc);
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
*/
a.full = rfixed_const(100);
rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk);
rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);
return 0;
}
int evergreen_gpu_reset(struct radeon_device *rdev)
{
/* FIXME: implement for evergreen */
return 0;
}
static int evergreen_startup(struct radeon_device *rdev)
{
#if 0
int r;
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
r = r600_init_microcode(rdev);
if (r) {
DRM_ERROR("Failed to load firmware!\n");
return r;
}
}
#endif
evergreen_mc_program(rdev);
#if 0
if (rdev->flags & RADEON_IS_AGP) {
evergreem_agp_enable(rdev);
} else {
r = evergreen_pcie_gart_enable(rdev);
if (r)
return r;
}
#endif
evergreen_gpu_init(rdev);
#if 0
if (!rdev->r600_blit.shader_obj) {
r = r600_blit_init(rdev);
if (r) {
DRM_ERROR("radeon: failed blitter (%d).\n", r);
return r;
}
}
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
if (unlikely(r != 0))
return r;
r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
&rdev->r600_blit.shader_gpu_addr);
radeon_bo_unreserve(rdev->r600_blit.shader_obj);
if (r) {
DRM_ERROR("failed to pin blit object %d\n", r);
return r;
}
/* Enable IRQ */
r = r600_irq_init(rdev);
if (r) {
DRM_ERROR("radeon: IH init failed (%d).\n", r);
radeon_irq_kms_fini(rdev);
return r;
}
r600_irq_set(rdev);
r = radeon_ring_init(rdev, rdev->cp.ring_size);
if (r)
return r;
r = evergreen_cp_load_microcode(rdev);
if (r)
return r;
r = r600_cp_resume(rdev);
if (r)
return r;
/* write back buffer are not vital so don't worry about failure */
r600_wb_enable(rdev);
#endif
return 0;
}
int evergreen_resume(struct radeon_device *rdev)
{
int r;
/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
* posting will perform necessary task to bring back GPU into good
* shape.
*/
/* post card */
atom_asic_init(rdev->mode_info.atom_context);
/* Initialize clocks */
r = radeon_clocks_init(rdev);
if (r) {
return r;
}
r = evergreen_startup(rdev);
if (r) {
DRM_ERROR("r600 startup failed on resume\n");
return r;
}
#if 0
r = r600_ib_test(rdev);
if (r) {
DRM_ERROR("radeon: failled testing IB (%d).\n", r);
return r;
}
#endif
return r;
}
int evergreen_suspend(struct radeon_device *rdev)
{
#if 0
int r;
/* FIXME: we should wait for ring to be empty */
r700_cp_stop(rdev);
rdev->cp.ready = false;
r600_wb_disable(rdev);
evergreen_pcie_gart_disable(rdev);
/* unpin shaders bo */
r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
if (likely(r == 0)) {
radeon_bo_unpin(rdev->r600_blit.shader_obj);
radeon_bo_unreserve(rdev->r600_blit.shader_obj);
}
#endif
return 0;
}
static bool evergreen_card_posted(struct radeon_device *rdev)
{
u32 reg;
/* first check CRTCs */
reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) |
RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) |
RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
if (reg & EVERGREEN_CRTC_MASTER_EN)
return true;
/* then check MEM_SIZE, in case the crtcs are off */
if (RREG32(CONFIG_MEMSIZE))
return true;
return false;
}
/* Plan is to move initialization in that function and use
* helper function so that radeon_device_init pretty much
* do nothing more than calling asic specific function. This
* should also allow to remove a bunch of callback function
* like vram_info.
*/
int evergreen_init(struct radeon_device *rdev)
{
int r;
r = radeon_dummy_page_init(rdev);
if (r)
return r;
/* This don't do much */
r = radeon_gem_init(rdev);
if (r)
return r;
/* Read BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
return -EINVAL;
}
/* Must be an ATOMBIOS */
if (!rdev->is_atom_bios) {
dev_err(rdev->dev, "Expecting atombios for R600 GPU\n");
return -EINVAL;
}
r = radeon_atombios_init(rdev);
if (r)
return r;
/* Post card if necessary */
if (!evergreen_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
}
DRM_INFO("GPU not posted. posting now...\n");
atom_asic_init(rdev->mode_info.atom_context);
}
/* Initialize scratch registers */
r600_scratch_init(rdev);
/* Initialize surface registers */
radeon_surface_init(rdev);
/* Initialize clocks */
radeon_get_clock_info(rdev->ddev);
r = radeon_clocks_init(rdev);
if (r)
return r;
/* Initialize power management */
radeon_pm_init(rdev);
/* Fence driver */
r = radeon_fence_driver_init(rdev);
if (r)
return r;
/* initialize AGP */
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
if (r)
radeon_agp_disable(rdev);
}
/* initialize memory controller */
r = evergreen_mc_init(rdev);
if (r)
return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
return r;
#if 0
r = radeon_irq_kms_init(rdev);
if (r)
return r;
rdev->cp.ring_obj = NULL;
r600_ring_init(rdev, 1024 * 1024);
rdev->ih.ring_obj = NULL;
r600_ih_ring_init(rdev, 64 * 1024);
r = r600_pcie_gart_init(rdev);
if (r)
return r;
#endif
rdev->accel_working = false;
r = evergreen_startup(rdev);
if (r) {
evergreen_suspend(rdev);
/*r600_wb_fini(rdev);*/
/*radeon_ring_fini(rdev);*/
/*evergreen_pcie_gart_fini(rdev);*/
rdev->accel_working = false;
}
if (rdev->accel_working) {
r = radeon_ib_pool_init(rdev);
if (r) {
DRM_ERROR("radeon: failed initializing IB pool (%d).\n", r);
rdev->accel_working = false;
}
r = r600_ib_test(rdev);
if (r) {
DRM_ERROR("radeon: failed testing IB (%d).\n", r);
rdev->accel_working = false;
}
}
return 0;
}
void evergreen_fini(struct radeon_device *rdev)
{
evergreen_suspend(rdev);
#if 0
r600_blit_fini(rdev);
r600_irq_fini(rdev);
radeon_irq_kms_fini(rdev);
radeon_ring_fini(rdev);
r600_wb_fini(rdev);
evergreen_pcie_gart_fini(rdev);
#endif
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_clocks_fini(rdev);
radeon_agp_fini(rdev);
radeon_bo_fini(rdev);
radeon_atombios_fini(rdev);
kfree(rdev->bios);
rdev->bios = NULL;
radeon_dummy_page_fini(rdev);
}

View File

@ -0,0 +1,176 @@
/*
* Copyright 2010 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Alex Deucher
*/
#ifndef __EVERGREEN_REG_H__
#define __EVERGREEN_REG_H__
/* evergreen */
#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS 0x310
#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH 0x324
#define EVERGREEN_D3VGA_CONTROL 0x3e0
#define EVERGREEN_D4VGA_CONTROL 0x3e4
#define EVERGREEN_D5VGA_CONTROL 0x3e8
#define EVERGREEN_D6VGA_CONTROL 0x3ec
#define EVERGREEN_P1PLL_SS_CNTL 0x414
#define EVERGREEN_P2PLL_SS_CNTL 0x454
# define EVERGREEN_PxPLL_SS_EN (1 << 12)
/* GRPH blocks at 0x6800, 0x7400, 0x10000, 0x10c00, 0x11800, 0x12400 */
#define EVERGREEN_GRPH_ENABLE 0x6800
#define EVERGREEN_GRPH_CONTROL 0x6804
# define EVERGREEN_GRPH_DEPTH(x) (((x) & 0x3) << 0)
# define EVERGREEN_GRPH_DEPTH_8BPP 0
# define EVERGREEN_GRPH_DEPTH_16BPP 1
# define EVERGREEN_GRPH_DEPTH_32BPP 2
# define EVERGREEN_GRPH_FORMAT(x) (((x) & 0x7) << 8)
/* 8 BPP */
# define EVERGREEN_GRPH_FORMAT_INDEXED 0
/* 16 BPP */
# define EVERGREEN_GRPH_FORMAT_ARGB1555 0
# define EVERGREEN_GRPH_FORMAT_ARGB565 1
# define EVERGREEN_GRPH_FORMAT_ARGB4444 2
# define EVERGREEN_GRPH_FORMAT_AI88 3
# define EVERGREEN_GRPH_FORMAT_MONO16 4
# define EVERGREEN_GRPH_FORMAT_BGRA5551 5
/* 32 BPP */
# define EVERGREEN_GRPH_FORMAT_ARGB8888 0
# define EVERGREEN_GRPH_FORMAT_ARGB2101010 1
# define EVERGREEN_GRPH_FORMAT_32BPP_DIG 2
# define EVERGREEN_GRPH_FORMAT_8B_ARGB2101010 3
# define EVERGREEN_GRPH_FORMAT_BGRA1010102 4
# define EVERGREEN_GRPH_FORMAT_8B_BGRA1010102 5
# define EVERGREEN_GRPH_FORMAT_RGB111110 6
# define EVERGREEN_GRPH_FORMAT_BGR101111 7
#define EVERGREEN_GRPH_SWAP_CONTROL 0x680c
# define EVERGREEN_GRPH_ENDIAN_SWAP(x) (((x) & 0x3) << 0)
# define EVERGREEN_GRPH_ENDIAN_NONE 0
# define EVERGREEN_GRPH_ENDIAN_8IN16 1
# define EVERGREEN_GRPH_ENDIAN_8IN32 2
# define EVERGREEN_GRPH_ENDIAN_8IN64 3
# define EVERGREEN_GRPH_RED_CROSSBAR(x) (((x) & 0x3) << 4)
# define EVERGREEN_GRPH_RED_SEL_R 0
# define EVERGREEN_GRPH_RED_SEL_G 1
# define EVERGREEN_GRPH_RED_SEL_B 2
# define EVERGREEN_GRPH_RED_SEL_A 3
# define EVERGREEN_GRPH_GREEN_CROSSBAR(x) (((x) & 0x3) << 6)
# define EVERGREEN_GRPH_GREEN_SEL_G 0
# define EVERGREEN_GRPH_GREEN_SEL_B 1
# define EVERGREEN_GRPH_GREEN_SEL_A 2
# define EVERGREEN_GRPH_GREEN_SEL_R 3
# define EVERGREEN_GRPH_BLUE_CROSSBAR(x) (((x) & 0x3) << 8)
# define EVERGREEN_GRPH_BLUE_SEL_B 0
# define EVERGREEN_GRPH_BLUE_SEL_A 1
# define EVERGREEN_GRPH_BLUE_SEL_R 2
# define EVERGREEN_GRPH_BLUE_SEL_G 3
# define EVERGREEN_GRPH_ALPHA_CROSSBAR(x) (((x) & 0x3) << 10)
# define EVERGREEN_GRPH_ALPHA_SEL_A 0
# define EVERGREEN_GRPH_ALPHA_SEL_R 1
# define EVERGREEN_GRPH_ALPHA_SEL_G 2
# define EVERGREEN_GRPH_ALPHA_SEL_B 3
#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS 0x6810
#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS 0x6814
# define EVERGREEN_GRPH_DFQ_ENABLE (1 << 0)
# define EVERGREEN_GRPH_SURFACE_ADDRESS_MASK 0xffffff00
#define EVERGREEN_GRPH_PITCH 0x6818
#define EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x681c
#define EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x6820
#define EVERGREEN_GRPH_SURFACE_OFFSET_X 0x6824
#define EVERGREEN_GRPH_SURFACE_OFFSET_Y 0x6828
#define EVERGREEN_GRPH_X_START 0x682c
#define EVERGREEN_GRPH_Y_START 0x6830
#define EVERGREEN_GRPH_X_END 0x6834
#define EVERGREEN_GRPH_Y_END 0x6838
/* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */
#define EVERGREEN_CUR_CONTROL 0x6998
# define EVERGREEN_CURSOR_EN (1 << 0)
# define EVERGREEN_CURSOR_MODE(x) (((x) & 0x3) << 8)
# define EVERGREEN_CURSOR_MONO 0
# define EVERGREEN_CURSOR_24_1 1
# define EVERGREEN_CURSOR_24_8_PRE_MULT 2
# define EVERGREEN_CURSOR_24_8_UNPRE_MULT 3
# define EVERGREEN_CURSOR_2X_MAGNIFY (1 << 16)
# define EVERGREEN_CURSOR_FORCE_MC_ON (1 << 20)
# define EVERGREEN_CURSOR_URGENT_CONTROL(x) (((x) & 0x7) << 24)
# define EVERGREEN_CURSOR_URGENT_ALWAYS 0
# define EVERGREEN_CURSOR_URGENT_1_8 1
# define EVERGREEN_CURSOR_URGENT_1_4 2
# define EVERGREEN_CURSOR_URGENT_3_8 3
# define EVERGREEN_CURSOR_URGENT_1_2 4
#define EVERGREEN_CUR_SURFACE_ADDRESS 0x699c
# define EVERGREEN_CUR_SURFACE_ADDRESS_MASK 0xfffff000
#define EVERGREEN_CUR_SIZE 0x69a0
#define EVERGREEN_CUR_SURFACE_ADDRESS_HIGH 0x69a4
#define EVERGREEN_CUR_POSITION 0x69a8
#define EVERGREEN_CUR_HOT_SPOT 0x69ac
#define EVERGREEN_CUR_COLOR1 0x69b0
#define EVERGREEN_CUR_COLOR2 0x69b4
#define EVERGREEN_CUR_UPDATE 0x69b8
# define EVERGREEN_CURSOR_UPDATE_PENDING (1 << 0)
# define EVERGREEN_CURSOR_UPDATE_TAKEN (1 << 1)
# define EVERGREEN_CURSOR_UPDATE_LOCK (1 << 16)
# define EVERGREEN_CURSOR_DISABLE_MULTIPLE_UPDATE (1 << 24)
/* LUT blocks at 0x69e0, 0x75e0, 0x101e0, 0x10de0, 0x119e0, 0x125e0 */
#define EVERGREEN_DC_LUT_RW_MODE 0x69e0
#define EVERGREEN_DC_LUT_RW_INDEX 0x69e4
#define EVERGREEN_DC_LUT_SEQ_COLOR 0x69e8
#define EVERGREEN_DC_LUT_PWL_DATA 0x69ec
#define EVERGREEN_DC_LUT_30_COLOR 0x69f0
#define EVERGREEN_DC_LUT_VGA_ACCESS_ENABLE 0x69f4
#define EVERGREEN_DC_LUT_WRITE_EN_MASK 0x69f8
#define EVERGREEN_DC_LUT_AUTOFILL 0x69fc
#define EVERGREEN_DC_LUT_CONTROL 0x6a00
#define EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE 0x6a04
#define EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN 0x6a08
#define EVERGREEN_DC_LUT_BLACK_OFFSET_RED 0x6a0c
#define EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE 0x6a10
#define EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN 0x6a14
#define EVERGREEN_DC_LUT_WHITE_OFFSET_RED 0x6a18
#define EVERGREEN_DATA_FORMAT 0x6b00
# define EVERGREEN_INTERLEAVE_EN (1 << 0)
#define EVERGREEN_DESKTOP_HEIGHT 0x6b04
#define EVERGREEN_VIEWPORT_START 0x6d70
#define EVERGREEN_VIEWPORT_SIZE 0x6d74
/* display controller offsets used for crtc/cur/lut/grph/viewport/etc. */
#define EVERGREEN_CRTC0_REGISTER_OFFSET (0x6df0 - 0x6df0)
#define EVERGREEN_CRTC1_REGISTER_OFFSET (0x79f0 - 0x6df0)
#define EVERGREEN_CRTC2_REGISTER_OFFSET (0x105f0 - 0x6df0)
#define EVERGREEN_CRTC3_REGISTER_OFFSET (0x111f0 - 0x6df0)
#define EVERGREEN_CRTC4_REGISTER_OFFSET (0x11df0 - 0x6df0)
#define EVERGREEN_CRTC5_REGISTER_OFFSET (0x129f0 - 0x6df0)
/* CRTC blocks at 0x6df0, 0x79f0, 0x105f0, 0x111f0, 0x11df0, 0x129f0 */
#define EVERGREEN_CRTC_CONTROL 0x6e70
# define EVERGREEN_CRTC_MASTER_EN (1 << 0)
#define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4
#define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0
#define EVERGREEN_DC_GPIO_HPD_A 0x64b4
#define EVERGREEN_DC_GPIO_HPD_EN 0x64b8
#define EVERGREEN_DC_GPIO_HPD_Y 0x64bc
#endif

View File

@ -197,13 +197,13 @@ int r100_pci_gart_enable(struct radeon_device *rdev)
{ {
uint32_t tmp; uint32_t tmp;
radeon_gart_restore(rdev);
/* discard memory request outside of configured range */ /* discard memory request outside of configured range */
tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS; tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS;
WREG32(RADEON_AIC_CNTL, tmp); WREG32(RADEON_AIC_CNTL, tmp);
/* set address range for PCI address translate */ /* set address range for PCI address translate */
WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_location); WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_start);
tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1; WREG32(RADEON_AIC_HI_ADDR, rdev->mc.gtt_end);
WREG32(RADEON_AIC_HI_ADDR, tmp);
/* set PCI GART page-table base address */ /* set PCI GART page-table base address */
WREG32(RADEON_AIC_PT_BASE, rdev->gart.table_addr); WREG32(RADEON_AIC_PT_BASE, rdev->gart.table_addr);
tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN; tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN;
@ -312,9 +312,11 @@ int r100_irq_process(struct radeon_device *rdev)
/* Vertical blank interrupts */ /* Vertical blank interrupts */
if (status & RADEON_CRTC_VBLANK_STAT) { if (status & RADEON_CRTC_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 0); drm_handle_vblank(rdev->ddev, 0);
wake_up(&rdev->irq.vblank_queue);
} }
if (status & RADEON_CRTC2_VBLANK_STAT) { if (status & RADEON_CRTC2_VBLANK_STAT) {
drm_handle_vblank(rdev->ddev, 1); drm_handle_vblank(rdev->ddev, 1);
wake_up(&rdev->irq.vblank_queue);
} }
if (status & RADEON_FP_DETECT_STAT) { if (status & RADEON_FP_DETECT_STAT) {
queue_hotplug = true; queue_hotplug = true;
@ -366,8 +368,8 @@ void r100_fence_ring_emit(struct radeon_device *rdev,
radeon_ring_write(rdev, PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); radeon_ring_write(rdev, PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0));
radeon_ring_write(rdev, RADEON_RB3D_ZC_FLUSH_ALL); radeon_ring_write(rdev, RADEON_RB3D_ZC_FLUSH_ALL);
/* Wait until IDLE & CLEAN */ /* Wait until IDLE & CLEAN */
radeon_ring_write(rdev, PACKET0(0x1720, 0)); radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
radeon_ring_write(rdev, (1 << 16) | (1 << 17)); radeon_ring_write(rdev, RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_3D_IDLECLEAN);
radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0)); radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0));
radeon_ring_write(rdev, rdev->config.r100.hdp_cntl | radeon_ring_write(rdev, rdev->config.r100.hdp_cntl |
RADEON_HDP_READ_BUFFER_INVALIDATE); RADEON_HDP_READ_BUFFER_INVALIDATE);
@ -1701,7 +1703,7 @@ int r100_gui_wait_for_idle(struct radeon_device *rdev)
} }
for (i = 0; i < rdev->usec_timeout; i++) { for (i = 0; i < rdev->usec_timeout; i++) {
tmp = RREG32(RADEON_RBBM_STATUS); tmp = RREG32(RADEON_RBBM_STATUS);
if (!(tmp & (1 << 31))) { if (!(tmp & RADEON_RBBM_ACTIVE)) {
return 0; return 0;
} }
DRM_UDELAY(1); DRM_UDELAY(1);
@ -1716,8 +1718,8 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev)
for (i = 0; i < rdev->usec_timeout; i++) { for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */ /* read MC_STATUS */
tmp = RREG32(0x0150); tmp = RREG32(RADEON_MC_STATUS);
if (tmp & (1 << 2)) { if (tmp & RADEON_MC_IDLE) {
return 0; return 0;
} }
DRM_UDELAY(1); DRM_UDELAY(1);
@ -1790,7 +1792,7 @@ int r100_gpu_reset(struct radeon_device *rdev)
} }
/* Check if GPU is idle */ /* Check if GPU is idle */
status = RREG32(RADEON_RBBM_STATUS); status = RREG32(RADEON_RBBM_STATUS);
if (status & (1 << 31)) { if (status & RADEON_RBBM_ACTIVE) {
DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
return -1; return -1;
} }
@ -1800,6 +1802,9 @@ int r100_gpu_reset(struct radeon_device *rdev)
void r100_set_common_regs(struct radeon_device *rdev) void r100_set_common_regs(struct radeon_device *rdev)
{ {
struct drm_device *dev = rdev->ddev;
bool force_dac2 = false;
/* set these so they don't interfere with anything */ /* set these so they don't interfere with anything */
WREG32(RADEON_OV0_SCALE_CNTL, 0); WREG32(RADEON_OV0_SCALE_CNTL, 0);
WREG32(RADEON_SUBPIC_CNTL, 0); WREG32(RADEON_SUBPIC_CNTL, 0);
@ -1808,6 +1813,68 @@ void r100_set_common_regs(struct radeon_device *rdev)
WREG32(RADEON_DVI_I2C_CNTL_1, 0); WREG32(RADEON_DVI_I2C_CNTL_1, 0);
WREG32(RADEON_CAP0_TRIG_CNTL, 0); WREG32(RADEON_CAP0_TRIG_CNTL, 0);
WREG32(RADEON_CAP1_TRIG_CNTL, 0); WREG32(RADEON_CAP1_TRIG_CNTL, 0);
/* always set up dac2 on rn50 and some rv100 as lots
* of servers seem to wire it up to a VGA port but
* don't report it in the bios connector
* table.
*/
switch (dev->pdev->device) {
/* RN50 */
case 0x515e:
case 0x5969:
force_dac2 = true;
break;
/* RV100*/
case 0x5159:
case 0x515a:
/* DELL triple head servers */
if ((dev->pdev->subsystem_vendor == 0x1028 /* DELL */) &&
((dev->pdev->subsystem_device == 0x016c) ||
(dev->pdev->subsystem_device == 0x016d) ||
(dev->pdev->subsystem_device == 0x016e) ||
(dev->pdev->subsystem_device == 0x016f) ||
(dev->pdev->subsystem_device == 0x0170) ||
(dev->pdev->subsystem_device == 0x017d) ||
(dev->pdev->subsystem_device == 0x017e) ||
(dev->pdev->subsystem_device == 0x0183) ||
(dev->pdev->subsystem_device == 0x018a) ||
(dev->pdev->subsystem_device == 0x019a)))
force_dac2 = true;
break;
}
if (force_dac2) {
u32 disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
u32 tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
u32 dac2_cntl = RREG32(RADEON_DAC_CNTL2);
/* For CRT on DAC2, don't turn it on if BIOS didn't
enable it, even it's detected.
*/
/* force it to crtc0 */
dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL;
dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL;
disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
/* set up the TV DAC */
tv_dac_cntl &= ~(RADEON_TV_DAC_PEDESTAL |
RADEON_TV_DAC_STD_MASK |
RADEON_TV_DAC_RDACPD |
RADEON_TV_DAC_GDACPD |
RADEON_TV_DAC_BDACPD |
RADEON_TV_DAC_BGADJ_MASK |
RADEON_TV_DAC_DACADJ_MASK);
tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
RADEON_TV_DAC_NHOLD |
RADEON_TV_DAC_STD_PS2 |
(0x58 << 16));
WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
WREG32(RADEON_DAC_CNTL2, dac2_cntl);
}
} }
/* /*
@ -1889,17 +1956,20 @@ static u32 r100_get_accessible_vram(struct radeon_device *rdev)
void r100_vram_init_sizes(struct radeon_device *rdev) void r100_vram_init_sizes(struct radeon_device *rdev)
{ {
u64 config_aper_size; u64 config_aper_size;
u32 accessible;
/* work out accessible VRAM */
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
rdev->mc.visible_vram_size = r100_get_accessible_vram(rdev);
/* FIXME we don't use the second aperture yet when we could use it */
if (rdev->mc.visible_vram_size > rdev->mc.aper_size)
rdev->mc.visible_vram_size = rdev->mc.aper_size;
config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE); config_aper_size = RREG32(RADEON_CONFIG_APER_SIZE);
if (rdev->flags & RADEON_IS_IGP) { if (rdev->flags & RADEON_IS_IGP) {
uint32_t tom; uint32_t tom;
/* read NB_TOM to get the amount of ram stolen for the GPU */ /* read NB_TOM to get the amount of ram stolen for the GPU */
tom = RREG32(RADEON_NB_TOM); tom = RREG32(RADEON_NB_TOM);
rdev->mc.real_vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16); rdev->mc.real_vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16);
/* for IGPs we need to keep VRAM where it was put by the BIOS */
rdev->mc.vram_location = (tom & 0xffff) << 16;
WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
rdev->mc.mc_vram_size = rdev->mc.real_vram_size; rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
} else { } else {
@ -1911,30 +1981,19 @@ void r100_vram_init_sizes(struct radeon_device *rdev)
rdev->mc.real_vram_size = 8192 * 1024; rdev->mc.real_vram_size = 8192 * 1024;
WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size); WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
} }
/* let driver place VRAM */ /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM -
rdev->mc.vram_location = 0xFFFFFFFFUL; * Novell bug 204882 + along with lots of ubuntu ones
/* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM - */
* Novell bug 204882 + along with lots of ubuntu ones */
if (config_aper_size > rdev->mc.real_vram_size) if (config_aper_size > rdev->mc.real_vram_size)
rdev->mc.mc_vram_size = config_aper_size; rdev->mc.mc_vram_size = config_aper_size;
else else
rdev->mc.mc_vram_size = rdev->mc.real_vram_size; rdev->mc.mc_vram_size = rdev->mc.real_vram_size;
} }
/* FIXME remove this once we support unmappable VRAM */
/* work out accessible VRAM */ if (rdev->mc.mc_vram_size > rdev->mc.aper_size) {
accessible = r100_get_accessible_vram(rdev);
rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
if (accessible > rdev->mc.aper_size)
accessible = rdev->mc.aper_size;
if (rdev->mc.mc_vram_size > rdev->mc.aper_size)
rdev->mc.mc_vram_size = rdev->mc.aper_size; rdev->mc.mc_vram_size = rdev->mc.aper_size;
if (rdev->mc.real_vram_size > rdev->mc.aper_size)
rdev->mc.real_vram_size = rdev->mc.aper_size; rdev->mc.real_vram_size = rdev->mc.aper_size;
}
} }
void r100_vga_set_state(struct radeon_device *rdev, bool state) void r100_vga_set_state(struct radeon_device *rdev, bool state)
@ -1951,11 +2010,18 @@ void r100_vga_set_state(struct radeon_device *rdev, bool state)
WREG32(RADEON_CONFIG_CNTL, temp); WREG32(RADEON_CONFIG_CNTL, temp);
} }
void r100_vram_info(struct radeon_device *rdev) void r100_mc_init(struct radeon_device *rdev)
{ {
r100_vram_get_type(rdev); u64 base;
r100_vram_get_type(rdev);
r100_vram_init_sizes(rdev); r100_vram_init_sizes(rdev);
base = rdev->mc.aper_base;
if (rdev->flags & RADEON_IS_IGP)
base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
radeon_vram_location(rdev, &rdev->mc, base);
if (!(rdev->flags & RADEON_IS_AGP))
radeon_gtt_location(rdev, &rdev->mc);
} }
@ -3226,10 +3292,9 @@ void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save)
void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save) void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save)
{ {
/* Update base address for crtc */ /* Update base address for crtc */
WREG32(R_00023C_DISPLAY_BASE_ADDR, rdev->mc.vram_location); WREG32(R_00023C_DISPLAY_BASE_ADDR, rdev->mc.vram_start);
if (!(rdev->flags & RADEON_SINGLE_CRTC)) { if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
WREG32(R_00033C_CRTC2_DISPLAY_BASE_ADDR, WREG32(R_00033C_CRTC2_DISPLAY_BASE_ADDR, rdev->mc.vram_start);
rdev->mc.vram_location);
} }
/* Restore CRTC registers */ /* Restore CRTC registers */
WREG8(R_0003C2_GENMO_WT, save->GENMO_WT); WREG8(R_0003C2_GENMO_WT, save->GENMO_WT);
@ -3390,32 +3455,6 @@ void r100_fini(struct radeon_device *rdev)
rdev->bios = NULL; rdev->bios = NULL;
} }
int r100_mc_init(struct radeon_device *rdev)
{
int r;
u32 tmp;
/* Setup GPU memory space */
rdev->mc.vram_location = 0xFFFFFFFFUL;
rdev->mc.gtt_location = 0xFFFFFFFFUL;
if (rdev->flags & RADEON_IS_IGP) {
tmp = G_00015C_MC_FB_START(RREG32(R_00015C_NB_TOM));
rdev->mc.vram_location = tmp << 16;
}
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
if (r) {
radeon_agp_disable(rdev);
} else {
rdev->mc.gtt_location = rdev->mc.agp_base;
}
}
r = radeon_mc_setup(rdev);
if (r)
return r;
return 0;
}
int r100_init(struct radeon_device *rdev) int r100_init(struct radeon_device *rdev)
{ {
int r; int r;
@ -3458,12 +3497,15 @@ int r100_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev); radeon_get_clock_info(rdev->ddev);
/* Initialize power management */ /* Initialize power management */
radeon_pm_init(rdev); radeon_pm_init(rdev);
/* Get vram informations */ /* initialize AGP */
r100_vram_info(rdev); if (rdev->flags & RADEON_IS_AGP) {
/* Initialize memory controller (also test AGP) */ r = radeon_agp_init(rdev);
r = r100_mc_init(rdev); if (r) {
if (r) radeon_agp_disable(rdev);
return r; }
}
/* initialize VRAM */
r100_mc_init(rdev);
/* Fence driver */ /* Fence driver */
r = radeon_fence_driver_init(rdev); r = radeon_fence_driver_init(rdev);
if (r) if (r)

View File

@ -31,6 +31,7 @@
#include "radeon_reg.h" #include "radeon_reg.h"
#include "radeon.h" #include "radeon.h"
#include "r100d.h"
#include "r200_reg_safe.h" #include "r200_reg_safe.h"
#include "r100_track.h" #include "r100_track.h"
@ -79,6 +80,51 @@ static int r200_get_vtx_size_0(uint32_t vtx_fmt_0)
return vtx_size; return vtx_size;
} }
int r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_pages,
struct radeon_fence *fence)
{
uint32_t size;
uint32_t cur_size;
int i, num_loops;
int r = 0;
/* radeon pitch is /64 */
size = num_pages << PAGE_SHIFT;
num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
r = radeon_ring_lock(rdev, num_loops * 4 + 64);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
/* Must wait for 2D idle & clean before DMA or hangs might happen */
radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
radeon_ring_write(rdev, (1 << 16));
for (i = 0; i < num_loops; i++) {
cur_size = size;
if (cur_size > 0x1FFFFF) {
cur_size = 0x1FFFFF;
}
size -= cur_size;
radeon_ring_write(rdev, PACKET0(0x720, 2));
radeon_ring_write(rdev, src_offset);
radeon_ring_write(rdev, dst_offset);
radeon_ring_write(rdev, cur_size | (1 << 31) | (1 << 30));
src_offset += cur_size;
dst_offset += cur_size;
}
radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
radeon_ring_write(rdev, RADEON_WAIT_DMA_GUI_IDLE);
if (fence) {
r = radeon_fence_emit(rdev, fence);
}
radeon_ring_unlock_commit(rdev);
return r;
}
static int r200_get_vtx_size_1(uint32_t vtx_fmt_1) static int r200_get_vtx_size_1(uint32_t vtx_fmt_1)
{ {
int vtx_size, i, tex_size; int vtx_size, i, tex_size;

View File

@ -117,18 +117,19 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev)
r = radeon_gart_table_vram_pin(rdev); r = radeon_gart_table_vram_pin(rdev);
if (r) if (r)
return r; return r;
radeon_gart_restore(rdev);
/* discard memory request outside of configured range */ /* discard memory request outside of configured range */
tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location); WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_start);
tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - RADEON_GPU_PAGE_SIZE; tmp = rdev->mc.gtt_end & ~RADEON_GPU_PAGE_MASK;
WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp); WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp);
WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0); WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0);
WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0); WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0);
table_addr = rdev->gart.table_addr; table_addr = rdev->gart.table_addr;
WREG32_PCIE(RADEON_PCIE_TX_GART_BASE, table_addr); WREG32_PCIE(RADEON_PCIE_TX_GART_BASE, table_addr);
/* FIXME: setup default page */ /* FIXME: setup default page */
WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_location); WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_start);
WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0); WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0);
/* Clear error */ /* Clear error */
WREG32_PCIE(0x18, 0); WREG32_PCIE(0x18, 0);
@ -174,18 +175,20 @@ void r300_fence_ring_emit(struct radeon_device *rdev,
/* Who ever call radeon_fence_emit should call ring_lock and ask /* Who ever call radeon_fence_emit should call ring_lock and ask
* for enough space (today caller are ib schedule and buffer move) */ * for enough space (today caller are ib schedule and buffer move) */
/* Write SC register so SC & US assert idle */ /* Write SC register so SC & US assert idle */
radeon_ring_write(rdev, PACKET0(0x43E0, 0)); radeon_ring_write(rdev, PACKET0(R300_RE_SCISSORS_TL, 0));
radeon_ring_write(rdev, 0); radeon_ring_write(rdev, 0);
radeon_ring_write(rdev, PACKET0(0x43E4, 0)); radeon_ring_write(rdev, PACKET0(R300_RE_SCISSORS_BR, 0));
radeon_ring_write(rdev, 0); radeon_ring_write(rdev, 0);
/* Flush 3D cache */ /* Flush 3D cache */
radeon_ring_write(rdev, PACKET0(0x4E4C, 0)); radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
radeon_ring_write(rdev, (2 << 0)); radeon_ring_write(rdev, R300_RB3D_DC_FLUSH);
radeon_ring_write(rdev, PACKET0(0x4F18, 0)); radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
radeon_ring_write(rdev, (1 << 0)); radeon_ring_write(rdev, R300_ZC_FLUSH);
/* Wait until IDLE & CLEAN */ /* Wait until IDLE & CLEAN */
radeon_ring_write(rdev, PACKET0(0x1720, 0)); radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
radeon_ring_write(rdev, (1 << 17) | (1 << 16) | (1 << 9)); radeon_ring_write(rdev, (RADEON_WAIT_3D_IDLECLEAN |
RADEON_WAIT_2D_IDLECLEAN |
RADEON_WAIT_DMA_GUI_IDLE));
radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0)); radeon_ring_write(rdev, PACKET0(RADEON_HOST_PATH_CNTL, 0));
radeon_ring_write(rdev, rdev->config.r300.hdp_cntl | radeon_ring_write(rdev, rdev->config.r300.hdp_cntl |
RADEON_HDP_READ_BUFFER_INVALIDATE); RADEON_HDP_READ_BUFFER_INVALIDATE);
@ -198,50 +201,6 @@ void r300_fence_ring_emit(struct radeon_device *rdev,
radeon_ring_write(rdev, RADEON_SW_INT_FIRE); radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
} }
int r300_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_pages,
struct radeon_fence *fence)
{
uint32_t size;
uint32_t cur_size;
int i, num_loops;
int r = 0;
/* radeon pitch is /64 */
size = num_pages << PAGE_SHIFT;
num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
r = radeon_ring_lock(rdev, num_loops * 4 + 64);
if (r) {
DRM_ERROR("radeon: moving bo (%d).\n", r);
return r;
}
/* Must wait for 2D idle & clean before DMA or hangs might happen */
radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0 ));
radeon_ring_write(rdev, (1 << 16));
for (i = 0; i < num_loops; i++) {
cur_size = size;
if (cur_size > 0x1FFFFF) {
cur_size = 0x1FFFFF;
}
size -= cur_size;
radeon_ring_write(rdev, PACKET0(0x720, 2));
radeon_ring_write(rdev, src_offset);
radeon_ring_write(rdev, dst_offset);
radeon_ring_write(rdev, cur_size | (1 << 31) | (1 << 30));
src_offset += cur_size;
dst_offset += cur_size;
}
radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
radeon_ring_write(rdev, RADEON_WAIT_DMA_GUI_IDLE);
if (fence) {
r = radeon_fence_emit(rdev, fence);
}
radeon_ring_unlock_commit(rdev);
return r;
}
void r300_ring_start(struct radeon_device *rdev) void r300_ring_start(struct radeon_device *rdev)
{ {
unsigned gb_tile_config; unsigned gb_tile_config;
@ -281,8 +240,8 @@ void r300_ring_start(struct radeon_device *rdev)
radeon_ring_write(rdev, radeon_ring_write(rdev,
RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_2D_IDLECLEAN |
RADEON_WAIT_3D_IDLECLEAN); RADEON_WAIT_3D_IDLECLEAN);
radeon_ring_write(rdev, PACKET0(0x170C, 0)); radeon_ring_write(rdev, PACKET0(R300_DST_PIPE_CONFIG, 0));
radeon_ring_write(rdev, 1 << 31); radeon_ring_write(rdev, R300_PIPE_AUTO_CONFIG);
radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0)); radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0));
radeon_ring_write(rdev, 0); radeon_ring_write(rdev, 0);
radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0)); radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0));
@ -349,8 +308,8 @@ int r300_mc_wait_for_idle(struct radeon_device *rdev)
for (i = 0; i < rdev->usec_timeout; i++) { for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */ /* read MC_STATUS */
tmp = RREG32(0x0150); tmp = RREG32(RADEON_MC_STATUS);
if (tmp & (1 << 4)) { if (tmp & R300_MC_IDLE) {
return 0; return 0;
} }
DRM_UDELAY(1); DRM_UDELAY(1);
@ -395,8 +354,8 @@ void r300_gpu_init(struct radeon_device *rdev)
"programming pipes. Bad things might happen.\n"); "programming pipes. Bad things might happen.\n");
} }
tmp = RREG32(0x170C); tmp = RREG32(R300_DST_PIPE_CONFIG);
WREG32(0x170C, tmp | (1 << 31)); WREG32(R300_DST_PIPE_CONFIG, tmp | R300_PIPE_AUTO_CONFIG);
WREG32(R300_RB2D_DSTCACHE_MODE, WREG32(R300_RB2D_DSTCACHE_MODE,
R300_DC_AUTOFLUSH_ENABLE | R300_DC_AUTOFLUSH_ENABLE |
@ -437,8 +396,8 @@ int r300_ga_reset(struct radeon_device *rdev)
/* GA still busy soft reset it */ /* GA still busy soft reset it */
WREG32(0x429C, 0x200); WREG32(0x429C, 0x200);
WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0); WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0);
WREG32(0x43E0, 0); WREG32(R300_RE_SCISSORS_TL, 0);
WREG32(0x43E4, 0); WREG32(R300_RE_SCISSORS_BR, 0);
WREG32(0x24AC, 0); WREG32(0x24AC, 0);
} }
/* Wait to prevent race in RBBM_STATUS */ /* Wait to prevent race in RBBM_STATUS */
@ -488,7 +447,7 @@ int r300_gpu_reset(struct radeon_device *rdev)
} }
/* Check if GPU is idle */ /* Check if GPU is idle */
status = RREG32(RADEON_RBBM_STATUS); status = RREG32(RADEON_RBBM_STATUS);
if (status & (1 << 31)) { if (status & RADEON_RBBM_ACTIVE) {
DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status); DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
return -1; return -1;
} }
@ -500,13 +459,13 @@ int r300_gpu_reset(struct radeon_device *rdev)
/* /*
* r300,r350,rv350,rv380 VRAM info * r300,r350,rv350,rv380 VRAM info
*/ */
void r300_vram_info(struct radeon_device *rdev) void r300_mc_init(struct radeon_device *rdev)
{ {
uint32_t tmp; u64 base;
u32 tmp;
/* DDR for all card after R300 & IGP */ /* DDR for all card after R300 & IGP */
rdev->mc.vram_is_ddr = true; rdev->mc.vram_is_ddr = true;
tmp = RREG32(RADEON_MEM_CNTL); tmp = RREG32(RADEON_MEM_CNTL);
tmp &= R300_MEM_NUM_CHANNELS_MASK; tmp &= R300_MEM_NUM_CHANNELS_MASK;
switch (tmp) { switch (tmp) {
@ -515,8 +474,13 @@ void r300_vram_info(struct radeon_device *rdev)
case 2: rdev->mc.vram_width = 256; break; case 2: rdev->mc.vram_width = 256; break;
default: rdev->mc.vram_width = 128; break; default: rdev->mc.vram_width = 128; break;
} }
r100_vram_init_sizes(rdev); r100_vram_init_sizes(rdev);
base = rdev->mc.aper_base;
if (rdev->flags & RADEON_IS_IGP)
base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
radeon_vram_location(rdev, &rdev->mc, base);
if (!(rdev->flags & RADEON_IS_AGP))
radeon_gtt_location(rdev, &rdev->mc);
} }
void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes) void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
@ -578,6 +542,40 @@ void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
} }
int rv370_get_pcie_lanes(struct radeon_device *rdev)
{
u32 link_width_cntl;
if (rdev->flags & RADEON_IS_IGP)
return 0;
if (!(rdev->flags & RADEON_IS_PCIE))
return 0;
/* FIXME wait for idle */
if (rdev->family < CHIP_R600)
link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
else
link_width_cntl = RREG32_PCIE_P(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
switch ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) >> RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT) {
case RADEON_PCIE_LC_LINK_WIDTH_X0:
return 0;
case RADEON_PCIE_LC_LINK_WIDTH_X1:
return 1;
case RADEON_PCIE_LC_LINK_WIDTH_X2:
return 2;
case RADEON_PCIE_LC_LINK_WIDTH_X4:
return 4;
case RADEON_PCIE_LC_LINK_WIDTH_X8:
return 8;
case RADEON_PCIE_LC_LINK_WIDTH_X16:
default:
return 16;
}
}
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
static int rv370_debugfs_pcie_gart_info(struct seq_file *m, void *data) static int rv370_debugfs_pcie_gart_info(struct seq_file *m, void *data)
{ {
@ -707,6 +705,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
tile_flags |= R300_TXO_MACRO_TILE; tile_flags |= R300_TXO_MACRO_TILE;
if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
tile_flags |= R300_TXO_MICRO_TILE; tile_flags |= R300_TXO_MICRO_TILE;
else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
tile_flags |= R300_TXO_MICRO_TILE_SQUARE;
tmp = idx_value + ((u32)reloc->lobj.gpu_offset); tmp = idx_value + ((u32)reloc->lobj.gpu_offset);
tmp |= tile_flags; tmp |= tile_flags;
@ -757,6 +757,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
tile_flags |= R300_COLOR_TILE_ENABLE; tile_flags |= R300_COLOR_TILE_ENABLE;
if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
tile_flags |= R300_COLOR_MICROTILE_ENABLE; tile_flags |= R300_COLOR_MICROTILE_ENABLE;
else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
tile_flags |= R300_COLOR_MICROTILE_SQUARE_ENABLE;
tmp = idx_value & ~(0x7 << 16); tmp = idx_value & ~(0x7 << 16);
tmp |= tile_flags; tmp |= tile_flags;
@ -828,7 +830,9 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
tile_flags |= R300_DEPTHMACROTILE_ENABLE; tile_flags |= R300_DEPTHMACROTILE_ENABLE;
if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
tile_flags |= R300_DEPTHMICROTILE_TILED;; tile_flags |= R300_DEPTHMICROTILE_TILED;
else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
tile_flags |= R300_DEPTHMICROTILE_TILED_SQUARE;
tmp = idx_value & ~(0x7 << 16); tmp = idx_value & ~(0x7 << 16);
tmp |= tile_flags; tmp |= tile_flags;
@ -1387,12 +1391,15 @@ int r300_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev); radeon_get_clock_info(rdev->ddev);
/* Initialize power management */ /* Initialize power management */
radeon_pm_init(rdev); radeon_pm_init(rdev);
/* Get vram informations */ /* initialize AGP */
r300_vram_info(rdev); if (rdev->flags & RADEON_IS_AGP) {
/* Initialize memory controller (also test AGP) */ r = radeon_agp_init(rdev);
r = r420_mc_init(rdev); if (r) {
if (r) radeon_agp_disable(rdev);
return r; }
}
/* initialize memory controller */
r300_mc_init(rdev);
/* Fence driver */ /* Fence driver */
r = radeon_fence_driver_init(rdev); r = radeon_fence_driver_init(rdev);
if (r) if (r)

View File

@ -33,6 +33,7 @@
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
#include "drm_buffer.h"
#include "radeon_drm.h" #include "radeon_drm.h"
#include "radeon_drv.h" #include "radeon_drv.h"
#include "r300_reg.h" #include "r300_reg.h"
@ -299,46 +300,42 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
int reg; int reg;
int sz; int sz;
int i; int i;
int values[64]; u32 *value;
RING_LOCALS; RING_LOCALS;
sz = header.packet0.count; sz = header.packet0.count;
reg = (header.packet0.reghi << 8) | header.packet0.reglo; reg = (header.packet0.reghi << 8) | header.packet0.reglo;
if ((sz > 64) || (sz < 0)) { if ((sz > 64) || (sz < 0)) {
DRM_ERROR DRM_ERROR("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",
("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n", reg, sz);
reg, sz);
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < sz; i++) { for (i = 0; i < sz; i++) {
values[i] = ((int *)cmdbuf->buf)[i];
switch (r300_reg_flags[(reg >> 2) + i]) { switch (r300_reg_flags[(reg >> 2) + i]) {
case MARK_SAFE: case MARK_SAFE:
break; break;
case MARK_CHECK_OFFSET: case MARK_CHECK_OFFSET:
if (!radeon_check_offset(dev_priv, (u32) values[i])) { value = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
DRM_ERROR if (!radeon_check_offset(dev_priv, *value)) {
("Offset failed range check (reg=%04x sz=%d)\n", DRM_ERROR("Offset failed range check (reg=%04x sz=%d)\n",
reg, sz); reg, sz);
return -EINVAL; return -EINVAL;
} }
break; break;
default: default:
DRM_ERROR("Register %04x failed check as flag=%02x\n", DRM_ERROR("Register %04x failed check as flag=%02x\n",
reg + i * 4, r300_reg_flags[(reg >> 2) + i]); reg + i * 4, r300_reg_flags[(reg >> 2) + i]);
return -EINVAL; return -EINVAL;
} }
} }
BEGIN_RING(1 + sz); BEGIN_RING(1 + sz);
OUT_RING(CP_PACKET0(reg, sz - 1)); OUT_RING(CP_PACKET0(reg, sz - 1));
OUT_RING_TABLE(values, sz); OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += sz * 4;
cmdbuf->bufsz -= sz * 4;
return 0; return 0;
} }
@ -362,7 +359,7 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
if (!sz) if (!sz)
return 0; return 0;
if (sz * 4 > cmdbuf->bufsz) if (sz * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL; return -EINVAL;
if (reg + sz * 4 >= 0x10000) { if (reg + sz * 4 >= 0x10000) {
@ -380,12 +377,9 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
BEGIN_RING(1 + sz); BEGIN_RING(1 + sz);
OUT_RING(CP_PACKET0(reg, sz - 1)); OUT_RING(CP_PACKET0(reg, sz - 1));
OUT_RING_TABLE((int *)cmdbuf->buf, sz); OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += sz * 4;
cmdbuf->bufsz -= sz * 4;
return 0; return 0;
} }
@ -407,7 +401,7 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
if (!sz) if (!sz)
return 0; return 0;
if (sz * 16 > cmdbuf->bufsz) if (sz * 16 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL; return -EINVAL;
/* VAP is very sensitive so we purge cache before we program it /* VAP is very sensitive so we purge cache before we program it
@ -426,7 +420,7 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
BEGIN_RING(3 + sz * 4); BEGIN_RING(3 + sz * 4);
OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr); OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr);
OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1)); OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1));
OUT_RING_TABLE((int *)cmdbuf->buf, sz * 4); OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz * 4);
ADVANCE_RING(); ADVANCE_RING();
BEGIN_RING(2); BEGIN_RING(2);
@ -434,9 +428,6 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
OUT_RING(0); OUT_RING(0);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += sz * 16;
cmdbuf->bufsz -= sz * 16;
return 0; return 0;
} }
@ -449,14 +440,14 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
{ {
RING_LOCALS; RING_LOCALS;
if (8 * 4 > cmdbuf->bufsz) if (8 * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL; return -EINVAL;
BEGIN_RING(10); BEGIN_RING(10);
OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8)); OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8));
OUT_RING(R300_PRIM_TYPE_POINT | R300_PRIM_WALK_RING | OUT_RING(R300_PRIM_TYPE_POINT | R300_PRIM_WALK_RING |
(1 << R300_PRIM_NUM_VERTICES_SHIFT)); (1 << R300_PRIM_NUM_VERTICES_SHIFT));
OUT_RING_TABLE((int *)cmdbuf->buf, 8); OUT_RING_DRM_BUFFER(cmdbuf->buffer, 8);
ADVANCE_RING(); ADVANCE_RING();
BEGIN_RING(4); BEGIN_RING(4);
@ -468,9 +459,6 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
/* set flush flag */ /* set flush flag */
dev_priv->track_flush |= RADEON_FLUSH_EMITED; dev_priv->track_flush |= RADEON_FLUSH_EMITED;
cmdbuf->buf += 8 * 4;
cmdbuf->bufsz -= 8 * 4;
return 0; return 0;
} }
@ -480,28 +468,29 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
{ {
int count, i, k; int count, i, k;
#define MAX_ARRAY_PACKET 64 #define MAX_ARRAY_PACKET 64
u32 payload[MAX_ARRAY_PACKET]; u32 *data;
u32 narrays; u32 narrays;
RING_LOCALS; RING_LOCALS;
count = (header >> 16) & 0x3fff; count = (header & RADEON_CP_PACKET_COUNT_MASK) >> 16;
if ((count + 1) > MAX_ARRAY_PACKET) { if ((count + 1) > MAX_ARRAY_PACKET) {
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
count); count);
return -EINVAL; return -EINVAL;
} }
memset(payload, 0, MAX_ARRAY_PACKET * 4);
memcpy(payload, cmdbuf->buf + 4, (count + 1) * 4);
/* carefully check packet contents */ /* carefully check packet contents */
narrays = payload[0]; /* We have already read the header so advance the buffer. */
drm_buffer_advance(cmdbuf->buffer, 4);
narrays = *(u32 *)drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
k = 0; k = 0;
i = 1; i = 1;
while ((k < narrays) && (i < (count + 1))) { while ((k < narrays) && (i < (count + 1))) {
i++; /* skip attribute field */ i++; /* skip attribute field */
if (!radeon_check_offset(dev_priv, payload[i])) { data = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
if (!radeon_check_offset(dev_priv, *data)) {
DRM_ERROR DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i); k, i);
@ -512,7 +501,8 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
if (k == narrays) if (k == narrays)
break; break;
/* have one more to process, they come in pairs */ /* have one more to process, they come in pairs */
if (!radeon_check_offset(dev_priv, payload[i])) { data = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
if (!radeon_check_offset(dev_priv, *data)) {
DRM_ERROR DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n", ("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i); k, i);
@ -533,30 +523,30 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
BEGIN_RING(count + 2); BEGIN_RING(count + 2);
OUT_RING(header); OUT_RING(header);
OUT_RING_TABLE(payload, count + 1); OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 1);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += (count + 2) * 4;
cmdbuf->bufsz -= (count + 2) * 4;
return 0; return 0;
} }
static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf) drm_radeon_kcmd_buffer_t *cmdbuf)
{ {
u32 *cmd = (u32 *) cmdbuf->buf; u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
int count, ret; int count, ret;
RING_LOCALS; RING_LOCALS;
count=(cmd[0]>>16) & 0x3fff;
if (cmd[0] & 0x8000) { count = (*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16;
if (*cmd & 0x8000) {
u32 offset; u32 offset;
u32 *cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL if (*cmd1 & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10;
u32 *cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
offset = *cmd2 << 10;
ret = !radeon_check_offset(dev_priv, offset); ret = !radeon_check_offset(dev_priv, offset);
if (ret) { if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset); DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
@ -564,9 +554,10 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
} }
} }
if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) && if ((*cmd1 & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
(cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { (*cmd1 & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[3] << 10; u32 *cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
offset = *cmd3 << 10;
ret = !radeon_check_offset(dev_priv, offset); ret = !radeon_check_offset(dev_priv, offset);
if (ret) { if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset); DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
@ -577,28 +568,25 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
} }
BEGIN_RING(count+2); BEGIN_RING(count+2);
OUT_RING(cmd[0]); OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += (count+2)*4;
cmdbuf->bufsz -= (count+2)*4;
return 0; return 0;
} }
static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv, static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf) drm_radeon_kcmd_buffer_t *cmdbuf)
{ {
u32 *cmd; u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
u32 *cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
int count; int count;
int expected_count; int expected_count;
RING_LOCALS; RING_LOCALS;
cmd = (u32 *) cmdbuf->buf; count = (*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16;
count = (cmd[0]>>16) & 0x3fff;
expected_count = cmd[1] >> 16; expected_count = *cmd1 >> 16;
if (!(cmd[1] & R300_VAP_VF_CNTL__INDEX_SIZE_32bit)) if (!(*cmd1 & R300_VAP_VF_CNTL__INDEX_SIZE_32bit))
expected_count = (expected_count+1)/2; expected_count = (expected_count+1)/2;
if (count && count != expected_count) { if (count && count != expected_count) {
@ -608,55 +596,53 @@ static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
} }
BEGIN_RING(count+2); BEGIN_RING(count+2);
OUT_RING(cmd[0]); OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += (count+2)*4;
cmdbuf->bufsz -= (count+2)*4;
if (!count) { if (!count) {
drm_r300_cmd_header_t header; drm_r300_cmd_header_t stack_header, *header;
u32 *cmd1, *cmd2, *cmd3;
if (cmdbuf->bufsz < 4*4 + sizeof(header)) { if (drm_buffer_unprocessed(cmdbuf->buffer)
< 4*4 + sizeof(stack_header)) {
DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n"); DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n");
return -EINVAL; return -EINVAL;
} }
header.u = *(unsigned int *)cmdbuf->buf; header = drm_buffer_read_object(cmdbuf->buffer,
sizeof(stack_header), &stack_header);
cmdbuf->buf += sizeof(header); cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
cmdbuf->bufsz -= sizeof(header); cmd1 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
cmd = (u32 *) cmdbuf->buf; cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
if (header.header.cmd_type != R300_CMD_PACKET3 || if (header->header.cmd_type != R300_CMD_PACKET3 ||
header.packet3.packet != R300_CMD_PACKET3_RAW || header->packet3.packet != R300_CMD_PACKET3_RAW ||
cmd[0] != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) { *cmd != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) {
DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n"); DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n");
return -EINVAL; return -EINVAL;
} }
if ((cmd[1] & 0x8000ffff) != 0x80000810) { if ((*cmd1 & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); DRM_ERROR("Invalid indx_buffer reg address %08X\n",
*cmd1);
return -EINVAL; return -EINVAL;
} }
if (!radeon_check_offset(dev_priv, cmd[2])) { if (!radeon_check_offset(dev_priv, *cmd2)) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); DRM_ERROR("Invalid indx_buffer offset is %08X\n",
*cmd2);
return -EINVAL; return -EINVAL;
} }
if (cmd[3] != expected_count) { if (*cmd3 != expected_count) {
DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n", DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n",
cmd[3], expected_count); *cmd3, expected_count);
return -EINVAL; return -EINVAL;
} }
BEGIN_RING(4); BEGIN_RING(4);
OUT_RING(cmd[0]); OUT_RING_DRM_BUFFER(cmdbuf->buffer, 4);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), 3);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += 4*4;
cmdbuf->bufsz -= 4*4;
} }
return 0; return 0;
@ -665,39 +651,39 @@ static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv,
static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf) drm_radeon_kcmd_buffer_t *cmdbuf)
{ {
u32 header; u32 *header;
int count; int count;
RING_LOCALS; RING_LOCALS;
if (4 > cmdbuf->bufsz) if (4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL; return -EINVAL;
/* Fixme !! This simply emits a packet without much checking. /* Fixme !! This simply emits a packet without much checking.
We need to be smarter. */ We need to be smarter. */
/* obtain first word - actual packet3 header */ /* obtain first word - actual packet3 header */
header = *(u32 *) cmdbuf->buf; header = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
/* Is it packet 3 ? */ /* Is it packet 3 ? */
if ((header >> 30) != 0x3) { if ((*header >> 30) != 0x3) {
DRM_ERROR("Not a packet3 header (0x%08x)\n", header); DRM_ERROR("Not a packet3 header (0x%08x)\n", *header);
return -EINVAL; return -EINVAL;
} }
count = (header >> 16) & 0x3fff; count = (*header >> 16) & 0x3fff;
/* Check again now that we know how much data to expect */ /* Check again now that we know how much data to expect */
if ((count + 2) * 4 > cmdbuf->bufsz) { if ((count + 2) * 4 > drm_buffer_unprocessed(cmdbuf->buffer)) {
DRM_ERROR DRM_ERROR
("Expected packet3 of length %d but have only %d bytes left\n", ("Expected packet3 of length %d but have only %d bytes left\n",
(count + 2) * 4, cmdbuf->bufsz); (count + 2) * 4, drm_buffer_unprocessed(cmdbuf->buffer));
return -EINVAL; return -EINVAL;
} }
/* Is it a packet type we know about ? */ /* Is it a packet type we know about ? */
switch (header & 0xff00) { switch (*header & 0xff00) {
case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */ case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */
return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, header); return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, *header);
case RADEON_CNTL_BITBLT_MULTI: case RADEON_CNTL_BITBLT_MULTI:
return r300_emit_bitblt_multi(dev_priv, cmdbuf); return r300_emit_bitblt_multi(dev_priv, cmdbuf);
@ -723,18 +709,14 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
/* these packets are safe */ /* these packets are safe */
break; break;
default: default:
DRM_ERROR("Unknown packet3 header (0x%08x)\n", header); DRM_ERROR("Unknown packet3 header (0x%08x)\n", *header);
return -EINVAL; return -EINVAL;
} }
BEGIN_RING(count + 2); BEGIN_RING(count + 2);
OUT_RING(header); OUT_RING_DRM_BUFFER(cmdbuf->buffer, count + 2);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += (count + 2) * 4;
cmdbuf->bufsz -= (count + 2) * 4;
return 0; return 0;
} }
@ -748,8 +730,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
{ {
int n; int n;
int ret; int ret;
char *orig_buf = cmdbuf->buf; int orig_iter = cmdbuf->buffer->iterator;
int orig_bufsz = cmdbuf->bufsz;
/* This is a do-while-loop so that we run the interior at least once, /* This is a do-while-loop so that we run the interior at least once,
* even if cmdbuf->nbox is 0. Compare r300_emit_cliprects for rationale. * even if cmdbuf->nbox is 0. Compare r300_emit_cliprects for rationale.
@ -761,8 +742,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
if (ret) if (ret)
return ret; return ret;
cmdbuf->buf = orig_buf; cmdbuf->buffer->iterator = orig_iter;
cmdbuf->bufsz = orig_bufsz;
} }
switch (header.packet3.packet) { switch (header.packet3.packet) {
@ -785,9 +765,9 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
break; break;
default: default:
DRM_ERROR("bad packet3 type %i at %p\n", DRM_ERROR("bad packet3 type %i at byte %d\n",
header.packet3.packet, header.packet3.packet,
cmdbuf->buf - sizeof(header)); cmdbuf->buffer->iterator - (int)sizeof(header));
return -EINVAL; return -EINVAL;
} }
@ -923,12 +903,13 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
drm_r300_cmd_header_t header) drm_r300_cmd_header_t header)
{ {
u32 *ref_age_base; u32 *ref_age_base;
u32 i, buf_idx, h_pending; u32 i, *buf_idx, h_pending;
u64 ptr_addr; u64 *ptr_addr;
u64 stack_ptr_addr;
RING_LOCALS; RING_LOCALS;
if (cmdbuf->bufsz < if (drm_buffer_unprocessed(cmdbuf->buffer) <
(sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) { (sizeof(u64) + header.scratch.n_bufs * sizeof(*buf_idx))) {
return -EINVAL; return -EINVAL;
} }
@ -938,36 +919,35 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
dev_priv->scratch_ages[header.scratch.reg]++; dev_priv->scratch_ages[header.scratch.reg]++;
ptr_addr = get_unaligned((u64 *)cmdbuf->buf); ptr_addr = drm_buffer_read_object(cmdbuf->buffer,
ref_age_base = (u32 *)(unsigned long)ptr_addr; sizeof(stack_ptr_addr), &stack_ptr_addr);
ref_age_base = (u32 *)(unsigned long)*ptr_addr;
cmdbuf->buf += sizeof(u64);
cmdbuf->bufsz -= sizeof(u64);
for (i=0; i < header.scratch.n_bufs; i++) { for (i=0; i < header.scratch.n_bufs; i++) {
buf_idx = *(u32 *)cmdbuf->buf; buf_idx = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
buf_idx *= 2; /* 8 bytes per buf */ *buf_idx *= 2; /* 8 bytes per buf */
if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) { if (DRM_COPY_TO_USER(ref_age_base + *buf_idx,
&dev_priv->scratch_ages[header.scratch.reg],
sizeof(u32)))
return -EINVAL; return -EINVAL;
}
if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) { if (DRM_COPY_FROM_USER(&h_pending,
ref_age_base + *buf_idx + 1,
sizeof(u32)))
return -EINVAL; return -EINVAL;
}
if (h_pending == 0) { if (h_pending == 0)
return -EINVAL; return -EINVAL;
}
h_pending--; h_pending--;
if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) { if (DRM_COPY_TO_USER(ref_age_base + *buf_idx + 1,
&h_pending,
sizeof(u32)))
return -EINVAL; return -EINVAL;
}
cmdbuf->buf += sizeof(buf_idx); drm_buffer_advance(cmdbuf->buffer, sizeof(*buf_idx));
cmdbuf->bufsz -= sizeof(buf_idx);
} }
BEGIN_RING(2); BEGIN_RING(2);
@ -1009,19 +989,16 @@ static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
DRM_DEBUG("r500fp %d %d type: %d\n", sz, addr, type); DRM_DEBUG("r500fp %d %d type: %d\n", sz, addr, type);
if (!sz) if (!sz)
return 0; return 0;
if (sz * stride * 4 > cmdbuf->bufsz) if (sz * stride * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
return -EINVAL; return -EINVAL;
BEGIN_RING(3 + sz * stride); BEGIN_RING(3 + sz * stride);
OUT_RING_REG(R500_GA_US_VECTOR_INDEX, addr); OUT_RING_REG(R500_GA_US_VECTOR_INDEX, addr);
OUT_RING(CP_PACKET0_TABLE(R500_GA_US_VECTOR_DATA, sz * stride - 1)); OUT_RING(CP_PACKET0_TABLE(R500_GA_US_VECTOR_DATA, sz * stride - 1));
OUT_RING_TABLE((int *)cmdbuf->buf, sz * stride); OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz * stride);
ADVANCE_RING(); ADVANCE_RING();
cmdbuf->buf += sz * stride * 4;
cmdbuf->bufsz -= sz * stride * 4;
return 0; return 0;
} }
@ -1053,19 +1030,18 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
goto cleanup; goto cleanup;
} }
while (cmdbuf->bufsz >= sizeof(drm_r300_cmd_header_t)) { while (drm_buffer_unprocessed(cmdbuf->buffer)
>= sizeof(drm_r300_cmd_header_t)) {
int idx; int idx;
drm_r300_cmd_header_t header; drm_r300_cmd_header_t *header, stack_header;
header.u = *(unsigned int *)cmdbuf->buf; header = drm_buffer_read_object(cmdbuf->buffer,
sizeof(stack_header), &stack_header);
cmdbuf->buf += sizeof(header); switch (header->header.cmd_type) {
cmdbuf->bufsz -= sizeof(header);
switch (header.header.cmd_type) {
case R300_CMD_PACKET0: case R300_CMD_PACKET0:
DRM_DEBUG("R300_CMD_PACKET0\n"); DRM_DEBUG("R300_CMD_PACKET0\n");
ret = r300_emit_packet0(dev_priv, cmdbuf, header); ret = r300_emit_packet0(dev_priv, cmdbuf, *header);
if (ret) { if (ret) {
DRM_ERROR("r300_emit_packet0 failed\n"); DRM_ERROR("r300_emit_packet0 failed\n");
goto cleanup; goto cleanup;
@ -1074,7 +1050,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
case R300_CMD_VPU: case R300_CMD_VPU:
DRM_DEBUG("R300_CMD_VPU\n"); DRM_DEBUG("R300_CMD_VPU\n");
ret = r300_emit_vpu(dev_priv, cmdbuf, header); ret = r300_emit_vpu(dev_priv, cmdbuf, *header);
if (ret) { if (ret) {
DRM_ERROR("r300_emit_vpu failed\n"); DRM_ERROR("r300_emit_vpu failed\n");
goto cleanup; goto cleanup;
@ -1083,7 +1059,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
case R300_CMD_PACKET3: case R300_CMD_PACKET3:
DRM_DEBUG("R300_CMD_PACKET3\n"); DRM_DEBUG("R300_CMD_PACKET3\n");
ret = r300_emit_packet3(dev_priv, cmdbuf, header); ret = r300_emit_packet3(dev_priv, cmdbuf, *header);
if (ret) { if (ret) {
DRM_ERROR("r300_emit_packet3 failed\n"); DRM_ERROR("r300_emit_packet3 failed\n");
goto cleanup; goto cleanup;
@ -1117,8 +1093,8 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
int i; int i;
RING_LOCALS; RING_LOCALS;
BEGIN_RING(header.delay.count); BEGIN_RING(header->delay.count);
for (i = 0; i < header.delay.count; i++) for (i = 0; i < header->delay.count; i++)
OUT_RING(RADEON_CP_PACKET2); OUT_RING(RADEON_CP_PACKET2);
ADVANCE_RING(); ADVANCE_RING();
} }
@ -1126,7 +1102,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
case R300_CMD_DMA_DISCARD: case R300_CMD_DMA_DISCARD:
DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n"); DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
idx = header.dma.buf_idx; idx = header->dma.buf_idx;
if (idx < 0 || idx >= dma->buf_count) { if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n", DRM_ERROR("buffer index %d (of %d max)\n",
idx, dma->buf_count - 1); idx, dma->buf_count - 1);
@ -1149,12 +1125,12 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
case R300_CMD_WAIT: case R300_CMD_WAIT:
DRM_DEBUG("R300_CMD_WAIT\n"); DRM_DEBUG("R300_CMD_WAIT\n");
r300_cmd_wait(dev_priv, header); r300_cmd_wait(dev_priv, *header);
break; break;
case R300_CMD_SCRATCH: case R300_CMD_SCRATCH:
DRM_DEBUG("R300_CMD_SCRATCH\n"); DRM_DEBUG("R300_CMD_SCRATCH\n");
ret = r300_scratch(dev_priv, cmdbuf, header); ret = r300_scratch(dev_priv, cmdbuf, *header);
if (ret) { if (ret) {
DRM_ERROR("r300_scratch failed\n"); DRM_ERROR("r300_scratch failed\n");
goto cleanup; goto cleanup;
@ -1168,16 +1144,16 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
goto cleanup; goto cleanup;
} }
DRM_DEBUG("R300_CMD_R500FP\n"); DRM_DEBUG("R300_CMD_R500FP\n");
ret = r300_emit_r500fp(dev_priv, cmdbuf, header); ret = r300_emit_r500fp(dev_priv, cmdbuf, *header);
if (ret) { if (ret) {
DRM_ERROR("r300_emit_r500fp failed\n"); DRM_ERROR("r300_emit_r500fp failed\n");
goto cleanup; goto cleanup;
} }
break; break;
default: default:
DRM_ERROR("bad cmd_type %i at %p\n", DRM_ERROR("bad cmd_type %i at byte %d\n",
header.header.cmd_type, header->header.cmd_type,
cmdbuf->buf - sizeof(header)); cmdbuf->buffer->iterator - (int)sizeof(*header));
ret = -EINVAL; ret = -EINVAL;
goto cleanup; goto cleanup;
} }

View File

@ -952,6 +952,7 @@
# define R300_TXO_ENDIAN_HALFDW_SWAP (3 << 0) # define R300_TXO_ENDIAN_HALFDW_SWAP (3 << 0)
# define R300_TXO_MACRO_TILE (1 << 2) # define R300_TXO_MACRO_TILE (1 << 2)
# define R300_TXO_MICRO_TILE (1 << 3) # define R300_TXO_MICRO_TILE (1 << 3)
# define R300_TXO_MICRO_TILE_SQUARE (2 << 3)
# define R300_TXO_OFFSET_MASK 0xffffffe0 # define R300_TXO_OFFSET_MASK 0xffffffe0
# define R300_TXO_OFFSET_SHIFT 5 # define R300_TXO_OFFSET_SHIFT 5
/* END: Guess from R200 */ /* END: Guess from R200 */
@ -1360,6 +1361,7 @@
# define R300_COLORPITCH_MASK 0x00001FF8 /* GUESS */ # define R300_COLORPITCH_MASK 0x00001FF8 /* GUESS */
# define R300_COLOR_TILE_ENABLE (1 << 16) /* GUESS */ # define R300_COLOR_TILE_ENABLE (1 << 16) /* GUESS */
# define R300_COLOR_MICROTILE_ENABLE (1 << 17) /* GUESS */ # define R300_COLOR_MICROTILE_ENABLE (1 << 17) /* GUESS */
# define R300_COLOR_MICROTILE_SQUARE_ENABLE (2 << 17)
# define R300_COLOR_ENDIAN_NO_SWAP (0 << 18) /* GUESS */ # define R300_COLOR_ENDIAN_NO_SWAP (0 << 18) /* GUESS */
# define R300_COLOR_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */ # define R300_COLOR_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */
# define R300_COLOR_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */ # define R300_COLOR_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */

View File

@ -40,28 +40,6 @@ static void r420_set_reg_safe(struct radeon_device *rdev)
rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r420_reg_safe_bm); rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r420_reg_safe_bm);
} }
int r420_mc_init(struct radeon_device *rdev)
{
int r;
/* Setup GPU memory space */
rdev->mc.vram_location = 0xFFFFFFFFUL;
rdev->mc.gtt_location = 0xFFFFFFFFUL;
if (rdev->flags & RADEON_IS_AGP) {
r = radeon_agp_init(rdev);
if (r) {
radeon_agp_disable(rdev);
} else {
rdev->mc.gtt_location = rdev->mc.agp_base;
}
}
r = radeon_mc_setup(rdev);
if (r) {
return r;
}
return 0;
}
void r420_pipes_init(struct radeon_device *rdev) void r420_pipes_init(struct radeon_device *rdev)
{ {
unsigned tmp; unsigned tmp;
@ -69,7 +47,8 @@ void r420_pipes_init(struct radeon_device *rdev)
unsigned num_pipes; unsigned num_pipes;
/* GA_ENHANCE workaround TCL deadlock issue */ /* GA_ENHANCE workaround TCL deadlock issue */
WREG32(0x4274, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)); WREG32(R300_GA_ENHANCE, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL |
(1 << 2) | (1 << 3));
/* add idle wait as per freedesktop.org bug 24041 */ /* add idle wait as per freedesktop.org bug 24041 */
if (r100_gui_wait_for_idle(rdev)) { if (r100_gui_wait_for_idle(rdev)) {
printk(KERN_WARNING "Failed to wait GUI idle while " printk(KERN_WARNING "Failed to wait GUI idle while "
@ -97,17 +76,17 @@ void r420_pipes_init(struct radeon_device *rdev)
tmp = (7 << 1); tmp = (7 << 1);
break; break;
} }
WREG32(0x42C8, (1 << num_pipes) - 1); WREG32(R500_SU_REG_DEST, (1 << num_pipes) - 1);
/* Sub pixel 1/12 so we can have 4K rendering according to doc */ /* Sub pixel 1/12 so we can have 4K rendering according to doc */
tmp |= (1 << 4) | (1 << 0); tmp |= R300_TILE_SIZE_16 | R300_ENABLE_TILING;
WREG32(0x4018, tmp); WREG32(R300_GB_TILE_CONFIG, tmp);
if (r100_gui_wait_for_idle(rdev)) { if (r100_gui_wait_for_idle(rdev)) {
printk(KERN_WARNING "Failed to wait GUI idle while " printk(KERN_WARNING "Failed to wait GUI idle while "
"programming pipes. Bad things might happen.\n"); "programming pipes. Bad things might happen.\n");
} }
tmp = RREG32(0x170C); tmp = RREG32(R300_DST_PIPE_CONFIG);
WREG32(0x170C, tmp | (1 << 31)); WREG32(R300_DST_PIPE_CONFIG, tmp | R300_PIPE_AUTO_CONFIG);
WREG32(R300_RB2D_DSTCACHE_MODE, WREG32(R300_RB2D_DSTCACHE_MODE,
RREG32(R300_RB2D_DSTCACHE_MODE) | RREG32(R300_RB2D_DSTCACHE_MODE) |
@ -348,13 +327,15 @@ int r420_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev); radeon_get_clock_info(rdev->ddev);
/* Initialize power management */ /* Initialize power management */
radeon_pm_init(rdev); radeon_pm_init(rdev);
/* Get vram informations */ /* initialize AGP */
r300_vram_info(rdev); if (rdev->flags & RADEON_IS_AGP) {
/* Initialize memory controller (also test AGP) */ r = radeon_agp_init(rdev);
r = r420_mc_init(rdev); if (r) {
if (r) { radeon_agp_disable(rdev);
return r; }
} }
/* initialize memory controller */
r300_mc_init(rdev);
r420_debugfs(rdev); r420_debugfs(rdev);
/* Fence driver */ /* Fence driver */
r = radeon_fence_driver_init(rdev); r = radeon_fence_driver_init(rdev);

View File

@ -717,54 +717,62 @@
#define AVIVO_DVOA_BIT_DEPTH_CONTROL 0x7988 #define AVIVO_DVOA_BIT_DEPTH_CONTROL 0x7988
#define AVIVO_DC_GPIO_HPD_A 0x7e94 #define AVIVO_DC_GPIO_HPD_A 0x7e94
#define AVIVO_GPIO_0 0x7e30
#define AVIVO_GPIO_1 0x7e40
#define AVIVO_GPIO_2 0x7e50
#define AVIVO_GPIO_3 0x7e60
#define AVIVO_DC_GPIO_HPD_Y 0x7e9c #define AVIVO_DC_GPIO_HPD_Y 0x7e9c
#define AVIVO_I2C_STATUS 0x7d30 #define AVIVO_DC_I2C_STATUS1 0x7d30
# define AVIVO_I2C_STATUS_DONE (1 << 0) # define AVIVO_DC_I2C_DONE (1 << 0)
# define AVIVO_I2C_STATUS_NACK (1 << 1) # define AVIVO_DC_I2C_NACK (1 << 1)
# define AVIVO_I2C_STATUS_HALT (1 << 2) # define AVIVO_DC_I2C_HALT (1 << 2)
# define AVIVO_I2C_STATUS_GO (1 << 3) # define AVIVO_DC_I2C_GO (1 << 3)
# define AVIVO_I2C_STATUS_MASK 0x7 #define AVIVO_DC_I2C_RESET 0x7d34
/* If radeon_mm_i2c is to be believed, this is HALT, NACK, and maybe # define AVIVO_DC_I2C_SOFT_RESET (1 << 0)
* DONE? */ # define AVIVO_DC_I2C_ABORT (1 << 8)
# define AVIVO_I2C_STATUS_CMD_RESET 0x7 #define AVIVO_DC_I2C_CONTROL1 0x7d38
# define AVIVO_I2C_STATUS_CMD_WAIT (1 << 3) # define AVIVO_DC_I2C_START (1 << 0)
#define AVIVO_I2C_STOP 0x7d34 # define AVIVO_DC_I2C_STOP (1 << 1)
#define AVIVO_I2C_START_CNTL 0x7d38 # define AVIVO_DC_I2C_RECEIVE (1 << 2)
# define AVIVO_I2C_START (1 << 8) # define AVIVO_DC_I2C_EN (1 << 8)
# define AVIVO_I2C_CONNECTOR0 (0 << 16) # define AVIVO_DC_I2C_PIN_SELECT(x) ((x) << 16)
# define AVIVO_I2C_CONNECTOR1 (1 << 16) # define AVIVO_SEL_DDC1 0
#define R520_I2C_START (1<<0) # define AVIVO_SEL_DDC2 1
#define R520_I2C_STOP (1<<1) # define AVIVO_SEL_DDC3 2
#define R520_I2C_RX (1<<2) #define AVIVO_DC_I2C_CONTROL2 0x7d3c
#define R520_I2C_EN (1<<8) # define AVIVO_DC_I2C_ADDR_COUNT(x) ((x) << 0)
#define R520_I2C_DDC1 (0<<16) # define AVIVO_DC_I2C_DATA_COUNT(x) ((x) << 8)
#define R520_I2C_DDC2 (1<<16) #define AVIVO_DC_I2C_CONTROL3 0x7d40
#define R520_I2C_DDC3 (2<<16) # define AVIVO_DC_I2C_DATA_DRIVE_EN (1 << 0)
#define R520_I2C_DDC_MASK (3<<16) # define AVIVO_DC_I2C_DATA_DRIVE_SEL (1 << 1)
#define AVIVO_I2C_CONTROL2 0x7d3c # define AVIVO_DC_I2C_CLK_DRIVE_EN (1 << 7)
# define AVIVO_I2C_7D3C_SIZE_SHIFT 8 # define AVIVO_DC_I2C_RD_INTRA_BYTE_DELAY(x) ((x) << 8)
# define AVIVO_I2C_7D3C_SIZE_MASK (0xf << 8) # define AVIVO_DC_I2C_WR_INTRA_BYTE_DELAY(x) ((x) << 16)
#define AVIVO_I2C_CONTROL3 0x7d40 # define AVIVO_DC_I2C_TIME_LIMIT(x) ((x) << 24)
/* Reading is done 4 bytes at a time: read the bottom 8 bits from #define AVIVO_DC_I2C_DATA 0x7d44
* 7d44, four times in a row. #define AVIVO_DC_I2C_INTERRUPT_CONTROL 0x7d48
* Writing is a little more complex. First write DATA with # define AVIVO_DC_I2C_INTERRUPT_STATUS (1 << 0)
* 0xnnnnnnzz, then 0xnnnnnnyy, where nnnnnn is some non-deterministic # define AVIVO_DC_I2C_INTERRUPT_AK (1 << 8)
* magic number, zz is, I think, the slave address, and yy is the byte # define AVIVO_DC_I2C_INTERRUPT_ENABLE (1 << 16)
* you want to write. */ #define AVIVO_DC_I2C_ARBITRATION 0x7d50
#define AVIVO_I2C_DATA 0x7d44 # define AVIVO_DC_I2C_SW_WANTS_TO_USE_I2C (1 << 0)
#define R520_I2C_ADDR_COUNT_MASK (0x7) # define AVIVO_DC_I2C_SW_CAN_USE_I2C (1 << 1)
#define R520_I2C_DATA_COUNT_SHIFT (8) # define AVIVO_DC_I2C_SW_DONE_USING_I2C (1 << 8)
#define R520_I2C_DATA_COUNT_MASK (0xF00) # define AVIVO_DC_I2C_HW_NEEDS_I2C (1 << 9)
#define AVIVO_I2C_CNTL 0x7d50 # define AVIVO_DC_I2C_ABORT_HDCP_I2C (1 << 16)
# define AVIVO_I2C_EN (1 << 0) # define AVIVO_DC_I2C_HW_USING_I2C (1 << 17)
# define AVIVO_I2C_RESET (1 << 8)
#define AVIVO_DC_GPIO_DDC1_MASK 0x7e40
#define AVIVO_DC_GPIO_DDC1_A 0x7e44
#define AVIVO_DC_GPIO_DDC1_EN 0x7e48
#define AVIVO_DC_GPIO_DDC1_Y 0x7e4c
#define AVIVO_DC_GPIO_DDC2_MASK 0x7e50
#define AVIVO_DC_GPIO_DDC2_A 0x7e54
#define AVIVO_DC_GPIO_DDC2_EN 0x7e58
#define AVIVO_DC_GPIO_DDC2_Y 0x7e5c
#define AVIVO_DC_GPIO_DDC3_MASK 0x7e60
#define AVIVO_DC_GPIO_DDC3_A 0x7e64
#define AVIVO_DC_GPIO_DDC3_EN 0x7e68
#define AVIVO_DC_GPIO_DDC3_Y 0x7e6c
#define AVIVO_DISP_INTERRUPT_STATUS 0x7edc #define AVIVO_DISP_INTERRUPT_STATUS 0x7edc
# define AVIVO_D1_VBLANK_INTERRUPT (1 << 4) # define AVIVO_D1_VBLANK_INTERRUPT (1 << 4)

View File

@ -119,13 +119,15 @@ static void r520_vram_get_type(struct radeon_device *rdev)
rdev->mc.vram_width *= 2; rdev->mc.vram_width *= 2;
} }
void r520_vram_info(struct radeon_device *rdev) void r520_mc_init(struct radeon_device *rdev)
{ {
fixed20_12 a; fixed20_12 a;
r520_vram_get_type(rdev); r520_vram_get_type(rdev);
r100_vram_init_sizes(rdev); r100_vram_init_sizes(rdev);
radeon_vram_location(rdev, &rdev->mc, 0);
if (!(rdev->flags & RADEON_IS_AGP))
radeon_gtt_location(rdev, &rdev->mc);
/* FIXME: we should enforce default clock in case GPU is not in /* FIXME: we should enforce default clock in case GPU is not in
* default setup * default setup
*/ */
@ -267,12 +269,15 @@ int r520_init(struct radeon_device *rdev)
radeon_get_clock_info(rdev->ddev); radeon_get_clock_info(rdev->ddev);
/* Initialize power management */ /* Initialize power management */
radeon_pm_init(rdev); radeon_pm_init(rdev);
/* Get vram informations */ /* initialize AGP */
r520_vram_info(rdev); if (rdev->flags & RADEON_IS_AGP) {
/* Initialize memory controller (also test AGP) */ r = radeon_agp_init(rdev);
r = r420_mc_init(rdev); if (r) {
if (r) radeon_agp_disable(rdev);
return r; }
}
/* initialize memory controller */
r520_mc_init(rdev);
rv515_debugfs(rdev); rv515_debugfs(rdev);
/* Fence driver */ /* Fence driver */
r = radeon_fence_driver_init(rdev); r = radeon_fence_driver_init(rdev);

View File

@ -353,23 +353,14 @@ void r600_hpd_fini(struct radeon_device *rdev)
/* /*
* R600 PCIE GART * R600 PCIE GART
*/ */
int r600_gart_clear_page(struct radeon_device *rdev, int i)
{
void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
u64 pte;
if (i < 0 || i > rdev->gart.num_gpu_pages)
return -EINVAL;
pte = 0;
writeq(pte, ((void __iomem *)ptr) + (i * 8));
return 0;
}
void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) void r600_pcie_gart_tlb_flush(struct radeon_device *rdev)
{ {
unsigned i; unsigned i;
u32 tmp; u32 tmp;
/* flush hdp cache so updates hit vram */
WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
WREG32(VM_CONTEXT0_INVALIDATION_LOW_ADDR, rdev->mc.gtt_start >> 12); WREG32(VM_CONTEXT0_INVALIDATION_LOW_ADDR, rdev->mc.gtt_start >> 12);
WREG32(VM_CONTEXT0_INVALIDATION_HIGH_ADDR, (rdev->mc.gtt_end - 1) >> 12); WREG32(VM_CONTEXT0_INVALIDATION_HIGH_ADDR, (rdev->mc.gtt_end - 1) >> 12);
WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1)); WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1));
@ -416,6 +407,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev)
r = radeon_gart_table_vram_pin(rdev); r = radeon_gart_table_vram_pin(rdev);
if (r) if (r)
return r; return r;
radeon_gart_restore(rdev);
/* Setup L2 cache */ /* Setup L2 cache */
WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING | WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
@ -619,6 +611,68 @@ static void r600_mc_program(struct radeon_device *rdev)
rv515_vga_render_disable(rdev); rv515_vga_render_disable(rdev);
} }
/**
* r600_vram_gtt_location - try to find VRAM & GTT location
* @rdev: radeon device structure holding all necessary informations
* @mc: memory controller structure holding memory informations
*
* Function will place try to place VRAM at same place as in CPU (PCI)
* address space as some GPU seems to have issue when we reprogram at
* different address space.
*
* If there is not enough space to fit the unvisible VRAM after the
* aperture then we limit the VRAM size to the aperture.
*
* If we are using AGP then place VRAM adjacent to AGP aperture are we need
* them to be in one from GPU point of view so that we can program GPU to
* catch access outside them (weird GPU policy see ??).
*
* This function will never fails, worst case are limiting VRAM or GTT.
*
* Note: GTT start, end, size should be initialized before calling this
* function on AGP platform.
*/
void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc)
{
u64 size_bf, size_af;
if (mc->mc_vram_size > 0xE0000000) {
/* leave room for at least 512M GTT */
dev_warn(rdev->dev, "limiting VRAM\n");
mc->real_vram_size = 0xE0000000;
mc->mc_vram_size = 0xE0000000;
}
if (rdev->flags & RADEON_IS_AGP) {
size_bf = mc->gtt_start;
size_af = 0xFFFFFFFF - mc->gtt_end + 1;
if (size_bf > size_af) {
if (mc->mc_vram_size > size_bf) {
dev_warn(rdev->dev, "limiting VRAM\n");
mc->real_vram_size = size_bf;
mc->mc_vram_size = size_bf;
}
mc->vram_start = mc->gtt_start - mc->mc_vram_size;
} else {
if (mc->mc_vram_size > size_af) {
dev_warn(rdev->dev, "limiting VRAM\n");
mc->real_vram_size = size_af;
mc->mc_vram_size = size_af;
}
mc->vram_start = mc->gtt_end;
}
mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n",
mc->mc_vram_size >> 20, mc->vram_start,
mc->vram_end, mc->real_vram_size >> 20);
} else {
u64 base = 0;
if (rdev->flags & RADEON_IS_IGP)
base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24;
radeon_vram_location(rdev, &rdev->mc, base);
radeon_gtt_location(rdev, mc);
}
}
int r600_mc_init(struct radeon_device *rdev) int r600_mc_init(struct radeon_device *rdev)
{ {
fixed20_12 a; fixed20_12 a;
@ -658,75 +712,21 @@ int r600_mc_init(struct radeon_device *rdev)
/* Setup GPU memory space */ /* Setup GPU memory space */
rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
rdev->mc.visible_vram_size = rdev->mc.aper_size;
if (rdev->mc.mc_vram_size > rdev->mc.aper_size) /* FIXME remove this once we support unmappable VRAM */
if (rdev->mc.mc_vram_size > rdev->mc.aper_size) {
rdev->mc.mc_vram_size = rdev->mc.aper_size; rdev->mc.mc_vram_size = rdev->mc.aper_size;
if (rdev->mc.real_vram_size > rdev->mc.aper_size)
rdev->mc.real_vram_size = rdev->mc.aper_size; rdev->mc.real_vram_size = rdev->mc.aper_size;
if (rdev->flags & RADEON_IS_AGP) {
/* gtt_size is setup by radeon_agp_init */
rdev->mc.gtt_location = rdev->mc.agp_base;
tmp = 0xFFFFFFFFUL - rdev->mc.agp_base - rdev->mc.gtt_size;
/* Try to put vram before or after AGP because we
* we want SYSTEM_APERTURE to cover both VRAM and
* AGP so that GPU can catch out of VRAM/AGP access
*/
if (rdev->mc.gtt_location > rdev->mc.mc_vram_size) {
/* Enough place before */
rdev->mc.vram_location = rdev->mc.gtt_location -
rdev->mc.mc_vram_size;
} else if (tmp > rdev->mc.mc_vram_size) {
/* Enough place after */
rdev->mc.vram_location = rdev->mc.gtt_location +
rdev->mc.gtt_size;
} else {
/* Try to setup VRAM then AGP might not
* not work on some card
*/
rdev->mc.vram_location = 0x00000000UL;
rdev->mc.gtt_location = rdev->mc.mc_vram_size;
}
} else {
rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
rdev->mc.vram_location = (RREG32(MC_VM_FB_LOCATION) &
0xFFFF) << 24;
tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size;
if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) {
/* Enough place after vram */
rdev->mc.gtt_location = tmp;
} else if (rdev->mc.vram_location >= rdev->mc.gtt_size) {
/* Enough place before vram */
rdev->mc.gtt_location = 0;
} else {
/* Not enough place after or before shrink
* gart size
*/
if (rdev->mc.vram_location > (0xFFFFFFFFUL - tmp)) {
rdev->mc.gtt_location = 0;
rdev->mc.gtt_size = rdev->mc.vram_location;
} else {
rdev->mc.gtt_location = tmp;
rdev->mc.gtt_size = 0xFFFFFFFFUL - tmp;
}
}
rdev->mc.gtt_location = rdev->mc.mc_vram_size;
} }
rdev->mc.vram_start = rdev->mc.vram_location; r600_vram_gtt_location(rdev, &rdev->mc);
rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
rdev->mc.gtt_start = rdev->mc.gtt_location;
rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
/* FIXME: we should enforce default clock in case GPU is not in /* FIXME: we should enforce default clock in case GPU is not in
* default setup * default setup
*/ */
a.full = rfixed_const(100); a.full = rfixed_const(100);
rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk); rdev->pm.sclk.full = rfixed_const(rdev->clock.default_sclk);
rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a); rdev->pm.sclk.full = rfixed_div(rdev->pm.sclk, a);
if (rdev->flags & RADEON_IS_IGP) if (rdev->flags & RADEON_IS_IGP)
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
return 0; return 0;
} }
@ -981,6 +981,9 @@ void r600_gpu_init(struct radeon_device *rdev)
{ {
u32 tiling_config; u32 tiling_config;
u32 ramcfg; u32 ramcfg;
u32 backend_map;
u32 cc_rb_backend_disable;
u32 cc_gc_shader_pipe_config;
u32 tmp; u32 tmp;
int i, j; int i, j;
u32 sq_config; u32 sq_config;
@ -1090,8 +1093,11 @@ void r600_gpu_init(struct radeon_device *rdev)
default: default:
break; break;
} }
rdev->config.r600.tiling_npipes = rdev->config.r600.max_tile_pipes;
rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
tiling_config |= GROUP_SIZE(0); tiling_config |= GROUP_SIZE(0);
rdev->config.r600.tiling_group_size = 256;
tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT; tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
if (tmp > 3) { if (tmp > 3) {
tiling_config |= ROW_TILING(3); tiling_config |= ROW_TILING(3);
@ -1101,24 +1107,33 @@ void r600_gpu_init(struct radeon_device *rdev)
tiling_config |= SAMPLE_SPLIT(tmp); tiling_config |= SAMPLE_SPLIT(tmp);
} }
tiling_config |= BANK_SWAPS(1); tiling_config |= BANK_SWAPS(1);
tmp = r600_get_tile_pipe_to_backend_map(rdev->config.r600.max_tile_pipes,
rdev->config.r600.max_backends, cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000;
(0xff << rdev->config.r600.max_backends) & 0xff); cc_rb_backend_disable |=
tiling_config |= BACKEND_MAP(tmp); BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << rdev->config.r600.max_backends) & R6XX_MAX_BACKENDS_MASK);
cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
cc_gc_shader_pipe_config |=
INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << rdev->config.r600.max_pipes) & R6XX_MAX_PIPES_MASK);
cc_gc_shader_pipe_config |=
INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << rdev->config.r600.max_simds) & R6XX_MAX_SIMDS_MASK);
backend_map = r600_get_tile_pipe_to_backend_map(rdev->config.r600.max_tile_pipes,
(R6XX_MAX_BACKENDS -
r600_count_pipe_bits((cc_rb_backend_disable &
R6XX_MAX_BACKENDS_MASK) >> 16)),
(cc_rb_backend_disable >> 16));
tiling_config |= BACKEND_MAP(backend_map);
WREG32(GB_TILING_CONFIG, tiling_config); WREG32(GB_TILING_CONFIG, tiling_config);
WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff); WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff);
WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff); WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff);
tmp = BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << rdev->config.r600.max_backends) & R6XX_MAX_BACKENDS_MASK);
WREG32(CC_RB_BACKEND_DISABLE, tmp);
/* Setup pipes */ /* Setup pipes */
tmp = INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << rdev->config.r600.max_pipes) & R6XX_MAX_PIPES_MASK); WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
tmp |= INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << rdev->config.r600.max_simds) & R6XX_MAX_SIMDS_MASK); WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
WREG32(CC_GC_SHADER_PIPE_CONFIG, tmp);
WREG32(GC_USER_SHADER_PIPE_CONFIG, tmp);
tmp = R6XX_MAX_BACKENDS - r600_count_pipe_bits(tmp & INACTIVE_QD_PIPES_MASK); tmp = R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8);
WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK); WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK);
WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((tmp * 4) - 2) & VTX_REUSE_DEPTH_MASK); WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((tmp * 4) - 2) & VTX_REUSE_DEPTH_MASK);
@ -1783,12 +1798,17 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence) struct radeon_fence *fence)
{ {
/* Also consider EVENT_WRITE_EOP. it handles the interrupts + timestamps + events */ /* Also consider EVENT_WRITE_EOP. it handles the interrupts + timestamps + events */
radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
/* wait for 3D idle clean */
radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
/* Emit fence sequence & fire IRQ */ /* Emit fence sequence & fire IRQ */
radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2)); radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
radeon_ring_write(rdev, fence->seq); radeon_ring_write(rdev, fence->seq);
radeon_ring_write(rdev, PACKET0(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0));
radeon_ring_write(rdev, 1);
/* CP_INTERRUPT packet 3 no longer exists, use packet 0 */ /* CP_INTERRUPT packet 3 no longer exists, use packet 0 */
radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0)); radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));
radeon_ring_write(rdev, RB_INT_STAT); radeon_ring_write(rdev, RB_INT_STAT);
@ -2745,6 +2765,7 @@ int r600_irq_process(struct radeon_device *rdev)
case 0: /* D1 vblank */ case 0: /* D1 vblank */
if (disp_int & LB_D1_VBLANK_INTERRUPT) { if (disp_int & LB_D1_VBLANK_INTERRUPT) {
drm_handle_vblank(rdev->ddev, 0); drm_handle_vblank(rdev->ddev, 0);
wake_up(&rdev->irq.vblank_queue);
disp_int &= ~LB_D1_VBLANK_INTERRUPT; disp_int &= ~LB_D1_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D1 vblank\n"); DRM_DEBUG("IH: D1 vblank\n");
} }
@ -2765,6 +2786,7 @@ int r600_irq_process(struct radeon_device *rdev)
case 0: /* D2 vblank */ case 0: /* D2 vblank */
if (disp_int & LB_D2_VBLANK_INTERRUPT) { if (disp_int & LB_D2_VBLANK_INTERRUPT) {
drm_handle_vblank(rdev->ddev, 1); drm_handle_vblank(rdev->ddev, 1);
wake_up(&rdev->irq.vblank_queue);
disp_int &= ~LB_D2_VBLANK_INTERRUPT; disp_int &= ~LB_D2_VBLANK_INTERRUPT;
DRM_DEBUG("IH: D2 vblank\n"); DRM_DEBUG("IH: D2 vblank\n");
} }

View File

@ -35,7 +35,7 @@
*/ */
static int r600_audio_chipset_supported(struct radeon_device *rdev) static int r600_audio_chipset_supported(struct radeon_device *rdev)
{ {
return (rdev->family >= CHIP_R600 && rdev->family < CHIP_RV710) return rdev->family >= CHIP_R600
|| rdev->family == CHIP_RS600 || rdev->family == CHIP_RS600
|| rdev->family == CHIP_RS690 || rdev->family == CHIP_RS690
|| rdev->family == CHIP_RS740; || rdev->family == CHIP_RS740;
@ -146,16 +146,24 @@ static void r600_audio_update_hdmi(unsigned long param)
jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL)); jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL));
} }
/*
* turn on/off audio engine
*/
static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
{
DRM_INFO("%s audio support", enable ? "Enabling" : "Disabling");
WREG32_P(R600_AUDIO_ENABLE, enable ? 0x81000000 : 0x0, ~0x81000000);
}
/* /*
* initialize the audio vars and register the update timer * initialize the audio vars and register the update timer
*/ */
int r600_audio_init(struct radeon_device *rdev) int r600_audio_init(struct radeon_device *rdev)
{ {
if (!r600_audio_chipset_supported(rdev)) if (!radeon_audio || !r600_audio_chipset_supported(rdev))
return 0; return 0;
DRM_INFO("%s audio support", radeon_audio ? "Enabling" : "Disabling"); r600_audio_engine_enable(rdev, true);
WREG32_P(R600_AUDIO_ENABLE, radeon_audio ? 0x81000000 : 0x0, ~0x81000000);
rdev->audio_channels = -1; rdev->audio_channels = -1;
rdev->audio_rate = -1; rdev->audio_rate = -1;
@ -258,9 +266,10 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
*/ */
void r600_audio_fini(struct radeon_device *rdev) void r600_audio_fini(struct radeon_device *rdev)
{ {
if (!r600_audio_chipset_supported(rdev)) if (!radeon_audio || !r600_audio_chipset_supported(rdev))
return; return;
del_timer(&rdev->audio_timer); del_timer(&rdev->audio_timer);
WREG32_P(R600_AUDIO_ENABLE, 0x0, ~0x81000000);
r600_audio_engine_enable(rdev, false);
} }

View File

@ -49,7 +49,7 @@ set_render_target(drm_radeon_private_t *dev_priv, int format, int w, int h, u64
RING_LOCALS; RING_LOCALS;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
h = (h + 7) & ~7; h = ALIGN(h, 8);
if (h < 8) if (h < 8)
h = 8; h = 8;

View File

@ -25,7 +25,7 @@ set_render_target(struct radeon_device *rdev, int format,
u32 cb_color_info; u32 cb_color_info;
int pitch, slice; int pitch, slice;
h = (h + 7) & ~7; h = ALIGN(h, 8);
if (h < 8) if (h < 8)
h = 8; h = 8;
@ -396,15 +396,13 @@ set_default_state(struct radeon_device *rdev)
NUM_ES_STACK_ENTRIES(num_es_stack_entries)); NUM_ES_STACK_ENTRIES(num_es_stack_entries));
/* emit an IB pointing at default state */ /* emit an IB pointing at default state */
dwords = (rdev->r600_blit.state_len + 0xf) & ~0xf; dwords = ALIGN(rdev->r600_blit.state_len, 0x10);
gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset; gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.state_offset;
radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); radeon_ring_write(rdev, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC); radeon_ring_write(rdev, gpu_addr & 0xFFFFFFFC);
radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF); radeon_ring_write(rdev, upper_32_bits(gpu_addr) & 0xFF);
radeon_ring_write(rdev, dwords); radeon_ring_write(rdev, dwords);
radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
/* SQ config */ /* SQ config */
radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 6)); radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 6));
radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_OFFSET) >> 2); radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
@ -578,9 +576,9 @@ int r600_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
ring_size = num_loops * dwords_per_loop; ring_size = num_loops * dwords_per_loop;
/* set default + shaders */ /* set default + shaders */
ring_size += 40; /* shaders + def state */ ring_size += 40; /* shaders + def state */
ring_size += 7; /* fence emit for VB IB */ ring_size += 10; /* fence emit for VB IB */
ring_size += 5; /* done copy */ ring_size += 5; /* done copy */
ring_size += 7; /* fence emit for done copy */ ring_size += 10; /* fence emit for done copy */
r = radeon_ring_lock(rdev, ring_size); r = radeon_ring_lock(rdev, ring_size);
if (r) if (r)
return r; return r;
@ -594,13 +592,6 @@ void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
{ {
int r; int r;
radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
/* wait for 3D idle clean */
radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
if (rdev->r600_blit.vb_ib) if (rdev->r600_blit.vb_ib)
r600_vb_ib_put(rdev); r600_vb_ib_put(rdev);

View File

@ -9,11 +9,6 @@ const u32 r6xx_default_state[] =
0xc0012800, 0xc0012800,
0x80000000, 0x80000000,
0x80000000, 0x80000000,
0xc0004600,
0x00000016,
0xc0016800,
0x00000010,
0x00028000,
0xc0016800, 0xc0016800,
0x00000010, 0x00000010,
0x00008000, 0x00008000,
@ -531,11 +526,6 @@ const u32 r7xx_default_state[] =
0xc0012800, 0xc0012800,
0x80000000, 0x80000000,
0x80000000, 0x80000000,
0xc0004600,
0x00000016,
0xc0016800,
0x00000010,
0x00028000,
0xc0016800, 0xc0016800,
0x00000010, 0x00000010,
0x00008000, 0x00008000,

View File

@ -734,8 +734,8 @@ static void r600_gfx_init(struct drm_device *dev,
u32 hdp_host_path_cntl; u32 hdp_host_path_cntl;
u32 backend_map; u32 backend_map;
u32 gb_tiling_config = 0; u32 gb_tiling_config = 0;
u32 cc_rb_backend_disable = 0; u32 cc_rb_backend_disable;
u32 cc_gc_shader_pipe_config = 0; u32 cc_gc_shader_pipe_config;
u32 ramcfg; u32 ramcfg;
/* setup chip specs */ /* setup chip specs */
@ -857,29 +857,44 @@ static void r600_gfx_init(struct drm_device *dev,
gb_tiling_config |= R600_BANK_SWAPS(1); gb_tiling_config |= R600_BANK_SWAPS(1);
backend_map = r600_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes, cc_rb_backend_disable = RADEON_READ(R600_CC_RB_BACKEND_DISABLE) & 0x00ff0000;
dev_priv->r600_max_backends, cc_rb_backend_disable |=
(0xff << dev_priv->r600_max_backends) & 0xff); R600_BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R6XX_MAX_BACKENDS_MASK);
gb_tiling_config |= R600_BACKEND_MAP(backend_map);
cc_gc_shader_pipe_config = cc_gc_shader_pipe_config = RADEON_READ(R600_CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
cc_gc_shader_pipe_config |=
R600_INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R6XX_MAX_PIPES_MASK); R600_INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R6XX_MAX_PIPES_MASK);
cc_gc_shader_pipe_config |= cc_gc_shader_pipe_config |=
R600_INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R6XX_MAX_SIMDS_MASK); R600_INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R6XX_MAX_SIMDS_MASK);
cc_rb_backend_disable = backend_map = r600_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
R600_BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R6XX_MAX_BACKENDS_MASK); (R6XX_MAX_BACKENDS -
r600_count_pipe_bits((cc_rb_backend_disable &
R6XX_MAX_BACKENDS_MASK) >> 16)),
(cc_rb_backend_disable >> 16));
gb_tiling_config |= R600_BACKEND_MAP(backend_map);
RADEON_WRITE(R600_GB_TILING_CONFIG, gb_tiling_config); RADEON_WRITE(R600_GB_TILING_CONFIG, gb_tiling_config);
RADEON_WRITE(R600_DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); RADEON_WRITE(R600_DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
RADEON_WRITE(R600_HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); RADEON_WRITE(R600_HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
if (gb_tiling_config & 0xc0) {
dev_priv->r600_group_size = 512;
} else {
dev_priv->r600_group_size = 256;
}
dev_priv->r600_npipes = 1 << ((gb_tiling_config >> 1) & 0x7);
if (gb_tiling_config & 0x30) {
dev_priv->r600_nbanks = 8;
} else {
dev_priv->r600_nbanks = 4;
}
RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
num_qd_pipes = num_qd_pipes =
R6XX_MAX_BACKENDS - r600_count_pipe_bits(cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK); R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK) >> 8);
RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK); RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK);
RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK); RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK);
@ -1151,7 +1166,8 @@ static void r600_gfx_init(struct drm_device *dev,
} }
static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes, static u32 r700_get_tile_pipe_to_backend_map(drm_radeon_private_t *dev_priv,
u32 num_tile_pipes,
u32 num_backends, u32 num_backends,
u32 backend_disable_mask) u32 backend_disable_mask)
{ {
@ -1162,6 +1178,7 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
u32 swizzle_pipe[R7XX_MAX_PIPES]; u32 swizzle_pipe[R7XX_MAX_PIPES];
u32 cur_backend; u32 cur_backend;
u32 i; u32 i;
bool force_no_swizzle;
if (num_tile_pipes > R7XX_MAX_PIPES) if (num_tile_pipes > R7XX_MAX_PIPES)
num_tile_pipes = R7XX_MAX_PIPES; num_tile_pipes = R7XX_MAX_PIPES;
@ -1191,6 +1208,18 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
if (enabled_backends_count != num_backends) if (enabled_backends_count != num_backends)
num_backends = enabled_backends_count; num_backends = enabled_backends_count;
switch (dev_priv->flags & RADEON_FAMILY_MASK) {
case CHIP_RV770:
case CHIP_RV730:
force_no_swizzle = false;
break;
case CHIP_RV710:
case CHIP_RV740:
default:
force_no_swizzle = true;
break;
}
memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES); memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES);
switch (num_tile_pipes) { switch (num_tile_pipes) {
case 1: case 1:
@ -1201,49 +1230,100 @@ static u32 r700_get_tile_pipe_to_backend_map(u32 num_tile_pipes,
swizzle_pipe[1] = 1; swizzle_pipe[1] = 1;
break; break;
case 3: case 3:
swizzle_pipe[0] = 0; if (force_no_swizzle) {
swizzle_pipe[1] = 2; swizzle_pipe[0] = 0;
swizzle_pipe[2] = 1; swizzle_pipe[1] = 1;
swizzle_pipe[2] = 2;
} else {
swizzle_pipe[0] = 0;
swizzle_pipe[1] = 2;
swizzle_pipe[2] = 1;
}
break; break;
case 4: case 4:
swizzle_pipe[0] = 0; if (force_no_swizzle) {
swizzle_pipe[1] = 2; swizzle_pipe[0] = 0;
swizzle_pipe[2] = 3; swizzle_pipe[1] = 1;
swizzle_pipe[3] = 1; swizzle_pipe[2] = 2;
swizzle_pipe[3] = 3;
} else {
swizzle_pipe[0] = 0;
swizzle_pipe[1] = 2;
swizzle_pipe[2] = 3;
swizzle_pipe[3] = 1;
}
break; break;
case 5: case 5:
swizzle_pipe[0] = 0; if (force_no_swizzle) {
swizzle_pipe[1] = 2; swizzle_pipe[0] = 0;
swizzle_pipe[2] = 4; swizzle_pipe[1] = 1;
swizzle_pipe[3] = 1; swizzle_pipe[2] = 2;
swizzle_pipe[4] = 3; swizzle_pipe[3] = 3;
swizzle_pipe[4] = 4;
} else {
swizzle_pipe[0] = 0;
swizzle_pipe[1] = 2;
swizzle_pipe[2] = 4;
swizzle_pipe[3] = 1;
swizzle_pipe[4] = 3;
}
break; break;
case 6: case 6:
swizzle_pipe[0] = 0; if (force_no_swizzle) {
swizzle_pipe[1] = 2; swizzle_pipe[0] = 0;
swizzle_pipe[2] = 4; swizzle_pipe[1] = 1;
swizzle_pipe[3] = 5; swizzle_pipe[2] = 2;
swizzle_pipe[4] = 3; swizzle_pipe[3] = 3;
swizzle_pipe[5] = 1; swizzle_pipe[4] = 4;
swizzle_pipe[5] = 5;
} else {
swizzle_pipe[0] = 0;
swizzle_pipe[1] = 2;
swizzle_pipe[2] = 4;
swizzle_pipe[3] = 5;
swizzle_pipe[4] = 3;
swizzle_pipe[5] = 1;
}
break; break;
case 7: case 7:
swizzle_pipe[0] = 0; if (force_no_swizzle) {
swizzle_pipe[1] = 2; swizzle_pipe[0] = 0;
swizzle_pipe[2] = 4; swizzle_pipe[1] = 1;
swizzle_pipe[3] = 6; swizzle_pipe[2] = 2;
swizzle_pipe[4] = 3; swizzle_pipe[3] = 3;
swizzle_pipe[5] = 1; swizzle_pipe[4] = 4;
swizzle_pipe[6] = 5; swizzle_pipe[5] = 5;
swizzle_pipe[6] = 6;
} else {
swizzle_pipe[0] = 0;
swizzle_pipe[1] = 2;
swizzle_pipe[2] = 4;
swizzle_pipe[3] = 6;
swizzle_pipe[4] = 3;
swizzle_pipe[5] = 1;
swizzle_pipe[6] = 5;
}
break; break;
case 8: case 8:
swizzle_pipe[0] = 0; if (force_no_swizzle) {
swizzle_pipe[1] = 2; swizzle_pipe[0] = 0;
swizzle_pipe[2] = 4; swizzle_pipe[1] = 1;
swizzle_pipe[3] = 6; swizzle_pipe[2] = 2;
swizzle_pipe[4] = 3; swizzle_pipe[3] = 3;
swizzle_pipe[5] = 1; swizzle_pipe[4] = 4;
swizzle_pipe[6] = 7; swizzle_pipe[5] = 5;
swizzle_pipe[7] = 5; swizzle_pipe[6] = 6;
swizzle_pipe[7] = 7;
} else {
swizzle_pipe[0] = 0;
swizzle_pipe[1] = 2;
swizzle_pipe[2] = 4;
swizzle_pipe[3] = 6;
swizzle_pipe[4] = 3;
swizzle_pipe[5] = 1;
swizzle_pipe[6] = 7;
swizzle_pipe[7] = 5;
}
break; break;
} }
@ -1264,8 +1344,10 @@ static void r700_gfx_init(struct drm_device *dev,
drm_radeon_private_t *dev_priv) drm_radeon_private_t *dev_priv)
{ {
int i, j, num_qd_pipes; int i, j, num_qd_pipes;
u32 ta_aux_cntl;
u32 sx_debug_1; u32 sx_debug_1;
u32 smx_dc_ctl0; u32 smx_dc_ctl0;
u32 db_debug3;
u32 num_gs_verts_per_thread; u32 num_gs_verts_per_thread;
u32 vgt_gs_per_es; u32 vgt_gs_per_es;
u32 gs_prim_buffer_depth = 0; u32 gs_prim_buffer_depth = 0;
@ -1276,8 +1358,8 @@ static void r700_gfx_init(struct drm_device *dev,
u32 sq_dyn_gpr_size_simd_ab_0; u32 sq_dyn_gpr_size_simd_ab_0;
u32 backend_map; u32 backend_map;
u32 gb_tiling_config = 0; u32 gb_tiling_config = 0;
u32 cc_rb_backend_disable = 0; u32 cc_rb_backend_disable;
u32 cc_gc_shader_pipe_config = 0; u32 cc_gc_shader_pipe_config;
u32 mc_arb_ramcfg; u32 mc_arb_ramcfg;
u32 db_debug4; u32 db_debug4;
@ -1428,38 +1510,51 @@ static void r700_gfx_init(struct drm_device *dev,
gb_tiling_config |= R600_BANK_SWAPS(1); gb_tiling_config |= R600_BANK_SWAPS(1);
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740) cc_rb_backend_disable = RADEON_READ(R600_CC_RB_BACKEND_DISABLE) & 0x00ff0000;
backend_map = 0x28; cc_rb_backend_disable |=
else R600_BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R7XX_MAX_BACKENDS_MASK);
backend_map = r700_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
dev_priv->r600_max_backends,
(0xff << dev_priv->r600_max_backends) & 0xff);
gb_tiling_config |= R600_BACKEND_MAP(backend_map);
cc_gc_shader_pipe_config = cc_gc_shader_pipe_config = RADEON_READ(R600_CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
cc_gc_shader_pipe_config |=
R600_INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R7XX_MAX_PIPES_MASK); R600_INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << dev_priv->r600_max_pipes) & R7XX_MAX_PIPES_MASK);
cc_gc_shader_pipe_config |= cc_gc_shader_pipe_config |=
R600_INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R7XX_MAX_SIMDS_MASK); R600_INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << dev_priv->r600_max_simds) & R7XX_MAX_SIMDS_MASK);
cc_rb_backend_disable = if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740)
R600_BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << dev_priv->r600_max_backends) & R7XX_MAX_BACKENDS_MASK); backend_map = 0x28;
else
backend_map = r700_get_tile_pipe_to_backend_map(dev_priv,
dev_priv->r600_max_tile_pipes,
(R7XX_MAX_BACKENDS -
r600_count_pipe_bits((cc_rb_backend_disable &
R7XX_MAX_BACKENDS_MASK) >> 16)),
(cc_rb_backend_disable >> 16));
gb_tiling_config |= R600_BACKEND_MAP(backend_map);
RADEON_WRITE(R600_GB_TILING_CONFIG, gb_tiling_config); RADEON_WRITE(R600_GB_TILING_CONFIG, gb_tiling_config);
RADEON_WRITE(R600_DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); RADEON_WRITE(R600_DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
RADEON_WRITE(R600_HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); RADEON_WRITE(R600_HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
if (gb_tiling_config & 0xc0) {
dev_priv->r600_group_size = 512;
} else {
dev_priv->r600_group_size = 256;
}
dev_priv->r600_npipes = 1 << ((gb_tiling_config >> 1) & 0x7);
if (gb_tiling_config & 0x30) {
dev_priv->r600_nbanks = 8;
} else {
dev_priv->r600_nbanks = 4;
}
RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); RADEON_WRITE(R600_CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); RADEON_WRITE(R600_CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
RADEON_WRITE(R600_GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
RADEON_WRITE(R700_CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); RADEON_WRITE(R700_CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
RADEON_WRITE(R700_CGTS_SYS_TCC_DISABLE, 0); RADEON_WRITE(R700_CGTS_SYS_TCC_DISABLE, 0);
RADEON_WRITE(R700_CGTS_TCC_DISABLE, 0); RADEON_WRITE(R700_CGTS_TCC_DISABLE, 0);
RADEON_WRITE(R700_CGTS_USER_SYS_TCC_DISABLE, 0);
RADEON_WRITE(R700_CGTS_USER_TCC_DISABLE, 0);
num_qd_pipes = num_qd_pipes =
R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK); R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & R600_INACTIVE_QD_PIPES_MASK) >> 8);
RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK); RADEON_WRITE(R600_VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & R600_DEALLOC_DIST_MASK);
RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK); RADEON_WRITE(R600_VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & R600_VTX_REUSE_DEPTH_MASK);
@ -1469,10 +1564,8 @@ static void r700_gfx_init(struct drm_device *dev,
RADEON_WRITE(R600_CP_MEQ_THRESHOLDS, R700_STQ_SPLIT(0x30)); RADEON_WRITE(R600_CP_MEQ_THRESHOLDS, R700_STQ_SPLIT(0x30));
RADEON_WRITE(R600_TA_CNTL_AUX, (R600_DISABLE_CUBE_ANISO | ta_aux_cntl = RADEON_READ(R600_TA_CNTL_AUX);
R600_SYNC_GRADIENT | RADEON_WRITE(R600_TA_CNTL_AUX, ta_aux_cntl | R600_DISABLE_CUBE_ANISO);
R600_SYNC_WALKER |
R600_SYNC_ALIGNER));
sx_debug_1 = RADEON_READ(R700_SX_DEBUG_1); sx_debug_1 = RADEON_READ(R700_SX_DEBUG_1);
sx_debug_1 |= R700_ENABLE_NEW_SMX_ADDRESS; sx_debug_1 |= R700_ENABLE_NEW_SMX_ADDRESS;
@ -1483,14 +1576,28 @@ static void r700_gfx_init(struct drm_device *dev,
smx_dc_ctl0 |= R700_CACHE_DEPTH((dev_priv->r700_sx_num_of_sets * 64) - 1); smx_dc_ctl0 |= R700_CACHE_DEPTH((dev_priv->r700_sx_num_of_sets * 64) - 1);
RADEON_WRITE(R600_SMX_DC_CTL0, smx_dc_ctl0); RADEON_WRITE(R600_SMX_DC_CTL0, smx_dc_ctl0);
RADEON_WRITE(R700_SMX_EVENT_CTL, (R700_ES_FLUSH_CTL(4) | if ((dev_priv->flags & RADEON_FAMILY_MASK) != CHIP_RV740)
R700_GS_FLUSH_CTL(4) | RADEON_WRITE(R700_SMX_EVENT_CTL, (R700_ES_FLUSH_CTL(4) |
R700_ACK_FLUSH_CTL(3) | R700_GS_FLUSH_CTL(4) |
R700_SYNC_FLUSH_CTL)); R700_ACK_FLUSH_CTL(3) |
R700_SYNC_FLUSH_CTL));
if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV770) db_debug3 = RADEON_READ(R700_DB_DEBUG3);
RADEON_WRITE(R700_DB_DEBUG3, R700_DB_CLK_OFF_DELAY(0x1f)); db_debug3 &= ~R700_DB_CLK_OFF_DELAY(0x1f);
else { switch (dev_priv->flags & RADEON_FAMILY_MASK) {
case CHIP_RV770:
case CHIP_RV740:
db_debug3 |= R700_DB_CLK_OFF_DELAY(0x1f);
break;
case CHIP_RV710:
case CHIP_RV730:
default:
db_debug3 |= R700_DB_CLK_OFF_DELAY(2);
break;
}
RADEON_WRITE(R700_DB_DEBUG3, db_debug3);
if ((dev_priv->flags & RADEON_FAMILY_MASK) != CHIP_RV770) {
db_debug4 = RADEON_READ(RV700_DB_DEBUG4); db_debug4 = RADEON_READ(RV700_DB_DEBUG4);
db_debug4 |= RV700_DISABLE_TILE_COVERED_FOR_PS_ITER; db_debug4 |= RV700_DISABLE_TILE_COVERED_FOR_PS_ITER;
RADEON_WRITE(RV700_DB_DEBUG4, db_debug4); RADEON_WRITE(RV700_DB_DEBUG4, db_debug4);
@ -1519,10 +1626,10 @@ static void r700_gfx_init(struct drm_device *dev,
R600_ALU_UPDATE_FIFO_HIWATER(0x8)); R600_ALU_UPDATE_FIFO_HIWATER(0x8));
switch (dev_priv->flags & RADEON_FAMILY_MASK) { switch (dev_priv->flags & RADEON_FAMILY_MASK) {
case CHIP_RV770: case CHIP_RV770:
sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x1);
break;
case CHIP_RV730: case CHIP_RV730:
case CHIP_RV710: case CHIP_RV710:
sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x1);
break;
case CHIP_RV740: case CHIP_RV740:
default: default:
sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4); sq_ms_fifo_sizes |= R600_FETCH_FIFO_HIWATER(0x4);
@ -2529,3 +2636,12 @@ int r600_cs_legacy_ioctl(struct drm_device *dev, void *data, struct drm_file *fp
mutex_unlock(&dev_priv->cs_mutex); mutex_unlock(&dev_priv->cs_mutex);
return r; return r;
} }
void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size)
{
struct drm_radeon_private *dev_priv = dev->dev_private;
*npipes = dev_priv->r600_npipes;
*nbanks = dev_priv->r600_nbanks;
*group_size = dev_priv->r600_group_size;
}

View File

@ -28,6 +28,7 @@
#include "drmP.h" #include "drmP.h"
#include "radeon.h" #include "radeon.h"
#include "r600d.h" #include "r600d.h"
#include "r600_reg_safe.h"
static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p, static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc); struct radeon_cs_reloc **cs_reloc);
@ -35,11 +36,313 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
struct radeon_cs_reloc **cs_reloc); struct radeon_cs_reloc **cs_reloc);
typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**); typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**);
static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm; static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm;
extern void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size);
struct r600_cs_track { struct r600_cs_track {
u32 cb_color0_base_last; /* configuration we miror so that we use same code btw kms/ums */
u32 group_size;
u32 nbanks;
u32 npipes;
/* value we track */
u32 nsamples;
u32 cb_color_base_last[8];
struct radeon_bo *cb_color_bo[8];
u32 cb_color_bo_offset[8];
struct radeon_bo *cb_color_frag_bo[8];
struct radeon_bo *cb_color_tile_bo[8];
u32 cb_color_info[8];
u32 cb_color_size_idx[8];
u32 cb_target_mask;
u32 cb_shader_mask;
u32 cb_color_size[8];
u32 vgt_strmout_en;
u32 vgt_strmout_buffer_en;
u32 db_depth_control;
u32 db_depth_info;
u32 db_depth_size_idx;
u32 db_depth_view;
u32 db_depth_size;
u32 db_offset;
struct radeon_bo *db_bo;
}; };
static inline int r600_bpe_from_format(u32 *bpe, u32 format)
{
switch (format) {
case V_038004_COLOR_8:
case V_038004_COLOR_4_4:
case V_038004_COLOR_3_3_2:
case V_038004_FMT_1:
*bpe = 1;
break;
case V_038004_COLOR_16:
case V_038004_COLOR_16_FLOAT:
case V_038004_COLOR_8_8:
case V_038004_COLOR_5_6_5:
case V_038004_COLOR_6_5_5:
case V_038004_COLOR_1_5_5_5:
case V_038004_COLOR_4_4_4_4:
case V_038004_COLOR_5_5_5_1:
*bpe = 2;
break;
case V_038004_FMT_8_8_8:
*bpe = 3;
break;
case V_038004_COLOR_32:
case V_038004_COLOR_32_FLOAT:
case V_038004_COLOR_16_16:
case V_038004_COLOR_16_16_FLOAT:
case V_038004_COLOR_8_24:
case V_038004_COLOR_8_24_FLOAT:
case V_038004_COLOR_24_8:
case V_038004_COLOR_24_8_FLOAT:
case V_038004_COLOR_10_11_11:
case V_038004_COLOR_10_11_11_FLOAT:
case V_038004_COLOR_11_11_10:
case V_038004_COLOR_11_11_10_FLOAT:
case V_038004_COLOR_2_10_10_10:
case V_038004_COLOR_8_8_8_8:
case V_038004_COLOR_10_10_10_2:
case V_038004_FMT_5_9_9_9_SHAREDEXP:
case V_038004_FMT_32_AS_8:
case V_038004_FMT_32_AS_8_8:
*bpe = 4;
break;
case V_038004_COLOR_X24_8_32_FLOAT:
case V_038004_COLOR_32_32:
case V_038004_COLOR_32_32_FLOAT:
case V_038004_COLOR_16_16_16_16:
case V_038004_COLOR_16_16_16_16_FLOAT:
*bpe = 8;
break;
case V_038004_FMT_16_16_16:
case V_038004_FMT_16_16_16_FLOAT:
*bpe = 6;
break;
case V_038004_FMT_32_32_32:
case V_038004_FMT_32_32_32_FLOAT:
*bpe = 12;
break;
case V_038004_COLOR_32_32_32_32:
case V_038004_COLOR_32_32_32_32_FLOAT:
*bpe = 16;
break;
case V_038004_FMT_GB_GR:
case V_038004_FMT_BG_RG:
case V_038004_COLOR_INVALID:
*bpe = 16;
return -EINVAL;
}
return 0;
}
static void r600_cs_track_init(struct r600_cs_track *track)
{
int i;
for (i = 0; i < 8; i++) {
track->cb_color_base_last[i] = 0;
track->cb_color_size[i] = 0;
track->cb_color_size_idx[i] = 0;
track->cb_color_info[i] = 0;
track->cb_color_bo[i] = NULL;
track->cb_color_bo_offset[i] = 0xFFFFFFFF;
}
track->cb_target_mask = 0xFFFFFFFF;
track->cb_shader_mask = 0xFFFFFFFF;
track->db_bo = NULL;
/* assume the biggest format and that htile is enabled */
track->db_depth_info = 7 | (1 << 25);
track->db_depth_view = 0xFFFFC000;
track->db_depth_size = 0xFFFFFFFF;
track->db_depth_size_idx = 0;
track->db_depth_control = 0xFFFFFFFF;
}
static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
{
struct r600_cs_track *track = p->track;
u32 bpe = 0, pitch, slice_tile_max, size, tmp, height;
volatile u32 *ib = p->ib->ptr;
if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
return -EINVAL;
}
size = radeon_bo_size(track->cb_color_bo[i]);
if (r600_bpe_from_format(&bpe, G_0280A0_FORMAT(track->cb_color_info[i]))) {
dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
__func__, __LINE__, G_0280A0_FORMAT(track->cb_color_info[i]),
i, track->cb_color_info[i]);
return -EINVAL;
}
pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) << 3;
slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
if (!pitch) {
dev_warn(p->dev, "%s:%d cb pitch (%d) for %d invalid (0x%08X)\n",
__func__, __LINE__, pitch, i, track->cb_color_size[i]);
return -EINVAL;
}
height = size / (pitch * bpe);
if (height > 8192)
height = 8192;
switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
case V_0280A0_ARRAY_LINEAR_GENERAL:
case V_0280A0_ARRAY_LINEAR_ALIGNED:
if (pitch & 0x3f) {
dev_warn(p->dev, "%s:%d cb pitch (%d x %d = %d) invalid\n",
__func__, __LINE__, pitch, bpe, pitch * bpe);
return -EINVAL;
}
if ((pitch * bpe) & (track->group_size - 1)) {
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
__func__, __LINE__, pitch);
return -EINVAL;
}
break;
case V_0280A0_ARRAY_1D_TILED_THIN1:
if ((pitch * 8 * bpe * track->nsamples) & (track->group_size - 1)) {
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
__func__, __LINE__, pitch);
return -EINVAL;
}
height &= ~0x7;
if (!height)
height = 8;
break;
case V_0280A0_ARRAY_2D_TILED_THIN1:
if (pitch & ((8 * track->nbanks) - 1)) {
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
__func__, __LINE__, pitch);
return -EINVAL;
}
tmp = pitch * 8 * bpe * track->nsamples;
tmp = tmp / track->nbanks;
if (tmp & (track->group_size - 1)) {
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
__func__, __LINE__, pitch);
return -EINVAL;
}
height &= ~((16 * track->npipes) - 1);
if (!height)
height = 16 * track->npipes;
break;
default:
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
track->cb_color_info[i]);
return -EINVAL;
}
/* check offset */
tmp = height * pitch;
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
dev_warn(p->dev, "%s offset[%d] %d to big\n", __func__, i, track->cb_color_bo_offset[i]);
return -EINVAL;
}
/* limit max tile */
tmp = (height * pitch) >> 6;
if (tmp < slice_tile_max)
slice_tile_max = tmp;
tmp = S_028060_PITCH_TILE_MAX((pitch >> 3) - 1) |
S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
ib[track->cb_color_size_idx[i]] = tmp;
return 0;
}
static int r600_cs_track_check(struct radeon_cs_parser *p)
{
struct r600_cs_track *track = p->track;
u32 tmp;
int r, i;
volatile u32 *ib = p->ib->ptr;
/* on legacy kernel we don't perform advanced check */
if (p->rdev == NULL)
return 0;
/* we don't support out buffer yet */
if (track->vgt_strmout_en || track->vgt_strmout_buffer_en) {
dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
return -EINVAL;
}
/* check that we have a cb for each enabled target, we don't check
* shader_mask because it seems mesa isn't always setting it :(
*/
tmp = track->cb_target_mask;
for (i = 0; i < 8; i++) {
if ((tmp >> (i * 4)) & 0xF) {
/* at least one component is enabled */
if (track->cb_color_bo[i] == NULL) {
dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
return -EINVAL;
}
/* perform rewrite of CB_COLOR[0-7]_SIZE */
r = r600_cs_track_validate_cb(p, i);
if (r)
return r;
}
}
/* Check depth buffer */
if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
G_028800_Z_ENABLE(track->db_depth_control)) {
u32 nviews, bpe, ntiles;
if (track->db_bo == NULL) {
dev_warn(p->dev, "z/stencil with no depth buffer\n");
return -EINVAL;
}
if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
dev_warn(p->dev, "this kernel doesn't support z/stencil htile\n");
return -EINVAL;
}
switch (G_028010_FORMAT(track->db_depth_info)) {
case V_028010_DEPTH_16:
bpe = 2;
break;
case V_028010_DEPTH_X8_24:
case V_028010_DEPTH_8_24:
case V_028010_DEPTH_X8_24_FLOAT:
case V_028010_DEPTH_8_24_FLOAT:
case V_028010_DEPTH_32_FLOAT:
bpe = 4;
break;
case V_028010_DEPTH_X24_8_32_FLOAT:
bpe = 8;
break;
default:
dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
return -EINVAL;
}
if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
if (!track->db_depth_size_idx) {
dev_warn(p->dev, "z/stencil buffer size not set\n");
return -EINVAL;
}
printk_once(KERN_WARNING "You have old & broken userspace please consider updating mesa\n");
tmp = radeon_bo_size(track->db_bo) - track->db_offset;
tmp = (tmp / bpe) >> 6;
if (!tmp) {
dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
track->db_depth_size, bpe, track->db_offset,
radeon_bo_size(track->db_bo));
return -EINVAL;
}
ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
} else {
ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
tmp = ntiles * bpe * 64 * nviews;
if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n",
track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
radeon_bo_size(track->db_bo));
return -EINVAL;
}
}
}
return 0;
}
/** /**
* r600_cs_packet_parse() - parse cp packet and point ib index to next packet * r600_cs_packet_parse() - parse cp packet and point ib index to next packet
* @parser: parser structure holding parsing context. * @parser: parser structure holding parsing context.
@ -359,6 +662,334 @@ static int r600_cs_parse_packet0(struct radeon_cs_parser *p,
return 0; return 0;
} }
/**
* r600_cs_check_reg() - check if register is authorized or not
* @parser: parser structure holding parsing context
* @reg: register we are testing
* @idx: index into the cs buffer
*
* This function will test against r600_reg_safe_bm and return 0
* if register is safe. If register is not flag as safe this function
* will test it against a list of register needind special handling.
*/
static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
{
struct r600_cs_track *track = (struct r600_cs_track *)p->track;
struct radeon_cs_reloc *reloc;
u32 last_reg = ARRAY_SIZE(r600_reg_safe_bm);
u32 m, i, tmp, *ib;
int r;
i = (reg >> 7);
if (i > last_reg) {
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
return -EINVAL;
}
m = 1 << ((reg >> 2) & 31);
if (!(r600_reg_safe_bm[i] & m))
return 0;
ib = p->ib->ptr;
switch (reg) {
/* force following reg to 0 in an attemp to disable out buffer
* which will need us to better understand how it works to perform
* security check on it (Jerome)
*/
case R_0288A8_SQ_ESGS_RING_ITEMSIZE:
case R_008C44_SQ_ESGS_RING_SIZE:
case R_0288B0_SQ_ESTMP_RING_ITEMSIZE:
case R_008C54_SQ_ESTMP_RING_SIZE:
case R_0288C0_SQ_FBUF_RING_ITEMSIZE:
case R_008C74_SQ_FBUF_RING_SIZE:
case R_0288B4_SQ_GSTMP_RING_ITEMSIZE:
case R_008C5C_SQ_GSTMP_RING_SIZE:
case R_0288AC_SQ_GSVS_RING_ITEMSIZE:
case R_008C4C_SQ_GSVS_RING_SIZE:
case R_0288BC_SQ_PSTMP_RING_ITEMSIZE:
case R_008C6C_SQ_PSTMP_RING_SIZE:
case R_0288C4_SQ_REDUC_RING_ITEMSIZE:
case R_008C7C_SQ_REDUC_RING_SIZE:
case R_0288B8_SQ_VSTMP_RING_ITEMSIZE:
case R_008C64_SQ_VSTMP_RING_SIZE:
case R_0288C8_SQ_GS_VERT_ITEMSIZE:
/* get value to populate the IB don't remove */
tmp =radeon_get_ib_value(p, idx);
ib[idx] = 0;
break;
case R_028800_DB_DEPTH_CONTROL:
track->db_depth_control = radeon_get_ib_value(p, idx);
break;
case R_028010_DB_DEPTH_INFO:
track->db_depth_info = radeon_get_ib_value(p, idx);
break;
case R_028004_DB_DEPTH_VIEW:
track->db_depth_view = radeon_get_ib_value(p, idx);
break;
case R_028000_DB_DEPTH_SIZE:
track->db_depth_size = radeon_get_ib_value(p, idx);
track->db_depth_size_idx = idx;
break;
case R_028AB0_VGT_STRMOUT_EN:
track->vgt_strmout_en = radeon_get_ib_value(p, idx);
break;
case R_028B20_VGT_STRMOUT_BUFFER_EN:
track->vgt_strmout_buffer_en = radeon_get_ib_value(p, idx);
break;
case R_028238_CB_TARGET_MASK:
track->cb_target_mask = radeon_get_ib_value(p, idx);
break;
case R_02823C_CB_SHADER_MASK:
track->cb_shader_mask = radeon_get_ib_value(p, idx);
break;
case R_028C04_PA_SC_AA_CONFIG:
tmp = G_028C04_MSAA_NUM_SAMPLES(radeon_get_ib_value(p, idx));
track->nsamples = 1 << tmp;
break;
case R_0280A0_CB_COLOR0_INFO:
case R_0280A4_CB_COLOR1_INFO:
case R_0280A8_CB_COLOR2_INFO:
case R_0280AC_CB_COLOR3_INFO:
case R_0280B0_CB_COLOR4_INFO:
case R_0280B4_CB_COLOR5_INFO:
case R_0280B8_CB_COLOR6_INFO:
case R_0280BC_CB_COLOR7_INFO:
tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
break;
case R_028060_CB_COLOR0_SIZE:
case R_028064_CB_COLOR1_SIZE:
case R_028068_CB_COLOR2_SIZE:
case R_02806C_CB_COLOR3_SIZE:
case R_028070_CB_COLOR4_SIZE:
case R_028074_CB_COLOR5_SIZE:
case R_028078_CB_COLOR6_SIZE:
case R_02807C_CB_COLOR7_SIZE:
tmp = (reg - R_028060_CB_COLOR0_SIZE) / 4;
track->cb_color_size[tmp] = radeon_get_ib_value(p, idx);
track->cb_color_size_idx[tmp] = idx;
break;
/* This register were added late, there is userspace
* which does provide relocation for those but set
* 0 offset. In order to avoid breaking old userspace
* we detect this and set address to point to last
* CB_COLOR0_BASE, note that if userspace doesn't set
* CB_COLOR0_BASE before this register we will report
* error. Old userspace always set CB_COLOR0_BASE
* before any of this.
*/
case R_0280E0_CB_COLOR0_FRAG:
case R_0280E4_CB_COLOR1_FRAG:
case R_0280E8_CB_COLOR2_FRAG:
case R_0280EC_CB_COLOR3_FRAG:
case R_0280F0_CB_COLOR4_FRAG:
case R_0280F4_CB_COLOR5_FRAG:
case R_0280F8_CB_COLOR6_FRAG:
case R_0280FC_CB_COLOR7_FRAG:
tmp = (reg - R_0280E0_CB_COLOR0_FRAG) / 4;
if (!r600_cs_packet_next_is_pkt3_nop(p)) {
if (!track->cb_color_base_last[tmp]) {
dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
return -EINVAL;
}
ib[idx] = track->cb_color_base_last[tmp];
printk_once(KERN_WARNING "You have old & broken userspace "
"please consider updating mesa & xf86-video-ati\n");
track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp];
} else {
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
return -EINVAL;
}
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->cb_color_frag_bo[tmp] = reloc->robj;
}
break;
case R_0280C0_CB_COLOR0_TILE:
case R_0280C4_CB_COLOR1_TILE:
case R_0280C8_CB_COLOR2_TILE:
case R_0280CC_CB_COLOR3_TILE:
case R_0280D0_CB_COLOR4_TILE:
case R_0280D4_CB_COLOR5_TILE:
case R_0280D8_CB_COLOR6_TILE:
case R_0280DC_CB_COLOR7_TILE:
tmp = (reg - R_0280C0_CB_COLOR0_TILE) / 4;
if (!r600_cs_packet_next_is_pkt3_nop(p)) {
if (!track->cb_color_base_last[tmp]) {
dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
return -EINVAL;
}
ib[idx] = track->cb_color_base_last[tmp];
printk_once(KERN_WARNING "You have old & broken userspace "
"please consider updating mesa & xf86-video-ati\n");
track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp];
} else {
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
return -EINVAL;
}
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->cb_color_tile_bo[tmp] = reloc->robj;
}
break;
case CB_COLOR0_BASE:
case CB_COLOR1_BASE:
case CB_COLOR2_BASE:
case CB_COLOR3_BASE:
case CB_COLOR4_BASE:
case CB_COLOR5_BASE:
case CB_COLOR6_BASE:
case CB_COLOR7_BASE:
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
dev_warn(p->dev, "bad SET_CONTEXT_REG "
"0x%04X\n", reg);
return -EINVAL;
}
tmp = (reg - CB_COLOR0_BASE) / 4;
track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->cb_color_base_last[tmp] = ib[idx];
track->cb_color_bo[tmp] = reloc->robj;
break;
case DB_DEPTH_BASE:
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
dev_warn(p->dev, "bad SET_CONTEXT_REG "
"0x%04X\n", reg);
return -EINVAL;
}
track->db_offset = radeon_get_ib_value(p, idx);
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->db_bo = reloc->robj;
break;
case DB_HTILE_DATA_BASE:
case SQ_PGM_START_FS:
case SQ_PGM_START_ES:
case SQ_PGM_START_VS:
case SQ_PGM_START_GS:
case SQ_PGM_START_PS:
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
dev_warn(p->dev, "bad SET_CONTEXT_REG "
"0x%04X\n", reg);
return -EINVAL;
}
ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
break;
default:
dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
return -EINVAL;
}
return 0;
}
static inline unsigned minify(unsigned size, unsigned levels)
{
size = size >> levels;
if (size < 1)
size = 1;
return size;
}
static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels,
unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
unsigned *l0_size, unsigned *mipmap_size)
{
unsigned offset, i, level, face;
unsigned width, height, depth, rowstride, size;
w0 = minify(w0, 0);
h0 = minify(h0, 0);
d0 = minify(d0, 0);
for(i = 0, offset = 0, level = blevel; i < nlevels; i++, level++) {
width = minify(w0, i);
height = minify(h0, i);
depth = minify(d0, i);
for(face = 0; face < nfaces; face++) {
rowstride = ((width * bpe) + 255) & ~255;
size = height * rowstride * depth;
offset += size;
offset = (offset + 0x1f) & ~0x1f;
}
}
*l0_size = (((w0 * bpe) + 255) & ~255) * h0 * d0;
*mipmap_size = offset;
if (!blevel)
*mipmap_size -= *l0_size;
if (!nlevels)
*mipmap_size = *l0_size;
}
/**
* r600_check_texture_resource() - check if register is authorized or not
* @p: parser structure holding parsing context
* @idx: index into the cs buffer
* @texture: texture's bo structure
* @mipmap: mipmap's bo structure
*
* This function will check that the resource has valid field and that
* the texture and mipmap bo object are big enough to cover this resource.
*/
static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
struct radeon_bo *texture,
struct radeon_bo *mipmap)
{
u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
u32 word0, word1, l0_size, mipmap_size;
/* on legacy kernel we don't perform advanced check */
if (p->rdev == NULL)
return 0;
word0 = radeon_get_ib_value(p, idx + 0);
word1 = radeon_get_ib_value(p, idx + 1);
w0 = G_038000_TEX_WIDTH(word0) + 1;
h0 = G_038004_TEX_HEIGHT(word1) + 1;
d0 = G_038004_TEX_DEPTH(word1);
nfaces = 1;
switch (G_038000_DIM(word0)) {
case V_038000_SQ_TEX_DIM_1D:
case V_038000_SQ_TEX_DIM_2D:
case V_038000_SQ_TEX_DIM_3D:
break;
case V_038000_SQ_TEX_DIM_CUBEMAP:
nfaces = 6;
break;
case V_038000_SQ_TEX_DIM_1D_ARRAY:
case V_038000_SQ_TEX_DIM_2D_ARRAY:
case V_038000_SQ_TEX_DIM_2D_MSAA:
case V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA:
default:
dev_warn(p->dev, "this kernel doesn't support %d texture dim\n", G_038000_DIM(word0));
return -EINVAL;
}
if (r600_bpe_from_format(&bpe, G_038004_DATA_FORMAT(word1))) {
dev_warn(p->dev, "%s:%d texture invalid format %d\n",
__func__, __LINE__, G_038004_DATA_FORMAT(word1));
return -EINVAL;
}
word0 = radeon_get_ib_value(p, idx + 4);
word1 = radeon_get_ib_value(p, idx + 5);
blevel = G_038010_BASE_LEVEL(word0);
nlevels = G_038014_LAST_LEVEL(word1);
r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe, &l0_size, &mipmap_size);
/* using get ib will give us the offset into the texture bo */
word0 = radeon_get_ib_value(p, idx + 2);
if ((l0_size + word0) > radeon_bo_size(texture)) {
dev_warn(p->dev, "texture bo too small (%d %d %d %d -> %d have %ld)\n",
w0, h0, bpe, word0, l0_size, radeon_bo_size(texture));
return -EINVAL;
}
/* using get ib will give us the offset into the mipmap bo */
word0 = radeon_get_ib_value(p, idx + 3);
if ((mipmap_size + word0) > radeon_bo_size(mipmap)) {
dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));
return -EINVAL;
}
return 0;
}
static int r600_packet3_check(struct radeon_cs_parser *p, static int r600_packet3_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt) struct radeon_cs_packet *pkt)
{ {
@ -408,12 +1039,22 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
} }
ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
r = r600_cs_track_check(p);
if (r) {
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
return r;
}
break; break;
case PACKET3_DRAW_INDEX_AUTO: case PACKET3_DRAW_INDEX_AUTO:
if (pkt->count != 1) { if (pkt->count != 1) {
DRM_ERROR("bad DRAW_INDEX_AUTO\n"); DRM_ERROR("bad DRAW_INDEX_AUTO\n");
return -EINVAL; return -EINVAL;
} }
r = r600_cs_track_check(p);
if (r) {
dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
return r;
}
break; break;
case PACKET3_DRAW_INDEX_IMMD_BE: case PACKET3_DRAW_INDEX_IMMD_BE:
case PACKET3_DRAW_INDEX_IMMD: case PACKET3_DRAW_INDEX_IMMD:
@ -421,6 +1062,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
DRM_ERROR("bad DRAW_INDEX_IMMD\n"); DRM_ERROR("bad DRAW_INDEX_IMMD\n");
return -EINVAL; return -EINVAL;
} }
r = r600_cs_track_check(p);
if (r) {
dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
return r;
}
break; break;
case PACKET3_WAIT_REG_MEM: case PACKET3_WAIT_REG_MEM:
if (pkt->count != 5) { if (pkt->count != 5) {
@ -493,30 +1139,9 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
} }
for (i = 0; i < pkt->count; i++) { for (i = 0; i < pkt->count; i++) {
reg = start_reg + (4 * i); reg = start_reg + (4 * i);
switch (reg) { r = r600_cs_check_reg(p, reg, idx+1+i);
case SQ_ESGS_RING_BASE: if (r)
case SQ_GSVS_RING_BASE: return r;
case SQ_ESTMP_RING_BASE:
case SQ_GSTMP_RING_BASE:
case SQ_VSTMP_RING_BASE:
case SQ_PSTMP_RING_BASE:
case SQ_FBUF_RING_BASE:
case SQ_REDUC_RING_BASE:
case SX_MEMORY_EXPORT_BASE:
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
DRM_ERROR("bad SET_CONFIG_REG "
"0x%04X\n", reg);
return -EINVAL;
}
ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
break;
case CP_COHER_BASE:
/* use PACKET3_SURFACE_SYNC */
return -EINVAL;
default:
break;
}
} }
break; break;
case PACKET3_SET_CONTEXT_REG: case PACKET3_SET_CONTEXT_REG:
@ -530,106 +1155,9 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
} }
for (i = 0; i < pkt->count; i++) { for (i = 0; i < pkt->count; i++) {
reg = start_reg + (4 * i); reg = start_reg + (4 * i);
switch (reg) { r = r600_cs_check_reg(p, reg, idx+1+i);
/* This register were added late, there is userspace if (r)
* which does provide relocation for those but set return r;
* 0 offset. In order to avoid breaking old userspace
* we detect this and set address to point to last
* CB_COLOR0_BASE, note that if userspace doesn't set
* CB_COLOR0_BASE before this register we will report
* error. Old userspace always set CB_COLOR0_BASE
* before any of this.
*/
case R_0280E0_CB_COLOR0_FRAG:
case R_0280E4_CB_COLOR1_FRAG:
case R_0280E8_CB_COLOR2_FRAG:
case R_0280EC_CB_COLOR3_FRAG:
case R_0280F0_CB_COLOR4_FRAG:
case R_0280F4_CB_COLOR5_FRAG:
case R_0280F8_CB_COLOR6_FRAG:
case R_0280FC_CB_COLOR7_FRAG:
case R_0280C0_CB_COLOR0_TILE:
case R_0280C4_CB_COLOR1_TILE:
case R_0280C8_CB_COLOR2_TILE:
case R_0280CC_CB_COLOR3_TILE:
case R_0280D0_CB_COLOR4_TILE:
case R_0280D4_CB_COLOR5_TILE:
case R_0280D8_CB_COLOR6_TILE:
case R_0280DC_CB_COLOR7_TILE:
if (!r600_cs_packet_next_is_pkt3_nop(p)) {
if (!track->cb_color0_base_last) {
dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg);
return -EINVAL;
}
ib[idx+1+i] = track->cb_color0_base_last;
printk_once(KERN_WARNING "radeon: You have old & broken userspace "
"please consider updating mesa & xf86-video-ati\n");
} else {
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
return -EINVAL;
}
ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
}
break;
case DB_DEPTH_BASE:
case DB_HTILE_DATA_BASE:
case CB_COLOR0_BASE:
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
DRM_ERROR("bad SET_CONTEXT_REG "
"0x%04X\n", reg);
return -EINVAL;
}
ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
track->cb_color0_base_last = ib[idx+1+i];
break;
case CB_COLOR1_BASE:
case CB_COLOR2_BASE:
case CB_COLOR3_BASE:
case CB_COLOR4_BASE:
case CB_COLOR5_BASE:
case CB_COLOR6_BASE:
case CB_COLOR7_BASE:
case SQ_PGM_START_FS:
case SQ_PGM_START_ES:
case SQ_PGM_START_VS:
case SQ_PGM_START_GS:
case SQ_PGM_START_PS:
r = r600_cs_packet_next_reloc(p, &reloc);
if (r) {
DRM_ERROR("bad SET_CONTEXT_REG "
"0x%04X\n", reg);
return -EINVAL;
}
ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
break;
case VGT_DMA_BASE:
case VGT_DMA_BASE_HI:
/* These should be handled by DRAW_INDEX packet 3 */
case VGT_STRMOUT_BASE_OFFSET_0:
case VGT_STRMOUT_BASE_OFFSET_1:
case VGT_STRMOUT_BASE_OFFSET_2:
case VGT_STRMOUT_BASE_OFFSET_3:
case VGT_STRMOUT_BASE_OFFSET_HI_0:
case VGT_STRMOUT_BASE_OFFSET_HI_1:
case VGT_STRMOUT_BASE_OFFSET_HI_2:
case VGT_STRMOUT_BASE_OFFSET_HI_3:
case VGT_STRMOUT_BUFFER_BASE_0:
case VGT_STRMOUT_BUFFER_BASE_1:
case VGT_STRMOUT_BUFFER_BASE_2:
case VGT_STRMOUT_BUFFER_BASE_3:
case VGT_STRMOUT_BUFFER_OFFSET_0:
case VGT_STRMOUT_BUFFER_OFFSET_1:
case VGT_STRMOUT_BUFFER_OFFSET_2:
case VGT_STRMOUT_BUFFER_OFFSET_3:
/* These should be handled by STRMOUT_BUFFER packet 3 */
DRM_ERROR("bad context reg: 0x%08x\n", reg);
return -EINVAL;
default:
break;
}
} }
break; break;
case PACKET3_SET_RESOURCE: case PACKET3_SET_RESOURCE:
@ -646,6 +1174,9 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < (pkt->count / 7); i++) { for (i = 0; i < (pkt->count / 7); i++) {
struct radeon_bo *texture, *mipmap;
u32 size, offset;
switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) { switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) {
case SQ_TEX_VTX_VALID_TEXTURE: case SQ_TEX_VTX_VALID_TEXTURE:
/* tex base */ /* tex base */
@ -655,6 +1186,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
return -EINVAL; return -EINVAL;
} }
ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
texture = reloc->robj;
/* tex mip base */ /* tex mip base */
r = r600_cs_packet_next_reloc(p, &reloc); r = r600_cs_packet_next_reloc(p, &reloc);
if (r) { if (r) {
@ -662,6 +1194,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
return -EINVAL; return -EINVAL;
} }
ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
mipmap = reloc->robj;
r = r600_check_texture_resource(p, idx+(i*7)+1,
texture, mipmap);
if (r)
return r;
break; break;
case SQ_TEX_VTX_VALID_BUFFER: case SQ_TEX_VTX_VALID_BUFFER:
/* vtx base */ /* vtx base */
@ -670,6 +1207,13 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
DRM_ERROR("bad SET_RESOURCE\n"); DRM_ERROR("bad SET_RESOURCE\n");
return -EINVAL; return -EINVAL;
} }
offset = radeon_get_ib_value(p, idx+1+(i*7)+0);
size = radeon_get_ib_value(p, idx+1+(i*7)+1);
if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
/* force size to size of the buffer */
dev_warn(p->dev, "vbo resource seems too big for the bo\n");
ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj);
}
ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff); ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
ib[idx+1+(i*7)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; ib[idx+1+(i*7)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
break; break;
@ -760,11 +1304,28 @@ int r600_cs_parse(struct radeon_cs_parser *p)
struct r600_cs_track *track; struct r600_cs_track *track;
int r; int r;
track = kzalloc(sizeof(*track), GFP_KERNEL); if (p->track == NULL) {
p->track = track; /* initialize tracker, we are in kms */
track = kzalloc(sizeof(*track), GFP_KERNEL);
if (track == NULL)
return -ENOMEM;
r600_cs_track_init(track);
if (p->rdev->family < CHIP_RV770) {
track->npipes = p->rdev->config.r600.tiling_npipes;
track->nbanks = p->rdev->config.r600.tiling_nbanks;
track->group_size = p->rdev->config.r600.tiling_group_size;
} else if (p->rdev->family <= CHIP_RV740) {
track->npipes = p->rdev->config.rv770.tiling_npipes;
track->nbanks = p->rdev->config.rv770.tiling_nbanks;
track->group_size = p->rdev->config.rv770.tiling_group_size;
}
p->track = track;
}
do { do {
r = r600_cs_packet_parse(p, &pkt, p->idx); r = r600_cs_packet_parse(p, &pkt, p->idx);
if (r) { if (r) {
kfree(p->track);
p->track = NULL;
return r; return r;
} }
p->idx += pkt.count + 2; p->idx += pkt.count + 2;
@ -779,9 +1340,13 @@ int r600_cs_parse(struct radeon_cs_parser *p)
break; break;
default: default:
DRM_ERROR("Unknown packet type %d !\n", pkt.type); DRM_ERROR("Unknown packet type %d !\n", pkt.type);
kfree(p->track);
p->track = NULL;
return -EINVAL; return -EINVAL;
} }
if (r) { if (r) {
kfree(p->track);
p->track = NULL;
return r; return r;
} }
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
@ -791,6 +1356,8 @@ int r600_cs_parse(struct radeon_cs_parser *p)
mdelay(1); mdelay(1);
} }
#endif #endif
kfree(p->track);
p->track = NULL;
return 0; return 0;
} }
@ -833,9 +1400,16 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
{ {
struct radeon_cs_parser parser; struct radeon_cs_parser parser;
struct radeon_cs_chunk *ib_chunk; struct radeon_cs_chunk *ib_chunk;
struct radeon_ib fake_ib; struct radeon_ib fake_ib;
struct r600_cs_track *track;
int r; int r;
/* initialize tracker */
track = kzalloc(sizeof(*track), GFP_KERNEL);
if (track == NULL)
return -ENOMEM;
r600_cs_track_init(track);
r600_cs_legacy_get_tiling_conf(dev, &track->npipes, &track->nbanks, &track->group_size);
/* initialize parser */ /* initialize parser */
memset(&parser, 0, sizeof(struct radeon_cs_parser)); memset(&parser, 0, sizeof(struct radeon_cs_parser));
parser.filp = filp; parser.filp = filp;
@ -843,6 +1417,7 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
parser.rdev = NULL; parser.rdev = NULL;
parser.family = family; parser.family = family;
parser.ib = &fake_ib; parser.ib = &fake_ib;
parser.track = track;
fake_ib.ptr = ib; fake_ib.ptr = ib;
r = radeon_cs_parser_init(&parser, data); r = radeon_cs_parser_init(&parser, data);
if (r) { if (r) {

View File

@ -883,6 +883,16 @@
#define R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 #define R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480
#define R_028C04_PA_SC_AA_CONFIG 0x028C04
#define S_028C04_MSAA_NUM_SAMPLES(x) (((x) & 0x3) << 0)
#define G_028C04_MSAA_NUM_SAMPLES(x) (((x) >> 0) & 0x3)
#define C_028C04_MSAA_NUM_SAMPLES 0xFFFFFFFC
#define S_028C04_AA_MASK_CENTROID_DTMN(x) (((x) & 0x1) << 4)
#define G_028C04_AA_MASK_CENTROID_DTMN(x) (((x) >> 4) & 0x1)
#define C_028C04_AA_MASK_CENTROID_DTMN 0xFFFFFFEF
#define S_028C04_MAX_SAMPLE_DIST(x) (((x) & 0xF) << 13)
#define G_028C04_MAX_SAMPLE_DIST(x) (((x) >> 13) & 0xF)
#define C_028C04_MAX_SAMPLE_DIST 0xFFFE1FFF
#define R_0280E0_CB_COLOR0_FRAG 0x0280E0 #define R_0280E0_CB_COLOR0_FRAG 0x0280E0
#define S_0280E0_BASE_256B(x) (((x) & 0xFFFFFFFF) << 0) #define S_0280E0_BASE_256B(x) (((x) & 0xFFFFFFFF) << 0)
#define G_0280E0_BASE_256B(x) (((x) >> 0) & 0xFFFFFFFF) #define G_0280E0_BASE_256B(x) (((x) >> 0) & 0xFFFFFFFF)
@ -905,6 +915,461 @@
#define R_0280D4_CB_COLOR5_TILE 0x0280D4 #define R_0280D4_CB_COLOR5_TILE 0x0280D4
#define R_0280D8_CB_COLOR6_TILE 0x0280D8 #define R_0280D8_CB_COLOR6_TILE 0x0280D8
#define R_0280DC_CB_COLOR7_TILE 0x0280DC #define R_0280DC_CB_COLOR7_TILE 0x0280DC
#define R_0280A0_CB_COLOR0_INFO 0x0280A0
#define S_0280A0_ENDIAN(x) (((x) & 0x3) << 0)
#define G_0280A0_ENDIAN(x) (((x) >> 0) & 0x3)
#define C_0280A0_ENDIAN 0xFFFFFFFC
#define S_0280A0_FORMAT(x) (((x) & 0x3F) << 2)
#define G_0280A0_FORMAT(x) (((x) >> 2) & 0x3F)
#define C_0280A0_FORMAT 0xFFFFFF03
#define V_0280A0_COLOR_INVALID 0x00000000
#define V_0280A0_COLOR_8 0x00000001
#define V_0280A0_COLOR_4_4 0x00000002
#define V_0280A0_COLOR_3_3_2 0x00000003
#define V_0280A0_COLOR_16 0x00000005
#define V_0280A0_COLOR_16_FLOAT 0x00000006
#define V_0280A0_COLOR_8_8 0x00000007
#define V_0280A0_COLOR_5_6_5 0x00000008
#define V_0280A0_COLOR_6_5_5 0x00000009
#define V_0280A0_COLOR_1_5_5_5 0x0000000A
#define V_0280A0_COLOR_4_4_4_4 0x0000000B
#define V_0280A0_COLOR_5_5_5_1 0x0000000C
#define V_0280A0_COLOR_32 0x0000000D
#define V_0280A0_COLOR_32_FLOAT 0x0000000E
#define V_0280A0_COLOR_16_16 0x0000000F
#define V_0280A0_COLOR_16_16_FLOAT 0x00000010
#define V_0280A0_COLOR_8_24 0x00000011
#define V_0280A0_COLOR_8_24_FLOAT 0x00000012
#define V_0280A0_COLOR_24_8 0x00000013
#define V_0280A0_COLOR_24_8_FLOAT 0x00000014
#define V_0280A0_COLOR_10_11_11 0x00000015
#define V_0280A0_COLOR_10_11_11_FLOAT 0x00000016
#define V_0280A0_COLOR_11_11_10 0x00000017
#define V_0280A0_COLOR_11_11_10_FLOAT 0x00000018
#define V_0280A0_COLOR_2_10_10_10 0x00000019
#define V_0280A0_COLOR_8_8_8_8 0x0000001A
#define V_0280A0_COLOR_10_10_10_2 0x0000001B
#define V_0280A0_COLOR_X24_8_32_FLOAT 0x0000001C
#define V_0280A0_COLOR_32_32 0x0000001D
#define V_0280A0_COLOR_32_32_FLOAT 0x0000001E
#define V_0280A0_COLOR_16_16_16_16 0x0000001F
#define V_0280A0_COLOR_16_16_16_16_FLOAT 0x00000020
#define V_0280A0_COLOR_32_32_32_32 0x00000022
#define V_0280A0_COLOR_32_32_32_32_FLOAT 0x00000023
#define S_0280A0_ARRAY_MODE(x) (((x) & 0xF) << 8)
#define G_0280A0_ARRAY_MODE(x) (((x) >> 8) & 0xF)
#define C_0280A0_ARRAY_MODE 0xFFFFF0FF
#define V_0280A0_ARRAY_LINEAR_GENERAL 0x00000000
#define V_0280A0_ARRAY_LINEAR_ALIGNED 0x00000001
#define V_0280A0_ARRAY_1D_TILED_THIN1 0x00000002
#define V_0280A0_ARRAY_2D_TILED_THIN1 0x00000004
#define S_0280A0_NUMBER_TYPE(x) (((x) & 0x7) << 12)
#define G_0280A0_NUMBER_TYPE(x) (((x) >> 12) & 0x7)
#define C_0280A0_NUMBER_TYPE 0xFFFF8FFF
#define S_0280A0_READ_SIZE(x) (((x) & 0x1) << 15)
#define G_0280A0_READ_SIZE(x) (((x) >> 15) & 0x1)
#define C_0280A0_READ_SIZE 0xFFFF7FFF
#define S_0280A0_COMP_SWAP(x) (((x) & 0x3) << 16)
#define G_0280A0_COMP_SWAP(x) (((x) >> 16) & 0x3)
#define C_0280A0_COMP_SWAP 0xFFFCFFFF
#define S_0280A0_TILE_MODE(x) (((x) & 0x3) << 18)
#define G_0280A0_TILE_MODE(x) (((x) >> 18) & 0x3)
#define C_0280A0_TILE_MODE 0xFFF3FFFF
#define S_0280A0_BLEND_CLAMP(x) (((x) & 0x1) << 20)
#define G_0280A0_BLEND_CLAMP(x) (((x) >> 20) & 0x1)
#define C_0280A0_BLEND_CLAMP 0xFFEFFFFF
#define S_0280A0_CLEAR_COLOR(x) (((x) & 0x1) << 21)
#define G_0280A0_CLEAR_COLOR(x) (((x) >> 21) & 0x1)
#define C_0280A0_CLEAR_COLOR 0xFFDFFFFF
#define S_0280A0_BLEND_BYPASS(x) (((x) & 0x1) << 22)
#define G_0280A0_BLEND_BYPASS(x) (((x) >> 22) & 0x1)
#define C_0280A0_BLEND_BYPASS 0xFFBFFFFF
#define S_0280A0_BLEND_FLOAT32(x) (((x) & 0x1) << 23)
#define G_0280A0_BLEND_FLOAT32(x) (((x) >> 23) & 0x1)
#define C_0280A0_BLEND_FLOAT32 0xFF7FFFFF
#define S_0280A0_SIMPLE_FLOAT(x) (((x) & 0x1) << 24)
#define G_0280A0_SIMPLE_FLOAT(x) (((x) >> 24) & 0x1)
#define C_0280A0_SIMPLE_FLOAT 0xFEFFFFFF
#define S_0280A0_ROUND_MODE(x) (((x) & 0x1) << 25)
#define G_0280A0_ROUND_MODE(x) (((x) >> 25) & 0x1)
#define C_0280A0_ROUND_MODE 0xFDFFFFFF
#define S_0280A0_TILE_COMPACT(x) (((x) & 0x1) << 26)
#define G_0280A0_TILE_COMPACT(x) (((x) >> 26) & 0x1)
#define C_0280A0_TILE_COMPACT 0xFBFFFFFF
#define S_0280A0_SOURCE_FORMAT(x) (((x) & 0x1) << 27)
#define G_0280A0_SOURCE_FORMAT(x) (((x) >> 27) & 0x1)
#define C_0280A0_SOURCE_FORMAT 0xF7FFFFFF
#define R_0280A4_CB_COLOR1_INFO 0x0280A4
#define R_0280A8_CB_COLOR2_INFO 0x0280A8
#define R_0280AC_CB_COLOR3_INFO 0x0280AC
#define R_0280B0_CB_COLOR4_INFO 0x0280B0
#define R_0280B4_CB_COLOR5_INFO 0x0280B4
#define R_0280B8_CB_COLOR6_INFO 0x0280B8
#define R_0280BC_CB_COLOR7_INFO 0x0280BC
#define R_028060_CB_COLOR0_SIZE 0x028060
#define S_028060_PITCH_TILE_MAX(x) (((x) & 0x3FF) << 0)
#define G_028060_PITCH_TILE_MAX(x) (((x) >> 0) & 0x3FF)
#define C_028060_PITCH_TILE_MAX 0xFFFFFC00
#define S_028060_SLICE_TILE_MAX(x) (((x) & 0xFFFFF) << 10)
#define G_028060_SLICE_TILE_MAX(x) (((x) >> 10) & 0xFFFFF)
#define C_028060_SLICE_TILE_MAX 0xC00003FF
#define R_028064_CB_COLOR1_SIZE 0x028064
#define R_028068_CB_COLOR2_SIZE 0x028068
#define R_02806C_CB_COLOR3_SIZE 0x02806C
#define R_028070_CB_COLOR4_SIZE 0x028070
#define R_028074_CB_COLOR5_SIZE 0x028074
#define R_028078_CB_COLOR6_SIZE 0x028078
#define R_02807C_CB_COLOR7_SIZE 0x02807C
#define R_028238_CB_TARGET_MASK 0x028238
#define S_028238_TARGET0_ENABLE(x) (((x) & 0xF) << 0)
#define G_028238_TARGET0_ENABLE(x) (((x) >> 0) & 0xF)
#define C_028238_TARGET0_ENABLE 0xFFFFFFF0
#define S_028238_TARGET1_ENABLE(x) (((x) & 0xF) << 4)
#define G_028238_TARGET1_ENABLE(x) (((x) >> 4) & 0xF)
#define C_028238_TARGET1_ENABLE 0xFFFFFF0F
#define S_028238_TARGET2_ENABLE(x) (((x) & 0xF) << 8)
#define G_028238_TARGET2_ENABLE(x) (((x) >> 8) & 0xF)
#define C_028238_TARGET2_ENABLE 0xFFFFF0FF
#define S_028238_TARGET3_ENABLE(x) (((x) & 0xF) << 12)
#define G_028238_TARGET3_ENABLE(x) (((x) >> 12) & 0xF)
#define C_028238_TARGET3_ENABLE 0xFFFF0FFF
#define S_028238_TARGET4_ENABLE(x) (((x) & 0xF) << 16)
#define G_028238_TARGET4_ENABLE(x) (((x) >> 16) & 0xF)
#define C_028238_TARGET4_ENABLE 0xFFF0FFFF
#define S_028238_TARGET5_ENABLE(x) (((x) & 0xF) << 20)
#define G_028238_TARGET5_ENABLE(x) (((x) >> 20) & 0xF)
#define C_028238_TARGET5_ENABLE 0xFF0FFFFF
#define S_028238_TARGET6_ENABLE(x) (((x) & 0xF) << 24)
#define G_028238_TARGET6_ENABLE(x) (((x) >> 24) & 0xF)
#define C_028238_TARGET6_ENABLE 0xF0FFFFFF
#define S_028238_TARGET7_ENABLE(x) (((x) & 0xF) << 28)
#define G_028238_TARGET7_ENABLE(x) (((x) >> 28) & 0xF)
#define C_028238_TARGET7_ENABLE 0x0FFFFFFF
#define R_02823C_CB_SHADER_MASK 0x02823C
#define S_02823C_OUTPUT0_ENABLE(x) (((x) & 0xF) << 0)
#define G_02823C_OUTPUT0_ENABLE(x) (((x) >> 0) & 0xF)
#define C_02823C_OUTPUT0_ENABLE 0xFFFFFFF0
#define S_02823C_OUTPUT1_ENABLE(x) (((x) & 0xF) << 4)
#define G_02823C_OUTPUT1_ENABLE(x) (((x) >> 4) & 0xF)
#define C_02823C_OUTPUT1_ENABLE 0xFFFFFF0F
#define S_02823C_OUTPUT2_ENABLE(x) (((x) & 0xF) << 8)
#define G_02823C_OUTPUT2_ENABLE(x) (((x) >> 8) & 0xF)
#define C_02823C_OUTPUT2_ENABLE 0xFFFFF0FF
#define S_02823C_OUTPUT3_ENABLE(x) (((x) & 0xF) << 12)
#define G_02823C_OUTPUT3_ENABLE(x) (((x) >> 12) & 0xF)
#define C_02823C_OUTPUT3_ENABLE 0xFFFF0FFF
#define S_02823C_OUTPUT4_ENABLE(x) (((x) & 0xF) << 16)
#define G_02823C_OUTPUT4_ENABLE(x) (((x) >> 16) & 0xF)
#define C_02823C_OUTPUT4_ENABLE 0xFFF0FFFF
#define S_02823C_OUTPUT5_ENABLE(x) (((x) & 0xF) << 20)
#define G_02823C_OUTPUT5_ENABLE(x) (((x) >> 20) & 0xF)
#define C_02823C_OUTPUT5_ENABLE 0xFF0FFFFF
#define S_02823C_OUTPUT6_ENABLE(x) (((x) & 0xF) << 24)
#define G_02823C_OUTPUT6_ENABLE(x) (((x) >> 24) & 0xF)
#define C_02823C_OUTPUT6_ENABLE 0xF0FFFFFF
#define S_02823C_OUTPUT7_ENABLE(x) (((x) & 0xF) << 28)
#define G_02823C_OUTPUT7_ENABLE(x) (((x) >> 28) & 0xF)
#define C_02823C_OUTPUT7_ENABLE 0x0FFFFFFF
#define R_028AB0_VGT_STRMOUT_EN 0x028AB0
#define S_028AB0_STREAMOUT(x) (((x) & 0x1) << 0)
#define G_028AB0_STREAMOUT(x) (((x) >> 0) & 0x1)
#define C_028AB0_STREAMOUT 0xFFFFFFFE
#define R_028B20_VGT_STRMOUT_BUFFER_EN 0x028B20
#define S_028B20_BUFFER_0_EN(x) (((x) & 0x1) << 0)
#define G_028B20_BUFFER_0_EN(x) (((x) >> 0) & 0x1)
#define C_028B20_BUFFER_0_EN 0xFFFFFFFE
#define S_028B20_BUFFER_1_EN(x) (((x) & 0x1) << 1)
#define G_028B20_BUFFER_1_EN(x) (((x) >> 1) & 0x1)
#define C_028B20_BUFFER_1_EN 0xFFFFFFFD
#define S_028B20_BUFFER_2_EN(x) (((x) & 0x1) << 2)
#define G_028B20_BUFFER_2_EN(x) (((x) >> 2) & 0x1)
#define C_028B20_BUFFER_2_EN 0xFFFFFFFB
#define S_028B20_BUFFER_3_EN(x) (((x) & 0x1) << 3)
#define G_028B20_BUFFER_3_EN(x) (((x) >> 3) & 0x1)
#define C_028B20_BUFFER_3_EN 0xFFFFFFF7
#define S_028B20_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_028B20_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_028B20_SIZE 0x00000000
#define R_038000_SQ_TEX_RESOURCE_WORD0_0 0x038000
#define S_038000_DIM(x) (((x) & 0x7) << 0)
#define G_038000_DIM(x) (((x) >> 0) & 0x7)
#define C_038000_DIM 0xFFFFFFF8
#define V_038000_SQ_TEX_DIM_1D 0x00000000
#define V_038000_SQ_TEX_DIM_2D 0x00000001
#define V_038000_SQ_TEX_DIM_3D 0x00000002
#define V_038000_SQ_TEX_DIM_CUBEMAP 0x00000003
#define V_038000_SQ_TEX_DIM_1D_ARRAY 0x00000004
#define V_038000_SQ_TEX_DIM_2D_ARRAY 0x00000005
#define V_038000_SQ_TEX_DIM_2D_MSAA 0x00000006
#define V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA 0x00000007
#define S_038000_TILE_MODE(x) (((x) & 0xF) << 3)
#define G_038000_TILE_MODE(x) (((x) >> 3) & 0xF)
#define C_038000_TILE_MODE 0xFFFFFF87
#define S_038000_TILE_TYPE(x) (((x) & 0x1) << 7)
#define G_038000_TILE_TYPE(x) (((x) >> 7) & 0x1)
#define C_038000_TILE_TYPE 0xFFFFFF7F
#define S_038000_PITCH(x) (((x) & 0x7FF) << 8)
#define G_038000_PITCH(x) (((x) >> 8) & 0x7FF)
#define C_038000_PITCH 0xFFF800FF
#define S_038000_TEX_WIDTH(x) (((x) & 0x1FFF) << 19)
#define G_038000_TEX_WIDTH(x) (((x) >> 19) & 0x1FFF)
#define C_038000_TEX_WIDTH 0x0007FFFF
#define R_038004_SQ_TEX_RESOURCE_WORD1_0 0x038004
#define S_038004_TEX_HEIGHT(x) (((x) & 0x1FFF) << 0)
#define G_038004_TEX_HEIGHT(x) (((x) >> 0) & 0x1FFF)
#define C_038004_TEX_HEIGHT 0xFFFFE000
#define S_038004_TEX_DEPTH(x) (((x) & 0x1FFF) << 13)
#define G_038004_TEX_DEPTH(x) (((x) >> 13) & 0x1FFF)
#define C_038004_TEX_DEPTH 0xFC001FFF
#define S_038004_DATA_FORMAT(x) (((x) & 0x3F) << 26)
#define G_038004_DATA_FORMAT(x) (((x) >> 26) & 0x3F)
#define C_038004_DATA_FORMAT 0x03FFFFFF
#define V_038004_COLOR_INVALID 0x00000000
#define V_038004_COLOR_8 0x00000001
#define V_038004_COLOR_4_4 0x00000002
#define V_038004_COLOR_3_3_2 0x00000003
#define V_038004_COLOR_16 0x00000005
#define V_038004_COLOR_16_FLOAT 0x00000006
#define V_038004_COLOR_8_8 0x00000007
#define V_038004_COLOR_5_6_5 0x00000008
#define V_038004_COLOR_6_5_5 0x00000009
#define V_038004_COLOR_1_5_5_5 0x0000000A
#define V_038004_COLOR_4_4_4_4 0x0000000B
#define V_038004_COLOR_5_5_5_1 0x0000000C
#define V_038004_COLOR_32 0x0000000D
#define V_038004_COLOR_32_FLOAT 0x0000000E
#define V_038004_COLOR_16_16 0x0000000F
#define V_038004_COLOR_16_16_FLOAT 0x00000010
#define V_038004_COLOR_8_24 0x00000011
#define V_038004_COLOR_8_24_FLOAT 0x00000012
#define V_038004_COLOR_24_8 0x00000013
#define V_038004_COLOR_24_8_FLOAT 0x00000014
#define V_038004_COLOR_10_11_11 0x00000015
#define V_038004_COLOR_10_11_11_FLOAT 0x00000016
#define V_038004_COLOR_11_11_10 0x00000017
#define V_038004_COLOR_11_11_10_FLOAT 0x00000018
#define V_038004_COLOR_2_10_10_10 0x00000019
#define V_038004_COLOR_8_8_8_8 0x0000001A
#define V_038004_COLOR_10_10_10_2 0x0000001B
#define V_038004_COLOR_X24_8_32_FLOAT 0x0000001C
#define V_038004_COLOR_32_32 0x0000001D
#define V_038004_COLOR_32_32_FLOAT 0x0000001E
#define V_038004_COLOR_16_16_16_16 0x0000001F
#define V_038004_COLOR_16_16_16_16_FLOAT 0x00000020
#define V_038004_COLOR_32_32_32_32 0x00000022
#define V_038004_COLOR_32_32_32_32_FLOAT 0x00000023
#define V_038004_FMT_1 0x00000025
#define V_038004_FMT_GB_GR 0x00000027
#define V_038004_FMT_BG_RG 0x00000028
#define V_038004_FMT_32_AS_8 0x00000029
#define V_038004_FMT_32_AS_8_8 0x0000002A
#define V_038004_FMT_5_9_9_9_SHAREDEXP 0x0000002B
#define V_038004_FMT_8_8_8 0x0000002C
#define V_038004_FMT_16_16_16 0x0000002D
#define V_038004_FMT_16_16_16_FLOAT 0x0000002E
#define V_038004_FMT_32_32_32 0x0000002F
#define V_038004_FMT_32_32_32_FLOAT 0x00000030
#define R_038010_SQ_TEX_RESOURCE_WORD4_0 0x038010
#define S_038010_FORMAT_COMP_X(x) (((x) & 0x3) << 0)
#define G_038010_FORMAT_COMP_X(x) (((x) >> 0) & 0x3)
#define C_038010_FORMAT_COMP_X 0xFFFFFFFC
#define S_038010_FORMAT_COMP_Y(x) (((x) & 0x3) << 2)
#define G_038010_FORMAT_COMP_Y(x) (((x) >> 2) & 0x3)
#define C_038010_FORMAT_COMP_Y 0xFFFFFFF3
#define S_038010_FORMAT_COMP_Z(x) (((x) & 0x3) << 4)
#define G_038010_FORMAT_COMP_Z(x) (((x) >> 4) & 0x3)
#define C_038010_FORMAT_COMP_Z 0xFFFFFFCF
#define S_038010_FORMAT_COMP_W(x) (((x) & 0x3) << 6)
#define G_038010_FORMAT_COMP_W(x) (((x) >> 6) & 0x3)
#define C_038010_FORMAT_COMP_W 0xFFFFFF3F
#define S_038010_NUM_FORMAT_ALL(x) (((x) & 0x3) << 8)
#define G_038010_NUM_FORMAT_ALL(x) (((x) >> 8) & 0x3)
#define C_038010_NUM_FORMAT_ALL 0xFFFFFCFF
#define S_038010_SRF_MODE_ALL(x) (((x) & 0x1) << 10)
#define G_038010_SRF_MODE_ALL(x) (((x) >> 10) & 0x1)
#define C_038010_SRF_MODE_ALL 0xFFFFFBFF
#define S_038010_FORCE_DEGAMMA(x) (((x) & 0x1) << 11)
#define G_038010_FORCE_DEGAMMA(x) (((x) >> 11) & 0x1)
#define C_038010_FORCE_DEGAMMA 0xFFFFF7FF
#define S_038010_ENDIAN_SWAP(x) (((x) & 0x3) << 12)
#define G_038010_ENDIAN_SWAP(x) (((x) >> 12) & 0x3)
#define C_038010_ENDIAN_SWAP 0xFFFFCFFF
#define S_038010_REQUEST_SIZE(x) (((x) & 0x3) << 14)
#define G_038010_REQUEST_SIZE(x) (((x) >> 14) & 0x3)
#define C_038010_REQUEST_SIZE 0xFFFF3FFF
#define S_038010_DST_SEL_X(x) (((x) & 0x7) << 16)
#define G_038010_DST_SEL_X(x) (((x) >> 16) & 0x7)
#define C_038010_DST_SEL_X 0xFFF8FFFF
#define S_038010_DST_SEL_Y(x) (((x) & 0x7) << 19)
#define G_038010_DST_SEL_Y(x) (((x) >> 19) & 0x7)
#define C_038010_DST_SEL_Y 0xFFC7FFFF
#define S_038010_DST_SEL_Z(x) (((x) & 0x7) << 22)
#define G_038010_DST_SEL_Z(x) (((x) >> 22) & 0x7)
#define C_038010_DST_SEL_Z 0xFE3FFFFF
#define S_038010_DST_SEL_W(x) (((x) & 0x7) << 25)
#define G_038010_DST_SEL_W(x) (((x) >> 25) & 0x7)
#define C_038010_DST_SEL_W 0xF1FFFFFF
#define S_038010_BASE_LEVEL(x) (((x) & 0xF) << 28)
#define G_038010_BASE_LEVEL(x) (((x) >> 28) & 0xF)
#define C_038010_BASE_LEVEL 0x0FFFFFFF
#define R_038014_SQ_TEX_RESOURCE_WORD5_0 0x038014
#define S_038014_LAST_LEVEL(x) (((x) & 0xF) << 0)
#define G_038014_LAST_LEVEL(x) (((x) >> 0) & 0xF)
#define C_038014_LAST_LEVEL 0xFFFFFFF0
#define S_038014_BASE_ARRAY(x) (((x) & 0x1FFF) << 4)
#define G_038014_BASE_ARRAY(x) (((x) >> 4) & 0x1FFF)
#define C_038014_BASE_ARRAY 0xFFFE000F
#define S_038014_LAST_ARRAY(x) (((x) & 0x1FFF) << 17)
#define G_038014_LAST_ARRAY(x) (((x) >> 17) & 0x1FFF)
#define C_038014_LAST_ARRAY 0xC001FFFF
#define R_0288A8_SQ_ESGS_RING_ITEMSIZE 0x0288A8
#define S_0288A8_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288A8_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288A8_ITEMSIZE 0xFFFF8000
#define R_008C44_SQ_ESGS_RING_SIZE 0x008C44
#define S_008C44_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_008C44_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_008C44_MEM_SIZE 0x00000000
#define R_0288B0_SQ_ESTMP_RING_ITEMSIZE 0x0288B0
#define S_0288B0_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288B0_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288B0_ITEMSIZE 0xFFFF8000
#define R_008C54_SQ_ESTMP_RING_SIZE 0x008C54
#define S_008C54_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_008C54_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_008C54_MEM_SIZE 0x00000000
#define R_0288C0_SQ_FBUF_RING_ITEMSIZE 0x0288C0
#define S_0288C0_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288C0_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288C0_ITEMSIZE 0xFFFF8000
#define R_008C74_SQ_FBUF_RING_SIZE 0x008C74
#define S_008C74_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_008C74_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_008C74_MEM_SIZE 0x00000000
#define R_0288B4_SQ_GSTMP_RING_ITEMSIZE 0x0288B4
#define S_0288B4_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288B4_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288B4_ITEMSIZE 0xFFFF8000
#define R_008C5C_SQ_GSTMP_RING_SIZE 0x008C5C
#define S_008C5C_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_008C5C_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_008C5C_MEM_SIZE 0x00000000
#define R_0288AC_SQ_GSVS_RING_ITEMSIZE 0x0288AC
#define S_0288AC_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288AC_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288AC_ITEMSIZE 0xFFFF8000
#define R_008C4C_SQ_GSVS_RING_SIZE 0x008C4C
#define S_008C4C_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_008C4C_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_008C4C_MEM_SIZE 0x00000000
#define R_0288BC_SQ_PSTMP_RING_ITEMSIZE 0x0288BC
#define S_0288BC_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288BC_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288BC_ITEMSIZE 0xFFFF8000
#define R_008C6C_SQ_PSTMP_RING_SIZE 0x008C6C
#define S_008C6C_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_008C6C_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_008C6C_MEM_SIZE 0x00000000
#define R_0288C4_SQ_REDUC_RING_ITEMSIZE 0x0288C4
#define S_0288C4_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288C4_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288C4_ITEMSIZE 0xFFFF8000
#define R_008C7C_SQ_REDUC_RING_SIZE 0x008C7C
#define S_008C7C_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_008C7C_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_008C7C_MEM_SIZE 0x00000000
#define R_0288B8_SQ_VSTMP_RING_ITEMSIZE 0x0288B8
#define S_0288B8_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288B8_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288B8_ITEMSIZE 0xFFFF8000
#define R_008C64_SQ_VSTMP_RING_SIZE 0x008C64
#define S_008C64_MEM_SIZE(x) (((x) & 0xFFFFFFFF) << 0)
#define G_008C64_MEM_SIZE(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_008C64_MEM_SIZE 0x00000000
#define R_0288C8_SQ_GS_VERT_ITEMSIZE 0x0288C8
#define S_0288C8_ITEMSIZE(x) (((x) & 0x7FFF) << 0)
#define G_0288C8_ITEMSIZE(x) (((x) >> 0) & 0x7FFF)
#define C_0288C8_ITEMSIZE 0xFFFF8000
#define R_028010_DB_DEPTH_INFO 0x028010
#define S_028010_FORMAT(x) (((x) & 0x7) << 0)
#define G_028010_FORMAT(x) (((x) >> 0) & 0x7)
#define C_028010_FORMAT 0xFFFFFFF8
#define V_028010_DEPTH_INVALID 0x00000000
#define V_028010_DEPTH_16 0x00000001
#define V_028010_DEPTH_X8_24 0x00000002
#define V_028010_DEPTH_8_24 0x00000003
#define V_028010_DEPTH_X8_24_FLOAT 0x00000004
#define V_028010_DEPTH_8_24_FLOAT 0x00000005
#define V_028010_DEPTH_32_FLOAT 0x00000006
#define V_028010_DEPTH_X24_8_32_FLOAT 0x00000007
#define S_028010_READ_SIZE(x) (((x) & 0x1) << 3)
#define G_028010_READ_SIZE(x) (((x) >> 3) & 0x1)
#define C_028010_READ_SIZE 0xFFFFFFF7
#define S_028010_ARRAY_MODE(x) (((x) & 0xF) << 15)
#define G_028010_ARRAY_MODE(x) (((x) >> 15) & 0xF)
#define C_028010_ARRAY_MODE 0xFFF87FFF
#define S_028010_TILE_SURFACE_ENABLE(x) (((x) & 0x1) << 25)
#define G_028010_TILE_SURFACE_ENABLE(x) (((x) >> 25) & 0x1)
#define C_028010_TILE_SURFACE_ENABLE 0xFDFFFFFF
#define S_028010_TILE_COMPACT(x) (((x) & 0x1) << 26)
#define G_028010_TILE_COMPACT(x) (((x) >> 26) & 0x1)
#define C_028010_TILE_COMPACT 0xFBFFFFFF
#define S_028010_ZRANGE_PRECISION(x) (((x) & 0x1) << 31)
#define G_028010_ZRANGE_PRECISION(x) (((x) >> 31) & 0x1)
#define C_028010_ZRANGE_PRECISION 0x7FFFFFFF
#define R_028000_DB_DEPTH_SIZE 0x028000
#define S_028000_PITCH_TILE_MAX(x) (((x) & 0x3FF) << 0)
#define G_028000_PITCH_TILE_MAX(x) (((x) >> 0) & 0x3FF)
#define C_028000_PITCH_TILE_MAX 0xFFFFFC00
#define S_028000_SLICE_TILE_MAX(x) (((x) & 0xFFFFF) << 10)
#define G_028000_SLICE_TILE_MAX(x) (((x) >> 10) & 0xFFFFF)
#define C_028000_SLICE_TILE_MAX 0xC00003FF
#define R_028004_DB_DEPTH_VIEW 0x028004
#define S_028004_SLICE_START(x) (((x) & 0x7FF) << 0)
#define G_028004_SLICE_START(x) (((x) >> 0) & 0x7FF)
#define C_028004_SLICE_START 0xFFFFF800
#define S_028004_SLICE_MAX(x) (((x) & 0x7FF) << 13)
#define G_028004_SLICE_MAX(x) (((x) >> 13) & 0x7FF)
#define C_028004_SLICE_MAX 0xFF001FFF
#define R_028800_DB_DEPTH_CONTROL 0x028800
#define S_028800_STENCIL_ENABLE(x) (((x) & 0x1) << 0)
#define G_028800_STENCIL_ENABLE(x) (((x) >> 0) & 0x1)
#define C_028800_STENCIL_ENABLE 0xFFFFFFFE
#define S_028800_Z_ENABLE(x) (((x) & 0x1) << 1)
#define G_028800_Z_ENABLE(x) (((x) >> 1) & 0x1)
#define C_028800_Z_ENABLE 0xFFFFFFFD
#define S_028800_Z_WRITE_ENABLE(x) (((x) & 0x1) << 2)
#define G_028800_Z_WRITE_ENABLE(x) (((x) >> 2) & 0x1)
#define C_028800_Z_WRITE_ENABLE 0xFFFFFFFB
#define S_028800_ZFUNC(x) (((x) & 0x7) << 4)
#define G_028800_ZFUNC(x) (((x) >> 4) & 0x7)
#define C_028800_ZFUNC 0xFFFFFF8F
#define S_028800_BACKFACE_ENABLE(x) (((x) & 0x1) << 7)
#define G_028800_BACKFACE_ENABLE(x) (((x) >> 7) & 0x1)
#define C_028800_BACKFACE_ENABLE 0xFFFFFF7F
#define S_028800_STENCILFUNC(x) (((x) & 0x7) << 8)
#define G_028800_STENCILFUNC(x) (((x) >> 8) & 0x7)
#define C_028800_STENCILFUNC 0xFFFFF8FF
#define S_028800_STENCILFAIL(x) (((x) & 0x7) << 11)
#define G_028800_STENCILFAIL(x) (((x) >> 11) & 0x7)
#define C_028800_STENCILFAIL 0xFFFFC7FF
#define S_028800_STENCILZPASS(x) (((x) & 0x7) << 14)
#define G_028800_STENCILZPASS(x) (((x) >> 14) & 0x7)
#define C_028800_STENCILZPASS 0xFFFE3FFF
#define S_028800_STENCILZFAIL(x) (((x) & 0x7) << 17)
#define G_028800_STENCILZFAIL(x) (((x) >> 17) & 0x7)
#define C_028800_STENCILZFAIL 0xFFF1FFFF
#define S_028800_STENCILFUNC_BF(x) (((x) & 0x7) << 20)
#define G_028800_STENCILFUNC_BF(x) (((x) >> 20) & 0x7)
#define C_028800_STENCILFUNC_BF 0xFF8FFFFF
#define S_028800_STENCILFAIL_BF(x) (((x) & 0x7) << 23)
#define G_028800_STENCILFAIL_BF(x) (((x) >> 23) & 0x7)
#define C_028800_STENCILFAIL_BF 0xFC7FFFFF
#define S_028800_STENCILZPASS_BF(x) (((x) & 0x7) << 26)
#define G_028800_STENCILZPASS_BF(x) (((x) >> 26) & 0x7)
#define C_028800_STENCILZPASS_BF 0xE3FFFFFF
#define S_028800_STENCILZFAIL_BF(x) (((x) & 0x7) << 29)
#define G_028800_STENCILZFAIL_BF(x) (((x) >> 29) & 0x7)
#define C_028800_STENCILZFAIL_BF 0x1FFFFFFF
#endif #endif

View File

@ -89,6 +89,7 @@ extern int radeon_testing;
extern int radeon_connector_table; extern int radeon_connector_table;
extern int radeon_tv; extern int radeon_tv;
extern int radeon_new_pll; extern int radeon_new_pll;
extern int radeon_dynpm;
extern int radeon_audio; extern int radeon_audio;
/* /*
@ -118,6 +119,21 @@ struct radeon_device;
/* /*
* BIOS. * BIOS.
*/ */
#define ATRM_BIOS_PAGE 4096
#if defined(CONFIG_VGA_SWITCHEROO)
bool radeon_atrm_supported(struct pci_dev *pdev);
int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len);
#else
static inline bool radeon_atrm_supported(struct pci_dev *pdev)
{
return false;
}
static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len){
return -EINVAL;
}
#endif
bool radeon_get_bios(struct radeon_device *rdev); bool radeon_get_bios(struct radeon_device *rdev);
@ -138,17 +154,23 @@ void radeon_dummy_page_fini(struct radeon_device *rdev);
struct radeon_clock { struct radeon_clock {
struct radeon_pll p1pll; struct radeon_pll p1pll;
struct radeon_pll p2pll; struct radeon_pll p2pll;
struct radeon_pll dcpll;
struct radeon_pll spll; struct radeon_pll spll;
struct radeon_pll mpll; struct radeon_pll mpll;
/* 10 Khz units */ /* 10 Khz units */
uint32_t default_mclk; uint32_t default_mclk;
uint32_t default_sclk; uint32_t default_sclk;
uint32_t default_dispclk;
uint32_t dp_extclk;
}; };
/* /*
* Power management * Power management
*/ */
int radeon_pm_init(struct radeon_device *rdev); int radeon_pm_init(struct radeon_device *rdev);
void radeon_pm_compute_clocks(struct radeon_device *rdev);
void radeon_combios_get_power_modes(struct radeon_device *rdev);
void radeon_atombios_get_power_modes(struct radeon_device *rdev);
/* /*
* Fences. * Fences.
@ -275,6 +297,7 @@ union radeon_gart_table {
}; };
#define RADEON_GPU_PAGE_SIZE 4096 #define RADEON_GPU_PAGE_SIZE 4096
#define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1)
struct radeon_gart { struct radeon_gart {
dma_addr_t table_addr; dma_addr_t table_addr;
@ -309,21 +332,19 @@ struct radeon_mc {
/* for some chips with <= 32MB we need to lie /* for some chips with <= 32MB we need to lie
* about vram size near mc fb location */ * about vram size near mc fb location */
u64 mc_vram_size; u64 mc_vram_size;
u64 gtt_location; u64 visible_vram_size;
u64 gtt_size; u64 gtt_size;
u64 gtt_start; u64 gtt_start;
u64 gtt_end; u64 gtt_end;
u64 vram_location;
u64 vram_start; u64 vram_start;
u64 vram_end; u64 vram_end;
unsigned vram_width; unsigned vram_width;
u64 real_vram_size; u64 real_vram_size;
int vram_mtrr; int vram_mtrr;
bool vram_is_ddr; bool vram_is_ddr;
bool igp_sideport_enabled; bool igp_sideport_enabled;
}; };
int radeon_mc_setup(struct radeon_device *rdev);
bool radeon_combios_sideport_present(struct radeon_device *rdev); bool radeon_combios_sideport_present(struct radeon_device *rdev);
bool radeon_atombios_sideport_present(struct radeon_device *rdev); bool radeon_atombios_sideport_present(struct radeon_device *rdev);
@ -348,6 +369,7 @@ struct radeon_irq {
bool sw_int; bool sw_int;
/* FIXME: use a define max crtc rather than hardcode it */ /* FIXME: use a define max crtc rather than hardcode it */
bool crtc_vblank_int[2]; bool crtc_vblank_int[2];
wait_queue_head_t vblank_queue;
/* FIXME: use defines for max hpd/dacs */ /* FIXME: use defines for max hpd/dacs */
bool hpd[6]; bool hpd[6];
spinlock_t sw_lock; spinlock_t sw_lock;
@ -379,6 +401,7 @@ struct radeon_ib {
struct radeon_ib_pool { struct radeon_ib_pool {
struct mutex mutex; struct mutex mutex;
struct radeon_bo *robj; struct radeon_bo *robj;
struct list_head bogus_ib;
struct radeon_ib ibs[RADEON_IB_POOL_SIZE]; struct radeon_ib ibs[RADEON_IB_POOL_SIZE];
bool ready; bool ready;
unsigned head_id; unsigned head_id;
@ -433,6 +456,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib);
int radeon_ib_pool_init(struct radeon_device *rdev); int radeon_ib_pool_init(struct radeon_device *rdev);
void radeon_ib_pool_fini(struct radeon_device *rdev); void radeon_ib_pool_fini(struct radeon_device *rdev);
int radeon_ib_test(struct radeon_device *rdev); int radeon_ib_test(struct radeon_device *rdev);
extern void radeon_ib_bogus_add(struct radeon_device *rdev, struct radeon_ib *ib);
/* Ring access between begin & end cannot sleep */ /* Ring access between begin & end cannot sleep */
void radeon_ring_free_size(struct radeon_device *rdev); void radeon_ring_free_size(struct radeon_device *rdev);
int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw); int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw);
@ -570,7 +594,99 @@ struct radeon_wb {
* Equation between gpu/memory clock and available bandwidth is hw dependent * Equation between gpu/memory clock and available bandwidth is hw dependent
* (type of memory, bus size, efficiency, ...) * (type of memory, bus size, efficiency, ...)
*/ */
enum radeon_pm_state {
PM_STATE_DISABLED,
PM_STATE_MINIMUM,
PM_STATE_PAUSED,
PM_STATE_ACTIVE
};
enum radeon_pm_action {
PM_ACTION_NONE,
PM_ACTION_MINIMUM,
PM_ACTION_DOWNCLOCK,
PM_ACTION_UPCLOCK
};
enum radeon_voltage_type {
VOLTAGE_NONE = 0,
VOLTAGE_GPIO,
VOLTAGE_VDDC,
VOLTAGE_SW
};
enum radeon_pm_state_type {
POWER_STATE_TYPE_DEFAULT,
POWER_STATE_TYPE_POWERSAVE,
POWER_STATE_TYPE_BATTERY,
POWER_STATE_TYPE_BALANCED,
POWER_STATE_TYPE_PERFORMANCE,
};
enum radeon_pm_clock_mode_type {
POWER_MODE_TYPE_DEFAULT,
POWER_MODE_TYPE_LOW,
POWER_MODE_TYPE_MID,
POWER_MODE_TYPE_HIGH,
};
struct radeon_voltage {
enum radeon_voltage_type type;
/* gpio voltage */
struct radeon_gpio_rec gpio;
u32 delay; /* delay in usec from voltage drop to sclk change */
bool active_high; /* voltage drop is active when bit is high */
/* VDDC voltage */
u8 vddc_id; /* index into vddc voltage table */
u8 vddci_id; /* index into vddci voltage table */
bool vddci_enabled;
/* r6xx+ sw */
u32 voltage;
};
struct radeon_pm_non_clock_info {
/* pcie lanes */
int pcie_lanes;
/* standardized non-clock flags */
u32 flags;
};
struct radeon_pm_clock_info {
/* memory clock */
u32 mclk;
/* engine clock */
u32 sclk;
/* voltage info */
struct radeon_voltage voltage;
/* standardized clock flags - not sure we'll need these */
u32 flags;
};
struct radeon_power_state {
enum radeon_pm_state_type type;
/* XXX: use a define for num clock modes */
struct radeon_pm_clock_info clock_info[8];
/* number of valid clock modes in this power state */
int num_clock_modes;
struct radeon_pm_clock_info *default_clock_mode;
/* non clock info about this state */
struct radeon_pm_non_clock_info non_clock_info;
bool voltage_drop_active;
};
/*
* Some modes are overclocked by very low value, accept them
*/
#define RADEON_MODE_OVERCLOCK_MARGIN 500 /* 5 MHz */
struct radeon_pm { struct radeon_pm {
struct mutex mutex;
struct delayed_work idle_work;
enum radeon_pm_state state;
enum radeon_pm_action planned_action;
unsigned long action_timeout;
bool downclocked;
int active_crtcs;
int req_vblank;
fixed20_12 max_bandwidth; fixed20_12 max_bandwidth;
fixed20_12 igp_sideport_mclk; fixed20_12 igp_sideport_mclk;
fixed20_12 igp_system_mclk; fixed20_12 igp_system_mclk;
@ -582,6 +698,15 @@ struct radeon_pm {
fixed20_12 core_bandwidth; fixed20_12 core_bandwidth;
fixed20_12 sclk; fixed20_12 sclk;
fixed20_12 needed_bandwidth; fixed20_12 needed_bandwidth;
/* XXX: use a define for num power modes */
struct radeon_power_state power_state[8];
/* number of valid power states */
int num_power_states;
struct radeon_power_state *current_power_state;
struct radeon_pm_clock_info *current_clock_mode;
struct radeon_power_state *requested_power_state;
struct radeon_pm_clock_info *requested_clock_mode;
struct radeon_power_state *default_power_state;
}; };
@ -651,6 +776,7 @@ struct radeon_asic {
void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock); void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
uint32_t (*get_memory_clock)(struct radeon_device *rdev); uint32_t (*get_memory_clock)(struct radeon_device *rdev);
void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock); void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
int (*get_pcie_lanes)(struct radeon_device *rdev);
void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes); void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
void (*set_clock_gating)(struct radeon_device *rdev, int enable); void (*set_clock_gating)(struct radeon_device *rdev, int enable);
int (*set_surface_reg)(struct radeon_device *rdev, int reg, int (*set_surface_reg)(struct radeon_device *rdev, int reg,
@ -701,6 +827,9 @@ struct r600_asic {
unsigned sx_max_export_pos_size; unsigned sx_max_export_pos_size;
unsigned sx_max_export_smx_size; unsigned sx_max_export_smx_size;
unsigned sq_num_cf_insts; unsigned sq_num_cf_insts;
unsigned tiling_nbanks;
unsigned tiling_npipes;
unsigned tiling_group_size;
}; };
struct rv770_asic { struct rv770_asic {
@ -721,6 +850,9 @@ struct rv770_asic {
unsigned sc_prim_fifo_size; unsigned sc_prim_fifo_size;
unsigned sc_hiz_tile_fifo_size; unsigned sc_hiz_tile_fifo_size;
unsigned sc_earlyz_tile_fifo_fize; unsigned sc_earlyz_tile_fifo_fize;
unsigned tiling_nbanks;
unsigned tiling_npipes;
unsigned tiling_group_size;
}; };
union radeon_asic_config { union radeon_asic_config {
@ -830,6 +962,8 @@ struct radeon_device {
struct r600_ih ih; /* r6/700 interrupt ring */ struct r600_ih ih; /* r6/700 interrupt ring */
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct work_struct hotplug_work; struct work_struct hotplug_work;
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
/* audio stuff */ /* audio stuff */
struct timer_list audio_timer; struct timer_list audio_timer;
@ -838,6 +972,8 @@ struct radeon_device {
int audio_bits_per_sample; int audio_bits_per_sample;
uint8_t audio_status_bits; uint8_t audio_status_bits;
uint8_t audio_category_code; uint8_t audio_category_code;
bool powered_down;
}; };
int radeon_device_init(struct radeon_device *rdev, int radeon_device_init(struct radeon_device *rdev,
@ -895,6 +1031,8 @@ static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32
#define WREG32_MC(reg, v) rdev->mc_wreg(rdev, (reg), (v)) #define WREG32_MC(reg, v) rdev->mc_wreg(rdev, (reg), (v))
#define RREG32_PCIE(reg) rv370_pcie_rreg(rdev, (reg)) #define RREG32_PCIE(reg) rv370_pcie_rreg(rdev, (reg))
#define WREG32_PCIE(reg, v) rv370_pcie_wreg(rdev, (reg), (v)) #define WREG32_PCIE(reg, v) rv370_pcie_wreg(rdev, (reg), (v))
#define RREG32_PCIE_P(reg) rdev->pciep_rreg(rdev, (reg))
#define WREG32_PCIE_P(reg, v) rdev->pciep_wreg(rdev, (reg), (v))
#define WREG32_P(reg, val, mask) \ #define WREG32_P(reg, val, mask) \
do { \ do { \
uint32_t tmp_ = RREG32(reg); \ uint32_t tmp_ = RREG32(reg); \
@ -956,7 +1094,7 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
#define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600)) #define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600))
#define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620)) #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620))
#define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730)) #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730))
#define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR))
/* /*
* BIOS helpers. * BIOS helpers.
@ -1015,6 +1153,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_set_engine_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e)) #define radeon_set_engine_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))
#define radeon_get_memory_clock(rdev) (rdev)->asic->get_memory_clock((rdev)) #define radeon_get_memory_clock(rdev) (rdev)->asic->get_memory_clock((rdev))
#define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_memory_clock((rdev), (e)) #define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_memory_clock((rdev), (e))
#define radeon_get_pcie_lanes(rdev) (rdev)->asic->get_pcie_lanes((rdev))
#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l)) #define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l))
#define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e)) #define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e))
#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s))) #define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->set_surface_reg((rdev), (r), (f), (p), (o), (s)))
@ -1029,6 +1168,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
/* AGP */ /* AGP */
extern void radeon_agp_disable(struct radeon_device *rdev); extern void radeon_agp_disable(struct radeon_device *rdev);
extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); extern int radeon_gart_table_vram_pin(struct radeon_device *rdev);
extern void radeon_gart_restore(struct radeon_device *rdev);
extern int radeon_modeset_init(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev);
extern void radeon_modeset_fini(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev);
extern bool radeon_card_posted(struct radeon_device *rdev); extern bool radeon_card_posted(struct radeon_device *rdev);
@ -1042,6 +1182,10 @@ extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enabl
extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain); extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo); extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
extern int radeon_resume_kms(struct drm_device *dev);
extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state);
/* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ /* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */
struct r100_mc_save { struct r100_mc_save {
@ -1096,7 +1240,7 @@ extern void r200_set_safe_registers(struct radeon_device *rdev);
/* r300,r350,rv350,rv370,rv380 */ /* r300,r350,rv350,rv370,rv380 */
extern void r300_set_reg_safe(struct radeon_device *rdev); extern void r300_set_reg_safe(struct radeon_device *rdev);
extern void r300_mc_program(struct radeon_device *rdev); extern void r300_mc_program(struct radeon_device *rdev);
extern void r300_vram_info(struct radeon_device *rdev); extern void r300_mc_init(struct radeon_device *rdev);
extern void r300_clock_startup(struct radeon_device *rdev); extern void r300_clock_startup(struct radeon_device *rdev);
extern int r300_mc_wait_for_idle(struct radeon_device *rdev); extern int r300_mc_wait_for_idle(struct radeon_device *rdev);
extern int rv370_pcie_gart_init(struct radeon_device *rdev); extern int rv370_pcie_gart_init(struct radeon_device *rdev);
@ -1105,7 +1249,6 @@ extern int rv370_pcie_gart_enable(struct radeon_device *rdev);
extern void rv370_pcie_gart_disable(struct radeon_device *rdev); extern void rv370_pcie_gart_disable(struct radeon_device *rdev);
/* r420,r423,rv410 */ /* r420,r423,rv410 */
extern int r420_mc_init(struct radeon_device *rdev);
extern u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg); extern u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg);
extern void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v); extern void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v);
extern int r420_debugfs_pipes_info_init(struct radeon_device *rdev); extern int r420_debugfs_pipes_info_init(struct radeon_device *rdev);
@ -1147,13 +1290,13 @@ extern void rs690_line_buffer_adjust(struct radeon_device *rdev,
struct drm_display_mode *mode2); struct drm_display_mode *mode2);
/* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */ /* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */
extern void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
extern bool r600_card_posted(struct radeon_device *rdev); extern bool r600_card_posted(struct radeon_device *rdev);
extern void r600_cp_stop(struct radeon_device *rdev); extern void r600_cp_stop(struct radeon_device *rdev);
extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size); extern void r600_ring_init(struct radeon_device *rdev, unsigned ring_size);
extern int r600_cp_resume(struct radeon_device *rdev); extern int r600_cp_resume(struct radeon_device *rdev);
extern void r600_cp_fini(struct radeon_device *rdev); extern void r600_cp_fini(struct radeon_device *rdev);
extern int r600_count_pipe_bits(uint32_t val); extern int r600_count_pipe_bits(uint32_t val);
extern int r600_gart_clear_page(struct radeon_device *rdev, int i);
extern int r600_mc_wait_for_idle(struct radeon_device *rdev); extern int r600_mc_wait_for_idle(struct radeon_device *rdev);
extern int r600_pcie_gart_init(struct radeon_device *rdev); extern int r600_pcie_gart_init(struct radeon_device *rdev);
extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev); extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev);
@ -1189,6 +1332,14 @@ extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder,
uint8_t status_bits, uint8_t status_bits,
uint8_t category_code); uint8_t category_code);
/* evergreen */
struct evergreen_mc_save {
u32 vga_control[6];
u32 vga_render_control;
u32 vga_hdp_control;
u32 crtc_control[6];
};
#include "radeon_object.h" #include "radeon_object.h"
#endif #endif

View File

@ -237,6 +237,10 @@ int radeon_agp_init(struct radeon_device *rdev)
rdev->mc.agp_base = rdev->ddev->agp->agp_info.aper_base; rdev->mc.agp_base = rdev->ddev->agp->agp_info.aper_base;
rdev->mc.gtt_size = rdev->ddev->agp->agp_info.aper_size << 20; rdev->mc.gtt_size = rdev->ddev->agp->agp_info.aper_size << 20;
rdev->mc.gtt_start = rdev->mc.agp_base;
rdev->mc.gtt_end = rdev->mc.gtt_start + rdev->mc.gtt_size - 1;
dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n",
rdev->mc.gtt_size >> 20, rdev->mc.gtt_start, rdev->mc.gtt_end);
/* workaround some hw issues */ /* workaround some hw issues */
if (rdev->family < CHIP_R200) { if (rdev->family < CHIP_R200) {

View File

@ -43,7 +43,7 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock
void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
/* /*
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 * r100,rv100,rs100,rv200,rs200
*/ */
extern int r100_init(struct radeon_device *rdev); extern int r100_init(struct radeon_device *rdev);
extern void r100_fini(struct radeon_device *rdev); extern void r100_fini(struct radeon_device *rdev);
@ -108,6 +108,52 @@ static struct radeon_asic r100_asic = {
.set_engine_clock = &radeon_legacy_set_engine_clock, .set_engine_clock = &radeon_legacy_set_engine_clock,
.get_memory_clock = &radeon_legacy_get_memory_clock, .get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL, .set_memory_clock = NULL,
.get_pcie_lanes = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &r100_bandwidth_update,
.hpd_init = &r100_hpd_init,
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
.ioctl_wait_idle = NULL,
};
/*
* r200,rv250,rs300,rv280
*/
extern int r200_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_pages,
struct radeon_fence *fence);
static struct radeon_asic r200_asic = {
.init = &r100_init,
.fini = &r100_fini,
.suspend = &r100_suspend,
.resume = &r100_resume,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &r100_gpu_reset,
.gart_tlb_flush = &r100_pci_gart_tlb_flush,
.gart_set_page = &r100_pci_gart_set_page,
.cp_commit = &r100_cp_commit,
.ring_start = &r100_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
.irq_set = &r100_irq_set,
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
.fence_ring_emit = &r100_fence_ring_emit,
.cs_parse = &r100_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock,
.get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL,
.set_pcie_lanes = NULL, .set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating, .set_clock_gating = &radeon_legacy_set_clock_gating,
.set_surface_reg = r100_set_surface_reg, .set_surface_reg = r100_set_surface_reg,
@ -138,11 +184,8 @@ extern int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t
extern uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg); extern uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg);
extern void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); extern void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes); extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
extern int r300_copy_dma(struct radeon_device *rdev, extern int rv370_get_pcie_lanes(struct radeon_device *rdev);
uint64_t src_offset,
uint64_t dst_offset,
unsigned num_pages,
struct radeon_fence *fence);
static struct radeon_asic r300_asic = { static struct radeon_asic r300_asic = {
.init = &r300_init, .init = &r300_init,
.fini = &r300_fini, .fini = &r300_fini,
@ -162,7 +205,46 @@ static struct radeon_asic r300_asic = {
.fence_ring_emit = &r300_fence_ring_emit, .fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse, .cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit, .copy_blit = &r100_copy_blit,
.copy_dma = &r300_copy_dma, .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock,
.get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL,
.get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_legacy_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &r100_bandwidth_update,
.hpd_init = &r100_hpd_init,
.hpd_fini = &r100_hpd_fini,
.hpd_sense = &r100_hpd_sense,
.hpd_set_polarity = &r100_hpd_set_polarity,
.ioctl_wait_idle = NULL,
};
static struct radeon_asic r300_asic_pcie = {
.init = &r300_init,
.fini = &r300_fini,
.suspend = &r300_suspend,
.resume = &r300_resume,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
.gart_set_page = &rv370_pcie_gart_set_page,
.cp_commit = &r100_cp_commit,
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
.irq_set = &r100_irq_set,
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
.fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit,
.copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit, .copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock, .get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock, .set_engine_clock = &radeon_legacy_set_engine_clock,
@ -206,12 +288,13 @@ static struct radeon_asic r420_asic = {
.fence_ring_emit = &r300_fence_ring_emit, .fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse, .cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit, .copy_blit = &r100_copy_blit,
.copy_dma = &r300_copy_dma, .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit, .copy = &r100_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock, .get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock, .get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock,
.get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = &rv370_set_pcie_lanes, .set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating, .set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg, .set_surface_reg = r100_set_surface_reg,
@ -255,12 +338,13 @@ static struct radeon_asic rs400_asic = {
.fence_ring_emit = &r300_fence_ring_emit, .fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse, .cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit, .copy_blit = &r100_copy_blit,
.copy_dma = &r300_copy_dma, .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit, .copy = &r100_copy_blit,
.get_engine_clock = &radeon_legacy_get_engine_clock, .get_engine_clock = &radeon_legacy_get_engine_clock,
.set_engine_clock = &radeon_legacy_set_engine_clock, .set_engine_clock = &radeon_legacy_set_engine_clock,
.get_memory_clock = &radeon_legacy_get_memory_clock, .get_memory_clock = &radeon_legacy_get_memory_clock,
.set_memory_clock = NULL, .set_memory_clock = NULL,
.get_pcie_lanes = NULL,
.set_pcie_lanes = NULL, .set_pcie_lanes = NULL,
.set_clock_gating = &radeon_legacy_set_clock_gating, .set_clock_gating = &radeon_legacy_set_clock_gating,
.set_surface_reg = r100_set_surface_reg, .set_surface_reg = r100_set_surface_reg,
@ -314,14 +398,17 @@ static struct radeon_asic rs600_asic = {
.fence_ring_emit = &r300_fence_ring_emit, .fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse, .cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit, .copy_blit = &r100_copy_blit,
.copy_dma = &r300_copy_dma, .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit, .copy = &r100_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock, .get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock, .get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock,
.get_pcie_lanes = NULL,
.set_pcie_lanes = NULL, .set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating, .set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg,
.clear_surface_reg = r100_clear_surface_reg,
.bandwidth_update = &rs600_bandwidth_update, .bandwidth_update = &rs600_bandwidth_update,
.hpd_init = &rs600_hpd_init, .hpd_init = &rs600_hpd_init,
.hpd_fini = &rs600_hpd_fini, .hpd_fini = &rs600_hpd_fini,
@ -360,12 +447,13 @@ static struct radeon_asic rs690_asic = {
.fence_ring_emit = &r300_fence_ring_emit, .fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse, .cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit, .copy_blit = &r100_copy_blit,
.copy_dma = &r300_copy_dma, .copy_dma = &r200_copy_dma,
.copy = &r300_copy_dma, .copy = &r200_copy_dma,
.get_engine_clock = &radeon_atom_get_engine_clock, .get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock, .get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock,
.get_pcie_lanes = NULL,
.set_pcie_lanes = NULL, .set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating, .set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg, .set_surface_reg = r100_set_surface_reg,
@ -412,12 +500,13 @@ static struct radeon_asic rv515_asic = {
.fence_ring_emit = &r300_fence_ring_emit, .fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse, .cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit, .copy_blit = &r100_copy_blit,
.copy_dma = &r300_copy_dma, .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit, .copy = &r100_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock, .get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock, .get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock,
.get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = &rv370_set_pcie_lanes, .set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating, .set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg, .set_surface_reg = r100_set_surface_reg,
@ -455,12 +544,13 @@ static struct radeon_asic r520_asic = {
.fence_ring_emit = &r300_fence_ring_emit, .fence_ring_emit = &r300_fence_ring_emit,
.cs_parse = &r300_cs_parse, .cs_parse = &r300_cs_parse,
.copy_blit = &r100_copy_blit, .copy_blit = &r100_copy_blit,
.copy_dma = &r300_copy_dma, .copy_dma = &r200_copy_dma,
.copy = &r100_copy_blit, .copy = &r100_copy_blit,
.get_engine_clock = &radeon_atom_get_engine_clock, .get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock, .get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock,
.get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = &rv370_set_pcie_lanes, .set_pcie_lanes = &rv370_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating, .set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r100_set_surface_reg, .set_surface_reg = r100_set_surface_reg,
@ -538,8 +628,9 @@ static struct radeon_asic r600_asic = {
.set_engine_clock = &radeon_atom_set_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock, .get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock,
.get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = NULL, .set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating, .set_clock_gating = NULL,
.set_surface_reg = r600_set_surface_reg, .set_surface_reg = r600_set_surface_reg,
.clear_surface_reg = r600_clear_surface_reg, .clear_surface_reg = r600_clear_surface_reg,
.bandwidth_update = &rv515_bandwidth_update, .bandwidth_update = &rv515_bandwidth_update,
@ -583,6 +674,7 @@ static struct radeon_asic rv770_asic = {
.set_engine_clock = &radeon_atom_set_engine_clock, .set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock, .get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock, .set_memory_clock = &radeon_atom_set_memory_clock,
.get_pcie_lanes = &rv370_get_pcie_lanes,
.set_pcie_lanes = NULL, .set_pcie_lanes = NULL,
.set_clock_gating = &radeon_atom_set_clock_gating, .set_clock_gating = &radeon_atom_set_clock_gating,
.set_surface_reg = r600_set_surface_reg, .set_surface_reg = r600_set_surface_reg,
@ -595,4 +687,54 @@ static struct radeon_asic rv770_asic = {
.ioctl_wait_idle = r600_ioctl_wait_idle, .ioctl_wait_idle = r600_ioctl_wait_idle,
}; };
/*
* evergreen
*/
int evergreen_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev);
int evergreen_suspend(struct radeon_device *rdev);
int evergreen_resume(struct radeon_device *rdev);
int evergreen_gpu_reset(struct radeon_device *rdev);
void evergreen_bandwidth_update(struct radeon_device *rdev);
void evergreen_hpd_init(struct radeon_device *rdev);
void evergreen_hpd_fini(struct radeon_device *rdev);
bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
void evergreen_hpd_set_polarity(struct radeon_device *rdev,
enum radeon_hpd_id hpd);
static struct radeon_asic evergreen_asic = {
.init = &evergreen_init,
.fini = &evergreen_fini,
.suspend = &evergreen_suspend,
.resume = &evergreen_resume,
.cp_commit = NULL,
.gpu_reset = &evergreen_gpu_reset,
.vga_set_state = &r600_vga_set_state,
.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
.gart_set_page = &rs600_gart_set_page,
.ring_test = NULL,
.ring_ib_execute = NULL,
.irq_set = NULL,
.irq_process = NULL,
.get_vblank_counter = NULL,
.fence_ring_emit = NULL,
.cs_parse = NULL,
.copy_blit = NULL,
.copy_dma = NULL,
.copy = NULL,
.get_engine_clock = &radeon_atom_get_engine_clock,
.set_engine_clock = &radeon_atom_set_engine_clock,
.get_memory_clock = &radeon_atom_get_memory_clock,
.set_memory_clock = &radeon_atom_set_memory_clock,
.set_pcie_lanes = NULL,
.set_clock_gating = NULL,
.set_surface_reg = r600_set_surface_reg,
.clear_surface_reg = r600_clear_surface_reg,
.bandwidth_update = &evergreen_bandwidth_update,
.hpd_init = &evergreen_hpd_init,
.hpd_fini = &evergreen_hpd_fini,
.hpd_sense = &evergreen_hpd_sense,
.hpd_set_polarity = &evergreen_hpd_set_polarity,
};
#endif #endif

View File

@ -159,8 +159,15 @@ static struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device
struct radeon_gpio_rec *gpio) struct radeon_gpio_rec *gpio)
{ {
struct radeon_hpd hpd; struct radeon_hpd hpd;
u32 reg;
if (ASIC_IS_DCE4(rdev))
reg = EVERGREEN_DC_GPIO_HPD_A;
else
reg = AVIVO_DC_GPIO_HPD_A;
hpd.gpio = *gpio; hpd.gpio = *gpio;
if (gpio->reg == AVIVO_DC_GPIO_HPD_A) { if (gpio->reg == reg) {
switch(gpio->mask) { switch(gpio->mask) {
case (1 << 0): case (1 << 0):
hpd.hpd = RADEON_HPD_1; hpd.hpd = RADEON_HPD_1;
@ -574,6 +581,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
ddc_bus.valid = false; ddc_bus.valid = false;
} }
/* needed for aux chan transactions */
ddc_bus.hpd_id = hpd.hpd ? (hpd.hpd - 1) : 0;
conn_id = le16_to_cpu(path->usConnObjectId); conn_id = le16_to_cpu(path->usConnObjectId);
if (!radeon_atom_apply_quirks if (!radeon_atom_apply_quirks
@ -838,6 +848,7 @@ union firmware_info {
ATOM_FIRMWARE_INFO_V1_2 info_12; ATOM_FIRMWARE_INFO_V1_2 info_12;
ATOM_FIRMWARE_INFO_V1_3 info_13; ATOM_FIRMWARE_INFO_V1_3 info_13;
ATOM_FIRMWARE_INFO_V1_4 info_14; ATOM_FIRMWARE_INFO_V1_4 info_14;
ATOM_FIRMWARE_INFO_V2_1 info_21;
}; };
bool radeon_atom_get_clock_info(struct drm_device *dev) bool radeon_atom_get_clock_info(struct drm_device *dev)
@ -849,6 +860,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
uint8_t frev, crev; uint8_t frev, crev;
struct radeon_pll *p1pll = &rdev->clock.p1pll; struct radeon_pll *p1pll = &rdev->clock.p1pll;
struct radeon_pll *p2pll = &rdev->clock.p2pll; struct radeon_pll *p2pll = &rdev->clock.p2pll;
struct radeon_pll *dcpll = &rdev->clock.dcpll;
struct radeon_pll *spll = &rdev->clock.spll; struct radeon_pll *spll = &rdev->clock.spll;
struct radeon_pll *mpll = &rdev->clock.mpll; struct radeon_pll *mpll = &rdev->clock.mpll;
uint16_t data_offset; uint16_t data_offset;
@ -951,8 +963,19 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
rdev->clock.default_mclk = rdev->clock.default_mclk =
le32_to_cpu(firmware_info->info.ulDefaultMemoryClock); le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
if (ASIC_IS_DCE4(rdev)) {
rdev->clock.default_dispclk =
le32_to_cpu(firmware_info->info_21.ulDefaultDispEngineClkFreq);
if (rdev->clock.default_dispclk == 0)
rdev->clock.default_dispclk = 60000; /* 600 Mhz */
rdev->clock.dp_extclk =
le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
}
*dcpll = *p1pll;
return true; return true;
} }
return false; return false;
} }
@ -1091,6 +1114,30 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct
return ss; return ss;
} }
static void radeon_atom_apply_lvds_quirks(struct drm_device *dev,
struct radeon_encoder_atom_dig *lvds)
{
/* Toshiba A300-1BU laptop panel doesn't like new pll divider algo */
if ((dev->pdev->device == 0x95c4) &&
(dev->pdev->subsystem_vendor == 0x1179) &&
(dev->pdev->subsystem_device == 0xff50)) {
if ((lvds->native_mode.hdisplay == 1280) &&
(lvds->native_mode.vdisplay == 800))
lvds->pll_algo = PLL_ALGO_LEGACY;
}
/* Dell Studio 15 laptop panel doesn't like new pll divider algo */
if ((dev->pdev->device == 0x95c4) &&
(dev->pdev->subsystem_vendor == 0x1028) &&
(dev->pdev->subsystem_device == 0x029f)) {
if ((lvds->native_mode.hdisplay == 1280) &&
(lvds->native_mode.vdisplay == 800))
lvds->pll_algo = PLL_ALGO_LEGACY;
}
}
union lvds_info { union lvds_info {
struct _ATOM_LVDS_INFO info; struct _ATOM_LVDS_INFO info;
struct _ATOM_LVDS_INFO_V12 info_12; struct _ATOM_LVDS_INFO_V12 info_12;
@ -1161,6 +1208,21 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id); lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id);
if (ASIC_IS_AVIVO(rdev)) {
if (radeon_new_pll == 0)
lvds->pll_algo = PLL_ALGO_LEGACY;
else
lvds->pll_algo = PLL_ALGO_NEW;
} else {
if (radeon_new_pll == 1)
lvds->pll_algo = PLL_ALGO_NEW;
else
lvds->pll_algo = PLL_ALGO_LEGACY;
}
/* LVDS quirks */
radeon_atom_apply_lvds_quirks(dev, lvds);
encoder->native_mode = lvds->native_mode; encoder->native_mode = lvds->native_mode;
} }
return lvds; return lvds;
@ -1385,6 +1447,371 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
return tv_dac; return tv_dac;
} }
union power_info {
struct _ATOM_POWERPLAY_INFO info;
struct _ATOM_POWERPLAY_INFO_V2 info_2;
struct _ATOM_POWERPLAY_INFO_V3 info_3;
struct _ATOM_PPLIB_POWERPLAYTABLE info_4;
};
void radeon_atombios_get_power_modes(struct radeon_device *rdev)
{
struct radeon_mode_info *mode_info = &rdev->mode_info;
int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
u16 data_offset;
u8 frev, crev;
u32 misc, misc2 = 0, sclk, mclk;
union power_info *power_info;
struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
struct _ATOM_PPLIB_STATE *power_state;
int num_modes = 0, i, j;
int state_index = 0, mode_index = 0;
atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset);
power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
rdev->pm.default_power_state = NULL;
if (power_info) {
if (frev < 4) {
num_modes = power_info->info.ucNumOfPowerModeEntries;
if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)
num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK;
for (i = 0; i < num_modes; i++) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
switch (frev) {
case 1:
rdev->pm.power_state[state_index].num_clock_modes = 1;
rdev->pm.power_state[state_index].clock_info[0].mclk =
le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock);
rdev->pm.power_state[state_index].clock_info[0].sclk =
le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock);
/* skip invalid modes */
if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
(rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
continue;
/* skip overclock modes for now */
if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
(rdev->pm.power_state[state_index].clock_info[0].sclk >
rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
continue;
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
radeon_lookup_gpio(rdev,
power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
true;
else
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
false;
} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_VDDC;
rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex;
}
/* order matters! */
if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_POWERSAVE;
if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
}
state_index++;
break;
case 2:
rdev->pm.power_state[state_index].num_clock_modes = 1;
rdev->pm.power_state[state_index].clock_info[0].mclk =
le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock);
rdev->pm.power_state[state_index].clock_info[0].sclk =
le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock);
/* skip invalid modes */
if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
(rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
continue;
/* skip overclock modes for now */
if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
(rdev->pm.power_state[state_index].clock_info[0].sclk >
rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
continue;
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
radeon_lookup_gpio(rdev,
power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
true;
else
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
false;
} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_VDDC;
rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex;
}
/* order matters! */
if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_POWERSAVE;
if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
}
state_index++;
break;
case 3:
rdev->pm.power_state[state_index].num_clock_modes = 1;
rdev->pm.power_state[state_index].clock_info[0].mclk =
le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock);
rdev->pm.power_state[state_index].clock_info[0].sclk =
le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock);
/* skip invalid modes */
if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
(rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
continue;
/* skip overclock modes for now */
if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
(rdev->pm.power_state[state_index].clock_info[0].sclk >
rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
continue;
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
radeon_lookup_gpio(rdev,
power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex);
if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
true;
else
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
false;
} else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_VDDC;
rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id =
power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex;
if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) {
rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled =
true;
rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id =
power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex;
}
}
/* order matters! */
if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_POWERSAVE;
if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE)
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
}
state_index++;
break;
}
}
} else if (frev == 4) {
for (i = 0; i < power_info->info_4.ucNumStates; i++) {
mode_index = 0;
power_state = (struct _ATOM_PPLIB_STATE *)
(mode_info->atom_context->bios +
data_offset +
le16_to_cpu(power_info->info_4.usStateArrayOffset) +
i * power_info->info_4.ucStateEntrySize);
non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
(mode_info->atom_context->bios +
data_offset +
le16_to_cpu(power_info->info_4.usNonClockInfoArrayOffset) +
(power_state->ucNonClockStateIndex *
power_info->info_4.ucNonClockSize));
for (j = 0; j < (power_info->info_4.ucStateEntrySize - 1); j++) {
if (rdev->flags & RADEON_IS_IGP) {
struct _ATOM_PPLIB_RS780_CLOCK_INFO *clock_info =
(struct _ATOM_PPLIB_RS780_CLOCK_INFO *)
(mode_info->atom_context->bios +
data_offset +
le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) +
(power_state->ucClockStateIndices[j] *
power_info->info_4.ucClockInfoSize));
sclk = le16_to_cpu(clock_info->usLowEngineClockLow);
sclk |= clock_info->ucLowEngineClockHigh << 16;
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
/* skip invalid modes */
if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)
continue;
/* skip overclock modes for now */
if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk >
rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN)
continue;
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
VOLTAGE_SW;
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
clock_info->usVDDC;
mode_index++;
} else {
struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info =
(struct _ATOM_PPLIB_R600_CLOCK_INFO *)
(mode_info->atom_context->bios +
data_offset +
le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) +
(power_state->ucClockStateIndices[j] *
power_info->info_4.ucClockInfoSize));
sclk = le16_to_cpu(clock_info->usEngineClockLow);
sclk |= clock_info->ucEngineClockHigh << 16;
mclk = le16_to_cpu(clock_info->usMemoryClockLow);
mclk |= clock_info->ucMemoryClockHigh << 16;
rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
/* skip invalid modes */
if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) ||
(rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0))
continue;
/* skip overclock modes for now */
if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk >
rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
(rdev->pm.power_state[state_index].clock_info[mode_index].sclk >
rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
continue;
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
VOLTAGE_SW;
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage =
clock_info->usVDDC;
mode_index++;
}
}
rdev->pm.power_state[state_index].num_clock_modes = mode_index;
if (mode_index) {
misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
misc2 = le16_to_cpu(non_clock_info->usClassification);
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
break;
case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BALANCED;
break;
case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_PERFORMANCE;
break;
}
if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) {
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[mode_index - 1];
}
state_index++;
}
}
}
} else {
/* XXX figure out some good default low power mode for cards w/out power tables */
}
if (rdev->pm.default_power_state == NULL) {
/* add the default mode */
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.power_state[state_index].num_clock_modes = 1;
rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[0];
rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
if (rdev->asic->get_pcie_lanes)
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev);
else
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16;
rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
state_index++;
}
rdev->pm.num_power_states = state_index;
rdev->pm.current_power_state = rdev->pm.default_power_state;
rdev->pm.current_clock_mode =
rdev->pm.default_power_state->default_clock_mode;
}
void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
{ {
DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
@ -1395,16 +1822,6 @@ void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
} }
void radeon_atom_static_pwrmgt_setup(struct radeon_device *rdev, int enable)
{
ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION args;
int index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt);
args.ucEnable = enable;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev) uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev)
{ {
GET_ENGINE_CLOCK_PS_ALLOCATION args; GET_ENGINE_CLOCK_PS_ALLOCATION args;

View File

@ -0,0 +1,257 @@
/*
* Copyright (c) 2010 Red Hat Inc.
* Author : Dave Airlie <airlied@redhat.com>
*
* Licensed under GPLv2
*
* ATPX support for both Intel/ATI
*/
#include <linux/vga_switcheroo.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <linux/pci.h>
#define ATPX_VERSION 0
#define ATPX_GPU_PWR 2
#define ATPX_MUX_SELECT 3
#define ATPX_INTEGRATED 0
#define ATPX_DISCRETE 1
#define ATPX_MUX_IGD 0
#define ATPX_MUX_DISCRETE 1
static struct radeon_atpx_priv {
bool atpx_detected;
/* handle for device - and atpx */
acpi_handle dhandle;
acpi_handle atpx_handle;
acpi_handle atrm_handle;
} radeon_atpx_priv;
/* retrieve the ROM in 4k blocks */
static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
int offset, int len)
{
acpi_status status;
union acpi_object atrm_arg_elements[2], *obj;
struct acpi_object_list atrm_arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
atrm_arg.count = 2;
atrm_arg.pointer = &atrm_arg_elements[0];
atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
atrm_arg_elements[0].integer.value = offset;
atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
atrm_arg_elements[1].integer.value = len;
status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
if (ACPI_FAILURE(status)) {
printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
return -ENODEV;
}
obj = (union acpi_object *)buffer.pointer;
memcpy(bios+offset, obj->buffer.pointer, len);
kfree(buffer.pointer);
return len;
}
bool radeon_atrm_supported(struct pci_dev *pdev)
{
/* get the discrete ROM only via ATRM */
if (!radeon_atpx_priv.atpx_detected)
return false;
if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
return false;
return true;
}
int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len)
{
return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len);
}
static int radeon_atpx_get_version(acpi_handle handle)
{
acpi_status status;
union acpi_object atpx_arg_elements[2], *obj;
struct acpi_object_list atpx_arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
atpx_arg.count = 2;
atpx_arg.pointer = &atpx_arg_elements[0];
atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
atpx_arg_elements[0].integer.value = ATPX_VERSION;
atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
atpx_arg_elements[1].integer.value = ATPX_VERSION;
status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
if (ACPI_FAILURE(status)) {
printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status));
return -ENOSYS;
}
obj = (union acpi_object *)buffer.pointer;
if (obj && (obj->type == ACPI_TYPE_BUFFER))
printk(KERN_INFO "radeon atpx: version is %d\n", *((u8 *)(obj->buffer.pointer) + 2));
kfree(buffer.pointer);
return 0;
}
static int radeon_atpx_execute(acpi_handle handle, int cmd_id, u16 value)
{
acpi_status status;
union acpi_object atpx_arg_elements[2];
struct acpi_object_list atpx_arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
uint8_t buf[4] = {0};
if (!handle)
return -EINVAL;
atpx_arg.count = 2;
atpx_arg.pointer = &atpx_arg_elements[0];
atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
atpx_arg_elements[0].integer.value = cmd_id;
buf[2] = value & 0xff;
buf[3] = (value >> 8) & 0xff;
atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
atpx_arg_elements[1].buffer.length = 4;
atpx_arg_elements[1].buffer.pointer = buf;
status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
if (ACPI_FAILURE(status)) {
printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status));
return -ENOSYS;
}
kfree(buffer.pointer);
return 0;
}
static int radeon_atpx_set_discrete_state(acpi_handle handle, int state)
{
return radeon_atpx_execute(handle, ATPX_GPU_PWR, state);
}
static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id)
{
return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id);
}
static int radeon_atpx_switchto(enum vga_switcheroo_client_id id)
{
if (id == VGA_SWITCHEROO_IGD)
radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 0);
else
radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 1);
return 0;
}
static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,
enum vga_switcheroo_state state)
{
/* on w500 ACPI can't change intel gpu state */
if (id == VGA_SWITCHEROO_IGD)
return 0;
radeon_atpx_set_discrete_state(radeon_atpx_priv.atpx_handle, state);
return 0;
}
static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
{
acpi_handle dhandle, atpx_handle, atrm_handle;
acpi_status status;
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
if (!dhandle)
return false;
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
if (ACPI_FAILURE(status))
return false;
status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
if (ACPI_FAILURE(status))
return false;
radeon_atpx_priv.dhandle = dhandle;
radeon_atpx_priv.atpx_handle = atpx_handle;
radeon_atpx_priv.atrm_handle = atrm_handle;
return true;
}
static int radeon_atpx_init(void)
{
/* set up the ATPX handle */
radeon_atpx_get_version(radeon_atpx_priv.atpx_handle);
return 0;
}
static int radeon_atpx_get_client_id(struct pci_dev *pdev)
{
if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
return VGA_SWITCHEROO_IGD;
else
return VGA_SWITCHEROO_DIS;
}
static struct vga_switcheroo_handler radeon_atpx_handler = {
.switchto = radeon_atpx_switchto,
.power_state = radeon_atpx_power_state,
.init = radeon_atpx_init,
.get_client_id = radeon_atpx_get_client_id,
};
static bool radeon_atpx_detect(void)
{
char acpi_method_name[255] = { 0 };
struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
struct pci_dev *pdev = NULL;
bool has_atpx = false;
int vga_count = 0;
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
vga_count++;
has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
}
if (has_atpx && vga_count == 2) {
acpi_get_name(radeon_atpx_priv.atpx_handle, ACPI_FULL_PATHNAME, &buffer);
printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
acpi_method_name);
radeon_atpx_priv.atpx_detected = true;
return true;
}
return false;
}
void radeon_register_atpx_handler(void)
{
bool r;
/* detect if we have any ATPX + 2 VGA in the system */
r = radeon_atpx_detect();
if (!r)
return;
vga_switcheroo_register_handler(&radeon_atpx_handler);
}
void radeon_unregister_atpx_handler(void)
{
vga_switcheroo_unregister_handler();
}

View File

@ -30,6 +30,7 @@
#include "radeon.h" #include "radeon.h"
#include "atom.h" #include "atom.h"
#include <linux/vga_switcheroo.h>
/* /*
* BIOS. * BIOS.
*/ */
@ -62,7 +63,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
iounmap(bios); iounmap(bios);
return false; return false;
} }
memcpy(rdev->bios, bios, size); memcpy_fromio(rdev->bios, bios, size);
iounmap(bios); iounmap(bios);
return true; return true;
} }
@ -93,6 +94,38 @@ static bool radeon_read_bios(struct radeon_device *rdev)
return true; return true;
} }
/* ATRM is used to get the BIOS on the discrete cards in
* dual-gpu systems.
*/
static bool radeon_atrm_get_bios(struct radeon_device *rdev)
{
int ret;
int size = 64 * 1024;
int i;
if (!radeon_atrm_supported(rdev->pdev))
return false;
rdev->bios = kmalloc(size, GFP_KERNEL);
if (!rdev->bios) {
DRM_ERROR("Unable to allocate bios\n");
return false;
}
for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
ret = radeon_atrm_get_bios_chunk(rdev->bios,
(i * ATRM_BIOS_PAGE),
ATRM_BIOS_PAGE);
if (ret <= 0)
break;
}
if (i == 0 || rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
kfree(rdev->bios);
return false;
}
return true;
}
static bool r700_read_disabled_bios(struct radeon_device *rdev) static bool r700_read_disabled_bios(struct radeon_device *rdev)
{ {
uint32_t viph_control; uint32_t viph_control;
@ -388,16 +421,16 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)
return legacy_read_disabled_bios(rdev); return legacy_read_disabled_bios(rdev);
} }
bool radeon_get_bios(struct radeon_device *rdev) bool radeon_get_bios(struct radeon_device *rdev)
{ {
bool r; bool r;
uint16_t tmp; uint16_t tmp;
if (rdev->flags & RADEON_IS_IGP) { r = radeon_atrm_get_bios(rdev);
if (r == false)
r = igp_read_bios_from_vram(rdev); r = igp_read_bios_from_vram(rdev);
if (r == false) if (r == false)
r = radeon_read_bios(rdev);
} else
r = radeon_read_bios(rdev); r = radeon_read_bios(rdev);
if (r == false) { if (r == false) {
r = radeon_read_disabled_bios(rdev); r = radeon_read_disabled_bios(rdev);
@ -408,6 +441,13 @@ bool radeon_get_bios(struct radeon_device *rdev)
return false; return false;
} }
if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) { if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
printk("BIOS signature incorrect %x %x\n", rdev->bios[0], rdev->bios[1]);
goto free_bios;
}
tmp = RBIOS16(0x18);
if (RBIOS8(tmp + 0x14) != 0x0) {
DRM_INFO("Not an x86 BIOS ROM, not using.\n");
goto free_bios; goto free_bios;
} }

View File

@ -96,6 +96,7 @@ void radeon_get_clock_info(struct drm_device *dev)
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
struct radeon_pll *p1pll = &rdev->clock.p1pll; struct radeon_pll *p1pll = &rdev->clock.p1pll;
struct radeon_pll *p2pll = &rdev->clock.p2pll; struct radeon_pll *p2pll = &rdev->clock.p2pll;
struct radeon_pll *dcpll = &rdev->clock.dcpll;
struct radeon_pll *spll = &rdev->clock.spll; struct radeon_pll *spll = &rdev->clock.spll;
struct radeon_pll *mpll = &rdev->clock.mpll; struct radeon_pll *mpll = &rdev->clock.mpll;
int ret; int ret;
@ -204,6 +205,17 @@ void radeon_get_clock_info(struct drm_device *dev)
p2pll->max_frac_feedback_div = 0; p2pll->max_frac_feedback_div = 0;
} }
/* dcpll is DCE4 only */
dcpll->min_post_div = 2;
dcpll->max_post_div = 0x7f;
dcpll->min_frac_feedback_div = 0;
dcpll->max_frac_feedback_div = 9;
dcpll->min_ref_div = 2;
dcpll->max_ref_div = 0x3ff;
dcpll->min_feedback_div = 4;
dcpll->max_feedback_div = 0xfff;
dcpll->best_vco = 0;
p1pll->min_ref_div = 2; p1pll->min_ref_div = 2;
p1pll->max_ref_div = 0x3ff; p1pll->max_ref_div = 0x3ff;
p1pll->min_feedback_div = 4; p1pll->min_feedback_div = 4;
@ -846,8 +858,10 @@ int radeon_static_clocks_init(struct drm_device *dev)
/* XXX make sure engine is idle */ /* XXX make sure engine is idle */
if (radeon_dynclks != -1) { if (radeon_dynclks != -1) {
if (radeon_dynclks) if (radeon_dynclks) {
radeon_set_clock_gating(rdev, 1); if (rdev->asic->set_clock_gating)
radeon_set_clock_gating(rdev, 1);
}
} }
radeon_apply_clock_quirks(rdev); radeon_apply_clock_quirks(rdev);
return 0; return 0;

View File

@ -150,6 +150,9 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
int rev; int rev;
uint16_t offset = 0, check_offset; uint16_t offset = 0, check_offset;
if (!rdev->bios)
return 0;
switch (table) { switch (table) {
/* absolute offset tables */ /* absolute offset tables */
case COMBIOS_ASIC_INIT_1_TABLE: case COMBIOS_ASIC_INIT_1_TABLE:
@ -443,6 +446,39 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
} }
bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
{
int edid_info;
struct edid *edid;
edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE);
if (!edid_info)
return false;
edid = kmalloc(EDID_LENGTH * (DRM_MAX_EDID_EXT_NUM + 1),
GFP_KERNEL);
if (edid == NULL)
return false;
memcpy((unsigned char *)edid,
(unsigned char *)(rdev->bios + edid_info), EDID_LENGTH);
if (!drm_edid_is_valid(edid)) {
kfree(edid);
return false;
}
rdev->mode_info.bios_hardcoded_edid = edid;
return true;
}
struct edid *
radeon_combios_get_hardcoded_edid(struct radeon_device *rdev)
{
if (rdev->mode_info.bios_hardcoded_edid)
return rdev->mode_info.bios_hardcoded_edid;
return NULL;
}
static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev, static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
int ddc_line) int ddc_line)
{ {
@ -486,9 +522,65 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
i2c.y_data_reg = ddc_line; i2c.y_data_reg = ddc_line;
} }
if (rdev->family < CHIP_R200) switch (rdev->family) {
i2c.hw_capable = false; case CHIP_R100:
else { case CHIP_RV100:
case CHIP_RS100:
case CHIP_RV200:
case CHIP_RS200:
case CHIP_RS300:
switch (ddc_line) {
case RADEON_GPIO_DVI_DDC:
/* in theory this should be hw capable,
* but it doesn't seem to work
*/
i2c.hw_capable = false;
break;
default:
i2c.hw_capable = false;
break;
}
break;
case CHIP_R200:
switch (ddc_line) {
case RADEON_GPIO_DVI_DDC:
case RADEON_GPIO_MONID:
i2c.hw_capable = true;
break;
default:
i2c.hw_capable = false;
break;
}
break;
case CHIP_RV250:
case CHIP_RV280:
switch (ddc_line) {
case RADEON_GPIO_VGA_DDC:
case RADEON_GPIO_DVI_DDC:
case RADEON_GPIO_CRT2_DDC:
i2c.hw_capable = true;
break;
default:
i2c.hw_capable = false;
break;
}
break;
case CHIP_R300:
case CHIP_R350:
switch (ddc_line) {
case RADEON_GPIO_VGA_DDC:
case RADEON_GPIO_DVI_DDC:
i2c.hw_capable = true;
break;
default:
i2c.hw_capable = false;
break;
}
break;
case CHIP_RV350:
case CHIP_RV380:
case CHIP_RS400:
case CHIP_RS480:
switch (ddc_line) { switch (ddc_line) {
case RADEON_GPIO_VGA_DDC: case RADEON_GPIO_VGA_DDC:
case RADEON_GPIO_DVI_DDC: case RADEON_GPIO_DVI_DDC:
@ -504,9 +596,14 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
i2c.hw_capable = false; i2c.hw_capable = false;
break; break;
} }
break;
default:
i2c.hw_capable = false;
break;
} }
i2c.mm_i2c = false; i2c.mm_i2c = false;
i2c.i2c_id = 0; i2c.i2c_id = 0;
i2c.hpd_id = 0;
if (ddc_line) if (ddc_line)
i2c.valid = true; i2c.valid = true;
@ -527,9 +624,6 @@ bool radeon_combios_get_clock_info(struct drm_device *dev)
int8_t rev; int8_t rev;
uint16_t sclk, mclk; uint16_t sclk, mclk;
if (rdev->bios == NULL)
return false;
pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE); pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE);
if (pll_info) { if (pll_info) {
rev = RBIOS8(pll_info); rev = RBIOS8(pll_info);
@ -654,9 +748,6 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
if (!p_dac) if (!p_dac)
return NULL; return NULL;
if (rdev->bios == NULL)
goto out;
/* check CRT table */ /* check CRT table */
dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);
if (dac_info) { if (dac_info) {
@ -673,7 +764,6 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
found = 1; found = 1;
} }
out:
if (!found) /* fallback to defaults */ if (!found) /* fallback to defaults */
radeon_legacy_get_primary_dac_info_from_table(rdev, p_dac); radeon_legacy_get_primary_dac_info_from_table(rdev, p_dac);
@ -687,9 +777,6 @@ radeon_combios_get_tv_info(struct radeon_device *rdev)
uint16_t tv_info; uint16_t tv_info;
enum radeon_tv_std tv_std = TV_STD_NTSC; enum radeon_tv_std tv_std = TV_STD_NTSC;
if (rdev->bios == NULL)
return tv_std;
tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
if (tv_info) { if (tv_info) {
if (RBIOS8(tv_info + 6) == 'T') { if (RBIOS8(tv_info + 6) == 'T') {
@ -793,9 +880,6 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
if (!tv_dac) if (!tv_dac)
return NULL; return NULL;
if (rdev->bios == NULL)
goto out;
/* first check TV table */ /* first check TV table */
dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
if (dac_info) { if (dac_info) {
@ -857,7 +941,6 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
} }
} }
out:
if (!found) /* fallback to defaults */ if (!found) /* fallback to defaults */
radeon_legacy_get_tv_dac_info_from_table(rdev, tv_dac); radeon_legacy_get_tv_dac_info_from_table(rdev, tv_dac);
@ -945,11 +1028,6 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
int tmp, i; int tmp, i;
struct radeon_encoder_lvds *lvds = NULL; struct radeon_encoder_lvds *lvds = NULL;
if (rdev->bios == NULL) {
lvds = radeon_legacy_get_lvds_info_from_regs(rdev);
goto out;
}
lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE);
if (lcd_info) { if (lcd_info) {
@ -1050,7 +1128,7 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
DRM_INFO("No panel info found in BIOS\n"); DRM_INFO("No panel info found in BIOS\n");
lvds = radeon_legacy_get_lvds_info_from_regs(rdev); lvds = radeon_legacy_get_lvds_info_from_regs(rdev);
} }
out:
if (lvds) if (lvds)
encoder->native_mode = lvds->native_mode; encoder->native_mode = lvds->native_mode;
return lvds; return lvds;
@ -1102,9 +1180,6 @@ bool radeon_legacy_get_tmds_info_from_combios(struct radeon_encoder *encoder,
int i, n; int i, n;
uint8_t ver; uint8_t ver;
if (rdev->bios == NULL)
return false;
tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE);
if (tmds_info) { if (tmds_info) {
@ -1184,9 +1259,6 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
enum radeon_combios_ddc gpio; enum radeon_combios_ddc gpio;
struct radeon_i2c_bus_rec i2c_bus; struct radeon_i2c_bus_rec i2c_bus;
if (rdev->bios == NULL)
return false;
tmds->i2c_bus = NULL; tmds->i2c_bus = NULL;
if (rdev->flags & RADEON_IS_IGP) { if (rdev->flags & RADEON_IS_IGP) {
offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE); offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
@ -1253,7 +1325,10 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO"); tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
break; break;
case DDC_LCD: /* MM i2c */ case DDC_LCD: /* MM i2c */
DRM_ERROR("MM i2c requires hw i2c engine\n"); i2c_bus.valid = true;
i2c_bus.hw_capable = true;
i2c_bus.mm_i2c = true;
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
break; break;
default: default:
DRM_ERROR("Unsupported gpio %d\n", gpio); DRM_ERROR("Unsupported gpio %d\n", gpio);
@ -1909,9 +1984,6 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
struct radeon_i2c_bus_rec ddc_i2c; struct radeon_i2c_bus_rec ddc_i2c;
struct radeon_hpd hpd; struct radeon_hpd hpd;
if (rdev->bios == NULL)
return false;
conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE); conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE);
if (conn_info) { if (conn_info) {
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
@ -2278,6 +2350,115 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
return true; return true;
} }
void radeon_combios_get_power_modes(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
u16 offset, misc, misc2 = 0;
u8 rev, blocks, tmp;
int state_index = 0;
rdev->pm.default_power_state = NULL;
if (rdev->flags & RADEON_IS_MOBILITY) {
offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
if (offset) {
rev = RBIOS8(offset);
blocks = RBIOS8(offset + 0x2);
/* power mode 0 tends to be the only valid one */
rdev->pm.power_state[state_index].num_clock_modes = 1;
rdev->pm.power_state[state_index].clock_info[0].mclk = RBIOS32(offset + 0x5 + 0x2);
rdev->pm.power_state[state_index].clock_info[0].sclk = RBIOS32(offset + 0x5 + 0x6);
if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) ||
(rdev->pm.power_state[state_index].clock_info[0].sclk == 0))
goto default_mode;
/* skip overclock modes for now */
if ((rdev->pm.power_state[state_index].clock_info[0].mclk >
rdev->clock.default_mclk + RADEON_MODE_OVERCLOCK_MARGIN) ||
(rdev->pm.power_state[state_index].clock_info[0].sclk >
rdev->clock.default_sclk + RADEON_MODE_OVERCLOCK_MARGIN))
goto default_mode;
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_BATTERY;
misc = RBIOS16(offset + 0x5 + 0x0);
if (rev > 4)
misc2 = RBIOS16(offset + 0x5 + 0xe);
if (misc & 0x4) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_GPIO;
if (misc & 0x8)
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
true;
else
rdev->pm.power_state[state_index].clock_info[0].voltage.active_high =
false;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.valid = true;
if (rev < 6) {
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg =
RBIOS16(offset + 0x5 + 0xb) * 4;
tmp = RBIOS8(offset + 0x5 + 0xd);
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.mask = (1 << tmp);
} else {
u8 entries = RBIOS8(offset + 0x5 + 0xb);
u16 voltage_table_offset = RBIOS16(offset + 0x5 + 0xc);
if (entries && voltage_table_offset) {
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.reg =
RBIOS16(voltage_table_offset) * 4;
tmp = RBIOS8(voltage_table_offset + 0x2);
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.mask = (1 << tmp);
} else
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio.valid = false;
}
switch ((misc2 & 0x700) >> 8) {
case 0:
default:
rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 0;
break;
case 1:
rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 33;
break;
case 2:
rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 66;
break;
case 3:
rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 99;
break;
case 4:
rdev->pm.power_state[state_index].clock_info[0].voltage.delay = 132;
break;
}
} else
rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
if (rev > 6)
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes =
RBIOS8(offset + 0x5 + 0x10);
state_index++;
} else {
/* XXX figure out some good default low power mode for mobility cards w/out power tables */
}
} else {
/* XXX figure out some good default low power mode for desktop cards */
}
default_mode:
/* add the default mode */
rdev->pm.power_state[state_index].type =
POWER_STATE_TYPE_DEFAULT;
rdev->pm.power_state[state_index].num_clock_modes = 1;
rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0];
rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
if (rdev->asic->get_pcie_lanes)
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = radeon_get_pcie_lanes(rdev);
else
rdev->pm.power_state[state_index].non_clock_info.pcie_lanes = 16;
rdev->pm.default_power_state = &rdev->pm.power_state[state_index];
rdev->pm.num_power_states = state_index + 1;
rdev->pm.current_power_state = rdev->pm.default_power_state;
rdev->pm.current_clock_mode =
rdev->pm.default_power_state->default_clock_mode;
}
void radeon_external_tmds_setup(struct drm_encoder *encoder) void radeon_external_tmds_setup(struct drm_encoder *encoder)
{ {
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@ -2289,23 +2470,21 @@ void radeon_external_tmds_setup(struct drm_encoder *encoder)
switch (tmds->dvo_chip) { switch (tmds->dvo_chip) {
case DVO_SIL164: case DVO_SIL164:
/* sil 164 */ /* sil 164 */
radeon_i2c_do_lock(tmds->i2c_bus, 1); radeon_i2c_put_byte(tmds->i2c_bus,
radeon_i2c_sw_put_byte(tmds->i2c_bus, tmds->slave_addr,
tmds->slave_addr, 0x08, 0x30);
0x08, 0x30); radeon_i2c_put_byte(tmds->i2c_bus,
radeon_i2c_sw_put_byte(tmds->i2c_bus,
tmds->slave_addr, tmds->slave_addr,
0x09, 0x00); 0x09, 0x00);
radeon_i2c_sw_put_byte(tmds->i2c_bus, radeon_i2c_put_byte(tmds->i2c_bus,
tmds->slave_addr, tmds->slave_addr,
0x0a, 0x90); 0x0a, 0x90);
radeon_i2c_sw_put_byte(tmds->i2c_bus, radeon_i2c_put_byte(tmds->i2c_bus,
tmds->slave_addr, tmds->slave_addr,
0x0c, 0x89); 0x0c, 0x89);
radeon_i2c_sw_put_byte(tmds->i2c_bus, radeon_i2c_put_byte(tmds->i2c_bus,
tmds->slave_addr, tmds->slave_addr,
0x08, 0x3b); 0x08, 0x3b);
radeon_i2c_do_lock(tmds->i2c_bus, 0);
break; break;
case DVO_SIL1178: case DVO_SIL1178:
/* sil 1178 - untested */ /* sil 1178 - untested */
@ -2338,9 +2517,6 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder)
uint32_t reg, val, and_mask, or_mask; uint32_t reg, val, and_mask, or_mask;
struct radeon_encoder_ext_tmds *tmds = radeon_encoder->enc_priv; struct radeon_encoder_ext_tmds *tmds = radeon_encoder->enc_priv;
if (rdev->bios == NULL)
return false;
if (!tmds) if (!tmds)
return false; return false;
@ -2390,11 +2566,9 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder)
index++; index++;
val = RBIOS8(index); val = RBIOS8(index);
index++; index++;
radeon_i2c_do_lock(tmds->i2c_bus, 1); radeon_i2c_put_byte(tmds->i2c_bus,
radeon_i2c_sw_put_byte(tmds->i2c_bus, slave_addr,
slave_addr, reg, val);
reg, val);
radeon_i2c_do_lock(tmds->i2c_bus, 0);
break; break;
default: default:
DRM_ERROR("Unknown id %d\n", id >> 13); DRM_ERROR("Unknown id %d\n", id >> 13);
@ -2447,11 +2621,9 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder)
reg = id & 0x1fff; reg = id & 0x1fff;
val = RBIOS8(index); val = RBIOS8(index);
index += 1; index += 1;
radeon_i2c_do_lock(tmds->i2c_bus, 1); radeon_i2c_put_byte(tmds->i2c_bus,
radeon_i2c_sw_put_byte(tmds->i2c_bus, tmds->slave_addr,
tmds->slave_addr, reg, val);
reg, val);
radeon_i2c_do_lock(tmds->i2c_bus, 0);
break; break;
default: default:
DRM_ERROR("Unknown id %d\n", id >> 13); DRM_ERROR("Unknown id %d\n", id >> 13);

View File

@ -479,10 +479,8 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec
ret = connector_status_connected; ret = connector_status_connected;
else { else {
if (radeon_connector->ddc_bus) { if (radeon_connector->ddc_bus) {
radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, radeon_connector->edid = drm_get_edid(&radeon_connector->base,
&radeon_connector->ddc_bus->adapter); &radeon_connector->ddc_bus->adapter);
radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
if (radeon_connector->edid) if (radeon_connector->edid)
ret = connector_status_connected; ret = connector_status_connected;
} }
@ -587,19 +585,14 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect
if (!encoder) if (!encoder)
ret = connector_status_disconnected; ret = connector_status_disconnected;
if (radeon_connector->ddc_bus) { if (radeon_connector->ddc_bus)
radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
dret = radeon_ddc_probe(radeon_connector); dret = radeon_ddc_probe(radeon_connector);
radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
}
if (dret) { if (dret) {
if (radeon_connector->edid) { if (radeon_connector->edid) {
kfree(radeon_connector->edid); kfree(radeon_connector->edid);
radeon_connector->edid = NULL; radeon_connector->edid = NULL;
} }
radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
if (!radeon_connector->edid) { if (!radeon_connector->edid) {
DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
@ -744,19 +737,14 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
enum drm_connector_status ret = connector_status_disconnected; enum drm_connector_status ret = connector_status_disconnected;
bool dret = false; bool dret = false;
if (radeon_connector->ddc_bus) { if (radeon_connector->ddc_bus)
radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
dret = radeon_ddc_probe(radeon_connector); dret = radeon_ddc_probe(radeon_connector);
radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
}
if (dret) { if (dret) {
if (radeon_connector->edid) { if (radeon_connector->edid) {
kfree(radeon_connector->edid); kfree(radeon_connector->edid);
radeon_connector->edid = NULL; radeon_connector->edid = NULL;
} }
radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
if (!radeon_connector->edid) { if (!radeon_connector->edid) {
DRM_ERROR("%s: probed a monitor but no|invalid EDID\n", DRM_ERROR("%s: probed a monitor but no|invalid EDID\n",
@ -952,7 +940,7 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector)
if (radeon_connector->edid) if (radeon_connector->edid)
kfree(radeon_connector->edid); kfree(radeon_connector->edid);
if (radeon_dig_connector->dp_i2c_bus) if (radeon_dig_connector->dp_i2c_bus)
radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); radeon_i2c_destroy_dp(radeon_dig_connector->dp_i2c_bus);
kfree(radeon_connector->con_priv); kfree(radeon_connector->con_priv);
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
@ -988,12 +976,10 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto
ret = connector_status_connected; ret = connector_status_connected;
} }
} else { } else {
radeon_i2c_do_lock(radeon_connector->ddc_bus, 1);
if (radeon_ddc_probe(radeon_connector)) { if (radeon_ddc_probe(radeon_connector)) {
radeon_dig_connector->dp_sink_type = sink_type; radeon_dig_connector->dp_sink_type = sink_type;
ret = connector_status_connected; ret = connector_status_connected;
} }
radeon_i2c_do_lock(radeon_connector->ddc_bus, 0);
} }
return ret; return ret;

View File

@ -1644,6 +1644,7 @@ static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_pri
radeon_cp_load_microcode(dev_priv); radeon_cp_load_microcode(dev_priv);
radeon_cp_init_ring_buffer(dev, dev_priv, file_priv); radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
dev_priv->have_z_offset = 0;
radeon_do_engine_reset(dev); radeon_do_engine_reset(dev);
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);

Some files were not shown because too many files have changed in this diff Show More