From be5bf1346e49d5c2e0080913fd55e6898a8744cf Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 1 Apr 2007 16:48:38 +1000 Subject: copy over some files and reorg radeon to add ttm fencing not working yet --- linux-core/Makefile.kernel | 2 +- linux-core/radeon_buffer.c | 117 +++++++++++++++++++++++++++++++++++++++++ linux-core/radeon_drv.c | 39 ++++++++++++++ linux-core/radeon_fence.c | 128 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_drm.h | 9 ++++ shared-core/radeon_drv.h | 48 ++++++++++++++++- shared-core/radeon_irq.c | 20 +++---- 7 files changed, 351 insertions(+), 12 deletions(-) create mode 100644 linux-core/radeon_buffer.c create mode 100644 linux-core/radeon_fence.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 6f5b021b..510509cc 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -27,7 +27,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_fb.o nv10_fb.o nv40_fb.o \ nv04_graph.o nv10_graph.o nv20_graph.o nv30_graph.o \ nv40_graph.o -radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_fence.o radeon_buffer.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c new file mode 100644 index 00000000..796191c1 --- /dev/null +++ b/linux-core/radeon_buffer.c @@ -0,0 +1,117 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + + +drm_ttm_backend_t *radeon_create_ttm_backend_entry(drm_device_t * dev) +{ + return drm_agp_init_ttm(dev, NULL); +} + +int radeon_fence_types(drm_buffer_object_t *bo, uint32_t * class, uint32_t * type) +{ + *class = 0; + if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) + *type = 3; + else + *type = 1; + return 0; +} + +int radeon_invalidate_caches(drm_device_t * dev, uint32_t flags) +{ + /* + * FIXME: Only emit once per batchbuffer submission. + */ +#if 0 + uint32_t flush_cmd = MI_NO_WRITE_FLUSH; + + if (flags & DRM_BO_FLAG_READ) + flush_cmd |= MI_READ_FLUSH; + if (flags & DRM_BO_FLAG_EXE) + flush_cmd |= MI_EXE_FLUSH; + + return 0; +// return radeon_emit_mi_flush(dev, flush_cmd); +#endif + return 0; +} + +uint32_t radeon_evict_mask(drm_buffer_object_t *bo) +{ + switch (bo->mem.mem_type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return DRM_BO_FLAG_MEM_LOCAL; + default: + return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; + } +} + +int radeon_init_mem_type(drm_device_t * dev, uint32_t type, + drm_mem_type_manager_t * man) +{ + switch (type) { + case DRM_BO_MEM_LOCAL: + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CACHED; + man->drm_bus_maptype = 0; + break; + case DRM_BO_MEM_TT: + if (!(drm_core_has_AGP(dev) && dev->agp)) { + DRM_ERROR("AGP is not enabled for memory type %u\n", + (unsigned)type); + return -EINVAL; + } + man->io_offset = dev->agp->agp_info.aper_base; + man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; + man->drm_bus_maptype = _DRM_AGP; + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; + } + return 0; +} + +int radeon_move(drm_buffer_object_t * bo, + int evict, int no_wait, drm_bo_mem_reg_t * new_mem) +{ + + return 0; +} + diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 43b9aca0..6f63a7c4 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -56,6 +56,38 @@ static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; + +#ifdef RADEON_HAVE_FENCE +static drm_fence_driver_t radeon_fence_driver = { + .num_classes = 1, + .wrap_diff = (1 << 30), + .flush_diff = (1 << 29), + .sequence_mask = 0xffffffffU, + .lazy_capable = 1, + .emit = radeon_fence_emit_sequence, + .poke_flush = radeon_poke_flush, + .has_irq = radeon_fence_has_irq, +}; +#endif +#ifdef RADEON_HAVE_BUFFER + +static uint32_t radeon_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; +static uint32_t radeon_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_LOCAL}; + +static drm_bo_driver_t radeon_bo_driver = { + .mem_type_prio = radeon_mem_prios, + .mem_busy_prio = radeon_busy_prios, + .num_mem_type_prio = sizeof(radeon_mem_prios)/sizeof(uint32_t), + .num_mem_busy_prio = sizeof(radeon_busy_prios)/sizeof(uint32_t), + .create_ttm_backend_entry = radeon_create_ttm_backend_entry, + .fence_type = radeon_fence_types, + .invalidate_caches = radeon_invalidate_caches, + .init_mem_type = radeon_init_mem_type, + .evict_mask = radeon_evict_mask, + .move = radeon_move, +}; +#endif + static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { .driver_features = @@ -100,6 +132,13 @@ static struct drm_driver driver = { .remove = __devexit_p(drm_cleanup_pci), }, +#ifdef RADEON_HAVE_FENCE + .fence_driver = &radeon_fence_driver, +#endif +#ifdef RADEON_HAVE_BUFFER + .bo_driver = &radeon_bo_driver, +#endif + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c new file mode 100644 index 00000000..57b318af --- /dev/null +++ b/linux-core/radeon_fence.c @@ -0,0 +1,128 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +/* + * Implements an intel sync flush operation. + */ + +static void radeon_perform_flush(drm_device_t * dev) +{ + drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_class_manager_t *fc = &dev->fm.class[0]; + drm_fence_driver_t *driver = dev->driver->fence_driver; + uint32_t pending_flush_types = 0; + uint32_t flush_flags = 0; + uint32_t flush_sequence = 0; + uint32_t i_status; + uint32_t diff; + uint32_t sequence; + + if (!dev_priv) + return; + + pending_flush_types = fc->pending_flush | + ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); + + if (pending_flush_types) { + drm_fence_handler(dev, 0, 0,0); + + } + + return; +} + +void radeon_poke_flush(drm_device_t * dev, uint32_t class) +{ + drm_fence_manager_t *fm = &dev->fm; + unsigned long flags; + + if (class != 0) + return; + + write_lock_irqsave(&fm->lock, flags); + radeon_perform_flush(dev); + write_unlock_irqrestore(&fm->lock, flags); +} + +int radeon_fence_emit_sequence(drm_device_t *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type) +{ + drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; + RING_LOCALS; + + if (!dev_priv) + return -EINVAL; + + *native_type = DRM_FENCE_TYPE_EXE; + if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) { + *native_type |= DRM_RADEON_FENCE_TYPE_RW; + + BEGIN_RING(4); + + RADEON_FLUSH_CACHE(); + RADEON_FLUSH_ZCACHE(); + ADVANCE_RING(); + } + + radeon_emit_irq(dev); + *sequence = (uint32_t) dev_priv->counter; + + + return 0; +} + +void radeon_fence_handler(drm_device_t * dev) +{ + drm_fence_manager_t *fm = &dev->fm; + + write_lock(&fm->lock); + radeon_perform_flush(dev); + write_unlock(&fm->lock); +} + +int radeon_fence_has_irq(drm_device_t *dev, uint32_t class, uint32_t flags) +{ + /* + * We have an irq that tells us when we have a new breadcrumb. + */ + + if (class == 0 && flags == DRM_FENCE_TYPE_EXE) + return 1; + + return 0; +} diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index e96e7851..bdf45802 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -434,8 +434,17 @@ typedef struct { int pfCurrentPage; /* which buffer is being displayed? */ int crtc2_base; /* CRTC2 frame offset */ int tiling_enabled; /* set by drm, read by 2d + 3d clients */ + + unsigned int last_fence; } drm_radeon_sarea_t; +/* The only fence class we support */ +#define DRM_RADEON_FENCE_CLASS_ACCEL 0 +/* Fence type that guarantees read-write flush */ +#define DRM_RADEON_FENCE_TYPE_RW 2 +/* cache flushes programmed just before the fence */ +#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000 + /* WARNING: If you change any of these defines, make sure to change the * defines in the Xserver file (xf86drmRadeon.h) * diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 3e56af30..9f6cff89 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -102,6 +102,11 @@ #define DRIVER_MINOR 26 #define DRIVER_PATCHLEVEL 0 +#if defined(__linux__) +#define RADEON_HAVE_FENCE +#define RADEON_HAVE_BUFFER +#endif + /* * Radeon chip families */ @@ -276,8 +281,8 @@ typedef struct drm_radeon_private { struct mem_block *fb_heap; /* SW interrupt */ - wait_queue_head_t swi_queue; - atomic_t swi_emitted; + wait_queue_head_t irq_queue; + int counter; struct radeon_surface surfaces[RADEON_MAX_SURFACES]; struct radeon_virt_surface virt_surfaces[2*RADEON_MAX_SURFACES]; @@ -376,6 +381,30 @@ extern int r300_do_cp_cmdbuf(drm_device_t *dev, DRMFILE filp, drm_file_t* filp_priv, drm_radeon_kcmd_buffer_t* cmdbuf); + +#ifdef RADEON_HAVE_FENCE +/* i915_fence.c */ + + +extern void radeon_fence_handler(drm_device_t *dev); +extern int radeon_fence_emit_sequence(drm_device_t *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type); +extern void radeon_poke_flush(drm_device_t *dev, uint32_t class); +extern int radeon_fence_has_irq(drm_device_t *dev, uint32_t class, uint32_t flags); +#endif + +#ifdef RADEON_HAVE_BUFFER +/* radeon_buffer.c */ +extern drm_ttm_backend_t *radeon_create_ttm_backend_entry(drm_device_t *dev); +extern int radeon_fence_types(struct drm_buffer_object *bo, uint32_t *class, uint32_t *type); +extern int radeon_invalidate_caches(drm_device_t *dev, uint32_t buffer_flags); +extern uint32_t radeon_evict_mask(drm_buffer_object_t *bo); +extern int radeon_init_mem_type(drm_device_t * dev, uint32_t type, + drm_mem_type_manager_t * man); +extern int radeon_move(drm_buffer_object_t * bo, + int evict, int no_wait, drm_bo_mem_reg_t * new_mem); +#endif /* Flags for stats.boxes */ #define RADEON_BOX_DMA_IDLE 0x1 @@ -1184,4 +1213,19 @@ do { \ write &= mask; \ } while (0) +/* Breadcrumb - swi irq */ +#define READ_BREADCRUMB(dev_priv) RADEON_READ(RADEON_LAST_SWI_REG) + +static inline int radeon_update_breadcrumb(drm_device_t *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + dev_priv->sarea_priv->last_fence = ++dev_priv->counter; + + if (dev_priv->counter > 0x7FFFFFFFUL) + dev_priv->sarea_priv->last_fence = dev_priv->counter = 1; + + return dev_priv->counter; +} + #endif /* __RADEON_DRV_H__ */ diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index 3ff0baa2..8678f5d1 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -79,7 +79,10 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) /* SW interrupt */ if (stat & RADEON_SW_INT_TEST) { - DRM_WAKEUP(&dev_priv->swi_queue); + DRM_WAKEUP(&dev_priv->irq_queue); +#ifdef RADEON_HAVE_FENCE + radeon_fence_handler(dev); +#endif } /* VBLANK interrupt */ @@ -98,8 +101,7 @@ static int radeon_emit_irq(drm_device_t * dev) unsigned int ret; RING_LOCALS; - atomic_inc(&dev_priv->swi_emitted); - ret = atomic_read(&dev_priv->swi_emitted); + ret = radeon_update_breadcrumb(dev); BEGIN_RING(4); OUT_RING_REG(RADEON_LAST_SWI_REG, ret); @@ -110,19 +112,19 @@ static int radeon_emit_irq(drm_device_t * dev) return ret; } -static int radeon_wait_irq(drm_device_t * dev, int swi_nr) +static int radeon_wait_irq(drm_device_t * dev, int irq_nr) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; int ret = 0; - if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) + if (READ_BREADCRUMB(dev_priv) >= irq_nr) return 0; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; - DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, - RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); + DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, + READ_BREADCRUMB(dev_priv) >= irq_nr); return ret; } @@ -224,8 +226,8 @@ void radeon_driver_irq_postinstall(drm_device_t * dev) drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; - atomic_set(&dev_priv->swi_emitted, 0); - DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); + dev_priv->counter = 0; + DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); /* Turn on SW and VBL ints */ RADEON_WRITE(RADEON_GEN_INT_CNTL, -- cgit v1.2.3 From b1f0b2d960a8f488332652677073ab95ce72cd3f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 1 Apr 2007 18:24:23 +1000 Subject: radeon: de-static irq function, fixup fence/buffer --- linux-core/radeon_buffer.c | 23 ++++++++++------------- linux-core/radeon_fence.c | 9 +++------ shared-core/radeon_drv.h | 1 + shared-core/radeon_irq.c | 2 +- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 796191c1..b525ddfa 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -51,20 +51,13 @@ int radeon_fence_types(drm_buffer_object_t *bo, uint32_t * class, uint32_t * typ int radeon_invalidate_caches(drm_device_t * dev, uint32_t flags) { - /* - * FIXME: Only emit once per batchbuffer submission. - */ -#if 0 - uint32_t flush_cmd = MI_NO_WRITE_FLUSH; + drm_radeon_private_t *dev_priv = dev->dev_private; + RING_LOCALS; - if (flags & DRM_BO_FLAG_READ) - flush_cmd |= MI_READ_FLUSH; - if (flags & DRM_BO_FLAG_EXE) - flush_cmd |= MI_EXE_FLUSH; - - return 0; -// return radeon_emit_mi_flush(dev, flush_cmd); -#endif + BEGIN_RING(4); + RADEON_FLUSH_CACHE(); + RADEON_FLUSH_ZCACHE(); + ADVANCE_RING(); return 0; } @@ -111,7 +104,11 @@ int radeon_init_mem_type(drm_device_t * dev, uint32_t type, int radeon_move(drm_buffer_object_t * bo, int evict, int no_wait, drm_bo_mem_reg_t * new_mem) { + drm_bo_mem_reg_t *old_mem = &bo->mem; + if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } return 0; } diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c index 57b318af..7de3650d 100644 --- a/linux-core/radeon_fence.c +++ b/linux-core/radeon_fence.c @@ -45,10 +45,6 @@ static void radeon_perform_flush(drm_device_t * dev) drm_fence_class_manager_t *fc = &dev->fm.class[0]; drm_fence_driver_t *driver = dev->driver->fence_driver; uint32_t pending_flush_types = 0; - uint32_t flush_flags = 0; - uint32_t flush_sequence = 0; - uint32_t i_status; - uint32_t diff; uint32_t sequence; if (!dev_priv) @@ -58,8 +54,9 @@ static void radeon_perform_flush(drm_device_t * dev) ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); if (pending_flush_types) { - drm_fence_handler(dev, 0, 0,0); - + sequence = READ_BREADCRUMB(dev_priv); + + drm_fence_handler(dev, 0, sequence, pending_flush_types); } return; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 9f6cff89..6d2bcc8f 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -355,6 +355,7 @@ extern void radeon_mem_release(DRMFILE filp, struct mem_block *heap); /* radeon_irq.c */ extern int radeon_irq_emit(DRM_IOCTL_ARGS); extern int radeon_irq_wait(DRM_IOCTL_ARGS); +extern int radeon_emit_irq(drm_device_t * dev); extern void radeon_do_release(drm_device_t * dev); extern int radeon_driver_vblank_wait(drm_device_t * dev, diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index 8678f5d1..4f3099dc 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -95,7 +95,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_HANDLED; } -static int radeon_emit_irq(drm_device_t * dev) +int radeon_emit_irq(drm_device_t * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; unsigned int ret; -- cgit v1.2.3 From bdc5a8b62ef2f59e05f69da2150212c0243f6efb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 1 Apr 2007 19:09:00 +1000 Subject: radeon: enable buffer manager --- shared-core/radeon_cp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index e02796e7..93c75d10 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2244,6 +2244,9 @@ int radeon_driver_firstopen(struct drm_device *dev) if (ret != 0) return ret; +#ifdef RADEON_HAVE_BUFFER + drm_bo_driver_init(dev); +#endif return 0; } -- cgit v1.2.3 From e835820e2359952bd42a66137c6b7ab243a5a541 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 3 Apr 2007 19:04:48 +1000 Subject: add initial PCIE GART framework for TTM --- linux-core/ati_pcigart.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++ linux-core/drmP.h | 3 ++ linux-core/radeon_buffer.c | 7 +++- 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index bb30dd74..f3f91129 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -228,3 +228,88 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) return ret; } EXPORT_SYMBOL(drm_ati_pcigart_init); + +static int ati_pcigart_needs_unbind_cache_adjust(drm_ttm_backend_t *backend) +{ + return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); +} + +static int ati_pcigart_populate(drm_ttm_backend_t *backend, + unsigned long num_pages, + struct page **pages) +{ + ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + + return -1; +} + +static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, + unsigned long offset, + int cached) +{ + ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + + return -1; +} + +static int ati_pcigart_unbind_ttm(drm_ttm_backend_t *backend) +{ + ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + + return -1; +} + +static void ati_pcigart_clear_ttm(drm_ttm_backend_t *backend) +{ + ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; +} + +static void ati_pcigart_destroy_ttm(drm_ttm_backend_t *backend) +{ + ati_pcigart_ttm_priv *atipci_priv; + + if (backend) { + DRM_DEBUG("\n"); + atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + if (atipci_priv) { + drm_ctl_free(atipci_priv, sizeof(*atipci_priv), DRM_MEM_MAPPINGS); + backend->private = NULL; + } + if (backend->flags & DRM_BE_FLAG_NEEDS_FREE) { + drm_ctl_free(backend, sizeof(*backend), DRM_MEM_MAPPINGS); + } + } +} + + +drm_ttm_backend_t *ati_pcigart_init_ttm(struct drm_device *dev, + drm_ttm_backend_t *backend) +{ + drm_ttm_backend_t *atipci_be; + ati_pcigart_ttm_priv *atipci_priv; + + atipci_be = (backend != NULL) ? backend : + drm_ctl_calloc(1, sizeof (*atipci_be), DRM_MEM_MAPPINGS); + + if (!atipci_be) + return NULL; + + atipci_priv = drm_ctl_calloc(1, sizeof(*atipci_priv), DRM_MEM_MAPPINGS); + if (!atipci_priv) { + drm_ctl_free(atipci_be, sizeof(*atipci_be), DRM_MEM_MAPPINGS); + return NULL; + } + + atipci_priv->populated = FALSE; + atipci_be->needs_ub_cache_adjust = ati_pcigart_needs_unbind_cache_adjust; + atipci_be->populate = ati_pcigart_populate; + atipci_be->clear = ati_pcigart_clear_ttm; + atipci_be->bind = ati_pcigart_bind_ttm; + atipci_be->unbind = ati_pcigart_unbind_ttm; + atipci_be->destroy = ati_pcigart_destroy_ttm; + + DRM_FLAG_MASKED(atipci_be->flags, (backend == NULL) ? DRM_BE_FLAG_NEEDS_FREE : 0, DRM_BE_FLAG_NEEDS_FREE); + atipci_be->drm_map_type = _DRM_SCATTER_GATHER; + return atipci_be; +} +EXPORT_SYMBOL(ati_pcigart_init_ttm); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 648e29bc..b6da6926 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -840,6 +840,9 @@ typedef struct drm_agp_ttm_priv { } drm_agp_ttm_priv; #endif +typedef struct ati_pcigart_ttm_priv { + int populated; +} ati_pcigart_ttm_priv; static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index b525ddfa..d5a1456a 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -36,7 +36,12 @@ drm_ttm_backend_t *radeon_create_ttm_backend_entry(drm_device_t * dev) { - return drm_agp_init_ttm(dev, NULL); + drm_radeon_private_t *dev_priv = dev->dev_private; + + if(dev_priv->flags & RADEON_IS_AGP) + return drm_agp_init_ttm(dev, NULL); + else + return ati_pcigart_init_ttm(dev, NULL); } int radeon_fence_types(drm_buffer_object_t *bo, uint32_t * class, uint32_t * type) -- cgit v1.2.3 From 29ac7b1fe364a4be1db7e22d2b400bef04fc240d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 3 Apr 2007 21:20:00 +1000 Subject: radeon: add setup for PCIE GART ttm --- linux-core/ati_pcigart.c | 32 +++++++++++++++++++++++++++++++- linux-core/drmP.h | 8 ++++++++ linux-core/radeon_buffer.c | 30 ++++++++++++++++++++---------- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index f3f91129..108e1875 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -239,8 +239,22 @@ static int ati_pcigart_populate(drm_ttm_backend_t *backend, struct page **pages) { ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + struct page **cur_page, **last_page = pages + num_pages; + struct ati_pcigart_memory *mem; - return -1; + DRM_DEBUG("%d\n", num_pages); + if (drm_alloc_memctl(num_pages * sizeof(void *))) + return -1; + + mem = drm_alloc(sizeof(struct ati_pcigart_memory), DRM_MEM_MAPPINGS); + if (!mem) { + drm_free_memctl(num_pages * sizeof(void *)); + return -1; + } + + mem->page_count = num_pages; + atipci_priv->mem = mem; + return 0; } static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, @@ -249,6 +263,7 @@ static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, { ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + DRM_DEBUG("\n"); return -1; } @@ -256,12 +271,24 @@ static int ati_pcigart_unbind_ttm(drm_ttm_backend_t *backend) { ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + DRM_DEBUG("\n"); return -1; } static void ati_pcigart_clear_ttm(drm_ttm_backend_t *backend) { ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + struct ati_pcigart_memory *mem = atipci_priv->mem; + + DRM_DEBUG("\n"); + if (mem) { + unsigned long num_pages = mem->page_count; + backend->unbind(backend); + /* free test */ + drm_free(mem, sizeof(struct ati_pcigart_memory), DRM_MEM_MAPPINGS); + drm_free_memctl(num_pages * sizeof(void *)); + } + atipci_priv->mem = NULL; } static void ati_pcigart_destroy_ttm(drm_ttm_backend_t *backend) @@ -272,6 +299,9 @@ static void ati_pcigart_destroy_ttm(drm_ttm_backend_t *backend) DRM_DEBUG("\n"); atipci_priv = (ati_pcigart_ttm_priv *)backend->private; if (atipci_priv) { + if (atipci_priv->mem) { + backend->clear(backend); + } drm_ctl_free(atipci_priv, sizeof(*atipci_priv), DRM_MEM_MAPPINGS); backend->private = NULL; } diff --git a/linux-core/drmP.h b/linux-core/drmP.h index b6da6926..3ddd405f 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -840,8 +840,16 @@ typedef struct drm_agp_ttm_priv { } drm_agp_ttm_priv; #endif +#define ATI_PCIGART_FLAG_VMALLOC 1 +struct ati_pcigart_memory { + size_t page_count; + unsigned long *memory; + int flags; +}; + typedef struct ati_pcigart_ttm_priv { int populated; + struct ati_pcigart_memory *mem; } ati_pcigart_ttm_priv; static __inline__ int drm_core_check_feature(struct drm_device *dev, diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index d5a1456a..dd387604 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -80,6 +80,8 @@ uint32_t radeon_evict_mask(drm_buffer_object_t *bo) int radeon_init_mem_type(drm_device_t * dev, uint32_t type, drm_mem_type_manager_t * man) { + drm_radeon_private_t *dev_priv = dev->dev_private; + switch (type) { case DRM_BO_MEM_LOCAL: man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | @@ -87,17 +89,25 @@ int radeon_init_mem_type(drm_device_t * dev, uint32_t type, man->drm_bus_maptype = 0; break; case DRM_BO_MEM_TT: - if (!(drm_core_has_AGP(dev) && dev->agp)) { - DRM_ERROR("AGP is not enabled for memory type %u\n", - (unsigned)type); - return -EINVAL; + if (dev_priv->flags & RADEON_IS_AGP) { + if (!(drm_core_has_AGP(dev) && dev->agp)) { + DRM_ERROR("AGP is not enabled for memory type %u\n", + (unsigned)type); + return -EINVAL; + } + man->io_offset = dev->agp->agp_info.aper_base; + man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; + man->drm_bus_maptype = _DRM_AGP; + } else { + man->io_offset = 0; + man->io_size = dev_priv->gart_size; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_MEMTYPE_MAPPABLE; + man->drm_bus_maptype = _DRM_SCATTER_GATHER; } - man->io_offset = dev->agp->agp_info.aper_base; - man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; - man->io_addr = NULL; - man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; - man->drm_bus_maptype = _DRM_AGP; break; default: DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); -- cgit v1.2.3 From 8fe8793a0fdf4e6082a0f0b0fc4650f171737356 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Apr 2007 11:20:23 +1000 Subject: borrow edid.h from fb directory --- linux-core/edid.h | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 linux-core/edid.h diff --git a/linux-core/edid.h b/linux-core/edid.h new file mode 100644 index 00000000..bd89fb3b --- /dev/null +++ b/linux-core/edid.h @@ -0,0 +1,138 @@ +/* + * drivers/video/edid.h - EDID/DDC Header + * + * Based on: + * 1. XFree86 4.3.0, edid.h + * Copyright 1998 by Egbert Eich + * + * 2. John Fremlin and + * Ani Joshi + * + * DDC is a Trademark of VESA (Video Electronics Standard Association). + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. +*/ + +#ifndef __EDID_H__ +#define __EDID_H__ + +#define EDID_LENGTH 0x80 +#define EDID_HEADER 0x00 +#define EDID_HEADER_END 0x07 + +#define ID_MANUFACTURER_NAME 0x08 +#define ID_MANUFACTURER_NAME_END 0x09 +#define ID_MODEL 0x0a + +#define ID_SERIAL_NUMBER 0x0c + +#define MANUFACTURE_WEEK 0x10 +#define MANUFACTURE_YEAR 0x11 + +#define EDID_STRUCT_VERSION 0x12 +#define EDID_STRUCT_REVISION 0x13 + +#define EDID_STRUCT_DISPLAY 0x14 + +#define DPMS_FLAGS 0x18 +#define ESTABLISHED_TIMING_1 0x23 +#define ESTABLISHED_TIMING_2 0x24 +#define MANUFACTURERS_TIMINGS 0x25 + +/* standard timings supported */ +#define STD_TIMING 8 +#define STD_TIMING_DESCRIPTION_SIZE 2 +#define STD_TIMING_DESCRIPTIONS_START 0x26 + +#define DETAILED_TIMING_DESCRIPTIONS_START 0x36 +#define DETAILED_TIMING_DESCRIPTION_SIZE 18 +#define NO_DETAILED_TIMING_DESCRIPTIONS 4 + +#define DETAILED_TIMING_DESCRIPTION_1 0x36 +#define DETAILED_TIMING_DESCRIPTION_2 0x48 +#define DETAILED_TIMING_DESCRIPTION_3 0x5a +#define DETAILED_TIMING_DESCRIPTION_4 0x6c + +#define DESCRIPTOR_DATA 5 + +#define UPPER_NIBBLE( x ) \ + (((128|64|32|16) & (x)) >> 4) + +#define LOWER_NIBBLE( x ) \ + ((1|2|4|8) & (x)) + +#define COMBINE_HI_8LO( hi, lo ) \ + ( (((unsigned)hi) << 8) | (unsigned)lo ) + +#define COMBINE_HI_4LO( hi, lo ) \ + ( (((unsigned)hi) << 4) | (unsigned)lo ) + +#define PIXEL_CLOCK_LO (unsigned)block[ 0 ] +#define PIXEL_CLOCK_HI (unsigned)block[ 1 ] +#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*10000) +#define H_ACTIVE_LO (unsigned)block[ 2 ] +#define H_BLANKING_LO (unsigned)block[ 3 ] +#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] ) +#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO ) +#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] ) +#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO ) + +#define V_ACTIVE_LO (unsigned)block[ 5 ] +#define V_BLANKING_LO (unsigned)block[ 6 ] +#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] ) +#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO ) +#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] ) +#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO ) + +#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ] +#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ] + +#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] ) +#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] ) + +#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2)) +#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2) + +#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4) +#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6) + +#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO ) +#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO ) + +#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO ) +#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO ) + +#define H_SIZE_LO (unsigned)block[ 12 ] +#define V_SIZE_LO (unsigned)block[ 13 ] + +#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] ) +#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] ) + +#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO ) +#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO ) + +#define H_BORDER (unsigned)block[ 15 ] +#define V_BORDER (unsigned)block[ 16 ] + +#define FLAGS (unsigned)block[ 17 ] + +#define INTERLACED (FLAGS&128) +#define SYNC_TYPE (FLAGS&3<<3) /* bits 4,3 */ +#define SYNC_SEPARATE (3<<3) +#define HSYNC_POSITIVE (FLAGS & 4) +#define VSYNC_POSITIVE (FLAGS & 2) + +#define V_MIN_RATE block[ 5 ] +#define V_MAX_RATE block[ 6 ] +#define H_MIN_RATE block[ 7 ] +#define H_MAX_RATE block[ 8 ] +#define MAX_PIXEL_CLOCK (((int)block[ 9 ]) * 10) +#define GTF_SUPPORT block[10] + +#define DPMS_ACTIVE_OFF (1 << 5) +#define DPMS_SUSPEND (1 << 6) +#define DPMS_STANDBY (1 << 7) + +#endif /* __EDID_H__ */ -- cgit v1.2.3 From 52f9028c84baea81230dc673b756552e8e90aecd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Apr 2007 11:21:06 +1000 Subject: Initial import of modesetting for intel driver in DRM --- linux-core/Makefile.kernel | 6 +- linux-core/drmP.h | 5 + linux-core/drm_crtc.c | 540 +++++++++++++++++++++ linux-core/drm_crtc.h | 428 +++++++++++++++++ linux-core/drm_edid.c | 515 ++++++++++++++++++++ linux-core/drm_modes.c | 304 ++++++++++++ linux-core/i915_drv.c | 1 + linux-core/intel_crt.c | 226 +++++++++ linux-core/intel_display.c | 1087 ++++++++++++++++++++++++++++++++++++++++++ linux-core/intel_drv.h | 69 +++ linux-core/intel_i2c.c | 164 +++++++ linux-core/intel_lvds.c | 108 +++++ linux-core/intel_modes.c | 49 ++ linux-core/intel_sdvo.c | 999 ++++++++++++++++++++++++++++++++++++++ linux-core/intel_sdvo_regs.h | 302 ++++++++++++ shared-core/i915_dma.c | 135 ++++-- shared-core/i915_drv.h | 474 ++++++++++++++++++ 17 files changed, 5358 insertions(+), 54 deletions(-) create mode 100644 linux-core/drm_crtc.c create mode 100644 linux-core/drm_crtc.h create mode 100644 linux-core/drm_edid.c create mode 100644 linux-core/drm_modes.c create mode 100644 linux-core/intel_crt.c create mode 100644 linux-core/intel_display.c create mode 100644 linux-core/intel_drv.h create mode 100644 linux-core/intel_i2c.c create mode 100644 linux-core/intel_lvds.c create mode 100644 linux-core/intel_modes.c create mode 100644 linux-core/intel_sdvo.c create mode 100644 linux-core/intel_sdvo_regs.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 6f5b021b..ac403f64 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,13 +13,15 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ - drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o + drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ + drm_edid.o drm_modes.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ - i915_buffer.o + i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \ + intel_sdvo.o intel_modes.o intel_i2c.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o \ nv04_timer.o \ diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 648e29bc..db62ab83 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -164,6 +164,8 @@ #include "drm_compat.h" +#include "drm_crtc.h" + /***********************************************************************/ /** \name Macros to make printk easier */ /*@{*/ @@ -827,6 +829,9 @@ typedef struct drm_device { unsigned int drw_info_length; drm_drawable_info_t **drw_info; /*@} */ + + /* DRM mode setting */ + struct drm_crtc_config crtc_config; } drm_device_t; #if __OS_HAS_AGP diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c new file mode 100644 index 00000000..a52d82bc --- /dev/null +++ b/linux-core/drm_crtc.c @@ -0,0 +1,540 @@ +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" + +struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) +{ + struct drm_framebuffer *fb; + + spin_lock(&dev->crtc_config.config_lock); + /* Limit to single framebuffer for now */ + if (dev->crtc_config.num_fb > 1) { + DRM_ERROR("Attempt to add multiple framebuffers failed\n"); + return NULL; + } + spin_unlock(&dev->crtc_config.config_lock); + + fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); + if (!fb) { + + return NULL; + } + + fb->dev = dev; + spin_lock(&dev->crtc_config.config_lock); + dev->crtc_config.num_fb++; + list_add(&fb->head, &dev->crtc_config.fb_list); + spin_unlock(&dev->crtc_config.config_lock); + + return fb; +} + +void drm_framebuffer_destroy(struct drm_framebuffer *fb) +{ + drm_device_t *dev = fb->dev; + + spin_lock(&dev->crtc_config.config_lock); + list_del(&fb->head); + dev->crtc_config.num_fb--; + spin_unlock(&dev->crtc_config.config_lock); + + kfree(fb); +} + +struct drm_crtc *drm_crtc_create(drm_device_t *dev, + const struct drm_crtc_funcs *funcs) +{ + struct drm_crtc *crtc = NULL; + crtc = kmalloc(sizeof(struct drm_crtc), GFP_KERNEL); + if (!crtc) + return NULL; + + crtc->dev = dev; + crtc->funcs = funcs; + + spin_lock(&dev->crtc_config.config_lock); + + list_add_tail(&crtc->head, &dev->crtc_config.crtc_list); + dev->crtc_config.num_crtc++; + + spin_unlock(&dev->crtc_config.config_lock); + + return crtc; +} +EXPORT_SYMBOL(drm_crtc_create); + +void drm_crtc_destroy(struct drm_crtc *crtc) +{ + drm_device_t *dev = crtc->dev; + + if (crtc->funcs->cleanup) + (*crtc->funcs->cleanup)(crtc); + + spin_lock(&dev->crtc_config.config_lock); + list_del(&crtc->head); + dev->crtc_config.num_crtc--; + spin_unlock(&dev->crtc_config.config_lock); + kfree(crtc); +} +EXPORT_SYMBOL(drm_crtc_destroy); + +bool drm_crtc_in_use(struct drm_crtc *crtc) +{ + struct drm_output *output; + drm_device_t *dev = crtc->dev; + list_for_each_entry(output, &dev->crtc_config.output_list, head) + if (output->crtc == crtc) + return true; + return false; +} +EXPORT_SYMBOL(drm_crtc_in_use); + +void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) +{ + struct drm_output *output; + struct drm_display_mode *mode, *t; + int ret; + //if (maxX == 0 || maxY == 0) + // TODO + + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + + list_for_each_entry_safe(mode, t, &output->modes, head) + drm_mode_remove(output, mode); + + output->status = (*output->funcs->detect)(output); + + if (output->status == output_status_disconnected) { + /* TODO set EDID to NULL */ + continue; + } + + ret = (*output->funcs->get_modes)(output); + + if (ret) { + /* move the modes over to the main mode list */ + drm_mode_list_concat(&output->probed_modes, + &output->modes); + } + + if (maxX && maxY) + drm_mode_validate_size(dev, &output->modes, maxX, + maxY, 0); + list_for_each_entry_safe(mode, t, &output->modes, head) { + if (mode->status == MODE_OK) + mode->status = (*output->funcs->mode_valid)(output,mode); + } + + + drm_mode_prune_invalid(dev, &output->modes, TRUE); + + if (list_empty(&output->modes)) + continue; + + drm_mode_sort(&output->modes); + + DRM_DEBUG("Probed modes for %s\n", output->name); + list_for_each_entry_safe(mode, t, &output->modes, head) { + mode->vrefresh = drm_mode_vrefresh(mode); + + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + drm_mode_debug_printmodeline(dev, mode); + } + } +} + +bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y) +{ + drm_device_t *dev = crtc->dev; + struct drm_display_mode *adjusted_mode, saved_mode; + int saved_x, saved_y; + bool didLock = false; + bool ret = false; + struct drm_output *output; + + adjusted_mode = drm_mode_duplicate(mode); + + crtc->enabled = drm_crtc_in_use(crtc); + + if (!crtc->enabled) { + return true; + } + + didLock = crtc->funcs->lock(crtc); + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + + /* Update crtc values up front so the driver can rely on them for mode + * setting. + */ + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + + /* XXX short-circuit changes to base location only */ + + /* Pass our mode to the outputs and the CRTC to give them a chance to + * adjust it according to limitations or output properties, and also + * a chance to reject the mode entirely. + */ + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + + if (output->crtc != crtc) + continue; + + if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { + goto done; + } + } + + if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { + goto done; + } + + /* Prepare the outputs and CRTCs before setting the mode. */ + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + + if (output->crtc != crtc) + continue; + + /* Disable the output as the first thing we do. */ + output->funcs->prepare(output); + } + + crtc->funcs->prepare(crtc); + + /* Set up the DPLL and any output state that needs to adjust or depend + * on the DPLL. + */ + crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + if (output->crtc == crtc) + output->funcs->mode_set(output, mode, adjusted_mode); + } + + /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ + crtc->funcs->commit(crtc); + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + if (output->crtc == crtc) + { + output->funcs->commit(output); +#if 0 // TODO def RANDR_12_INTERFACE + if (output->randr_output) + RRPostPendingProperties (output->randr_output); +#endif + } + } + + /* XXX free adjustedmode */ + ret = TRUE; + /* TODO */ +// if (scrn->pScreen) +// drm_crtc_set_screen_sub_pixel_order(dev); + +done: + if (!ret) { + crtc->x = saved_x; + crtc->y = saved_y; + crtc->mode = saved_mode; + } + + if (didLock) + crtc->funcs->unlock (crtc); + + return ret; +} + +bool drm_set_desired_modes(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_output *output, *list_output; + + list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { + output = NULL; + + list_for_each_entry(list_output, &dev->crtc_config.output_list, head) { + if (list_output->crtc == crtc) { + output = list_output; + break; + } + } + /* Skip disabled crtcs */ + if (!output) + continue; + + memset(&crtc->mode, 0, sizeof(crtc->mode)); + if (!crtc->desired_mode.crtc_hdisplay) { + + } + if (!drm_crtc_set_mode(crtc, &crtc->desired_mode, + crtc->desired_x, crtc->desired_y)) + return false; + } + + drm_disable_unused_functions(dev); + return true; +} +EXPORT_SYMBOL(drm_set_desired_modes); + +void drm_disable_unused_functions(struct drm_device *dev) +{ + struct drm_output *output; + struct drm_crtc *crtc; + + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + if (!output->crtc) + (*output->funcs->dpms)(output, DPMSModeOff); + } + + list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { + if (!crtc->enabled) + crtc->funcs->dpms(crtc, DPMSModeOff); + } +} + +/** + * drm_mode_probed_add - add a mode to the specified output's probed mode list + * @output: output the new mode + * @mode: mode data + * + * Add @mode to @output's mode list for later use. + */ +void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode) +{ + printk(KERN_ERR "adding DDC mode %s to output %s\n", mode->name, + output->name); + spin_lock(&output->modes_lock); + list_add(&mode->head, &output->probed_modes); + spin_unlock(&output->modes_lock); +} +EXPORT_SYMBOL(drm_mode_probed_add); + +/** + * drm_mode_remove - remove and free a mode + * @output: output list to modify + * @mode: mode to remove + * + * Remove @mode from @output's mode list, then free it. + */ +void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) +{ + spin_lock(&output->modes_lock); + list_del(&mode->head); + spin_unlock(&output->modes_lock); + kfree(mode); +} +EXPORT_SYMBOL(drm_mode_remove); + +/* + * Probably belongs in the DRM device structure + */ +struct drm_output *drm_output_create(drm_device_t *dev, + const struct drm_output_funcs *funcs, + const char *name) +{ + struct drm_output *output = NULL; + + output = kmalloc(sizeof(struct drm_output), GFP_KERNEL); + if (!output) + return NULL; + + output->dev = dev; + output->funcs = funcs; + if (name) + strncpy(output->name, name, DRM_OUTPUT_LEN); + output->name[DRM_OUTPUT_LEN - 1] = 0; + output->subpixel_order = SubPixelUnknown; + INIT_LIST_HEAD(&output->probed_modes); + INIT_LIST_HEAD(&output->modes); + spin_lock_init(&output->modes_lock); + /* randr_output? */ + /* output_set_monitor(output)? */ + /* check for output_ignored(output)? */ + + spin_lock(&dev->crtc_config.config_lock); + list_add_tail(&output->head, &dev->crtc_config.output_list); + dev->crtc_config.num_output++; + + spin_unlock(&dev->crtc_config.config_lock); + + return output; + +} +EXPORT_SYMBOL(drm_output_create); + +void drm_output_destroy(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_display_mode *mode, *t; + + if (*output->funcs->cleanup) + (*output->funcs->cleanup)(output); + + list_for_each_entry_safe(mode, t, &output->probed_modes, head) + drm_mode_remove(output, mode); + + list_for_each_entry_safe(mode, t, &output->modes, head) + drm_mode_remove(output, mode); + + spin_lock(&dev->crtc_config.config_lock); + list_del(&output->head); + spin_unlock(&dev->crtc_config.config_lock); + kfree(output); +} +EXPORT_SYMBOL(drm_output_destroy); + +bool drm_output_rename(struct drm_output *output, const char *name) +{ + if (!name) + return false; + + strncpy(output->name, name, DRM_OUTPUT_LEN); + output->name[DRM_OUTPUT_LEN - 1] = 0; +// drm_output_set_monitor(output); +// if (drm_output_ignored(output)) +// return FALSE; + return TRUE; +} +EXPORT_SYMBOL(drm_output_rename); + +void drm_crtc_config_init(drm_device_t *dev) +{ + spin_lock_init(&dev->crtc_config.config_lock); + INIT_LIST_HEAD(&dev->crtc_config.fb_list); + INIT_LIST_HEAD(&dev->crtc_config.crtc_list); + INIT_LIST_HEAD(&dev->crtc_config.output_list); +} +EXPORT_SYMBOL(drm_crtc_config_init); + +void drm_framebuffer_set_object(drm_device_t *dev, unsigned long handle) +{ + struct drm_framebuffer *fb; + drm_user_object_t *uo; + drm_hash_item_t *hash; + drm_buffer_object_t *bo; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_ht_find_item(&dev->object_hash, handle, &hash); + if (ret) { + DRM_ERROR("Couldn't find handle.\n"); + goto out_err; + } + + uo = drm_hash_entry(hash, drm_user_object_t, hash); + if (uo->type != drm_buffer_type) { + ret = -EINVAL; + goto out_err; + } + + bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + + /* get the first fb */ + list_for_each_entry(fb, &dev->crtc_config.fb_list, head) { + fb->offset = bo->offset; + break; + } + ret = 0; +out_err: + mutex_unlock(&dev->struct_mutex); + return ret; +} +EXPORT_SYMBOL(drm_framebuffer_set_object); + +bool drm_initial_config(drm_device_t *dev, bool can_grow) +{ + /* do a hardcoded initial configuration here */ + struct drm_crtc *crtc, *vga_crtc = NULL, *dvi_crtc = NULL; + struct drm_framebuffer *fb; + struct drm_output *output, *use_output = NULL; + + fb = drm_framebuffer_create(dev); + if (!fb) + return false; + + fb->pitch = 1024; + fb->width = 1024; + fb->height = 768; + fb->depth = 24; + fb->bits_per_pixel = 32; + + /* bind both CRTCs to this fb */ + /* only initialise one crtc to enabled state */ + list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { + crtc->fb = fb; + if (!vga_crtc) { + vga_crtc = crtc; + crtc->enabled = 1; + crtc->desired_x = 0; + crtc->desired_y = 0; + } +#if 0 + else if (!dvi_crtc) { + dvi_crtc = crtc; + crtc->enabled = 1; + crtc->desired_x = 0; + crtc->desired_y = 0; + } +#endif + } + + drm_crtc_probe_output_modes(dev, 1024, 768); + + /* hard bind the CRTCS */ + + /* bind analog output to one crtc */ + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + struct drm_display_mode *des_mode; + + if (strncmp(output->name, "VGA", 3)) { + output->crtc = vga_crtc; + /* just pull the first mode out of that hat */ + list_for_each_entry(des_mode, &output->modes, head) + break; + DRM_DEBUG("Setting desired mode for output %s\n", output->name); + drm_mode_debug_printmodeline(dev, des_mode); + output->crtc->desired_mode = *des_mode; + output->initial_x = 0; + output->initial_y = 0; + use_output = output; + } else if (strncmp(output->name, "TMDS", 4)) { + output->crtc = vga_crtc; +#if 0 + /* just pull the first mode out of that hat */ + list_for_each_entry(des_mode, &output->modes, head) + break; + DRM_DEBUG("Setting desired mode for output %s\n", output->name); + drm_mode_debug_printmodeline(dev, des_mode); + output->crtc->desired_mode = *des_mode; +#endif + output->initial_x = 0; + output->initial_y = 0; + } else + output->crtc = NULL; + + } + + return false; +} +EXPORT_SYMBOL(drm_initial_config); + +void drm_crtc_config_cleanup(drm_device_t *dev) +{ + struct drm_output *output, *ot; + struct drm_crtc *crtc, *ct; + + list_for_each_entry_safe(output, ot, &dev->crtc_config.output_list, head) { + drm_output_destroy(output); + } + + + list_for_each_entry_safe(crtc, ct, &dev->crtc_config.crtc_list, head) { + drm_crtc_destroy(crtc); + } +} +EXPORT_SYMBOL(drm_crtc_config_cleanup); + diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h new file mode 100644 index 00000000..1be115d1 --- /dev/null +++ b/linux-core/drm_crtc.h @@ -0,0 +1,428 @@ +/* + * Copyright © 2006 Keith Packard + * Copyright © 2007 Intel Corporation + * Jesse Barnes + */ +#ifndef __DRM_CRTC_H__ +#define __DRM_CRTC_H__ + +#include +#include +#include +#include "drmP.h" +#include "drm.h" + +struct drm_device; + +/* + * Note on terminology: here, for brevity and convenience, we refer to output + * control chips as 'CRTCs'. They can control any type of output, VGA, LVDS, + * DVI, etc. And 'screen' refers to the whole of the visible display, which + * may span multiple monitors (and therefore multiple CRTC and output + * structures). + */ + +enum drm_mode_status { + MODE_OK = 0, /* Mode OK */ + MODE_HSYNC, /* hsync out of range */ + MODE_VSYNC, /* vsync out of range */ + MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_BAD_WIDTH, /* requires an unsupported linepitch */ + MODE_NOMODE, /* no mode with a maching name */ + MODE_NO_INTERLACE, /* interlaced mode not supported */ + MODE_NO_DBLESCAN, /* doublescan mode not supported */ + MODE_NO_VSCAN, /* multiscan mode not supported */ + MODE_MEM, /* insufficient video memory */ + MODE_VIRTUAL_X, /* mode width too large for specified virtual size */ + MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */ + MODE_MEM_VIRT, /* insufficient video memory given virtual size */ + MODE_NOCLOCK, /* no fixed clock available */ + MODE_CLOCK_HIGH, /* clock required is too high */ + MODE_CLOCK_LOW, /* clock required is too low */ + MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */ + MODE_BAD_HVALUE, /* horizontal timing was out of range */ + MODE_BAD_VVALUE, /* vertical timing was out of range */ + MODE_BAD_VSCAN, /* VScan value out of range */ + MODE_HSYNC_NARROW, /* horizontal sync too narrow */ + MODE_HSYNC_WIDE, /* horizontal sync too wide */ + MODE_HBLANK_NARROW, /* horizontal blanking too narrow */ + MODE_HBLANK_WIDE, /* horizontal blanking too wide */ + MODE_VSYNC_NARROW, /* vertical sync too narrow */ + MODE_VSYNC_WIDE, /* vertical sync too wide */ + MODE_VBLANK_NARROW, /* vertical blanking too narrow */ + MODE_VBLANK_WIDE, /* vertical blanking too wide */ + MODE_PANEL, /* exceeds panel dimensions */ + MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ + MODE_ONE_WIDTH, /* only one width is supported */ + MODE_ONE_HEIGHT, /* only one height is supported */ + MODE_ONE_SIZE, /* only one resolution is supported */ + MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ + MODE_BAD = -2, /* unspecified reason */ + MODE_ERROR = -1 /* error condition */ +}; + +#define DRM_MODE_TYPE_BUILTIN (1<<0) +#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED (1<<3) +#define DRM_MODE_TYPE_DEFAULT (1<<4) +#define DRM_MODE_TYPE_USERDEF (1<<5) +#define DRM_MODE_TYPE_DRIVER (1<<6) + +#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \ + DRM_MODE_TYPE_CRTC_C) + +#define DRM_DISPLAY_MODE_LEN 32 + +#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ + .name = nm, .status = 0, .type = (t), .clock = (c), \ + .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ + .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ + .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ + .vscan = (vs), .flags = (f) + +struct drm_display_mode { + /* Header */ + struct list_head head; + char name[DRM_DISPLAY_MODE_LEN]; + enum drm_mode_status status; + int type; + + /* Proposed mode values */ + int clock; + int hdisplay; + int hsync_start; + int hsync_end; + int htotal; + int hskew; + int vdisplay; + int vsync_start; + int vsync_end; + int vtotal; + int vscan; + unsigned int flags; + + /* Actual mode we give to hw */ + int clock_index; + int synth_clock; + int crtc_hdisplay; + int crtc_hblank_start; + int crtc_hblank_end; + int crtc_hsync_start; + int crtc_hsync_end; + int crtc_htotal; + int crtc_hskew; + int crtc_vdisplay; + int crtc_vblank_start; + int crtc_vblank_end; + int crtc_vsync_start; + int crtc_vsync_end; + int crtc_vtotal; + int crtc_hadjusted; + int crtc_vadjusted; + + /* Driver private mode info */ + int private_size; + int *private; + int private_flags; + + int vrefresh; + float hsync;//, vrefresh; +}; + +/* Video mode flags */ +#define V_PHSYNC (1<<0) +#define V_NHSYNC (1<<1) +#define V_PVSYNC (1<<2) +#define V_NVSYNC (1<<3) +#define V_INTERLACE (1<<4) +#define V_DBLSCAN (1<<5) +#define V_CSYNC (1<<6) +#define V_PCSYNC (1<<7) +#define V_NCSYNC (1<<8) +#define V_HSKEW (1<<9) /* hskew provided */ +#define V_BCAST (1<<10) +#define V_PIXMUX (1<<11) +#define V_DBLCLK (1<<12) +#define V_CLKDIV2 (1<<13) + +#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ +#define DPMSModeOn 0 +#define DPMSModeStandby 1 +#define DPMSModeSuspend 2 +#define DPMSModeOff 3 + +enum drm_output_status { + output_status_connected, + output_status_disconnected, + output_status_unknown, +}; + +enum subpixel_order { + SubPixelUnknown = 0, + SubPixelHorizontalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalRGB, + SubPixelVerticalBGR, + SubPixelNone, +}; + +struct drm_framebuffer { + struct drm_device *dev; + struct list_head head; + unsigned int pitch; + unsigned long offset; + unsigned int width; + unsigned int height; + /* depth can be 15 or 16 */ + unsigned int depth; + int bits_per_pixel; + int flags; +}; +struct drm_crtc; +struct drm_output; + +/** + * drm_crtc_funcs - control CRTCs for a given device + * @dpms: control display power levels + * @save: save CRTC state + * @resore: restore CRTC state + * @lock: lock the CRTC + * @unlock: unlock the CRTC + * @shadow_allocate: allocate shadow pixmap + * @shadow_create: create shadow pixmap for rotation support + * @shadow_destroy: free shadow pixmap + * @mode_fixup: fixup proposed mode + * @mode_set: set the desired mode on the CRTC + * @gamma_set: specify color ramp for CRTC + * @cleanup: cleanup driver private state prior to close + * + * The drm_crtc_funcs structure is the central CRTC management structure + * in the DRM. Each CRTC controls one or more outputs (note that the name + * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc. + * outputs, not just CRTs). + * + * Each driver is responsible for filling out this structure at startup time, + * in addition to providing other modesetting features, like i2c and DDC + * bus accessors. + */ +struct drm_crtc_funcs { + /* + * Control power levels on the CRTC. If the mode passed in is + * unsupported, the provider must use the next lowest power level. + */ + void (*dpms)(struct drm_crtc *crtc, int mode); + + /* JJJ: Are these needed? */ + /* Save CRTC state */ + void (*save)(struct drm_crtc *crtc); /* suspend? */ + /* Restore CRTC state */ + void (*restore)(struct drm_crtc *crtc); /* resume? */ + bool (*lock)(struct drm_crtc *crtc); + void (*unlock)(struct drm_crtc *crtc); + + void (*prepare)(struct drm_crtc *crtc); + void (*commit)(struct drm_crtc *crtc); + + /* Provider can fixup or change mode timings before modeset occurs */ + bool (*mode_fixup)(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + /* Actually set the mode */ + void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, int x, int y); + /* Set gamma on the CRTC */ + void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, + int size); + /* Driver cleanup routine */ + void (*cleanup)(struct drm_crtc *crtc); +}; + +/** + * drm_crtc - central CRTC control structure + * @enabled: is this CRTC enabled? + * @x: x position on screen + * @y: y position on screen + * @desired_mode: new desired mode + * @desired_x: desired x for desired_mode + * @desired_y: desired y for desired_mode + * @funcs: CRTC control functions + * @driver_private: arbitrary driver data + * + * Each CRTC may have one or more outputs associated with it. This structure + * allows the CRTC to be controlled. + */ +struct drm_crtc { + struct drm_device *dev; + struct list_head head; + + /* framebuffer the CRTC is currently bound to */ + struct drm_framebuffer *fb; + + bool enabled; + + /* JJJ: are these needed? */ + bool cursor_in_range; + bool cursor_shown; + + struct drm_display_mode mode; + + int x, y; + struct drm_display_mode desired_mode; + int desired_x, desired_y; + const struct drm_crtc_funcs *funcs; + void *driver_private; + + /* RRCrtcPtr randr_crtc? */ +}; + +extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, + const struct drm_crtc_funcs *funcs); + +/** + * drm_output_funcs - control outputs on a given device + * @init: setup this output + * @dpms: set power state (see drm_crtc_funcs above) + * @save: save output state + * @restore: restore output state + * @mode_valid: is this mode valid on the given output? + * @mode_fixup: try to fixup proposed mode for this output + * @mode_set: set this mode + * @detect: is this output active? + * @get_modes: get mode list for this output + * @set_property: property for this output may need update + * @cleanup: output is going away, cleanup + * + * Each CRTC may have one or more outputs attached to it. The functions + * below allow the core DRM code to control outputs, enumerate available modes, + * etc. + */ +struct drm_output_funcs { + void (*init)(struct drm_output *output); + void (*dpms)(struct drm_output *output, int mode); + void (*save)(struct drm_output *output); + void (*restore)(struct drm_output *output); + int (*mode_valid)(struct drm_output *output, + struct drm_display_mode *mode); + bool (*mode_fixup)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*prepare)(struct drm_output *output); + void (*commit)(struct drm_output *output); + void (*mode_set)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + enum drm_output_status (*detect)(struct drm_output *output); + int (*get_modes)(struct drm_output *output); + /* JJJ: type checking for properties via property value type */ + bool (*set_property)(struct drm_output *output, int prop, void *val); + void (*cleanup)(struct drm_output *output); +}; + +#define DRM_OUTPUT_LEN 32 +/** + * drm_output - central DRM output control structure + * @crtc: CRTC this output is currently connected to, NULL if none + * @possible_crtcs: bitmap of CRTCS this output could be attached to + * @possible_clones: bitmap of possible outputs this output could clone + * @interlace_allowed: can this output handle interlaced modes? + * @doublescan_allowed: can this output handle doublescan? + * @available_modes: modes available on this output (from get_modes() + user) + * @initial_x: initial x position for this output + * @initial_y: initial y position for this output + * @status: output connected? + * @subpixel_order: for this output + * @mm_width: displayable width of output in mm + * @mm_height: displayable height of output in mm + * @name: name of output (should be one of a few standard names) + * @funcs: output control functions + * @driver_private: private driver data + * + * Each output may be connected to one or more CRTCs, or may be clonable by + * another output if they can share a CRTC. Each output also has a specific + * position in the broader display (referred to as a 'screen' though it could + * span multiple monitors). + */ +struct drm_output { + struct drm_device *dev; + struct list_head head; + struct drm_crtc *crtc; + unsigned long possible_crtcs; + unsigned long possible_clones; + bool interlace_allowed; + bool doublescan_allowed; + spinlock_t modes_lock; + struct list_head modes; /* list of modes on this output */ + /* + OptionInfoPtr options; + XF86ConfMonitorPtr conf_monitor; + */ + int initial_x, initial_y; + enum drm_output_status status; + + /* these are modes added by probing with DDC or the BIOS */ + struct list_head probed_modes; + + /* xf86MonPtr MonInfo; */ + enum subpixel_order subpixel_order; + int mm_width, mm_height; + char name[DRM_OUTPUT_LEN]; + const struct drm_output_funcs *funcs; + void *driver_private; + /* RROutputPtr randr_output? */ +}; + +/** + * struct drm_crtc_config_funcs - configure CRTCs for a given screen layout + * @resize: adjust CRTCs as necessary for the proposed layout + * + * Currently only a resize hook is available. DRM will call back into the + * driver with a new screen width and height. If the driver can't support + * the proposed size, it can return false. Otherwise it should adjust + * the CRTC<->output mappings as needed and update its view of the screen. + */ +struct drm_crtc_config_funcs { + bool (*resize)(struct drm_device *dev, int width, int height); +}; + +/** + * drm_crtc_config - CRTC configuration control structure + * + */ +struct drm_crtc_config { + spinlock_t config_lock; + /* this is limited to one for now */ + int num_fb; + struct list_head fb_list; + int num_output; + struct list_head output_list; + + /* int compat_output? */ + int num_crtc; + struct list_head crtc_list; + + int min_width, min_height; + int max_width, max_height; + /* DamagePtr rotationDamage? */ + /* DGA stuff? */ + struct drm_crtc_config_funcs *funcs; +}; + +struct drm_output *drm_output_create(struct drm_device *dev, + const struct drm_output_funcs *funcs, + const char *name); +void drm_output_destroy(struct drm_output *output); +bool drm_output_rename(struct drm_output *output, const char *name); + +int drm_add_edid_modes(struct drm_output *output, + struct i2c_adapter *adapter); +void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode); +void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode); +extern struct drm_display_mode *drm_mode_duplicate(struct drm_display_mode *mode); +extern void drm_mode_debug_printmodeline(struct drm_device *dev, + struct drm_display_mode *mode); +extern void drm_crtc_config_init(struct drm_device *dev); +extern void drm_crtc_config_cleanup(struct drm_device *dev); +extern void drm_disable_unused_functions(struct drm_device *dev); +#endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c new file mode 100644 index 00000000..3c123751 --- /dev/null +++ b/linux-core/drm_edid.c @@ -0,0 +1,515 @@ +#include +#include +#include "drmP.h" +#include "intel_drv.h" + +/* + * DDC/EDID probing rippped off from FB layer + */ + +#include "edid.h" +#define DDC_ADDR 0x50 + +#ifdef BIG_ENDIAN +#error "EDID structure is little endian, need big endian versions" +#endif + +struct est_timings { + u8 t1; + u8 t2; + u8 mfg_rsvd; +} __attribute__((packed)); + +struct std_timing { + u8 hsize; /* need to multiply by 8 then add 248 */ + u8 vfreq:6; /* need to add 60 */ + u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ +} __attribute__((packed)); + +/* If detailed data is pixel timing */ +struct detailed_pixel_timing { + u8 hactive_lo; + u8 hblank_lo; + u8 hblank_hi:4; + u8 hactive_hi:4; + u8 vactive_lo; + u8 vblank_lo; + u8 vblank_hi:4; + u8 vactive_hi:4; + u8 hsync_offset_lo; + u8 hsync_pulse_width_lo; + u8 vsync_pulse_width_lo:4; + u8 vsync_offset_lo:4; + u8 hsync_pulse_width_hi:2; + u8 hsync_offset_hi:2; + u8 vsync_pulse_width_hi:2; + u8 vsync_offset_hi:2; + u8 width_mm_lo; + u8 height_mm_lo; + u8 height_mm_hi:4; + u8 width_mm_hi:4; + u8 hborder; + u8 vborder; + u8 unknown0:1; + u8 vsync_positive:1; + u8 hsync_positive:1; + u8 separate_sync:2; + u8 stereo:1; + u8 unknown6:1; + u8 interlaced:1; +} __attribute__((packed)); + +/* If it's not pixel timing, it'll be one of the below */ +struct detailed_data_string { + u8 str[13]; +} __attribute__((packed)); + +struct detailed_data_monitor_range { + u8 min_vfreq; + u8 max_vfreq; + u8 min_hfreq_khz; + u8 max_hfreq_khz; + u8 pixel_clock_mhz; /* need to multiply by 10 */ + u16 sec_gtf_toggle; /* A000=use above, 20=use below */ + u8 hfreq_start_khz; /* need to multiply by 2 */ + u8 c; /* need to divide by 2 */ + u16 m; + u8 k; + u8 j; /* need to divide by 2 */ +} __attribute__((packed)); + +struct detailed_data_wpindex { + u8 white_y_lo:2; + u8 white_x_lo:2; + u8 pad:4; + u8 white_x_hi; + u8 white_y_hi; + u8 gamma; /* need to divide by 100 then add 1 */ +} __attribute__((packed)); + +struct detailed_data_color_point { + u8 windex1; + u8 wpindex1[3]; + u8 windex2; + u8 wpindex2[3]; +} __attribute__((packed)); + +struct detailed_non_pixel { + u8 pad1; + u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name + fb=color point data, fa=standard timing data, + f9=undefined, f8=mfg. reserved */ + u8 pad2; + union { + struct detailed_data_string str; + struct detailed_data_monitor_range range; + struct detailed_data_wpindex color; + struct std_timing timings[5]; + } data; +} __attribute__((packed)); + +#define EDID_DETAIL_STD_MODES 0xfa +#define EDID_DETAIL_CPDATA 0xfb +#define EDID_DETAIL_NAME 0xfc +#define EDID_DETAIL_RANGE 0xfd +#define EDID_DETAIL_STRING 0xfe +#define EDID_DETAIL_SERIAL 0xff + +struct detailed_timing { + u16 pixel_clock; /* need to multiply by 10 KHz */ + union { + struct detailed_pixel_timing pixel_data; + struct detailed_non_pixel other_data; + } data; +} __attribute__((packed)); + +struct edid { + u8 header[8]; + /* Vendor & product info */ + u16 mfg_id; + u16 prod_code; + u32 serial; + u8 mfg_week; + u8 mfg_year; + /* EDID version */ + u8 version; + u8 revision; + /* Display info: */ + /* input definition */ + u8 serration_vsync:1; + u8 sync_on_green:1; + u8 composite_sync:1; + u8 separate_syncs:1; + u8 blank_to_black:1; + u8 video_level:2; + u8 digital:1; /* bits below must be zero if set */ + u8 width_cm; + u8 height_cm; + u8 gamma; + /* feature support */ + u8 default_gtf:1; + u8 preferred_timing:1; + u8 standard_color:1; + u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ + u8 pm_active_off:1; + u8 pm_suspend:1; + u8 pm_standby:1; + /* Color characteristics */ + u8 red_green_lo; + u8 black_white_lo; + u8 red_x; + u8 red_y; + u8 green_x; + u8 green_y; + u8 blue_x; + u8 blue_y; + u8 white_x; + u8 white_y; + /* Est. timings and mfg rsvd timings*/ + struct est_timings established_timings; + /* Standard timings 1-8*/ + struct std_timing standard_timings[8]; + /* Detailing timings 1-4 */ + struct detailed_timing detailed_timings[4]; + /* Number of 128 byte ext. blocks */ + u8 extensions; + /* Checksum */ + u8 checksum; +} __attribute__((packed)); + +static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; + +static bool edid_valid(struct edid *edid) +{ + int i; + u8 csum = 0; + u8 *raw_edid = (u8 *)edid; + + if (memcmp(edid->header, edid_header, sizeof(edid_header))) + goto bad; + if (edid->version != 1) + goto bad; + if (edid->revision <= 0 || edid->revision > 3) + goto bad; + + for (i = 0; i < EDID_LENGTH; i++) + csum += raw_edid[i]; + if (csum) + goto bad; + + return 1; + +bad: + return 0; +} + +/** + * drm_mode_std - convert standard mode info (width, height, refresh) into mode + * @t: standard timing params + * + * Take the standard timing params (in this case width, aspect, and refresh) + * and convert them into a real mode using CVT. + * + * Punts for now. + */ +struct drm_display_mode *drm_mode_std(struct std_timing *t) +{ +// struct fb_videomode mode; + +// fb_find_mode_cvt(&mode, 0, 0); + /* JJJ: convert to drm_display_mode */ + struct drm_display_mode *mode; + int hsize = t->hsize * 8 + 248, vsize; + + mode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); + if (!mode) + return NULL; + + if (t->aspect_ratio == 0) + vsize = (hsize * 10) / 16; + else if (t->aspect_ratio == 1) + vsize = (hsize * 3) / 4; + else if (t->aspect_ratio == 2) + vsize = (hsize * 4) / 5; + else + vsize = (hsize * 9) / 16; + + snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", hsize, vsize); + + return mode; +} + +struct drm_display_mode *drm_mode_detailed(struct detailed_timing *timing, + bool preferred) +{ + struct drm_display_mode *mode; + struct detailed_pixel_timing *pt = &timing->data.pixel_data; + + if (pt->stereo) { + printk(KERN_ERR "stereo mode not supported\n"); + return NULL; + } + if (!pt->separate_sync) { + printk(KERN_ERR "integrated sync not supported\n"); + return NULL; + } + + mode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); + if (!mode) + return NULL; + + mode->type = DRM_MODE_TYPE_DRIVER; + mode->type |= preferred ? DRM_MODE_TYPE_PREFERRED : 0; + mode->clock = timing->pixel_clock / 100; + + mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo; + mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) | + pt->hsync_offset_lo); + mode->hsync_end = mode->hsync_start + + ((pt->hsync_pulse_width_hi << 8) | + pt->hsync_pulse_width_lo); + mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo); + + mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo; + mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) | + pt->vsync_offset_lo); + mode->vsync_end = mode->vsync_start + + ((pt->vsync_pulse_width_hi << 8) | + pt->vsync_pulse_width_lo); + mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo); + + snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, + mode->vdisplay); + + if (pt->interlaced) + mode->flags |= V_INTERLACE; + + mode->flags |= pt->hsync_positive ? V_PHSYNC : V_NHSYNC; + mode->flags |= pt->vsync_positive ? V_PVSYNC : V_NVSYNC; + + return mode; +} + +static struct drm_display_mode established_modes[] = { + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, + 968, 1056, 0, 600, 601, 605, 628, 0, + V_PHSYNC | V_PVSYNC) }, /* 800x600@60Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824, + 896, 1024, 0, 600, 601, 603, 625, 0, + V_PHSYNC | V_PVSYNC) }, /* 800x600@56Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656, + 720, 840, 0, 480, 481, 484, 500, 0, + V_NHSYNC | V_NVSYNC) }, /* 640x480@75Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664, + 704, 832, 0, 480, 489, 491, 520, 0, + V_NHSYNC | V_NVSYNC) }, /* 640x480@72Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704, + 768, 864, 0, 480, 483, 486, 525, 0, + V_NHSYNC | V_NVSYNC) }, /* 640x480@67Hz */ + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ + { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738, + 846, 900, 0, 400, 421, 423, 449, 0, + V_NHSYNC | V_NVSYNC) }, /* 720x400@88Hz */ + { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738, + 846, 900, 0, 400, 412, 414, 449, 0, + V_NHSYNC | V_PVSYNC) }, /* 720x400@70Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296, + 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, + V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040, + 1136, 1312, 0, 768, 769, 772, 800, 0, + V_PHSYNC | V_PVSYNC) }, /* 1024x768@75Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048, + 1184, 1328, 0, 768, 771, 777, 806, 0, + V_NHSYNC | V_NVSYNC) }, /* 1024x768@70Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, + 1184, 1344, 0, 768, 771, 777, 806, 0, + V_NHSYNC | V_NVSYNC) }, /* 1024x768@60Hz */ + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032, + 1208, 1264, 0, 768, 768, 776, 817, 0, + V_PHSYNC | V_PVSYNC | V_INTERLACE) }, /* 1024x768@43Hz */ + { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864, + 928, 1152, 0, 624, 625, 628, 667, 0, + V_NHSYNC | V_NVSYNC) }, /* 832x624@75Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816, + 896, 1056, 0, 600, 601, 604, 625, 0, + V_PHSYNC | V_PVSYNC) }, /* 800x600@75Hz */ + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856, + 976, 1040, 0, 600, 637, 643, 666, 0, + V_PHSYNC | V_PVSYNC) }, /* 800x600@72Hz */ + { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, + 1344, 1600, 0, 864, 865, 868, 900, 0, + V_PHSYNC | V_PVSYNC) }, /* 1152x864@75Hz */ +}; + +#define EDID_EST_TIMINGS 16 +#define EDID_STD_TIMINGS 8 +#define EDID_DETAILED_TIMINGS 4 + +/** + * add_established_modes - get est. modes from EDID and add them + * @edid: EDID block to scan + * + * Each EDID block contains a bitmap of the supported "established modes" list + * (defined above). Tease them out and add them to the global modes list. + */ +static int add_established_modes(struct drm_output *output, struct edid *edid) +{ + unsigned long est_bits = edid->established_timings.t1 | + (edid->established_timings.t2 << 8) | + ((edid->established_timings.mfg_rsvd & 0x80) << 9); + int i, modes = 0; + + for (i = 0; i <= EDID_EST_TIMINGS; i++) + if (est_bits & (1<standard_timings[i]; + + /* If std timings bytes are 1, 1 it's empty */ + if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1) + continue; + + drm_mode_probed_add(output, + drm_mode_std(&edid->standard_timings[i])); + modes++; + } + + return modes; +} + +/** + * add_detailed_modes - get detailed mode info from EDID data + * @edid: EDID block to scan + * + * Some of the detailed timing sections may contain mode information. Grab + * it and add it to the list. + */ +static int add_detailed_info(struct drm_output *output, struct edid *edid) +{ + int i, j, modes = 0; + bool preferred = 0; + + for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { + struct detailed_timing *timing = &edid->detailed_timings[i]; + struct detailed_non_pixel *data = &timing->data.other_data; + + /* EDID up to and including 1.2 may put monitor info here */ + if (edid->version == 1 && edid->revision < 3) + continue; + + /* Detailed mode timing */ + if (timing->pixel_clock) { + if (i == 0 && edid->preferred_timing) + preferred = 1; + drm_mode_probed_add(output, + drm_mode_detailed(timing, preferred)); + modes++; + continue; + } + + /* Other timing or info */ + switch (data->type) { + case EDID_DETAIL_SERIAL: + break; + case EDID_DETAIL_STRING: + break; + case EDID_DETAIL_RANGE: + break; + case EDID_DETAIL_NAME: + break; + case EDID_DETAIL_CPDATA: + break; + case EDID_DETAIL_STD_MODES: + /* Five modes per detailed section */ + for (j = 0; j < 5; i++) { + struct std_timing *std; + + std = &data->data.timings[j]; + drm_mode_probed_add(output, drm_mode_std(std)); + modes++; + } + break; + default: + break; + } + } + + return modes; +} + +/** + * drm_add_edid_modes - add modes from EDID data, if available + * @output: output we're probing + * @adapter: i2c adapter to use for DDC + * + * Poke the given output's i2c channel to grab EDID data if possible. If we + * get any, add the specified modes to the output's mode list. + * + * Return number of modes added or 0 if we couldn't find any. + */ +int drm_add_edid_modes(struct drm_output *output, struct i2c_adapter *adapter) +{ + struct edid *edid; + u8 *raw_edid; + int i, est_modes, std_modes, det_modes; + + edid = (struct edid *)fb_ddc_read(adapter); + + if (!edid) { + dev_warn(&output->dev->pdev->dev, "no EDID data\n"); + goto out_err; + } + + if (!edid_valid(edid)) { + dev_warn(&output->dev->pdev->dev, "EDID invalid, ignoring.\n"); + goto out_err; + } + + est_modes = add_established_modes(output, edid); + std_modes = add_standard_modes(output, edid); + det_modes = add_detailed_info(output, edid); + printk(KERN_ERR "est modes: %d, std_modes: %d, det_modes: %d\n", + est_modes, std_modes, det_modes); + + raw_edid = (u8 *)edid; + printk(KERN_ERR "EDID:\n" KERN_ERR); + for (i = 0; i < EDID_LENGTH; i++) { + if (i != 0 && ((i % 16) == 0)) + printk("\n" KERN_ERR); + printk("%02x", raw_edid[i] & 0xff); + } + printk("\n"); + + printk(KERN_ERR "EDID info:\n"); + printk(KERN_ERR " mfg_id: 0x%04x\n", edid->mfg_id); + printk(KERN_ERR " digital? %s\n", edid->digital ? "Yes" : "No"); + printk(KERN_ERR " extensions: %d\n", edid->extensions); + + return est_modes + std_modes + det_modes; + +out_err: + kfree(edid); + return 0; +} +EXPORT_SYMBOL(drm_add_edid_modes); diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c new file mode 100644 index 00000000..2347a669 --- /dev/null +++ b/linux-core/drm_modes.c @@ -0,0 +1,304 @@ +/* + * Copyright © 2007 Dave Airlie + * + * Based on code from X.org - Copyright (c) 1997-2003 by The XFree86 Project, Inc. + */ + +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" + +void drm_mode_debug_printmodeline(struct drm_device *dev, + struct drm_display_mode *mode) +{ + DRM_DEBUG("Modeline \"%s\" %d %d %d %d %d %d %d %d %d %d\n", + mode->name, mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal); +} +EXPORT_SYMBOL(drm_mode_debug_printmodeline); + +void drm_mode_list_concat(struct list_head *head, struct list_head *new) +{ + + struct list_head *entry, *tmp; + + list_for_each_safe(entry, tmp, head) { + list_move_tail(entry, new); + } +} + +int drm_mode_width(struct drm_display_mode *mode) +{ + return mode->hdisplay; + +} +EXPORT_SYMBOL(drm_mode_width); + +int drm_mode_height(struct drm_display_mode *mode) +{ + return mode->vdisplay; +} +EXPORT_SYMBOL(drm_mode_height); + +int drm_mode_vrefresh(struct drm_display_mode *mode) +{ + int refresh = 0; + + if (mode->vrefresh > 0) + refresh = mode->vrefresh; + else if (mode->htotal > 0 && mode->vtotal > 0) { + refresh = ((mode->clock * 1000) * 1000) / mode->htotal / mode->vtotal; + if (mode->flags & V_INTERLACE) + refresh *= 2; + if (mode->flags & V_DBLSCAN) + refresh /= 2; + if (mode->vscan > 1) + refresh /= mode->vscan; + } + return refresh; +} +EXPORT_SYMBOL(drm_mode_vrefresh); + + +void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) +{ + if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) + return; + + p->crtc_hdisplay = p->hdisplay; + p->crtc_hsync_start = p->hsync_start; + p->crtc_hsync_end = p->hsync_end; + p->crtc_htotal = p->htotal; + p->crtc_hskew = p->hskew; + p->crtc_vdisplay = p->vdisplay; + p->crtc_vsync_start = p->vsync_start; + p->crtc_vsync_end = p->vsync_end; + p->crtc_vtotal = p->vtotal; + + if (p->flags & V_INTERLACE) { + if (adjust_flags & CRTC_INTERLACE_HALVE_V) { + p->crtc_vdisplay /= 2; + p->crtc_vsync_start /= 2; + p->crtc_vsync_end /= 2; + p->crtc_vtotal /= 2; + } + + p->crtc_vtotal |= 1; + } + + if (p->flags & V_DBLSCAN) { + p->crtc_vdisplay *= 2; + p->crtc_vsync_start *= 2; + p->crtc_vsync_end *= 2; + p->crtc_vtotal *= 2; + } + + if (p->vscan > 1) { + p->crtc_vdisplay *= p->vscan; + p->crtc_vsync_start *= p->vscan; + p->crtc_vsync_end *= p->vscan; + p->crtc_vtotal *= p->vscan; + } + + p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); + p->crtc_vblank_end = min(p->crtc_vsync_end, p->crtc_vtotal); + p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); + p->crtc_hblank_end = min(p->crtc_hsync_end, p->crtc_htotal); + + p->crtc_hadjusted = false; + p->crtc_vadjusted = false; +} +EXPORT_SYMBOL(drm_mode_set_crtcinfo); + + +struct drm_display_mode *drm_mode_duplicate(struct drm_display_mode *mode) +{ + struct drm_display_mode *nmode; + + nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); + if (!nmode) + return NULL; + + *nmode = *mode; + INIT_LIST_HEAD(&nmode->head); + return nmode; +} +EXPORT_SYMBOL(drm_mode_duplicate); + +bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2) +{ + if (mode1->clock == mode2->clock && + mode1->hdisplay == mode2->hdisplay && + mode1->hsync_start == mode2->hsync_start && + mode1->hsync_end == mode2->hsync_end && + mode1->htotal == mode2->htotal && + mode1->hskew == mode2->hskew && + mode1->vdisplay == mode2->vdisplay && + mode1->vsync_start == mode2->vsync_start && + mode1->vsync_end == mode2->vsync_end && + mode1->vtotal == mode2->vtotal && + mode1->vscan == mode2->vscan && + mode1->flags == mode2->flags) + return true; + + return false; +} +EXPORT_SYMBOL(drm_mode_equal); + +void drm_mode_validate_size(struct drm_device *dev, + struct list_head *mode_list, + int maxX, int maxY, int maxPitch) +{ + struct drm_display_mode *mode; + + list_for_each_entry(mode, mode_list, head) { + if (maxPitch > 0 && mode->hdisplay > maxPitch) + mode->status = MODE_BAD_WIDTH; + + if (maxX > 0 && mode->hdisplay > maxX) + mode->status = MODE_VIRTUAL_X; + + if (maxY > 0 && mode->vdisplay > maxY) + mode->status = MODE_VIRTUAL_Y; + } +} +EXPORT_SYMBOL(drm_mode_validate_size); + +void drm_mode_validate_clocks(struct drm_device *dev, + struct list_head *mode_list, + int *min, int *max, int n_ranges) +{ + struct drm_display_mode *mode; + int i; + + list_for_each_entry(mode, mode_list, head) { + bool good = false; + for (i = 0; i < n_ranges; i++) { + if (mode->clock >= min[i] && mode->clock <= max[i]) { + good = true; + break; + } + } + if (!good) + mode->status = MODE_CLOCK_RANGE; + } +} +EXPORT_SYMBOL(drm_mode_validate_clocks); + +void drm_mode_prune_invalid(struct drm_device *dev, + struct list_head *mode_list, bool verbose) +{ + struct drm_display_mode *mode, *t; + + list_for_each_entry_safe(mode, t, mode_list, head) { + if (mode->status != MODE_OK) { + list_del(&mode->head); + if (verbose) + DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status); + kfree(mode); + } + } +} + +static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b) +{ + struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head); + struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head); + int diff; + + diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) - + ((a->type & DRM_MODE_TYPE_PREFERRED) != 0); + if (diff) + return diff; + diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay; + if (diff) + return diff; + diff = b->clock - a->clock; + return diff; +} + +/* list sort from Mark J Roberts (mjr@znex.org) */ +void list_sort(struct list_head *head, int (*cmp)(struct list_head *a, struct list_head *b)) +{ + struct list_head *p, *q, *e, *list, *tail, *oldhead; + int insize, nmerges, psize, qsize, i; + + list = head->next; + list_del(head); + insize = 1; + for (;;) { + p = oldhead = list; + list = tail = NULL; + nmerges = 0; + + while (p) { + nmerges++; + q = p; + psize = 0; + for (i = 0; i < insize; i++) { + psize++; + q = q->next == oldhead ? NULL : q->next; + if (!q) + break; + } + + qsize = insize; + while (psize > 0 || (qsize > 0 && q)) { + if (!psize) { + e = q; + q = q->next; + qsize--; + if (q == oldhead) + q = NULL; + } else if (!qsize || !q) { + e = p; + p = p->next; + psize--; + if (p == oldhead) + p = NULL; + } else if (cmp(p, q) <= 0) { + e = p; + p = p->next; + psize--; + if (p == oldhead) + p = NULL; + } else { + e = q; + q = q->next; + qsize--; + if (q == oldhead) + q = NULL; + } + if (tail) + tail->next = e; + else + list = e; + e->prev = tail; + tail = e; + } + p = q; + } + + tail->next = list; + list->prev = tail; + + if (nmerges <= 1) + break; + + insize *= 2; + } + + head->next = list; + head->prev = list->prev; + list->prev->next = head; + list->prev = head; +} + +void drm_mode_sort(struct list_head *mode_list) +{ + list_sort(mode_list, drm_mode_compare); +} diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 7fdb0839..b9e624f9 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -79,6 +79,7 @@ static struct drm_driver driver = { DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, .load = i915_driver_load, + .unload = i915_driver_unload, .firstopen = i915_driver_firstopen, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c new file mode 100644 index 00000000..5ff9f791 --- /dev/null +++ b/linux-core/intel_crt.c @@ -0,0 +1,226 @@ +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +static void intel_crt_dpms(struct drm_output *output, int mode) +{ + drm_device_t *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + u32 temp; + + temp = I915_READ(ADPA); + temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); + temp &= ~ADPA_DAC_ENABLE; + + switch(mode) { + case DPMSModeOn: + temp |= ADPA_DAC_ENABLE; + break; + case DPMSModeStandby: + temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; + break; + case DPMSModeSuspend: + temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; + break; + case DPMSModeOff: + temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; + break; + } + + I915_WRITE(ADPA, temp); +} + +static void intel_crt_save(struct drm_output *output) +{ + +} + +static void intel_crt_restore(struct drm_output *output) +{ + +} + +static int intel_crt_mode_valid(struct drm_output *output, + struct drm_display_mode *mode) +{ + if (mode->flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + if (mode->clock > 400000 || mode->clock < 25000) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + +static bool intel_crt_mode_fixup(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void intel_crt_mode_set(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + drm_device_t *dev = output->dev; + struct drm_crtc *crtc = output->crtc; + struct intel_crtc *intel_crtc = crtc->driver_private; + drm_i915_private_t *dev_priv = dev->dev_private; + int dpll_md_reg; + u32 adpa, dpll_md; + + if (intel_crtc->pipe == 0) + dpll_md_reg = DPLL_A_MD; + else + dpll_md_reg = DPLL_B_MD; + + /* + * Disable separate mode multiplier used when cloning SDVO to CRT + * XXX this needs to be adjusted when we really are cloning + */ + if (IS_I965G(dev)) + { + dpll_md = I915_READ(dpll_md_reg); + I915_WRITE(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); + } + + adpa = 0; + if (adjusted_mode->flags & V_PHSYNC) + adpa |= ADPA_HSYNC_ACTIVE_HIGH; + if (adjusted_mode->flags & V_PVSYNC) + adpa |= ADPA_VSYNC_ACTIVE_HIGH; + + if (intel_crtc->pipe == 0) + adpa |= ADPA_PIPE_A_SELECT; + else + adpa |= ADPA_PIPE_B_SELECT; + + I915_WRITE(ADPA, adpa); +} + +/** + * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. + * + * Only for I945G/GM. + * + * \return TRUE if CRT is connected. + * \return FALSE if CRT is disconnected. + */ +static bool intel_crt_detect_hotplug(struct drm_output *output) +{ + drm_device_t *dev = output->dev; +// struct intel_output *intel_output = output->driver_private; + drm_i915_private_t *dev_priv = dev->dev_private; + u32 temp; + const int timeout_ms = 1000; + int starttime, curtime; + + temp = I915_READ(PORT_HOTPLUG_EN); + + I915_WRITE(PORT_HOTPLUG_EN, temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5)); +#if 0 + for (curtime = starttime = GetTimeInMillis(); + (curtime - starttime) < timeout_ms; curtime = GetTimeInMillis()) + { + if ((I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0) + break; + } +#endif + if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) == + CRT_HOTPLUG_MONITOR_COLOR) + { + return true; + } else { + return false; + } +} + +static bool intel_crt_detect_ddc(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + + /* CRT should always be at 0, but check anyway */ + if (intel_output->type != INTEL_OUTPUT_ANALOG) + return false; + + return intel_ddc_probe(output); +} + +static enum drm_output_status intel_crt_detect(struct drm_output *output) +{ + drm_device_t *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + if (IS_I945G(dev)| IS_I945GM(dev) || IS_I965G(dev)) { + if (intel_crt_detect_hotplug(output)) + return output_status_connected; + else + return output_status_disconnected; + } + + if (intel_crt_detect_ddc(output)) + return output_status_connected; + + /* TODO use load detect */ + return output_status_unknown; +} + +static void intel_crt_destroy(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + + intel_i2c_destroy(intel_output->ddc_bus); + + if (output->driver_private) + kfree(output->driver_private); +} + +/* + * Routines for controlling stuff on the analog port + */ +static const struct drm_output_funcs intel_crt_output_funcs = { + .dpms = intel_crt_dpms, + .save = intel_crt_save, + .restore = intel_crt_restore, + .mode_valid = intel_crt_mode_valid, + .mode_fixup = intel_crt_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_crt_mode_set, + .commit = intel_output_commit, + .detect = intel_crt_detect, + .get_modes = intel_ddc_get_modes, + .cleanup = intel_crt_destroy, +}; + +void intel_crt_init(drm_device_t *dev) +{ + struct drm_output *output; + struct intel_output *intel_output; + int modes; + + output = drm_output_create (dev, &intel_crt_output_funcs, "VGA"); + + intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); + if (!intel_output) { + drm_output_destroy(output); + return; + } + + intel_output->type = INTEL_OUTPUT_ANALOG; + output->driver_private = intel_output; + output->interlace_allowed = 0; + output->doublescan_allowed = 0; + + /* Set up the DDC bus. */ + intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return; + } +} diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c new file mode 100644 index 00000000..495f4704 --- /dev/null +++ b/linux-core/intel_display.c @@ -0,0 +1,1087 @@ +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +bool intel_pipe_has_type (struct drm_crtc *crtc, int type); + +typedef struct { + /* given values */ + int n; + int m1, m2; + int p1, p2; + /* derived values */ + int dot; + int vco; + int m; + int p; +} intel_clock_t; + +typedef struct { + int min, max; +} intel_range_t; + +typedef struct { + int dot_limit; + int p2_slow, p2_fast; +} intel_p2_t; + +#define INTEL_P2_NUM 2 + +typedef struct { + intel_range_t dot, vco, n, m, m1, m2, p, p1; + intel_p2_t p2; +} intel_limit_t; + +#define I8XX_DOT_MIN 25000 +#define I8XX_DOT_MAX 350000 +#define I8XX_VCO_MIN 930000 +#define I8XX_VCO_MAX 1400000 +#define I8XX_N_MIN 3 +#define I8XX_N_MAX 16 +#define I8XX_M_MIN 96 +#define I8XX_M_MAX 140 +#define I8XX_M1_MIN 18 +#define I8XX_M1_MAX 26 +#define I8XX_M2_MIN 6 +#define I8XX_M2_MAX 16 +#define I8XX_P_MIN 4 +#define I8XX_P_MAX 128 +#define I8XX_P1_MIN 2 +#define I8XX_P1_MAX 33 +#define I8XX_P1_LVDS_MIN 1 +#define I8XX_P1_LVDS_MAX 6 +#define I8XX_P2_SLOW 4 +#define I8XX_P2_FAST 2 +#define I8XX_P2_LVDS_SLOW 14 +#define I8XX_P2_LVDS_FAST 14 /* No fast option */ +#define I8XX_P2_SLOW_LIMIT 165000 + +#define I9XX_DOT_MIN 20000 +#define I9XX_DOT_MAX 400000 +#define I9XX_VCO_MIN 1400000 +#define I9XX_VCO_MAX 2800000 +#define I9XX_N_MIN 3 +#define I9XX_N_MAX 8 +#define I9XX_M_MIN 70 +#define I9XX_M_MAX 120 +#define I9XX_M1_MIN 10 +#define I9XX_M1_MAX 20 +#define I9XX_M2_MIN 5 +#define I9XX_M2_MAX 9 +#define I9XX_P_SDVO_DAC_MIN 5 +#define I9XX_P_SDVO_DAC_MAX 80 +#define I9XX_P_LVDS_MIN 7 +#define I9XX_P_LVDS_MAX 98 +#define I9XX_P1_MIN 1 +#define I9XX_P1_MAX 8 +#define I9XX_P2_SDVO_DAC_SLOW 10 +#define I9XX_P2_SDVO_DAC_FAST 5 +#define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000 +#define I9XX_P2_LVDS_SLOW 14 +#define I9XX_P2_LVDS_FAST 7 +#define I9XX_P2_LVDS_SLOW_LIMIT 112000 + +#define INTEL_LIMIT_I8XX_DVO_DAC 0 +#define INTEL_LIMIT_I8XX_LVDS 1 +#define INTEL_LIMIT_I9XX_SDVO_DAC 2 +#define INTEL_LIMIT_I9XX_LVDS 3 + +static const intel_limit_t intel_limits[] = { + { /* INTEL_LIMIT_I8XX_DVO_DAC */ + .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, + .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, + .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, + .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, + .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, + .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, + .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, + .p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX }, + .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, + .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, + }, + { /* INTEL_LIMIT_I8XX_LVDS */ + .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, + .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, + .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, + .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, + .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, + .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, + .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, + .p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX }, + .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, + .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST }, + }, + { /* INTEL_LIMIT_I9XX_SDVO_DAC */ + .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, + .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, + .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, + .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, + .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, + .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, + .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, + .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, + .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, + .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, + }, + { /* INTEL_LIMIT_I9XX_LVDS */ + .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, + .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, + .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, + .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, + .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, + .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, + .p = { .min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX }, + .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, + /* The single-channel range is 25-112Mhz, and dual-channel + * is 80-224Mhz. Prefer single channel as much as possible. + */ + .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, + .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, + }, +}; + +static const intel_limit_t *intel_limit (struct drm_crtc *crtc) +{ + drm_device_t *dev = crtc->dev; + const intel_limit_t *limit; + + if (IS_I9XX(dev)) { + if (intel_pipe_has_type (crtc, INTEL_OUTPUT_LVDS)) + limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; + else + limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; + } else { + if (intel_pipe_has_type (crtc, INTEL_OUTPUT_LVDS)) + limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS]; + else + limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC]; + } + return limit; +} + +/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ + +static void i8xx_clock(int refclk, intel_clock_t *clock) +{ + clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); + clock->p = clock->p1 * clock->p2; + clock->vco = refclk * clock->m / (clock->n + 2); + clock->dot = clock->vco / clock->p; +} + +/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ + +static void i9xx_clock(int refclk, intel_clock_t *clock) +{ + clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); + clock->p = clock->p1 * clock->p2; + clock->vco = refclk * clock->m / (clock->n + 2); + clock->dot = clock->vco / clock->p; +} + +static void intel_clock(struct drm_device *dev, int refclk, + intel_clock_t *clock) +{ + if (IS_I9XX(dev)) + return i9xx_clock (refclk, clock); + else + return i8xx_clock (refclk, clock); +} + +/** + * Returns whether any output on the specified pipe is of the specified type + */ +bool intel_pipe_has_type (struct drm_crtc *crtc, int type) +{ + struct drm_device *dev = crtc->dev; + struct drm_crtc_config *crtc_config = &dev->crtc_config; + struct drm_output *l_entry; + + list_for_each_entry(l_entry, &crtc_config->output_list, head) { + if (l_entry->crtc == crtc) { + struct intel_output *intel_output = l_entry->driver_private; + if (intel_output->type == type) + return true; + } + } + return false; +} + +#define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } +/** + * Returns whether the given set of divisors are valid for a given refclk with + * the given outputs. + */ + +static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock) +{ + const intel_limit_t *limit = intel_limit (crtc); + + if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) + INTELPllInvalid ("p1 out of range\n"); + if (clock->p < limit->p.min || limit->p.max < clock->p) + INTELPllInvalid ("p out of range\n"); + if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) + INTELPllInvalid ("m2 out of range\n"); + if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) + INTELPllInvalid ("m1 out of range\n"); + if (clock->m1 <= clock->m2) + INTELPllInvalid ("m1 <= m2\n"); + if (clock->m < limit->m.min || limit->m.max < clock->m) + INTELPllInvalid ("m out of range\n"); + if (clock->n < limit->n.min || limit->n.max < clock->n) + INTELPllInvalid ("n out of range\n"); + if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) + INTELPllInvalid ("vco out of range\n"); + /* XXX: We may need to be checking "Dot clock" depending on the multiplier, + * output, etc., rather than just a single range. + */ + if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) + INTELPllInvalid ("dot out of range\n"); + + return true; +} + +/** + * Returns a set of divisors for the desired target clock with the given + * refclk, or FALSE. The returned values represent the clock equation: + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. + */ +static bool intel_find_best_PLL(struct drm_crtc *crtc, int target, + int refclk, intel_clock_t *best_clock) +{ + drm_device_t *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + intel_clock_t clock; + const intel_limit_t *limit = intel_limit (crtc); + int err = target; + + if (IS_I9XX(dev)& intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + (I915_READ(LVDS) & LVDS_PORT_EN) != 0) + { + /* For LVDS, if the panel is on, just rely on its current settings for + * dual-channel. We haven't figured out how to reliably set up + * different single/dual channel state, if we even can. + */ + if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset (best_clock, 0, sizeof (*best_clock)); + + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) + { + for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && clock.m2 <= limit->m2.max; clock.m2++) + { + for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) + { + for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; clock.p1++) + { + int this_err; + + intel_clock (dev, refclk, &clock); + + if (!intel_PLL_is_valid(crtc, &clock)) + continue; + + this_err = abs(clock.dot - target); + if (this_err < err) { + *best_clock = clock; + err = this_err; + } + } + } + } + } + return (err != target); +} + +void +intel_wait_for_vblank(drm_device_t *dev) +{ + /* Wait for 20ms, i.e. one cycle at 50hz. */ + udelay(20000); +} + +void +intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) +{ + drm_device_t *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + unsigned long Start, Offset; + int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); + int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); + + Start = crtc->fb->offset; + Offset = ((y * crtc->fb->width + x) * (crtc->fb->bits_per_pixel / 8)); + + if (IS_I965G(dev)) { + I915_WRITE(dspbase, Offset); + I915_READ(dspbase); + I915_WRITE(dspsurf, Start); + I915_READ(dspsurf); + } else { + I915_WRITE(dspbase, Start + Offset); + I915_READ(dspbase); + } + + +#if 0 + drmI830Sarea *sPriv = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn->pScreen); + + if (!sPriv) + return; + + switch (pipe) { + case 0: + sPriv->pipeA_x = x; + sPriv->pipeA_y = y; + break; + case 1: + sPriv->pipeB_x = x; + sPriv->pipeB_y = y; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Can't update pipe %d in SAREA\n", pipe); + break; + } +#endif +} + +/** + * Sets the power management mode of the pipe and plane. + * + * This code should probably grow support for turning the cursor off and back + * on appropriately at the same time as we're turning the pipe off/on. + */ +static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + drm_device_t *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; + int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + u32 temp; + + /* XXX: When our outputs are all unaware of DPMS modes other than off + * and on, we should map those modes to DPMSModeOff in the CRTC. + */ + switch (mode) { + case DPMSModeOn: + case DPMSModeStandby: + case DPMSModeSuspend: + /* Enable the DPLL */ + temp = I915_READ(dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) + { + I915_WRITE(dpll_reg, temp); + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + } + + /* Enable the pipe */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) == 0) + I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); + + /* Enable the plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) + { + I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + } + + intel_crtc_load_lut(crtc); + + /* Give the overlay scaler a chance to enable if it's on this pipe */ + //intel_crtc_dpms_video(crtc, TRUE); TODO + break; + case DPMSModeOff: + /* Give the overlay scaler a chance to disable if it's on this pipe */ + //intel_crtc_dpms_video(crtc, FALSE); TODO + + /* Disable the VGA plane that we never use */ + I915_WRITE(VGACNTRL, VGA_DISP_DISABLE); + + /* Disable display plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) + { + I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + I915_READ(dspbase_reg); + } + + if (!IS_I9XX(dev)) { + /* Wait for vblank for the disable to take effect */ + intel_wait_for_vblank(dev); + } + + /* Next, disable display pipes */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); + I915_READ(pipeconf_reg); + } + + /* Wait for vblank for the disable to take effect. */ + intel_wait_for_vblank(dev); + + temp = I915_READ(dpll_reg); + if ((temp & DPLL_VCO_ENABLE) != 0) { + I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); + I915_READ(dpll_reg); + } + + /* Wait for the clocks to turn off. */ + udelay(150); + break; + } + +#if 0 //TODO + if (pI830->directRenderingEnabled) { + drmI830Sarea *sPriv = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn->pScreen); + Bool enabled = crtc->enabled && mode != DPMSModeOff; + + if (!sPriv) + return; + + switch (pipe) { + case 0: + sPriv->pipeA_w = enabled ? crtc->mode.HDisplay : 0; + sPriv->pipeA_h = enabled ? crtc->mode.VDisplay : 0; + break; + case 1: + sPriv->pipeB_w = enabled ? crtc->mode.HDisplay : 0; + sPriv->pipeB_h = enabled ? crtc->mode.VDisplay : 0; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Can't update pipe %d in SAREA\n", pipe); + break; + } + } +#endif +} + +static bool intel_crtc_lock(struct drm_crtc *crtc) +{ + /* Sync the engine before mode switch */ +// i830WaitSync(crtc->scrn); + +#if 0 // TODO def XF86DRI + return I830DRILock(crtc->scrn); +#else + return FALSE; +#endif +} + +static void intel_crtc_unlock (struct drm_crtc *crtc) +{ +#if 0 // TODO def XF86DRI + I830DRIUnlock (crtc->scrn); +#endif +} + +static void intel_crtc_prepare (struct drm_crtc *crtc) +{ + crtc->funcs->dpms (crtc, DPMSModeOff); +} + +static void intel_crtc_commit (struct drm_crtc *crtc) +{ + crtc->funcs->dpms (crtc, DPMSModeOn); +// if (crtc->scrn->pScreen != NULL) +// xf86_reload_cursors (crtc->scrn->pScreen); +} + +void intel_output_prepare (struct drm_output *output) +{ + output->funcs->dpms (output, DPMSModeOff); +} + +void intel_output_commit (struct drm_output *output) +{ + output->funcs->dpms (output, DPMSModeOn); +} + +static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + + +/** Returns the core display clock speed for i830 - i945 */ +static int intel_get_core_clock_speed(drm_device_t *dev) +{ + + /* Core clock values taken from the published datasheets. + * The 830 may go up to 166 Mhz, which we should check. + */ + if (IS_I945G(dev)) + return 400000; + else if (IS_I915G(dev)) + return 333000; + else if (IS_I945GM(dev) || IS_845G(dev)) + return 200000; + else if (IS_I915GM(dev)) { +#if 0 + u16 gcfgc = pciReadWord(dev->PciTag, I915_GCFGC); + + if (gcfgc & I915_LOW_FREQUENCY_ENABLE) + return 133000; + else { + switch (gcfgc & I915_DISPLAY_CLOCK_MASK) { + case I915_DISPLAY_CLOCK_333_MHZ: + return 333000; + default: + case I915_DISPLAY_CLOCK_190_200_MHZ: + return 190000; + } + } +#endif + } else if (IS_I865G(dev)) + return 266000; + else if (IS_I855(dev)) { +#if 0 + PCITAG bridge = pciTag(0, 0, 0); /* This is always the host bridge */ + u16 hpllcc = pciReadWord(bridge, I855_HPLLCC); + +#endif + u16 hpllcc = 0; + /* Assume that the hardware is in the high speed state. This + * should be the default. + */ + switch (hpllcc & I855_CLOCK_CONTROL_MASK) { + case I855_CLOCK_133_200: + case I855_CLOCK_100_200: + return 200000; + case I855_CLOCK_166_250: + return 250000; + case I855_CLOCK_100_133: + return 133000; + } + } else /* 852, 830 */ + return 133000; + + return 0; /* Silence gcc warning */ +} + + +/** + * Return the pipe currently connected to the panel fitter, + * or -1 if the panel fitter is not present or not in use + */ +static int intel_panel_fitter_pipe (drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 pfit_control; + + /* i830 doesn't have a panel fitter */ + if (IS_I830(dev)) + return -1; + + pfit_control = I915_READ(PFIT_CONTROL); + + /* See if the panel fitter is in use */ + if ((pfit_control & PFIT_ENABLE) == 0) + return -1; + + /* 965 can place panel fitter on either pipe */ + if (IS_I965G(dev)) + return (pfit_control >> 29) & 0x3; + + /* older chips can only use pipe 1 */ + return 1; +} + +static void intel_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y) +{ + drm_device_t *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + int fp_reg = (pipe == 0) ? FPA0 : FPB0; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; + int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; + int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; + int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; + int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; + int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; + int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; + int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; + int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; + int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; + int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; + int refclk; + intel_clock_t clock; + u32 dpll = 0, fp = 0, dspcntr, pipeconf; + bool ok, is_sdvo = false, is_dvo = false; + bool is_crt = false, is_lvds = false, is_tv = false; + struct drm_crtc_config *crtc_config = &dev->crtc_config; + struct drm_output *output; + + list_for_each_entry(output, &crtc_config->output_list, head) { + struct intel_output *intel_output = output->driver_private; + + if (output->crtc != crtc) + continue; + + switch (intel_output->type) { + case INTEL_OUTPUT_LVDS: + is_lvds = TRUE; + break; + case INTEL_OUTPUT_SDVO: + is_sdvo = TRUE; + break; + case INTEL_OUTPUT_DVO: + is_dvo = TRUE; + break; + case INTEL_OUTPUT_TVOUT: + is_tv = TRUE; + break; + case INTEL_OUTPUT_ANALOG: + is_crt = TRUE; + break; + } + } + + if (IS_I9XX(dev)) { + refclk = 96000; + } else { + refclk = 48000; + } + + ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock); + if (!ok) { + DRM_ERROR("Couldn't find PLL settings for mode!\n"); + return; + } + + fp = clock.n << 16 | clock.m1 << 8 | clock.m2; + + dpll = DPLL_VGA_MODE_DIS; + if (IS_I9XX(dev)) { + if (is_lvds) + dpll |= DPLLB_MODE_LVDS; + else + dpll |= DPLLB_MODE_DAC_SERIAL; + if (is_sdvo) + { + dpll |= DPLL_DVO_HIGH_SPEED; + if (IS_I945G(dev) || IS_I945GM(dev)) + { + int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; + } + } + + /* compute bitmask from p1 value */ + dpll |= (1 << (clock.p1 - 1)) << 16; + switch (clock.p2) { + case 5: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; + break; + case 7: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; + break; + case 10: + dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; + break; + case 14: + dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; + break; + } + if (IS_I965G(dev)) + dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); + } else { + if (is_lvds) { + dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + } else { + if (clock.p1 == 2) + dpll |= PLL_P1_DIVIDE_BY_TWO; + else + dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; + if (clock.p2 == 4) + dpll |= PLL_P2_DIVIDE_BY_4; + } + } + + if (is_tv) + { + /* XXX: just matching BIOS for now */ +/* dpll |= PLL_REF_INPUT_TVCLKINBC; */ + dpll |= 3; + } +#if 0 + else if (is_lvds) + dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN; +#endif + else + dpll |= PLL_REF_INPUT_DREFCLK; + + /* Set up the display plane register */ + dspcntr = DISPPLANE_GAMMA_ENABLE; + + switch (crtc->fb->bits_per_pixel) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (crtc->fb->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + DRM_ERROR("Unknown color depth\n"); + return; + } + + + if (pipe == 0) + dspcntr |= DISPPLANE_SEL_PIPE_A; + else + dspcntr |= DISPPLANE_SEL_PIPE_B; + + pipeconf = I915_READ(pipeconf_reg); + if (pipe == 0 && !IS_I965G(dev)) + { + /* Enable pixel doubling when the dot clock is > 90% of the (display) + * core speed. + * + * XXX: No double-wide on 915GM pipe B. Is that the only reason for the + * pipe == 0 check? + */ + if (mode->clock > intel_get_core_clock_speed(dev) * 9 / 10) + pipeconf |= PIPEACONF_DOUBLE_WIDE; + else + pipeconf &= ~PIPEACONF_DOUBLE_WIDE; + } + + dspcntr |= DISPLAY_PLANE_ENABLE; + pipeconf |= PIPEACONF_ENABLE; + dpll |= DPLL_VCO_ENABLE; + + + /* Disable the panel fitter if it was on our pipe */ + if (intel_panel_fitter_pipe(dev) == pipe) + I915_WRITE(PFIT_CONTROL, 0); + +#if 0 + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + xf86PrintModeline(pScrn->scrnIndex, mode); + if (!xf86ModesEqual(mode, adjusted_mode)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Adjusted mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + xf86PrintModeline(pScrn->scrnIndex, mode); + } + i830PrintPll("chosen", &clock); +#endif + + if (dpll & DPLL_VCO_ENABLE) + { + I915_WRITE(fp_reg, fp); + I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); + I915_READ(dpll_reg); + udelay(150); + } + + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ + if (is_lvds) + { + u32 lvds = I915_READ(LVDS); + + lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (clock.p2 == 7) + lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. + */ + + I915_WRITE(LVDS, lvds); + I915_READ(LVDS); + } + + I915_WRITE(fp_reg, fp); + I915_WRITE(dpll_reg, dpll); + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + + if (IS_I965G(dev)) { + int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | + ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); + } else { + /* write it again -- the BIOS does, after all */ + I915_WRITE(dpll_reg, dpll); + } + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + + I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16)); + I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16)); + I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16)); + I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | + ((adjusted_mode->crtc_vblank_end - 1) << 16)); + I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16)); + I915_WRITE(dspstride_reg, crtc->fb->pitch * (crtc->fb->bits_per_pixel / 8)); + /* pipesrc and dspsize control the size that is scaled from, which should + * always be the user's requested size. + */ + I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); + I915_WRITE(dsppos_reg, 0); + I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + I915_WRITE(pipeconf_reg, pipeconf); + I915_READ(pipeconf_reg); + + intel_wait_for_vblank(dev); + + I915_WRITE(dspcntr_reg, dspcntr); + + /* Flush the plane changes */ + intel_pipe_set_base(crtc, x, y); + +#ifdef XF86DRI // TODO +// I830DRISetVBlankInterrupt (pScrn, TRUE); +#endif + + intel_wait_for_vblank(dev); + + +} + +/** Loads the palette/gamma unit for the CRTC with the prepared values */ +void intel_crtc_load_lut(struct drm_crtc *crtc) +{ + drm_device_t *dev = crtc->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = crtc->driver_private; + int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; + int i; + + /* The clocks have to be on to load the palette. */ + if (!crtc->enabled) + return; + + for (i = 0; i < 256; i++) { + I915_WRITE(palreg + 4 * i, + (intel_crtc->lut_r[i] << 16) | + (intel_crtc->lut_g[i] << 8) | + intel_crtc->lut_b[i]); + } +} + +/** Sets the color ramps on behalf of RandR */ +static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, int size) +{ + struct intel_crtc *intel_crtc = crtc->driver_private; + int i; + + for (i = 0; i < 256; i++) { + intel_crtc->lut_r[i] = red[i] >> 8; + intel_crtc->lut_g[i] = green[i] >> 8; + intel_crtc->lut_b[i] = blue[i] >> 8; + } + + intel_crtc_load_lut(crtc); +} + +struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, + struct drm_crtc *crtc) +{ + return NULL; +} + +static const struct drm_crtc_funcs intel_crtc_funcs = { + .dpms = intel_crtc_dpms, + .lock = intel_crtc_lock, + .unlock = intel_crtc_unlock, + .mode_fixup = intel_crtc_mode_fixup, + .mode_set = intel_crtc_mode_set, + .gamma_set = intel_crtc_gamma_set, + .prepare = intel_crtc_prepare, + .commit = intel_crtc_commit, +}; + + +void intel_crtc_init(drm_device_t *dev, int pipe) +{ + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + int i; + + crtc = drm_crtc_create(dev, &intel_crtc_funcs); + if (crtc == NULL) + return; + + intel_crtc = kmalloc(sizeof(struct intel_crtc), GFP_KERNEL); + if (intel_crtc == NULL) { + kfree(crtc); + return; + } + + intel_crtc->pipe = pipe; + for (i = 0; i < 256; i++) { + intel_crtc->lut_r[i] = i; + intel_crtc->lut_g[i] = i; + intel_crtc->lut_b[i] = i; + } + + crtc->driver_private = intel_crtc; +} + +int intel_output_clones (drm_device_t *dev, int type_mask) +{ + int index_mask = 0; + struct drm_output *output; + int entry = 0; + + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + struct intel_output *intel_output = output->driver_private; + if (type_mask & (1 << intel_output->type)) + index_mask |= (1 << entry); + entry++; + } + return index_mask; +} + + +static void intel_setup_outputs(drm_device_t *dev) +{ + struct drm_output *output; + + intel_crt_init(dev); + + /* Set up integrated LVDS */ + if (IS_MOBILE(dev) && !IS_I830(dev)) + intel_lvds_init(dev); + + if (IS_I9XX(dev)) { + intel_sdvo_init(dev, SDVOB); + intel_sdvo_init(dev, SDVOC); + } + + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + struct intel_output *intel_output = output->driver_private; + int crtc_mask = 0, clone_mask = 0; + + /* valid crtcs */ + switch(intel_output->type) { + case INTEL_OUTPUT_DVO: + case INTEL_OUTPUT_SDVO: + crtc_mask = ((1 << 0)| + (1 << 1)); + clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | + (1 << INTEL_OUTPUT_DVO) | + (1 << INTEL_OUTPUT_SDVO)); + break; + case INTEL_OUTPUT_ANALOG: + crtc_mask = ((1 << 0)); + clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | + (1 << INTEL_OUTPUT_DVO) | + (1 << INTEL_OUTPUT_SDVO)); + break; + case INTEL_OUTPUT_LVDS: + crtc_mask = (1 << 1); + clone_mask = (1 << INTEL_OUTPUT_LVDS); + break; + case INTEL_OUTPUT_TVOUT: + crtc_mask = ((1 << 0) | + (1 << 1)); + clone_mask = (1 << INTEL_OUTPUT_TVOUT); + break; + } + output->possible_crtcs = crtc_mask; + output->possible_clones = intel_output_clones(dev, clone_mask); + } +} + +void intel_modeset_init(drm_device_t *dev) +{ + int num_pipe; + int i; + + drm_crtc_config_init(dev); + + + if (IS_MOBILE(dev) || IS_I9XX(dev)) + num_pipe = 2; + else + num_pipe = 1; + DRM_DEBUG("%d display pipe%s available.\n", + num_pipe, num_pipe > 1 ? "s" : ""); + + for (i = 0; i < num_pipe; i++) { + intel_crtc_init(dev, i); + } + + intel_setup_outputs(dev); + + drm_initial_config(dev, false); +} + +void intel_modeset_cleanup(drm_device_t *dev) +{ + drm_crtc_config_cleanup(dev); +} diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h new file mode 100644 index 00000000..5b8bef69 --- /dev/null +++ b/linux-core/intel_drv.h @@ -0,0 +1,69 @@ +#ifndef __INTEL_DRV_H__ +#define __INTEL_DRV_H__ + +#include +#include +#include +#include "drm_crtc.h" + +/* + * Display related stuff + */ + +/* store information about an Ixxx DVO */ +/* The i830->i865 use multiple DVOs with multiple i2cs */ +/* the i915, i945 have a single sDVO i2c bus - which is different */ +#define MAX_OUTPUTS 6 + +#define INTEL_I2C_BUS_DVO 1 +#define INTEL_I2C_BUS_SDVO 2 + +/* these are outputs from the chip - integrated only + external chips are via DVO or SDVO output */ +#define INTEL_OUTPUT_UNUSED 0 +#define INTEL_OUTPUT_ANALOG 1 +#define INTEL_OUTPUT_DVO 2 +#define INTEL_OUTPUT_SDVO 3 +#define INTEL_OUTPUT_LVDS 4 +#define INTEL_OUTPUT_TVOUT 5 + +#define INTEL_DVO_CHIP_NONE 0 +#define INTEL_DVO_CHIP_LVDS 1 +#define INTEL_DVO_CHIP_TMDS 2 +#define INTEL_DVO_CHIP_TVOUT 4 + +struct intel_i2c_chan { + drm_device_t *drm_dev; /* for getting at dev. private (mmio etc.) */ + u32 reg; /* GPIO reg */ + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; + u8 slave_addr; +}; + +struct intel_output { + int type; + struct intel_i2c_chan *i2c_bus; /* for control functions */ + struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ + bool load_detect_tmp; + void *dev_priv; +}; + +struct intel_crtc { + int pipe; + u8 lut_r[256], lut_g[256], lut_b[256]; +}; + +struct intel_i2c_chan *intel_i2c_create(drm_device_t *dev, const u32 reg, + const char *name); +void intel_i2c_destroy(struct intel_i2c_chan *chan); +int intel_ddc_get_modes(struct drm_output *output); +extern bool intel_ddc_probe(struct drm_output *output); + +extern void intel_crt_init(drm_device_t *dev); +extern void intel_sdvo_init(drm_device_t *dev, int output_device); +extern void intel_lvds_init(drm_device_t *dev); + +extern void intel_crtc_load_lut(struct drm_crtc *crtc); +extern void intel_output_prepare (struct drm_output *output); +extern void intel_output_commit (struct drm_output *output); +#endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c new file mode 100644 index 00000000..acae28a0 --- /dev/null +++ b/linux-core/intel_i2c.c @@ -0,0 +1,164 @@ +/* + * Copyright 2006 Dave Airlie + * Copyright © 2006 Intel Corporation + * Eric Anholt + * Jesse Barnes + */ + +#include +#include +#include +#include "drmP.h" +#include "drm.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* + * Intel GPIO access functions + */ + +#define I2C_RISEFALL_TIME 20 + +static int get_clock(void *data) +{ + struct intel_i2c_chan *chan = data; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 val; + + val = I915_READ(chan->reg); + return ((val & GPIO_CLOCK_VAL_IN) != 0); +} + +static int get_data(void *data) +{ + struct intel_i2c_chan *chan = data; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 val; + + val = I915_READ(chan->reg); + return ((val & GPIO_DATA_VAL_IN) != 0); +} + +static void set_clock(void *data, int state_high) +{ + struct intel_i2c_chan *chan = data; + drm_device_t *dev = chan->drm_dev; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 reserved = 0, clock_bits; + + /* On most chips, these bits must be preserved in software. */ + if (!IS_I830(dev) && !IS_845G(dev)) + reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | + GPIO_CLOCK_PULLUP_DISABLE); + + if (state_high) + clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; + else + clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | + GPIO_CLOCK_VAL_MASK; + I915_WRITE(chan->reg, reserved | clock_bits); + udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ +} + +static void set_data(void *data, int state_high) +{ + struct intel_i2c_chan *chan = data; + drm_device_t *dev = chan->drm_dev; + drm_i915_private_t *dev_priv = chan->drm_dev->dev_private; + u32 reserved = 0, data_bits; + + /* On most chips, these bits must be preserved in software. */ + if (!IS_I830(dev) && !IS_845G(dev)) + reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | + GPIO_CLOCK_PULLUP_DISABLE); + + if (state_high) + data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; + else + data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | + GPIO_DATA_VAL_MASK; + + I915_WRITE(chan->reg, reserved | data_bits); + udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ +} + +/** + * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg + * @dev: DRM device + * @output: driver specific output device + * @reg: GPIO reg to use + * @name: name for this bus + * + * Creates and registers a new i2c bus with the Linux i2c layer, for use + * in output probing and control (e.g. DDC or SDVO control functions). + * + * Possible values for @reg include: + * %GPIOA + * %GPIOB + * %GPIOC + * %GPIOD + * %GPIOE + * %GPIOF + * %GPIOG + * %GPIOH + * see PRM for details on how these different busses are used. + */ +struct intel_i2c_chan *intel_i2c_create(drm_device_t *dev, const u32 reg, + const char *name) +{ + struct intel_i2c_chan *chan; + + chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); + if (!chan) + goto out_free; + + chan->drm_dev = dev; + chan->reg = reg; + snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_HW_B_INTELFB; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &dev->pdev->dev; + chan->algo.setsda = set_data; + chan->algo.setscl = set_clock; + chan->algo.getsda = get_data; + chan->algo.getscl = get_clock; + chan->algo.udelay = 20; + chan->algo.timeout = usecs_to_jiffies(2200); + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + if(i2c_bit_add_bus(&chan->adapter)) + goto out_free; + + /* JJJ: raise SCL and SDA? */ + set_data(chan, 1); + set_clock(chan, 1); + udelay(20); + + return chan; + +out_free: + kfree(chan); + return NULL; +} + +/** + * intel_i2c_destroy - unregister and free i2c bus resources + * @output: channel to free + * + * Unregister the adapter from the i2c layer, then free the structure. + */ +void intel_i2c_destroy(struct intel_i2c_chan *chan) +{ + if (!chan) + return; + + i2c_del_adapter(&chan->adapter); + kfree(chan); +} + + + diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c new file mode 100644 index 00000000..c2ac5679 --- /dev/null +++ b/linux-core/intel_lvds.c @@ -0,0 +1,108 @@ +/* + * Copyright 2006 Dave Airlie + * Copyright © 2006 Intel Corporation + * Eric Anholt + * Jesse Barnes + */ + +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/** + * Sets the backlight level. + * + * \param level backlight level, from 0 to i830_lvds_get_max_backlight(). + */ +static void lvds_set_backlight(drm_device_t *dev, u32 level) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long blc_pwm_ctl; + + level &= BACKLIGHT_DUTY_CYCLE_MASK; + blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | + (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); +} + +/** + * Returns the maximum level of the backlight duty cycle field. + */ +static u32 lvds_get_max_backlight(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> + BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; +} + +int lvds_backlight(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + unsigned long dvoa_enabled, dvob_enabled, dvoc_enabled, lvds_enabled; + drm_i915_private_t *dev_priv = dev->dev_private; + + printk(KERN_ERR "max backlight value: %d\n", + lvds_get_max_backlight(dev)); + dvoa_enabled = I915_READ(DVOA); + dvob_enabled = I915_READ(DVOB); + dvoc_enabled = I915_READ(DVOC); + lvds_enabled = I915_READ(LVDS); + + printk(KERN_ERR "dvoa_enabled: 0x%08lx\n", dvoa_enabled); + printk(KERN_ERR "dvob_enabled: 0x%08lx\n", dvob_enabled); + printk(KERN_ERR "dvoc_enabled: 0x%08lx\n", dvoc_enabled); + printk(KERN_ERR "lvds_enabled: 0x%08lx\n", lvds_enabled); + printk(KERN_ERR "BLC_PWM_CTL: 0x%08x\n", I915_READ(BLC_PWM_CTL)); + + return 0; +} + +static const struct drm_output_funcs intel_lvds_output_funcs; + +/** + * intel_lvds_init - setup LVDS outputs on this device + * @dev: drm device + * + * Create the output, register the LVDS DDC bus, and try to figure out what + * modes we can display on the LVDS panel (if present). + */ +void intel_lvds_init(drm_device_t *dev) +{ + struct drm_output *output; + struct intel_output *intel_output; + int modes; + + output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS"); + if (!output) + return; + + intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); + if (!intel_output) { + drm_output_destroy(output); + return; + } + + intel_output->type = INTEL_OUTPUT_LVDS; + output->driver_private = intel_output; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlace_allowed = 0; + output->doublescan_allowed = 0; + + intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return; + } + + modes = intel_ddc_get_modes(output); + printk(KERN_ERR "LVDS: added %d modes from EDID.\n", modes); + intel_i2c_destroy(intel_output->ddc_bus); + drm_output_destroy(output); +} + diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c new file mode 100644 index 00000000..0e56147d --- /dev/null +++ b/linux-core/intel_modes.c @@ -0,0 +1,49 @@ +#include +#include +#include "drmP.h" +#include "intel_drv.h" + +/** + * intel_ddc_probe + * + */ +bool intel_ddc_probe(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + u8 out_buf[] = { 0x0, 0x0}; + u8 buf[2]; + int ret; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } + }; + + ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2); + if (ret == 2) + return true; + + return false; +} + +/** + * intel_ddc_get_modes - get modelist from monitor + * @output: DRM output device to use + * + * Fetch the EDID information from @output using the DDC bus. + */ +int intel_ddc_get_modes(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + + return drm_add_edid_modes(output, &intel_output->ddc_bus->adapter); +} diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c new file mode 100644 index 00000000..4094b788 --- /dev/null +++ b/linux-core/intel_sdvo.c @@ -0,0 +1,999 @@ +/* + * Copyright 2006 Dave Airlie + * Copyright © 2006 Intel Corporation + * Eric Anholt + * Jesse Barnes + */ + +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "intel_sdvo_regs.h" + +struct intel_sdvo_priv { + struct intel_i2c_chan *i2c_bus; + int slaveaddr; + int output_device; + + u16 active_outputs; + + struct intel_sdvo_caps caps; + int pixel_clock_min, pixel_clock_max; + + int save_sdvo_mult; + u16 save_active_outputs; + struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2; + struct intel_sdvo_dtd save_output_dtd[16]; + u32 save_SDVOX; +}; + +/** + * Writes the SDVOB or SDVOC with the given value, but always writes both + * SDVOB and SDVOC to work around apparent hardware issues (according to + * comments in the BIOS). + */ +static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) +{ + drm_device_t *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + u32 bval = val, cval = val; + int i; + + if (sdvo_priv->output_device == SDVOB) + cval = I915_READ(SDVOC); + else + bval = I915_READ(SDVOB); + + /* + * Write the registers twice for luck. Sometimes, + * writing them only once doesn't appear to 'stick'. + * The BIOS does this too. Yay, magic + */ + for (i = 0; i < 2; i++) + { + I915_WRITE(SDVOB, bval); + I915_READ(SDVOB); + I915_WRITE(SDVOC, cval); + I915_READ(SDVOC); + } +} + +static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr, + u8 *ch) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + u8 out_buf[2]; + u8 buf[2]; + int ret; + + struct i2c_msg msgs[] = { + { + .addr = sdvo_priv->i2c_bus->slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = sdvo_priv->i2c_bus->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = 0; + + if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2) + { +// DRM_DEBUG("got back from addr %02X = %02x\n", out_buf[0], buf[0]); + *ch = buf[0]; + return true; + } + + DRM_DEBUG("i2c transfer returned %d\n", ret); + return false; +} + + +static bool intel_sdvo_read_byte_quiet(struct drm_output *output, int addr, + u8 *ch) +{ + return true; + +} + +static bool intel_sdvo_write_byte(struct drm_output *output, int addr, + u8 ch) +{ + struct intel_output *intel_output = output->driver_private; + u8 out_buf[2]; + struct i2c_msg msgs[] = { + { + .addr = intel_output->i2c_bus->slave_addr, + .flags = 0, + .len = 2, + .buf = out_buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = ch; + + if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1) + { + return true; + } + return false; +} + +#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} +/** Mapping of command numbers to names, for debug output */ +const static struct _sdvo_cmd_name { + u8 cmd; + char *name; +} sdvo_cmd_names[] = { + SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT), + SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), +}; + +#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC") +#define SDVO_PRIV(output) ((struct intel_sdvo_priv *) (output)->dev_priv) + +static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd, + void *args, int args_len) +{ + struct intel_output *intel_output = output->driver_private; + int i; + + for (i = 0; i < args_len; i++) { + intel_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]); + } + intel_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd); +} + +static const char *cmd_status_names[] = { + "Power on", + "Success", + "Not supported", + "Invalid arg", + "Pending", + "Target not specified", + "Scaling not supported" +}; + +static u8 intel_sdvo_read_response(struct drm_output *output, void *response, + int response_len) +{ + int i; + u8 status; + + /* Read the command response */ + for (i = 0; i < response_len; i++) { + intel_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i, + &((u8 *)response)[i]); + } + + /* read the return status */ + intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + + return status; + +} + +int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) +{ + if (mode->clock >= 100000) + return 1; + else if (mode->clock >= 50000) + return 2; + else + return 4; +} + +static void intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target) +{ + intel_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); +} + +static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0, bool target_1) +{ + struct intel_sdvo_set_target_input_args targets = {0}; + u8 status; + + if (target_0 && target_1) + return SDVO_CMD_STATUS_NOTSUPP; + + if (target_1) + targets.target_1 = 1; + + intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, + sizeof(targets)); + + status = intel_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +/** + * Return whether each input is trained. + * + * This function is making an assumption about the layout of the response, + * which should be checked against the docs. + */ +static bool intel_sdvo_get_trained_inputs(struct drm_output *output, bool *input_1, bool *input_2) +{ + struct intel_sdvo_get_trained_inputs_response response; + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); + status = intel_sdvo_read_response(output, &response, sizeof(response)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return false; + + *input_1 = response.input0_trained; + *input_2 = response.input1_trained; + return TRUE; +} + +static bool intel_sdvo_get_active_outputs(struct drm_output *output, + u16 *outputs) +{ + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); + status = intel_sdvo_read_response(output, outputs, sizeof(*outputs)); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static bool intel_sdvo_set_active_outputs(struct drm_output *output, + u16 outputs) +{ + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, + sizeof(outputs)); + status = intel_sdvo_read_response(output, NULL, 0); + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static bool intel_sdvo_set_encoder_power_state(struct drm_output *output, + int mode) +{ + u8 status, state = SDVO_ENCODER_STATE_ON; + + switch (mode) { + case DPMSModeOn: + state = SDVO_ENCODER_STATE_ON; + break; + case DPMSModeStandby: + state = SDVO_ENCODER_STATE_STANDBY; + break; + case DPMSModeSuspend: + state = SDVO_ENCODER_STATE_SUSPEND; + break; + case DPMSModeOff: + state = SDVO_ENCODER_STATE_OFF; + break; + } + + intel_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, + sizeof(state)); + status = intel_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static bool intel_sdvo_get_input_pixel_clock_range(struct drm_output *output, + int *clock_min, + int *clock_max) +{ + struct intel_sdvo_pixel_clock_range clocks; + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, + NULL, 0); + + status = intel_sdvo_read_response(output, &clocks, sizeof(clocks)); + + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + /* Convert the values from units of 10 kHz to kHz. */ + *clock_min = clocks.min * 10; + *clock_max = clocks.max * 10; + + return TRUE; +} + +static bool intel_sdvo_set_target_output(struct drm_output *output, + u16 outputs) +{ + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, + sizeof(outputs)); + + status = intel_sdvo_read_response(output, NULL, 0); + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static bool intel_sdvo_get_timing(struct drm_output *output, u8 cmd, + struct intel_sdvo_dtd *dtd) +{ + u8 status; + + intel_sdvo_write_cmd(output, cmd, NULL, 0); + status = intel_sdvo_read_response(output, &dtd->part1, + sizeof(dtd->part1)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + intel_sdvo_write_cmd(output, cmd + 1, NULL, 0); + status = intel_sdvo_read_response(output, &dtd->part2, + sizeof(dtd->part2)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static bool intel_sdvo_get_input_timing(struct drm_output *output, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_get_timing(output, + SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); +} + +static bool intel_sdvo_get_output_timing(struct drm_output *output, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_get_timing(output, + SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); +} + +static bool intel_sdvo_set_timing(struct drm_output *output, u8 cmd, + struct intel_sdvo_dtd *dtd) +{ + u8 status; + + intel_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1)); + status = intel_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + intel_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); + status = intel_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static bool intel_sdvo_set_input_timing(struct drm_output *output, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_set_timing(output, + SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); +} + +static bool intel_sdvo_set_output_timing(struct drm_output *output, + struct intel_sdvo_dtd *dtd) +{ + return intel_sdvo_set_timing(output, + SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); +} + +#if 0 +static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output, + struct intel_sdvo_dtd *dtd) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + NULL, 0); + + status = intel_sdvo_read_response(output, &dtd->part1, + sizeof(dtd->part1)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + NULL, 0); + status = intel_sdvo_read_response(output, &dtd->part2, + sizeof(dtd->part2)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} +#endif + +static int intel_sdvo_get_clock_rate_mult(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + u8 response, status; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); + status = intel_sdvo_read_response(output, &response, 1); + + if (status != SDVO_CMD_STATUS_SUCCESS) { + DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n"); + return SDVO_CLOCK_RATE_MULT_1X; + } else { + DRM_DEBUG("Current clock rate multiplier: %d\n", response); + } + + return response; +} + +static bool intel_sdvo_set_clock_rate_mult(struct drm_output *output, u8 val) +{ + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); + status = intel_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static bool intel_sdvo_mode_fixup(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO + * device will be told of the multiplier during mode_set. + */ + adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); + return TRUE; +} + +static void intel_sdvo_mode_set(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + drm_device_t *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_crtc *crtc = output->crtc; + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + u16 width, height; + u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; + u16 h_sync_offset, v_sync_offset; + u32 sdvox; + struct intel_sdvo_dtd output_dtd; + int sdvo_pixel_multiply; + + if (!mode) + return; + + width = mode->crtc_hdisplay; + height = mode->crtc_vdisplay; + + /* do some mode translations */ + h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; + h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; + + v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; + v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; + + h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; + v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; + + output_dtd.part1.clock = mode->clock / 10; + output_dtd.part1.h_active = width & 0xff; + output_dtd.part1.h_blank = h_blank_len & 0xff; + output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) | + ((h_blank_len >> 8) & 0xf); + output_dtd.part1.v_active = height & 0xff; + output_dtd.part1.v_blank = v_blank_len & 0xff; + output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) | + ((v_blank_len >> 8) & 0xf); + + output_dtd.part2.h_sync_off = h_sync_offset; + output_dtd.part2.h_sync_width = h_sync_len & 0xff; + output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | + (v_sync_len & 0xf); + output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | + ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | + ((v_sync_len & 0x30) >> 4); + + output_dtd.part2.dtd_flags = 0x18; + if (mode->flags & V_PHSYNC) + output_dtd.part2.dtd_flags |= 0x2; + if (mode->flags & V_PVSYNC) + output_dtd.part2.dtd_flags |= 0x4; + + output_dtd.part2.sdvo_flags = 0; + output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0; + output_dtd.part2.reserved = 0; + + /* Set the output timing to the screen */ + intel_sdvo_set_target_output(output, sdvo_priv->active_outputs); + intel_sdvo_set_output_timing(output, &output_dtd); + + /* Set the input timing to the screen. Assume always input 0. */ + intel_sdvo_set_target_input(output, TRUE, FALSE); + + /* We would like to use i830_sdvo_create_preferred_input_timing() to + * provide the device with a timing it can support, if it supports that + * feature. However, presumably we would need to adjust the CRTC to + * output the preferred timing, and we don't support that currently. + */ +#if 0 + success = intel_sdvo_create_preferred_input_timing(output, clock, + width, height); + if (success) { + struct intel_sdvo_dtd *input_dtd; + + intel_sdvo_get_preferred_input_timing(output, &input_dtd); + intel_sdvo_set_input_timing(output, &input_dtd); + } +#else + intel_sdvo_set_input_timing(output, &output_dtd); +#endif + + switch (intel_sdvo_get_pixel_multiplier(mode)) { + case 1: + intel_sdvo_set_clock_rate_mult(output, + SDVO_CLOCK_RATE_MULT_1X); + break; + case 2: + intel_sdvo_set_clock_rate_mult(output, + SDVO_CLOCK_RATE_MULT_2X); + break; + case 4: + intel_sdvo_set_clock_rate_mult(output, + SDVO_CLOCK_RATE_MULT_4X); + break; + } + + /* Set the SDVO control regs. */ + sdvox = I915_READ(sdvo_priv->output_device); + switch (sdvo_priv->output_device) { + case SDVOB: + sdvox &= SDVOB_PRESERVE_MASK; + break; + case SDVOC: + sdvox &= SDVOC_PRESERVE_MASK; + break; + } + sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; + if (intel_crtc->pipe == 1) + sdvox |= SDVO_PIPE_B_SELECT; + + sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); + if (IS_I965G(dev)) { + /* done in crtc_mode_set as the dpll_md reg must be written + early */ + } else if (IS_I945G(dev) || IS_I945GM(dev)) { + /* done in crtc_mode_set as it lives inside the + dpll register */ + } else { + sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; + } + + intel_sdvo_write_sdvox(output, sdvox); +} + +static void intel_sdvo_dpms(struct drm_output *output, int mode) +{ + drm_device_t *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + u32 temp; + + if (mode != DPMSModeOn) { + intel_sdvo_set_active_outputs(output, 0); + if (0) + intel_sdvo_set_encoder_power_state(output, mode); + + if (mode == DPMSModeOff) { + temp = I915_READ(sdvo_priv->output_device); + if ((temp & SDVO_ENABLE) != 0) { + intel_sdvo_write_sdvox(output, temp & ~SDVO_ENABLE); + } + } + } else { + bool input1, input2; + int i; + u8 status; + + temp = I915_READ(sdvo_priv->output_device); + if ((temp & SDVO_ENABLE) == 0) + intel_sdvo_write_sdvox(output, temp | SDVO_ENABLE); + for (i = 0; i < 2; i++) + intel_wait_for_vblank(dev); + + status = intel_sdvo_get_trained_inputs(output, &input1, + &input2); + + + /* Warn if the device reported failure to sync. */ + if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { + DRM_ERROR("First %s output reported failure to sync\n", + SDVO_NAME(sdvo_priv)); + } + + if (0) + intel_sdvo_set_encoder_power_state(output, mode); + intel_sdvo_set_active_outputs(output, sdvo_priv->active_outputs); + } + return; +} + +static void intel_sdvo_save(struct drm_output *output) +{ + drm_device_t *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + int o; + + sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(output); + intel_sdvo_get_active_outputs(output, &sdvo_priv->save_active_outputs); + + if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { + intel_sdvo_set_target_input(output, TRUE, FALSE); + intel_sdvo_get_input_timing(output, + &sdvo_priv->save_input_dtd_1); + } + + if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { + intel_sdvo_set_target_input(output, FALSE, TRUE); + intel_sdvo_get_input_timing(output, + &sdvo_priv->save_input_dtd_2); + } + + for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) + { + u16 this_output = (1 << o); + if (sdvo_priv->caps.output_flags & this_output) + { + intel_sdvo_set_target_output(output, this_output); + intel_sdvo_get_output_timing(output, + &sdvo_priv->save_output_dtd[o]); + } + } + + sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device); +} + +static void intel_sdvo_restore(struct drm_output *output) +{ + drm_device_t *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + int o; + int i; + bool input1, input2; + u8 status; + + intel_sdvo_set_active_outputs(output, 0); + + for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) + { + u16 this_output = (1 << o); + if (sdvo_priv->caps.output_flags & this_output) { + intel_sdvo_set_target_output(output, this_output); + intel_sdvo_set_output_timing(output, &sdvo_priv->save_output_dtd[o]); + } + } + + if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { + intel_sdvo_set_target_input(output, TRUE, FALSE); + intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_1); + } + + if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { + intel_sdvo_set_target_input(output, FALSE, TRUE); + intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_2); + } + + intel_sdvo_set_clock_rate_mult(output, sdvo_priv->save_sdvo_mult); + + I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX); + + if (sdvo_priv->save_SDVOX & SDVO_ENABLE) + { + for (i = 0; i < 2; i++) + intel_wait_for_vblank(dev); + status = intel_sdvo_get_trained_inputs(output, &input1, &input2); + if (status == SDVO_CMD_STATUS_SUCCESS && !input1) + DRM_DEBUG("First %s output reported failure to sync\n", + SDVO_NAME(sdvo_priv)); + } + + intel_sdvo_set_active_outputs(output, sdvo_priv->save_active_outputs); +} + +static int intel_sdvo_mode_valid(struct drm_output *output, + struct drm_display_mode *mode) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + + if (mode->flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + if (sdvo_priv->pixel_clock_min > mode->clock) + return MODE_CLOCK_HIGH; + + if (sdvo_priv->pixel_clock_max < mode->clock) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static bool intel_sdvo_get_capabilities(struct drm_output *output, struct intel_sdvo_caps *caps) +{ + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); + status = intel_sdvo_read_response(output, caps, sizeof(*caps)); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + + +static void intel_sdvo_dump_cmd(struct drm_output *output, int opcode) +{ + + +} + +static void intel_sdvo_dump_device(struct drm_output *output) +{ + +} + +void intel_sdvo_dump(void) +{ + +} + + +static enum drm_output_status intel_sdvo_detect(struct drm_output *output) +{ + u8 response[2]; + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); + status = intel_sdvo_read_response(output, &response, 2); + + if (status != SDVO_CMD_STATUS_SUCCESS) + return output_status_unknown; + + DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); + if ((response[0] != 0) || (response[1] != 0)) + return output_status_connected; + else + return output_status_disconnected; +} + +static int intel_sdvo_get_modes(struct drm_output *output) +{ + struct drm_display_mode *modes; + + /* set the bus switch and get the modes */ + intel_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2); + intel_ddc_get_modes(output); + + if (list_empty(&output->probed_modes)) + return 0; + return 1; +#if 0 + /* Mac mini hack. On this device, I get DDC through the analog, which + * load-detects as disconnected. I fail to DDC through the SDVO DDC, + * but it does load-detect as connected. So, just steal the DDC bits + * from analog when we fail at finding it the right way. + */ + /* TODO */ + return NULL; + + return NULL; +#endif +} + +static void intel_sdvo_destroy(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + + if (intel_output->i2c_bus) + intel_i2c_destroy(intel_output->i2c_bus); + + if (intel_output) { + kfree(intel_output); + output->driver_private = NULL; + } +} + +static const struct drm_output_funcs intel_sdvo_output_funcs = { + .dpms = intel_sdvo_dpms, + .save = intel_sdvo_save, + .restore = intel_sdvo_restore, + .mode_valid = intel_sdvo_mode_valid, + .mode_fixup = intel_sdvo_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_sdvo_mode_set, + .commit = intel_output_commit, + .detect = intel_sdvo_detect, + .get_modes = intel_sdvo_get_modes, + .cleanup = intel_sdvo_destroy +}; + +void intel_sdvo_init(drm_device_t *dev, int output_device) +{ + struct drm_output *output; + struct intel_output *intel_output; + struct intel_sdvo_priv *sdvo_priv; + struct intel_i2c_chan *i2cbus = NULL; + u8 ch[0x40]; + int i; + char name[DRM_OUTPUT_LEN]; + char *name_prefix; + char *name_suffix; + + + output = drm_output_create(dev, &intel_sdvo_output_funcs, NULL); + if (!output) + return; + + intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); + if (!intel_output) { + drm_output_destroy(output); + return; + } + + sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); + intel_output->type = INTEL_OUTPUT_SDVO; + output->driver_private = intel_output; + output->interlace_allowed = 0; + output->doublescan_allowed = 0; + + /* setup the DDC bus. */ + if (output_device == SDVOB) + i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); + else + i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); + + if (i2cbus == NULL) { + drm_output_destroy(output); + return; + } + + sdvo_priv->i2c_bus = i2cbus; + + if (output_device == SDVOB) { + name_suffix = "-1"; + sdvo_priv->i2c_bus->slave_addr = 0x38; + } else { + name_suffix = "-2"; + sdvo_priv->i2c_bus->slave_addr = 0x39; + } + + sdvo_priv->output_device = output_device; + intel_output->i2c_bus = i2cbus; + intel_output->dev_priv = sdvo_priv; + + + /* Read the regs to test if we can talk to the device */ + for (i = 0; i < 0x40; i++) { + if (!intel_sdvo_read_byte(output, i, &ch[i])) { + DRM_DEBUG("No SDVO device found on SDVO%c\n", + output_device == SDVOB ? 'B' : 'C'); + drm_output_destroy(output); + return; + } + } + + intel_sdvo_get_capabilities(output, &sdvo_priv->caps); + + memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); + + if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) + { + sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="TMDS"; + } + else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) + { + sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; + output->subpixel_order = SubPixelHorizontalRGB; + name_prefix="TMDS"; + } + else + { + unsigned char bytes[2]; + + memcpy (bytes, &sdvo_priv->caps.output_flags, 2); + DRM_DEBUG("%s: No active TMDS outputs (0x%02x%02x)\n", + SDVO_NAME(sdvo_priv), + bytes[0], bytes[1]); + } + strcpy (name, name_prefix); + strcat (name, name_suffix); + if (!drm_output_rename(output, name)) + { + drm_output_destroy(output); + return; + } + + + /* Set the input timing to the screen. Assume always input 0. */ + intel_sdvo_set_target_input(output, TRUE, FALSE); + + intel_sdvo_get_input_pixel_clock_range(output, + &sdvo_priv->pixel_clock_min, + &sdvo_priv->pixel_clock_max); + + + DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, " + "clock range %dMHz - %dMHz, " + "input 1: %c, input 2: %c, " + "output 1: %c, output 2: %c\n", + SDVO_NAME(sdvo_priv), + sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, + sdvo_priv->caps.device_rev_id, + sdvo_priv->pixel_clock_min / 1000, + sdvo_priv->pixel_clock_max / 1000, + (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0 ? 'Y' : 'N', + sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1 ? 'Y' : 'N'); + + intel_output->ddc_bus = i2cbus; +} diff --git a/linux-core/intel_sdvo_regs.h b/linux-core/intel_sdvo_regs.h new file mode 100644 index 00000000..b8cb1dc6 --- /dev/null +++ b/linux-core/intel_sdvo_regs.h @@ -0,0 +1,302 @@ +/* + * Copyright © 2006 Intel Corporation + */ + +/** + * @file SDVO command definitions and structures. + */ + +#define SDVO_OUTPUT_FIRST (0) +#define SDVO_OUTPUT_TMDS0 (1 << 0) +#define SDVO_OUTPUT_RGB0 (1 << 1) +#define SDVO_OUTPUT_CVBS0 (1 << 2) +#define SDVO_OUTPUT_SVID0 (1 << 3) +#define SDVO_OUTPUT_YPRPB0 (1 << 4) +#define SDVO_OUTPUT_SCART0 (1 << 5) +#define SDVO_OUTPUT_LVDS0 (1 << 6) +#define SDVO_OUTPUT_TMDS1 (1 << 8) +#define SDVO_OUTPUT_RGB1 (1 << 13) +#define SDVO_OUTPUT_LVDS1 (1 << 14) +#define SDVO_OUTPUT_LAST (14) + +struct intel_sdvo_caps { + u8 vendor_id; + u8 device_id; + u8 device_rev_id; + u8 sdvo_version_major; + u8 sdvo_version_minor; + unsigned int sdvo_inputs_mask:2; + unsigned int smooth_scaling:1; + unsigned int sharp_scaling:1; + unsigned int up_scaling:1; + unsigned int down_scaling:1; + unsigned int stall_support:1; + unsigned int pad:1; + u16 output_flags; +} __attribute__((packed)); + +/** This matches the EDID DTD structure, more or less */ +struct intel_sdvo_dtd { + struct { + u16 clock; /**< pixel clock, in 10kHz units */ + u8 h_active; /**< lower 8 bits (pixels) */ + u8 h_blank; /**< lower 8 bits (pixels) */ + u8 h_high; /**< upper 4 bits each h_active, h_blank */ + u8 v_active; /**< lower 8 bits (lines) */ + u8 v_blank; /**< lower 8 bits (lines) */ + u8 v_high; /**< upper 4 bits each v_active, v_blank */ + } part1; + + struct { + u8 h_sync_off; /**< lower 8 bits, from hblank start */ + u8 h_sync_width; /**< lower 8 bits (pixels) */ + /** lower 4 bits each vsync offset, vsync width */ + u8 v_sync_off_width; + /** + * 2 high bits of hsync offset, 2 high bits of hsync width, + * bits 4-5 of vsync offset, and 2 high bits of vsync width. + */ + u8 sync_off_width_high; + u8 dtd_flags; + u8 sdvo_flags; + /** bits 6-7 of vsync offset at bits 6-7 */ + u8 v_sync_off_high; + u8 reserved; + } part2; +} __attribute__((packed)); + +struct intel_sdvo_pixel_clock_range { + u16 min; /**< pixel clock, in 10kHz units */ + u16 max; /**< pixel clock, in 10kHz units */ +} __attribute__((packed)); + +struct intel_sdvo_preferred_input_timing_args { + u16 clock; + u16 width; + u16 height; +} __attribute__((packed)); + +/* I2C registers for SDVO */ +#define SDVO_I2C_ARG_0 0x07 +#define SDVO_I2C_ARG_1 0x06 +#define SDVO_I2C_ARG_2 0x05 +#define SDVO_I2C_ARG_3 0x04 +#define SDVO_I2C_ARG_4 0x03 +#define SDVO_I2C_ARG_5 0x02 +#define SDVO_I2C_ARG_6 0x01 +#define SDVO_I2C_ARG_7 0x00 +#define SDVO_I2C_OPCODE 0x08 +#define SDVO_I2C_CMD_STATUS 0x09 +#define SDVO_I2C_RETURN_0 0x0a +#define SDVO_I2C_RETURN_1 0x0b +#define SDVO_I2C_RETURN_2 0x0c +#define SDVO_I2C_RETURN_3 0x0d +#define SDVO_I2C_RETURN_4 0x0e +#define SDVO_I2C_RETURN_5 0x0f +#define SDVO_I2C_RETURN_6 0x10 +#define SDVO_I2C_RETURN_7 0x11 +#define SDVO_I2C_VENDOR_BEGIN 0x20 + +/* Status results */ +#define SDVO_CMD_STATUS_POWER_ON 0x0 +#define SDVO_CMD_STATUS_SUCCESS 0x1 +#define SDVO_CMD_STATUS_NOTSUPP 0x2 +#define SDVO_CMD_STATUS_INVALID_ARG 0x3 +#define SDVO_CMD_STATUS_PENDING 0x4 +#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED 0x5 +#define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6 + +/* SDVO commands, argument/result registers */ + +#define SDVO_CMD_RESET 0x01 + +/** Returns a struct intel_sdvo_caps */ +#define SDVO_CMD_GET_DEVICE_CAPS 0x02 + +#define SDVO_CMD_GET_FIRMWARE_REV 0x86 +# define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0 +# define SDVO_DEVICE_FIRMWARE_MAJOR SDVO_I2C_RETURN_1 +# define SDVO_DEVICE_FIRMWARE_PATCH SDVO_I2C_RETURN_2 + +/** + * Reports which inputs are trained (managed to sync). + * + * Devices must have trained within 2 vsyncs of a mode change. + */ +#define SDVO_CMD_GET_TRAINED_INPUTS 0x03 +struct intel_sdvo_get_trained_inputs_response { + unsigned int input0_trained:1; + unsigned int input1_trained:1; + unsigned int pad:6; +} __attribute__((packed)); + +/** Returns a struct intel_sdvo_output_flags of active outputs. */ +#define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 + +/** + * Sets the current set of active outputs. + * + * Takes a struct intel_sdvo_output_flags. Must be preceded by a SET_IN_OUT_MAP + * on multi-output devices. + */ +#define SDVO_CMD_SET_ACTIVE_OUTPUTS 0x05 + +/** + * Returns the current mapping of SDVO inputs to outputs on the device. + * + * Returns two struct intel_sdvo_output_flags structures. + */ +#define SDVO_CMD_GET_IN_OUT_MAP 0x06 + +/** + * Sets the current mapping of SDVO inputs to outputs on the device. + * + * Takes two struct i380_sdvo_output_flags structures. + */ +#define SDVO_CMD_SET_IN_OUT_MAP 0x07 + +/** + * Returns a struct intel_sdvo_output_flags of attached displays. + */ +#define SDVO_CMD_GET_ATTACHED_DISPLAYS 0x0b + +/** + * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging. + */ +#define SDVO_CMD_GET_HOT_PLUG_SUPPORT 0x0c + +/** + * Takes a struct intel_sdvo_output_flags. + */ +#define SDVO_CMD_SET_ACTIVE_HOT_PLUG 0x0d + +/** + * Returns a struct intel_sdvo_output_flags of displays with hot plug + * interrupts enabled. + */ +#define SDVO_CMD_GET_ACTIVE_HOT_PLUG 0x0e + +#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE 0x0f +struct intel_sdvo_get_interrupt_event_source_response { + u16 interrupt_status; + unsigned int ambient_light_interrupt:1; + unsigned int pad:7; +} __attribute__((packed)); + +/** + * Selects which input is affected by future input commands. + * + * Commands affected include SET_INPUT_TIMINGS_PART[12], + * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12], + * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS. + */ +#define SDVO_CMD_SET_TARGET_INPUT 0x10 +struct intel_sdvo_set_target_input_args { + unsigned int target_1:1; + unsigned int pad:7; +} __attribute__((packed)); + +/** + * Takes a struct intel_sdvo_output_flags of which outputs are targetted by + * future output commands. + * + * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], + * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE. + */ +#define SDVO_CMD_SET_TARGET_OUTPUT 0x11 + +#define SDVO_CMD_GET_INPUT_TIMINGS_PART1 0x12 +#define SDVO_CMD_GET_INPUT_TIMINGS_PART2 0x13 +#define SDVO_CMD_SET_INPUT_TIMINGS_PART1 0x14 +#define SDVO_CMD_SET_INPUT_TIMINGS_PART2 0x15 +#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1 0x16 +#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2 0x17 +#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1 0x18 +#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2 0x19 +/* Part 1 */ +# define SDVO_DTD_CLOCK_LOW SDVO_I2C_ARG_0 +# define SDVO_DTD_CLOCK_HIGH SDVO_I2C_ARG_1 +# define SDVO_DTD_H_ACTIVE SDVO_I2C_ARG_2 +# define SDVO_DTD_H_BLANK SDVO_I2C_ARG_3 +# define SDVO_DTD_H_HIGH SDVO_I2C_ARG_4 +# define SDVO_DTD_V_ACTIVE SDVO_I2C_ARG_5 +# define SDVO_DTD_V_BLANK SDVO_I2C_ARG_6 +# define SDVO_DTD_V_HIGH SDVO_I2C_ARG_7 +/* Part 2 */ +# define SDVO_DTD_HSYNC_OFF SDVO_I2C_ARG_0 +# define SDVO_DTD_HSYNC_WIDTH SDVO_I2C_ARG_1 +# define SDVO_DTD_VSYNC_OFF_WIDTH SDVO_I2C_ARG_2 +# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH SDVO_I2C_ARG_3 +# define SDVO_DTD_DTD_FLAGS SDVO_I2C_ARG_4 +# define SDVO_DTD_DTD_FLAG_INTERLACED (1 << 7) +# define SDVO_DTD_DTD_FLAG_STEREO_MASK (3 << 5) +# define SDVO_DTD_DTD_FLAG_INPUT_MASK (3 << 3) +# define SDVO_DTD_DTD_FLAG_SYNC_MASK (3 << 1) +# define SDVO_DTD_SDVO_FLAS SDVO_I2C_ARG_5 +# define SDVO_DTD_SDVO_FLAG_STALL (1 << 7) +# define SDVO_DTD_SDVO_FLAG_CENTERED (0 << 6) +# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT (1 << 6) +# define SDVO_DTD_SDVO_FLAG_SCALING_MASK (3 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_NONE (0 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP (1 << 4) +# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH (2 << 4) +# define SDVO_DTD_VSYNC_OFF_HIGH SDVO_I2C_ARG_6 + +/** + * Generates a DTD based on the given width, height, and flags. + * + * This will be supported by any device supporting scaling or interlaced + * modes. + */ +#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING 0x1a +# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW SDVO_I2C_ARG_0 +# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH SDVO_I2C_ARG_1 +# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW SDVO_I2C_ARG_2 +# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH SDVO_I2C_ARG_3 +# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW SDVO_I2C_ARG_4 +# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH SDVO_I2C_ARG_5 +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS SDVO_I2C_ARG_6 +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED (1 << 0) +# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED (1 << 1) + +#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1 0x1b +#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2 0x1c + +/** Returns a struct intel_sdvo_pixel_clock_range */ +#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE 0x1d +/** Returns a struct intel_sdvo_pixel_clock_range */ +#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e + +/** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */ +#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f + +/** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ +#define SDVO_CMD_GET_CLOCK_RATE_MULT 0x20 +/** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ +#define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21 +# define SDVO_CLOCK_RATE_MULT_1X (1 << 0) +# define SDVO_CLOCK_RATE_MULT_2X (1 << 1) +# define SDVO_CLOCK_RATE_MULT_4X (1 << 3) + +#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 + +#define SDVO_CMD_GET_TV_FORMAT 0x28 + +#define SDVO_CMD_SET_TV_FORMAT 0x29 + +#define SDVO_CMD_GET_SUPPORTED_POWER_STATES 0x2a +#define SDVO_CMD_GET_ENCODER_POWER_STATE 0x2b +#define SDVO_CMD_SET_ENCODER_POWER_STATE 0x2c +# define SDVO_ENCODER_STATE_ON (1 << 0) +# define SDVO_ENCODER_STATE_STANDBY (1 << 1) +# define SDVO_ENCODER_STATE_SUSPEND (1 << 2) +# define SDVO_ENCODER_STATE_OFF (1 << 3) + +#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT 0x93 + +#define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a +# define SDVO_CONTROL_BUS_PROM 0x0 +# define SDVO_CONTROL_BUS_DDC1 0x1 +# define SDVO_CONTROL_BUS_DDC2 0x2 +# define SDVO_CONTROL_BUS_DDC3 0x3 + diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index aed3eea1..a5f1473a 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -31,13 +31,6 @@ #include "i915_drm.h" #include "i915_drv.h" -#define IS_I965G(dev) (dev->pci_device == 0x2972 || \ - dev->pci_device == 0x2982 || \ - dev->pci_device == 0x2992 || \ - dev->pci_device == 0x29A2 || \ - dev->pci_device == 0x2A02) - - /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time * the head pointer changes, so that EBUSY only happens if the ring @@ -87,6 +80,7 @@ void i915_kernel_lost_context(drm_device_t * dev) static int i915_dma_cleanup(drm_device_t * dev) { + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. @@ -94,25 +88,16 @@ static int i915_dma_cleanup(drm_device_t * dev) if (dev->irq) drm_irq_uninstall(dev); - if (dev->dev_private) { - drm_i915_private_t *dev_priv = - (drm_i915_private_t *) dev->dev_private; - - if (dev_priv->ring.virtual_start) { - drm_core_ioremapfree(&dev_priv->ring.map, dev); - } - - if (dev_priv->status_page_dmah) { - drm_pci_free(dev, dev_priv->status_page_dmah); - /* Need to rewrite hardware status page */ - I915_WRITE(0x02080, 0x1ffff000); - } - - drm_free(dev->dev_private, sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); - - dev->dev_private = NULL; + if (dev_priv->status_page_dmah) { + drm_pci_free(dev, dev_priv->status_page_dmah); + dev_priv->status_page_dmah = NULL; + dev_priv->hw_status_page = NULL; + dev_priv->dma_status_page = 0; + /* Need to rewrite hardware status page */ + I915_WRITE(0x02080, 0x1ffff000); } + + dev_priv->sarea_priv = NULL; return 0; } @@ -121,8 +106,6 @@ static int i915_initialize(drm_device_t * dev, drm_i915_private_t * dev_priv, drm_i915_init_t * init) { - memset(dev_priv, 0, sizeof(drm_i915_private_t)); - DRM_GETSAREA(); if (!dev_priv->sarea) { DRM_ERROR("can not find sarea!\n"); @@ -131,14 +114,6 @@ static int i915_initialize(drm_device_t * dev, return DRM_ERR(EINVAL); } - dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); - if (!dev_priv->mmio_map) { - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - DRM_ERROR("can not find mmio map!\n"); - return DRM_ERR(EINVAL); - } - dev_priv->sarea_priv = (drm_i915_sarea_t *) ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); @@ -195,7 +170,11 @@ static int i915_initialize(drm_device_t * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); - dev->dev_private = (void *)dev_priv; + + /* this probably doesn't belong here - TODO */ + drm_framebuffer_set_object(dev, dev_priv->sarea_priv->front_handle); + drm_set_desired_modes(dev); + return 0; } @@ -237,7 +216,7 @@ static int i915_dma_resume(drm_device_t * dev) static int i915_dma_init(DRM_IOCTL_ARGS) { DRM_DEVICE; - drm_i915_private_t *dev_priv; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_init_t init; int retcode = 0; @@ -246,10 +225,6 @@ static int i915_dma_init(DRM_IOCTL_ARGS) switch (init.func) { case I915_INIT_DMA: - dev_priv = drm_alloc(sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); - if (dev_priv == NULL) - return DRM_ERR(ENOMEM); retcode = i915_initialize(dev, dev_priv, &init); break; case I915_CLEANUP_DMA: @@ -882,6 +857,18 @@ static int i915_mmio(DRM_IOCTL_ARGS) int i915_driver_load(drm_device_t *dev, unsigned long flags) { + drm_i915_private_t *dev_priv; + int ret; + unsigned long mmiobase, mmiolen; + + dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return DRM_ERR(ENOMEM); + + memset(dev_priv, 0, sizeof(drm_i915_private_t)); + dev->dev_private = (void *)dev_priv; +// dev_priv->flags = flags; + /* i915 has 4 more counters */ dev->counters += 4; dev->types[6] = _DRM_STAT_IRQ; @@ -889,25 +876,55 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) dev->types[8] = _DRM_STAT_SECONDARY; dev->types[9] = _DRM_STAT_DMA; + if (IS_I9XX(dev)) { + dev_priv->mmiobase = drm_get_resource_start(dev, 0); + dev_priv->mmiolen = drm_get_resource_len(dev, 0); + } else if (drm_get_resource_start(dev, 1)) { + dev_priv->mmiobase = drm_get_resource_start(dev, 1); + dev_priv->mmiolen = drm_get_resource_len(dev, 1); + } else { + DRM_ERROR("Unable to find MMIO registers\n"); + return -ENODEV; + } + + ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, + _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio_map); + if (ret != 0) { + DRM_ERROR("Cannot add mapping for MMIO registers\n"); + return ret; + } + + DRM_DEBUG("dev_priv->mmio map is %08X\n", dev_priv->mmio_map); + intel_modeset_init(dev); + return 0; +} + +int i915_driver_unload(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + intel_modeset_cleanup(dev); + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + + dev->dev_private = NULL; return 0; } void i915_driver_lastclose(drm_device_t * dev) { - if (dev->dev_private) { - drm_i915_private_t *dev_priv = dev->dev_private; - i915_do_cleanup_pageflip(dev); - i915_mem_takedown(&(dev_priv->agp_heap)); - } + drm_i915_private_t *dev_priv = dev->dev_private; + + i915_mem_takedown(&(dev_priv->agp_heap)); + i915_dma_cleanup(dev); + + dev_priv->mmio_map = NULL; } void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) { - if (dev->dev_private) { - drm_i915_private_t *dev_priv = dev->dev_private; - i915_mem_release(dev, filp, dev_priv->agp_heap); - } + drm_i915_private_t *dev_priv = dev->dev_private; + i915_mem_release(dev, filp, dev_priv->agp_heap); } drm_ioctl_desc_t i915_ioctls[] = { @@ -950,8 +967,22 @@ int i915_driver_device_is_agp(drm_device_t * dev) int i915_driver_firstopen(struct drm_device *dev) { -#ifdef I915_HAVE_BUFFER + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + DRM_DEBUG("\n"); drm_bo_driver_init(dev); -#endif + + if (!dev_priv->mmio_map) { + ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, + _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio_map); + if (ret != 0) { + DRM_ERROR("Cannot add mapping for MMIO registers\n"); + return ret; + } + } + + DRM_DEBUG("dev_priv->mmio map is %08X\n", dev_priv->mmio_map); + return 0; } + diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index e8a7be29..f37f5873 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -92,6 +92,9 @@ typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; + unsigned long mmiobase; + unsigned long mmiolen; + drm_i915_sarea_t *sarea_priv; drm_i915_ring_buffer_t ring; @@ -145,6 +148,8 @@ extern int i915_max_ioctl; /* i915_dma.c */ extern void i915_kernel_lost_context(drm_device_t * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); +extern int i915_driver_unload(drm_device_t *dev); +extern int i915_driver_firstopen(struct drm_device *dev); extern void i915_driver_lastclose(drm_device_t * dev); extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp); extern int i915_driver_device_is_agp(drm_device_t * dev); @@ -206,6 +211,12 @@ extern int i915_move(drm_buffer_object_t *bo, int evict, #endif + +/* modesetting */ +extern void intel_modeset_init(drm_device_t *dev); +extern void intel_modeset_cleanup(drm_device_t *dev); + + #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) #define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg)) @@ -273,6 +284,30 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) #define I915_VBLANK_CLEAR (1UL<<1) +#define GPIOA 0x5010 +#define GPIOB 0x5014 +#define GPIOC 0x5018 +#define GPIOD 0x501c +#define GPIOE 0x5020 +#define GPIOF 0x5024 +#define GPIOG 0x5028 +#define GPIOH 0x502c +# define GPIO_CLOCK_DIR_MASK (1 << 0) +# define GPIO_CLOCK_DIR_IN (0 << 1) +# define GPIO_CLOCK_DIR_OUT (1 << 1) +# define GPIO_CLOCK_VAL_MASK (1 << 2) +# define GPIO_CLOCK_VAL_OUT (1 << 3) +# define GPIO_CLOCK_VAL_IN (1 << 4) +# define GPIO_CLOCK_PULLUP_DISABLE (1 << 5) +# define GPIO_DATA_DIR_MASK (1 << 8) +# define GPIO_DATA_DIR_IN (0 << 9) +# define GPIO_DATA_DIR_OUT (1 << 9) +# define GPIO_DATA_VAL_MASK (1 << 10) +# define GPIO_DATA_VAL_OUT (1 << 11) +# define GPIO_DATA_VAL_IN (1 << 12) +# define GPIO_DATA_PULLUP_DISABLE (1 << 13) + + #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 #define SR01 1 @@ -281,6 +316,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define PPCR 0x61204 #define PPCR_ON (1<<0) +#define DVOA 0x61120 +#define DVOA_ON (1<<31) #define DVOB 0x61140 #define DVOB_ON (1<<31) #define DVOC 0x61160 @@ -363,4 +400,441 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) #define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) + +#define BLC_PWM_CTL 0x61254 +#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) +/** + * This is the most significant 15 bits of the number of backlight cycles in a + * complete cycle of the modulated backlight control. + * + * The actual value is this field multiplied by two. + */ +#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) +#define BLM_LEGACY_MODE (1 << 16) +/** + * This is the number of cycles out of the backlight modulation cycle for which + * the backlight is on. + * + * This field must be no greater than the number of cycles in the complete + * backlight modulation cycle. + */ +#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) +#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) + +#define I915_GCFGC 0xf0 +#define I915_LOW_FREQUENCY_ENABLE (1 << 7) +#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4) +#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4) +#define I915_DISPLAY_CLOCK_MASK (7 << 4) + +#define I855_HPLLCC 0xc0 +#define I855_CLOCK_CONTROL_MASK (3 << 0) +#define I855_CLOCK_133_200 (0 << 0) +#define I855_CLOCK_100_200 (1 << 0) +#define I855_CLOCK_100_133 (2 << 0) +#define I855_CLOCK_166_250 (3 << 0) + +/* I830 CRTC registers */ +#define HTOTAL_A 0x60000 +#define HBLANK_A 0x60004 +#define HSYNC_A 0x60008 +#define VTOTAL_A 0x6000c +#define VBLANK_A 0x60010 +#define VSYNC_A 0x60014 +#define PIPEASRC 0x6001c +#define BCLRPAT_A 0x60020 +#define VSYNCSHIFT_A 0x60028 + +#define HTOTAL_B 0x61000 +#define HBLANK_B 0x61004 +#define HSYNC_B 0x61008 +#define VTOTAL_B 0x6100c +#define VBLANK_B 0x61010 +#define VSYNC_B 0x61014 +#define PIPEBSRC 0x6101c +#define BCLRPAT_B 0x61020 +#define VSYNCSHIFT_B 0x61028 + +#define PP_STATUS 0x61200 +# define PP_ON (1 << 31) +/** + * Indicates that all dependencies of the panel are on: + * + * - PLL enabled + * - pipe enabled + * - LVDS/DVOB/DVOC on + */ +# define PP_READY (1 << 30) +# define PP_SEQUENCE_NONE (0 << 28) +# define PP_SEQUENCE_ON (1 << 28) +# define PP_SEQUENCE_OFF (2 << 28) +# define PP_SEQUENCE_MASK 0x30000000 +#define PP_CONTROL 0x61204 +# define POWER_TARGET_ON (1 << 0) + +#define LVDSPP_ON 0x61208 +#define LVDSPP_OFF 0x6120c +#define PP_CYCLE 0x61210 + +#define PFIT_CONTROL 0x61230 +# define PFIT_ENABLE (1 << 31) +# define VERT_INTERP_DISABLE (0 << 10) +# define VERT_INTERP_BILINEAR (1 << 10) +# define VERT_INTERP_MASK (3 << 10) +# define VERT_AUTO_SCALE (1 << 9) +# define HORIZ_INTERP_DISABLE (0 << 6) +# define HORIZ_INTERP_BILINEAR (1 << 6) +# define HORIZ_INTERP_MASK (3 << 6) +# define HORIZ_AUTO_SCALE (1 << 5) +# define PANEL_8TO6_DITHER_ENABLE (1 << 3) + +#define PFIT_PGM_RATIOS 0x61234 +# define PFIT_VERT_SCALE_MASK 0xfff00000 +# define PFIT_HORIZ_SCALE_MASK 0x0000fff0 + +#define PFIT_AUTO_RATIOS 0x61238 + + +#define DPLL_A 0x06014 +#define DPLL_B 0x06018 +# define DPLL_VCO_ENABLE (1 << 31) +# define DPLL_DVO_HIGH_SPEED (1 << 30) +# define DPLL_SYNCLOCK_ENABLE (1 << 29) +# define DPLL_VGA_MODE_DIS (1 << 28) +# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ +# define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +# define DPLL_MODE_MASK (3 << 26) +# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ +# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ +# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ +# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ +# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ +# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ +/** + * The i830 generation, in DAC/serial mode, defines p1 as two plus this + * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set. + */ +# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 +/** + * The i830 generation, in LVDS mode, defines P1 as the bit number set within + * this field (only one bit may be set). + */ +# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 +# define DPLL_FPA01_P1_POST_DIV_SHIFT 16 +# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */ +# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ +# define PLL_REF_INPUT_DREFCLK (0 << 13) +# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ +# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ +# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +# define PLL_REF_INPUT_MASK (3 << 13) +# define PLL_LOAD_PULSE_PHASE_SHIFT 9 +/* + * Parallel to Serial Load Pulse phase selection. + * Selects the phase for the 10X DPLL clock for the PCIe + * digital display port. The range is 4 to 13; 10 or more + * is just a flip delay. The default is 6 + */ +# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) +# define DISPLAY_RATE_SELECT_FPA1 (1 << 8) + +/** + * SDVO multiplier for 945G/GM. Not used on 965. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +# define SDVO_MULTIPLIER_MASK 0x000000ff +# define SDVO_MULTIPLIER_SHIFT_HIRES 4 +# define SDVO_MULTIPLIER_SHIFT_VGA 0 + +/** @defgroup DPLL_MD + * @{ + */ +/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_A_MD 0x0601c +/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */ +#define DPLL_B_MD 0x06020 +/** + * UDI pixel divider, controlling how many pixels are stuffed into a packet. + * + * Value is pixels minus 1. Must be set to 1 pixel for SDVO. + */ +# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +# define DPLL_MD_UDI_DIVIDER_SHIFT 24 +/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ +# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +/** + * SDVO/UDI pixel multiplier. + * + * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus + * clock rate is 10 times the DPLL clock. At low resolution/refresh rate + * modes, the bus rate would be below the limits, so SDVO allows for stuffing + * dummy bytes in the datastream at an increased clock rate, with both sides of + * the link knowing how many bytes are fill. + * + * So, for a mode with a dotclock of 65Mhz, we would want to double the clock + * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be + * set to 130Mhz, and the SDVO multiplier set to 2x in this register and + * through an SDVO command. + * + * This register field has values of multiplication factor minus 1, with + * a maximum multiplier of 5 for SDVO. + */ +# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. + * This best be set to the default value (3) or the CRT won't work. No, + * I don't entirely understand what this does... + */ +# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +/** @} */ + +#define DPLL_TEST 0x606c +# define DPLLB_TEST_SDVO_DIV_1 (0 << 22) +# define DPLLB_TEST_SDVO_DIV_2 (1 << 22) +# define DPLLB_TEST_SDVO_DIV_4 (2 << 22) +# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) +# define DPLLB_TEST_N_BYPASS (1 << 19) +# define DPLLB_TEST_M_BYPASS (1 << 18) +# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) +# define DPLLA_TEST_N_BYPASS (1 << 3) +# define DPLLA_TEST_M_BYPASS (1 << 2) +# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) + +#define ADPA 0x61100 +#define ADPA_DAC_ENABLE (1<<31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_MASK (1<<30) +#define ADPA_PIPE_A_SELECT 0 +#define ADPA_PIPE_B_SELECT (1<<30) +#define ADPA_USE_VGA_HVPOLARITY (1<<15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_VSYNC_CNTL_DISABLE (1<<11) +#define ADPA_VSYNC_CNTL_ENABLE 0 +#define ADPA_HSYNC_CNTL_DISABLE (1<<10) +#define ADPA_HSYNC_CNTL_ENABLE 0 +#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) +#define ADPA_VSYNC_ACTIVE_LOW 0 +#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) +#define ADPA_HSYNC_ACTIVE_LOW 0 + +#define FPA0 0x06040 +#define FPA1 0x06044 +#define FPB0 0x06048 +#define FPB1 0x0604c +# define FP_N_DIV_MASK 0x003f0000 +# define FP_N_DIV_SHIFT 16 +# define FP_M1_DIV_MASK 0x00003f00 +# define FP_M1_DIV_SHIFT 8 +# define FP_M2_DIV_MASK 0x0000003f +# define FP_M2_DIV_SHIFT 0 + + +#define PORT_HOTPLUG_EN 0x61110 +# define SDVOB_HOTPLUG_INT_EN (1 << 26) +# define SDVOC_HOTPLUG_INT_EN (1 << 25) +# define TV_HOTPLUG_INT_EN (1 << 18) +# define CRT_HOTPLUG_INT_EN (1 << 9) +# define CRT_HOTPLUG_FORCE_DETECT (1 << 3) + +#define PORT_HOTPLUG_STAT 0x61114 +# define CRT_HOTPLUG_INT_STATUS (1 << 11) +# define TV_HOTPLUG_INT_STATUS (1 << 10) +# define CRT_HOTPLUG_MONITOR_MASK (3 << 8) +# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) +# define CRT_HOTPLUG_MONITOR_MONO (2 << 8) +# define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +# define SDVOC_HOTPLUG_INT_STATUS (1 << 7) +# define SDVOB_HOTPLUG_INT_STATUS (1 << 6) + +#define SDVOB 0x61140 +#define SDVOC 0x61160 +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) +/** + * 915G/GM SDVO pixel multiplier. + * + * Programmed value is multiplier - 1, up to 5x. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_SHIFT 23 +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) +#define SDVO_BORDER_ENABLE (1 << 7) +#define SDVOB_PCIE_CONCURRENCY (1 << 3) +#define SDVO_DETECTED (1 << 2) +/* Bits to be preserved when writing */ +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14)) +#define SDVOC_PRESERVE_MASK (1 << 17) + +/** @defgroup LVDS + * @{ + */ +/** + * This register controls the LVDS output enable, pipe selection, and data + * format selection. + * + * All of the clock/data pairs are force powered down by power sequencing. + */ +#define LVDS 0x61180 +/** + * Enables the LVDS port. This bit must be set before DPLLs are enabled, as + * the DPLL semantics change when the LVDS is assigned to that pipe. + */ +# define LVDS_PORT_EN (1 << 31) +/** Selects pipe B for LVDS data. Must be set on pre-965. */ +# define LVDS_PIPEB_SELECT (1 << 30) + +/** + * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per + * pixel. + */ +# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) +# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) +# define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +/** + * Controls the A3 data pair, which contains the additional LSBs for 24 bit + * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be + * on. + */ +# define LVDS_A3_POWER_MASK (3 << 6) +# define LVDS_A3_POWER_DOWN (0 << 6) +# define LVDS_A3_POWER_UP (3 << 6) +/** + * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP + * is set. + */ +# define LVDS_CLKB_POWER_MASK (3 << 4) +# define LVDS_CLKB_POWER_DOWN (0 << 4) +# define LVDS_CLKB_POWER_UP (3 << 4) + +/** + * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 + * setting for whether we are in dual-channel mode. The B3 pair will + * additionally only be powered up when LVDS_A3_POWER_UP is set. + */ +# define LVDS_B0B3_POWER_MASK (3 << 2) +# define LVDS_B0B3_POWER_DOWN (0 << 2) +# define LVDS_B0B3_POWER_UP (3 << 2) + +#define PIPEACONF 0x70008 +#define PIPEACONF_ENABLE (1<<31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1<<30) +#define I965_PIPECONF_ACTIVE (1<<30) +#define PIPEACONF_SINGLE_WIDE 0 +#define PIPEACONF_PIPE_UNLOCKED 0 +#define PIPEACONF_PIPE_LOCKED (1<<25) +#define PIPEACONF_PALETTE 0 +#define PIPEACONF_GAMMA (1<<24) +#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) + +#define PIPEBCONF 0x71008 +#define PIPEBCONF_ENABLE (1<<31) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_DOUBLE_WIDE (1<<30) +#define PIPEBCONF_DISABLE 0 +#define PIPEBCONF_GAMMA (1<<24) +#define PIPEBCONF_PALETTE 0 + +#define PIPEBGCMAXRED 0x71010 +#define PIPEBGCMAXGREEN 0x71014 +#define PIPEBGCMAXBLUE 0x71018 +#define PIPEBSTAT 0x71024 +#define PIPEBFRAMEHIGH 0x71040 +#define PIPEBFRAMEPIXEL 0x71044 + +#define DSPACNTR 0x70180 +#define DSPBCNTR 0x71180 +#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_DISABLE 0 +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_15_16BPP (0x4<<26) +#define DISPPLANE_16BPP (0x5<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP (0x7<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_A 0 +#define DISPPLANE_SEL_PIPE_B (1<<24) +#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SRC_KEY_DISABLE 0 +#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_NO_LINE_DOUBLE 0 +#define DISPPLANE_STEREO_POLARITY_FIRST 0 +#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +/* plane B only */ +#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_DISABLE 0 +#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 +#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) + +#define DSPABASE 0x70184 +#define DSPASTRIDE 0x70188 + +#define DSPBBASE 0x71184 +#define DSPBADDR DSPBBASE +#define DSPBSTRIDE 0x71188 + +#define DSPAKEYVAL 0x70194 +#define DSPAKEYMASK 0x70198 + +#define DSPAPOS 0x7018C /* reserved */ +#define DSPASIZE 0x70190 +#define DSPBPOS 0x7118C +#define DSPBSIZE 0x71190 + +#define DSPASURF 0x7019C +#define DSPATILEOFF 0x701A4 + +#define DSPBSURF 0x7119C +#define DSPBTILEOFF 0x711A4 + +#define VGACNTRL 0x71400 +# define VGA_DISP_DISABLE (1 << 31) +# define VGA_2X_MODE (1 << 30) +# define VGA_PIPE_B_SELECT (1 << 29) + +/* + * Palette registers + */ +#define PALETTE_A 0x0a000 +#define PALETTE_B 0x0a800 + +#define IS_I830(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82830_CGC) +#define IS_845G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82845G_IG) +#define IS_I85X(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82855GM_IG) +#define IS_I855(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82855GM_IG) +#define IS_I865G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82865_IG) + +#define IS_I915G(pI810) (dev->pci_device == PCI_DEVICE_ID_INTEL_82915G_IG)/* || dev->pci_device == PCI_DEVICE_ID_INTELPCI_CHIP_E7221_G)*/ +#define IS_I915GM(pI810) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82915GM_IG) +#define IS_I945G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82945G_IG) +#define IS_I945GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82945GM_IG) + +#define IS_I965G(dev) ((dev)->pci_device == 0x2972 || \ + (dev)->pci_device == 0x2982 || \ + (dev)->pci_device == 0x2992 || \ + (dev)->pci_device == 0x29A2) + + +#define IS_I9XX(pI810) (IS_I915G(pI810) || IS_I915GM(pI810) || IS_I945G(pI810) || IS_I945GM(pI810) || IS_I965G(pI810)) + +#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810) || IS_I915GM(pI810) || IS_I945GM(pI810)) + #endif -- cgit v1.2.3 From 5bffbd6e275efffbb649c20c528a11412ccf99cd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Apr 2007 13:34:50 +1000 Subject: initial userspace interface to get modes --- libdrm/Makefile.am | 4 +- linux-core/drm_crtc.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++- linux-core/drm_crtc.h | 15 +++++- linux-core/drm_drv.c | 1 + linux-core/drm_edid.c | 21 +++++---- linux-core/drm_modes.c | 7 ++- shared-core/drm.h | 72 ++++++++++++++++++++++++++++ 7 files changed, 229 insertions(+), 15 deletions(-) diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index e7e07e47..24c32038 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -23,9 +23,9 @@ libdrm_ladir = $(libdir) libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined AM_CFLAGS = -I$(top_srcdir)/shared-core -libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c +libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c xf86drmMode.c libdrmincludedir = ${includedir} -libdrminclude_HEADERS = xf86drm.h xf86mm.h +libdrminclude_HEADERS = xf86drm.h xf86mm.h xf86drmMode.h EXTRA_DIST = ChangeLog TODO diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a52d82bc..1311fa63 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -154,7 +154,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, bool ret = false; struct drm_output *output; - adjusted_mode = drm_mode_duplicate(mode); + adjusted_mode = drm_mode_duplicate(dev, mode); crtc->enabled = drm_crtc_in_use(crtc); @@ -230,6 +230,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, } /* XXX free adjustedmode */ + drm_crtc_mode_destroy(dev, adjusted_mode); ret = TRUE; /* TODO */ // if (scrn->pScreen) @@ -401,12 +402,48 @@ bool drm_output_rename(struct drm_output *output, const char *name) } EXPORT_SYMBOL(drm_output_rename); +struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev) +{ + int ret; + struct drm_display_mode *nmode; + + nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); + if (!nmode) + return NULL; + +again: + if (idr_pre_get(&dev->crtc_config.mode_idr, GFP_KERNEL) == 0) { + DRM_ERROR("Ran out memory getting a mode number\n"); + kfree(nmode); + return NULL; + } + + spin_lock(&dev->crtc_config.config_lock); + + ret = idr_get_new(&dev->crtc_config.mode_idr, nmode, &nmode->mode_id); + if (ret == -EAGAIN) { + udelay(1); + spin_unlock(&dev->crtc_config.config_lock); + goto again; + } + spin_unlock(&dev->crtc_config.config_lock); + return nmode; +} + +void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) +{ + idr_remove(&dev->crtc_config.mode_idr, mode->mode_id); + + kfree(mode); +} + void drm_crtc_config_init(drm_device_t *dev) { spin_lock_init(&dev->crtc_config.config_lock); INIT_LIST_HEAD(&dev->crtc_config.fb_list); INIT_LIST_HEAD(&dev->crtc_config.crtc_list); INIT_LIST_HEAD(&dev->crtc_config.output_list); + idr_init(&dev->crtc_config.mode_idr); } EXPORT_SYMBOL(drm_crtc_config_init); @@ -441,7 +478,7 @@ void drm_framebuffer_set_object(drm_device_t *dev, unsigned long handle) ret = 0; out_err: mutex_unlock(&dev->struct_mutex); - return ret; + return; } EXPORT_SYMBOL(drm_framebuffer_set_object); @@ -538,3 +575,86 @@ void drm_crtc_config_cleanup(drm_device_t *dev) } EXPORT_SYMBOL(drm_crtc_config_cleanup); +void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in) +{ + + out->id = in->mode_id; + out->clock = in->clock; + out->hdisplay = in->hdisplay; + out->hsync_start = in->hsync_start; + out->hsync_end = in->hsync_end; + out->htotal = in->htotal; + out->hskew = in->hskew; + out->vdisplay = in->vdisplay; + out->vsync_start = in->vsync_start; + out->vsync_end = in->vsync_end; + out->vtotal = in->vtotal; + out->vscan = in->vscan; + + out->flags = in->flags; +} + + +/* IOCTL code from userspace */ +int drm_mode_getresources(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_card_res __user *argp = (void __user *)arg; + struct drm_mode_card_res card_res; + struct list_head *lh; + struct drm_output *output; + struct drm_mode_modeinfo u_mode; + struct drm_display_mode *mode; + int retcode = 0; + int mode_count= 0; + + memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); + list_for_each_entry(output, &dev->crtc_config.output_list, + head) + { + list_for_each(lh, &output->modes) + mode_count++; + } + + if (copy_from_user(&card_res, argp, sizeof(card_res))) + return -EFAULT; + + if (card_res.count_modes >= mode_count) { + int copied = 0; + list_for_each_entry(output, &dev->crtc_config.output_list, + head) { + list_for_each_entry(mode, &output->modes, head) { + drm_crtc_convert_to_umode(&u_mode, mode); + if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { + retcode = -EFAULT; + goto done; + } + } + } + } + + else { + list_for_each(lh, &dev->crtc_config.crtc_list) + card_res.count_crtcs++; + + list_for_each_entry(output, &dev->crtc_config.output_list, + head) + { + list_for_each(lh, &output->modes) + card_res.count_modes++; + card_res.count_outputs++; + } + } + +done: + DRM_DEBUG("Counted %d %d %d\n", card_res.count_crtcs, + card_res.count_outputs, + card_res.count_modes); + + if (copy_to_user(argp, &card_res, sizeof(card_res))) + return -EFAULT; + + return retcode; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 1be115d1..003946bc 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "drmP.h" #include "drm.h" @@ -86,6 +87,7 @@ struct drm_display_mode { /* Header */ struct list_head head; char name[DRM_DISPLAY_MODE_LEN]; + int mode_id; enum drm_mode_status status; int type; @@ -392,6 +394,7 @@ struct drm_crtc_config_funcs { */ struct drm_crtc_config { spinlock_t config_lock; + struct idr mode_idr; /* this is limited to one for now */ int num_fb; struct list_head fb_list; @@ -419,10 +422,20 @@ int drm_add_edid_modes(struct drm_output *output, struct i2c_adapter *adapter); void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode); void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode); -extern struct drm_display_mode *drm_mode_duplicate(struct drm_display_mode *mode); +extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, + struct drm_display_mode *mode); extern void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_crtc_config_init(struct drm_device *dev); extern void drm_crtc_config_cleanup(struct drm_device *dev); extern void drm_disable_unused_functions(struct drm_device *dev); + +extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); +extern void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); + +/* IOCTLs */ +extern int drm_mode_getresources(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + #endif /* __DRM_CRTC_H__ */ + diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index b95f796f..9877db13 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -123,6 +123,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { DRM_AUTH }, [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources, DRM_ROOT_ONLY}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 3c123751..bf1ea94c 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -212,7 +212,8 @@ bad: * * Punts for now. */ -struct drm_display_mode *drm_mode_std(struct std_timing *t) +struct drm_display_mode *drm_mode_std(struct drm_device *dev, + struct std_timing *t) { // struct fb_videomode mode; @@ -221,7 +222,7 @@ struct drm_display_mode *drm_mode_std(struct std_timing *t) struct drm_display_mode *mode; int hsize = t->hsize * 8 + 248, vsize; - mode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); + mode = drm_crtc_mode_create(dev); if (!mode) return NULL; @@ -239,7 +240,8 @@ struct drm_display_mode *drm_mode_std(struct std_timing *t) return mode; } -struct drm_display_mode *drm_mode_detailed(struct detailed_timing *timing, +struct drm_display_mode *drm_mode_detailed(drm_device_t *dev, + struct detailed_timing *timing, bool preferred) { struct drm_display_mode *mode; @@ -254,7 +256,7 @@ struct drm_display_mode *drm_mode_detailed(struct detailed_timing *timing, return NULL; } - mode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); + mode = drm_crtc_mode_create(dev); if (!mode) return NULL; @@ -357,6 +359,7 @@ static struct drm_display_mode established_modes[] = { */ static int add_established_modes(struct drm_output *output, struct edid *edid) { + struct drm_device *dev = output->dev; unsigned long est_bits = edid->established_timings.t1 | (edid->established_timings.t2 << 8) | ((edid->established_timings.mfg_rsvd & 0x80) << 9); @@ -365,7 +368,7 @@ static int add_established_modes(struct drm_output *output, struct edid *edid) for (i = 0; i <= EDID_EST_TIMINGS; i++) if (est_bits & (1<dev; for (i = 0; i < EDID_STD_TIMINGS; i++) { struct std_timing *t = &edid->standard_timings[i]; @@ -391,7 +395,7 @@ static int add_standard_modes(struct drm_output *output, struct edid *edid) continue; drm_mode_probed_add(output, - drm_mode_std(&edid->standard_timings[i])); + drm_mode_std(dev, &edid->standard_timings[i])); modes++; } @@ -409,6 +413,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) { int i, j, modes = 0; bool preferred = 0; + struct drm_device *dev = output->dev; for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { struct detailed_timing *timing = &edid->detailed_timings[i]; @@ -423,7 +428,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) if (i == 0 && edid->preferred_timing) preferred = 1; drm_mode_probed_add(output, - drm_mode_detailed(timing, preferred)); + drm_mode_detailed(dev, timing, preferred)); modes++; continue; } @@ -446,7 +451,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) struct std_timing *std; std = &data->data.timings[j]; - drm_mode_probed_add(output, drm_mode_std(std)); + drm_mode_probed_add(output, drm_mode_std(dev, std)); modes++; } break; diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 2347a669..940fc981 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -115,15 +115,18 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) EXPORT_SYMBOL(drm_mode_set_crtcinfo); -struct drm_display_mode *drm_mode_duplicate(struct drm_display_mode *mode) +struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *mode) { struct drm_display_mode *nmode; + int new_id; - nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); + nmode = drm_crtc_mode_create(dev); if (!nmode) return NULL; + new_id = nmode->mode_id; *nmode = *mode; + nmode->mode_id = new_id; INIT_LIST_HEAD(&nmode->head); return nmode; } diff --git a/shared-core/drm.h b/shared-core/drm.h index 3c59cd40..33194dcc 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -888,6 +888,74 @@ typedef union drm_mm_init_arg{ } rep; } drm_mm_init_arg_t; +/* + * Drm mode setting + */ + +struct drm_mode_modeinfo { + + unsigned int id; + + unsigned int clock; + unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; + unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; + + unsigned int flags; +// int count_flag; +// unsigned int __user *modeFlags; +}; + +struct drm_mode_card_res { + + unsigned int fb_id; + + int count_crtcs; + int count_outputs; + int count_modes; + struct drm_mode_modeinfo __user *modes; + +}; + +struct drm_mode_crtc { + unsigned int crtc_id; /**< Id */ + unsigned int buffer_id; /**< Id of framebuffer */ + + int x, y; /**< Position on the frameuffer */ + unsigned int width, height; + unsigned int mode; /**< Current mode used */ + + int count_outputs; + unsigned int outputs; /**< Outputs that are connected */ + + int count_possibles; + unsigned int possibles; /**< Outputs that can be connected */ + + unsigned int __user *set_outputs; /**< Outputs to be connected */ + + int gamma_size; + +}; + +struct drm_mode_get_output { + + unsigned int output; /**< Id */ + unsigned int crtc; /**< Id of crtc */ + + unsigned int connection; + unsigned int width, height; /**< HxW in millimeters */ + unsigned int subpixel; + + int count_crtcs; + unsigned int crtcs; /**< possible crtc to connect to */ + + int count_clones; + unsigned int clones; /**< list of clones */ + + int count_modes; + unsigned int __user *modes; /**< list of modes it supports */ + +}; + /** * \name Ioctls Definitions */ @@ -959,6 +1027,10 @@ typedef union drm_mm_init_arg{ #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t) +#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) +#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, drm_mode_crtc_t) +#define DRM_IOCTL_MODE_GETOUTPUT DRM_IOWR(0xA2, drm_mode_get_output_t) + /*@}*/ /** -- cgit v1.2.3 From 7bb112fecadc6fe42e5828b861600691071ccd91 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Apr 2007 17:06:42 +1000 Subject: checkpoint commit: added getresources, crtc and output This adds the user interfaces from Jakob and hooks them up for 3 ioctls GetResources, GetCrtc and GetOutput. I've made the ids for everything fbs, crtcs, outputs and modes go via idr as per krh's suggestion on irc as it make the code nice and consistent. --- libdrm/xf86drmMode.c | 407 ++++++++++++++++++++++++++++++++++++++++++++++++++ libdrm/xf86drmMode.h | 290 +++++++++++++++++++++++++++++++++++ linux-core/drm_crtc.c | 218 ++++++++++++++++++++++----- linux-core/drm_crtc.h | 12 +- linux-core/drm_drv.c | 4 +- shared-core/drm.h | 20 ++- 6 files changed, 902 insertions(+), 49 deletions(-) create mode 100644 libdrm/xf86drmMode.c create mode 100644 libdrm/xf86drmMode.h diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c new file mode 100644 index 00000000..b48ca838 --- /dev/null +++ b/libdrm/xf86drmMode.c @@ -0,0 +1,407 @@ +/* + * \file xf86drmMode.c + * Header for DRM modesetting interface. + * + * \author Jakob Bornecrantz + * + * \par Acknowledgements: + * Feb 2007, Dave Airlie + */ + +/* + * Copyright (c) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +/* + * TODO the types we are after are defined in diffrent headers on diffrent + * platforms find which headers to include to get uint32_t + */ +#include + +#include "xf86drmMode.h" +#include "xf86drm.h" +#include + +/* + * Util functions + */ + +void* drmAllocCpy(void *array, int count, int entry_size) +{ + char *r; + int i; + + if (!count || !array || !entry_size) + return 0; + + if (!(r = drmMalloc(count*entry_size))) + return 0; + + for (i = 0; i < count; i++) + memcpy(r+(entry_size*i), array+(entry_size*i), entry_size); + + return r; +} + +/** + * Generate crtc and output ids. + * + * Will generate ids starting from 1 up to count if count is greater then 0. + */ +static uint32_t* drmAllocGenerate(int count) +{ + uint32_t *r; + int i; + + if(0 <= count) + return 0; + + if (!(r = drmMalloc(count*sizeof(*r)))) + return 0; + + for (i = 0; i < count; r[i] = ++i); + + return 0; +} + +/* + * A couple of free functions. + */ + +void drmModeFreeModeInfo(struct drm_mode_modeinfo *ptr) +{ + if (!ptr) + return; + + drmFree(ptr); +} + +void drmModeFreeResources(drmModeResPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->modes); + drmFree(ptr); + +} + +void drmModeFreeFrameBuffer(drmModeFrameBufferPtr ptr) +{ + if (!ptr) + return; + + /* we might add more frees later. */ + drmFree(ptr); +} + +void drmModeFreeCrtc(drmModeCrtcPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr); + +} + +void drmModeFreeOutput(drmModeOutputPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->modes); + drmFree(ptr); + +} + +/* + * ModeSetting functions. + */ + +drmModeResPtr drmModeGetResources(int fd) +{ + struct drm_mode_card_res res; + int i; + drmModeResPtr r = 0; + + res.count_crtcs = 0; + res.count_outputs = 0; + res.count_modes = 0; + res.modes = 0; + + if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) + return 0; + + if (res.count_crtcs) + res.crtc_id = drmMalloc(res.count_crtcs*sizeof(uint32_t)); + if (res.count_outputs) + res.output_id = drmMalloc(res.count_outputs*sizeof(uint32_t)); + if (res.count_modes) + res.modes = drmMalloc(res.count_modes*sizeof(*res.modes)); + + if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) + goto err_allocs; + + /* + * return + */ + + + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + + r->frameBufferId = res.fb_id; + r->count_crtcs = res.count_crtcs; + r->count_outputs = res.count_outputs; + r->count_modes = res.count_modes; + /* TODO we realy should test if these allocs fails. */ + r->crtcs = drmAllocCpy(res.crtc_id, res.count_crtcs, sizeof(uint32_t)); + r->outputs = drmAllocCpy(res.output_id, res.count_outputs, sizeof(uint32_t)); + r->modes = drmAllocCpy(res.modes, res.count_modes, sizeof(struct drm_mode_modeinfo)); + + drmFree(res.crtc_id); + drmFree(res.output_id); + drmFree(res.modes); + + return r; + +err_allocs: + drmFree(res.crtc_id); + drmFree(res.output_id); + drmFree(res.modes); + + return 0; +} + +#if 0 +int drmModeForceProbe(int fd, uint32_t outputId) +{ + /* TODO impl/keep? */ +} + +drmModeFrameBufferPtr drmModeGetFrameBuffer(int fd, uint32_t buf) +{ +// struct drm_mode_fb_cmd info; + drmModeFrameBufferPtr r; + + // if (ioctl(fd, DRM_IOCTL_MODE_GETFRAMEBUFFER, &info)) + return 0; + + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + + /* TODO change to new code + r->minWidth = info.minWidth; + r->maxWidth = info.maxWidth; + r->minHeight = info.minHeight; + r->maxHeight = info.maxHeight;*/ + + return r; +} + +uint32_t drmModeNewFrameBuffer(int fd, uint32_t width, uint32_t height, + uint8_t bpp, uint32_t pitch, drmBO *bo) +{ + drm_mode_fb_cmd_t f; + + f.handle = bo->handle; + f.width = width; + f.height = height; + f.pitch = pitch; + + // if (ioctl(fd, DRM_IOCTL_MODE_NEWFRAMEBUFFER, &f)) + return 0; + + return f.bufferId; +} + +int drmModeDesFrameBuffer(int fd, uint32_t bufferId) +{ + // return ioctl(fd, DRM_IOCTL_MODE_DESFRAMEBUFFER, bufferId); +} + +#endif +/* + * Crtc function. + */ + +drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) +{ + struct drm_mode_crtc crtc; + drmModeCrtcPtr r; + int i = 0; + + crtc.count_outputs = 0; + crtc.outputs = 0; + crtc.count_possibles = 0; + crtc.possibles = 0; + crtc.crtc_id = crtcId; + + if (ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc)) + return 0; + + /* + * return + */ + + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + + r->x = crtc.x; + r->y = crtc.y; + r->mode = crtc.mode; +// r->width = crtc.width; +// r->height = crtc.height; + r->bufferId = crtc.fb_id; + r->gamma_size = crtc.gamma_size; + r->count_outputs = crtc.count_outputs; + r->count_possibles = crtc.count_possibles; + /* TODO we realy should test if these alloc & cpy fails. */ + r->outputs = crtc.outputs; + r->possibles = crtc.possibles; + + return r; + +err_allocs: + + return 0; +} + +#if 0 +int drmModeSetCrtc( + int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t modeId, + uint32_t *outputs, int count + ) +{ + struct drm_mode_crtc crtc; + + crtc.count_outputs = 0; + crtc.outputs = 0; + crtc.count_possibles = 0; + crtc.possibles = 0; + + crtc.x = x; + crtc.y = y; + crtc.crtcId = crtcId; + crtc.bufferId = bufferId; + crtc.set_outputs = outputs; + crtc.count_outputs = count; + crtc.mode = modeId; + + // return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); +} + +drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtc, int *count) +{ + /* TODO impl */ +} + +int drmModeSetCrtcGamma(int fd, uint32_t crtcId, + drmModeGammaTriplePtr ptr, int count) +{ + /* TODO impl */ +} + +#endif +/* + * Output manipulation + */ +drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) +{ + struct drm_mode_get_output out; + drmModeOutputPtr r = 0; + + out.output = output_id; + out.count_crtcs = 0; + out.crtcs = 0; + out.count_clones = 0; + out.clones = 0; + out.count_modes = 0; + out.modes = 0; + + if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) + return 0; + + if (out.count_modes) + out.modes = drmMalloc(out.count_modes*sizeof(uint32_t)); + + if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) + goto err_allocs; + + if(!(r = drmMalloc(sizeof(*r)))) + return 0; + + r->connection = out.connection; + r->mmWidth = out.mm_width; + r->mmHeight = out.mm_height; + r->subpixel = out.subpixel; + r->count_crtcs = out.count_crtcs; + r->count_clones = out.count_clones; + r->count_modes = out.count_modes; + /* TODO we should test if these alloc & cpy fails. */ + r->crtcs = out.crtcs; + r->clones = out.clones; + r->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(uint32_t)); + + return r; + +err_allocs: + drmFree(out.modes); + + return 0; +} + +#if 0 +uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo) +{ + /* TODO impl */ +} + +int drmModeDesMode(int fd, uint32_t modeId) +{ + // return ioctl(fd, DRM_IOCTL_MODE_DESMODE, modeId); +} + +int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId) +{ + + drm_mode_outputmode_t res; + + res.outputId = outputId; + res.modeId = modeId; + + // return ioctl(fd, DRM_IOCTL_MODE_ADDMODE, &res); +} + +int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId) +{ + drm_mode_outputmode_t res; + + res.outputId = outputId; + res.modeId = modeId; + + // return ioctl(fd, DRM_IOCTL_MODE_DELMODE, &res); +} + +#endif + diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h new file mode 100644 index 00000000..c027a16d --- /dev/null +++ b/libdrm/xf86drmMode.h @@ -0,0 +1,290 @@ +/* + * \file xf86drmMode.h + * Header for DRM modesetting interface. + * + * \author Jakob Bornecrantz + * + * \par Acknowledgements: + * Feb 2007, Dave Airlie + */ + +/* + * Copyright (c) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#include +#include "xf86mm.h" + +/* + * This is the interface for modesetting for drm. + * + * In order to use this interface you must include either or another + * header defining uint32_t, int32_t and uint16_t. + * + * It aims to provide a randr compatible interface for modesettings in the + * kernel, the interface is also ment to be used by libraries like EGL. + * + * More information can be found in randrproto.txt which can be found here: + * http://gitweb.freedesktop.org/?p=xorg/proto/randrproto.git + * + * All framebuffer, crtc and output ids start at 1 while 0 is either an invalid + * parameter or used to indicate that the command should disconnect from the + * currently bound target, as with drmModeMapOutput. + * + * Currently only one framebuffer exist and has a id of 1, which is also the + * default framebuffer and should allways be avaible to the client, unless + * it is locked/used or any other limiting state is applied on it. + * + */ + +typedef struct _drmModeGammaTriple { + uint16_t r, g, b; +} drmModeGammaTriple, *drmModeGammaTriplePtr; + +typedef struct _drmModeRes { + + uint32_t frameBufferId; + + int count_crtcs; + uint32_t *crtcs; + + int count_outputs; + uint32_t *outputs; + + int count_modes; + struct drm_mode_modeinfo *modes; + +} drmModeRes, *drmModeResPtr; + +typedef struct _drmModeFrameBuffer { + + uint32_t minWidth, maxWidth; + uint32_t minHeight, maxHeight; + +} drmModeFrameBuffer, *drmModeFrameBufferPtr; + +typedef struct _drmModeCrtc { + + unsigned int bufferId; /**< Buffer currently connected to */ + + uint32_t x, y; /**< Position on the frameuffer */ + uint32_t width, height; + uint32_t mode; /**< Current mode used */ + + int count_outputs; + uint32_t outputs; /**< Outputs that are connected */ + + int count_possibles; + uint32_t possibles; /**< Outputs that can be connected */ + + int gamma_size; /**< Number of gamma stops */ + +} drmModeCrtc, *drmModeCrtcPtr; + +typedef enum { + DRM_MODE_CONNECTED = 1, + DRM_MODE_DISCONNECTED = 2, + DRM_MODE_UNKNOWNCONNECTION = 3 +} drmModeConnection; + +typedef enum { + DRM_MODE_SUBPIXEL_UNKNOWN = 1, + DRM_MODE_SUBPIXEL_HORIZONTAL_RGB = 2, + DRM_MODE_SUBPIXEL_HORIZONTAL_BGR = 3, + DRM_MODE_SUBPIXEL_VERTICAL_RGB = 4, + DRM_MODE_SUBPIXEL_VERTICAL_BGR = 5, + DRM_MODE_SUBPIXEL_NONE = 6 +} drmModeSubPixel; + +typedef struct _drmModeOutput { + + unsigned int crtc; /**< Crtc currently connected to */ + + drmModeConnection connection; + uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ + drmModeSubPixel subpixel; + + int count_crtcs; + uint32_t crtcs; /**< Possible crtc to connect to */ + + int count_clones; + uint32_t clones; /**< Mask of clones */ + + int count_modes; + uint32_t *modes; /**< List of modes ids */ + +} drmModeOutput, *drmModeOutputPtr; + +/* + * RRSetScreenConfig o + * RRGetScreenInfo o + * + * RRGetScreenSizeRange - see frameBuffer info + * RRSetScreenSize + * RRGetScreenResources + * + * RRGetOutputInfo + * + * RRListOutputProperties * + * RRQueryOutputProperty * + * RRConfigureOutputProperty * + * RRChangeOutputProperty * + * RRDeleteOutputProperty * + * RRGetOutputProperty * + * + * RRCreateMode + * RRDestroyMode + * RRAddOutputMode + * RRDeleteOutputMode + * + * RRGetCrtcInfo + * RRSetCrtcConfig + * + * RRGetCrtcGammaSize - see crtc info + * RRGetCrtcGamma + * RRSetCrtcGamma + * + * drmModeGetResources + * drmModeForceProbe + * + * drmModeGetFrameBufferInfo + * drmModeSetFrameBufferSize + * + * drmModeGetCrtcInfo + * drmModeSetCrtcConfig + * drmModeGetCrtcGamma + * drmModeSetCrtcGamma + * + * drmModeGetOutputInfo + * + * drmModeAddMode + * drmModeDestroyMode + * drmModeAddOutputMode + * drmModeDeleteOutputMode + */ + +extern void drmModeFreeModeInfo( struct drm_mode_modeinfo *ptr ); +extern void drmModeFreeResources( drmModeResPtr ptr ); +extern void drmModeFreeFrameBuffer( drmModeFrameBufferPtr ptr ); +extern void drmModeFreeCrtc( drmModeCrtcPtr ptr ); +extern void drmModeFreeOutput( drmModeOutputPtr ptr ); + +/** + * Retrives all of the resources associated with a card. + */ +extern drmModeResPtr drmModeGetResources(int fd); + +/** + * Forces a probe of the give output outputId, on 0 all will be probed. + */ +extern int drmModeForceProbe(int fd, uint32_t outputId); + + +/* + * FrameBuffer manipulation. + */ + +/** + * Retrive information about framebuffer bufferId + */ +extern drmModeFrameBufferPtr drmModeGetFramebuffer(int fd, + uint32_t bufferId); + +/** + * Creates a new framebuffer with an buffer object as its scanout buffer. + */ +extern uint32_t drmModeNewFrameBuffer(int fd, + uint32_t width, uint32_t height, + uint8_t bbp, uint32_t pitch, drmBO *bo); + +/** + * Destroies the given framebuffer. + */ +extern int drmModeDesFrameBuffer(int fd, uint32_t bufferId); + +/** + * Changes the scanout buffer to the given buffer object. + */ +extern int drmModeFlipFrameBuffer(int fd, uint32_t bufferId, drmBO *bo); + +/* + * Crtc function. + */ + +/** + * Retrive information about the ctrt crtcId + */ +extern drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId); + +/** + * Set the mode on a crtc crtcId with the given mode modeId. + */ +extern int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t modeId, + uint32_t *outputs, int count); + +/** + * Gets the gamma from a crtc + */ +extern drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtcId, + int *count); + +/** + * Sets the gamma on a crtc + */ +extern int drmModeSetCrtcGamma(int fd, uint32_t crtcId, + drmModeGammaTriplePtr ptr, int count); + + + +/* + * Output manipulation + */ + +/** + * Retrive information about the output outputId. + */ +extern drmModeOutputPtr drmModeGetOutput(int fd, + uint32_t outputId); + +/** + * Creates a new mode from the given mode info. + * Name must be unique. + */ +extern uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo); + +/** + * Destroys a mode created with CreateMode, must be unused. + */ +extern int drmModeDesMode(int fd, uint32_t modeId); + +/** + * Adds the given mode to an output. + */ +extern int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId); + +/** + * Deletes a mode Added with AddOutputMode from the output, + * must be unused, by the given mode. + */ +extern int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId); + diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1311fa63..2dbe6de1 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -3,6 +3,33 @@ #include "drm.h" #include "drm_crtc.h" +int drm_mode_idr_get(struct drm_device *dev, void *ptr) +{ + int new_id = 0; + int ret; +again: + if (idr_pre_get(&dev->crtc_config.crtc_idr, GFP_KERNEL) == 0) { + DRM_ERROR("Ran out memory getting a mode number\n"); + return 0; + } + + spin_lock(&dev->crtc_config.config_lock); + + ret = idr_get_new_above(&dev->crtc_config.crtc_idr, ptr, 1, &new_id); + if (ret == -EAGAIN) { + spin_unlock(&dev->crtc_config.config_lock); + goto again; + } + + spin_unlock(&dev->crtc_config.config_lock); + return new_id; +} + +void drm_mode_idr_put(struct drm_device *dev, int id) +{ + idr_remove(&dev->crtc_config.crtc_idr, id); +} + struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) { struct drm_framebuffer *fb; @@ -20,7 +47,8 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) return NULL; } - + + fb->id = drm_mode_idr_get(dev, fb); fb->dev = dev; spin_lock(&dev->crtc_config.config_lock); dev->crtc_config.num_fb++; @@ -35,6 +63,7 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) drm_device_t *dev = fb->dev; spin_lock(&dev->crtc_config.config_lock); + drm_mode_idr_put(dev, fb->id); list_del(&fb->head); dev->crtc_config.num_fb--; spin_unlock(&dev->crtc_config.config_lock); @@ -45,19 +74,21 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) struct drm_crtc *drm_crtc_create(drm_device_t *dev, const struct drm_crtc_funcs *funcs) { - struct drm_crtc *crtc = NULL; - crtc = kmalloc(sizeof(struct drm_crtc), GFP_KERNEL); + struct drm_crtc *crtc; + + crtc = kzalloc(sizeof(struct drm_crtc), GFP_KERNEL); if (!crtc) return NULL; crtc->dev = dev; crtc->funcs = funcs; - spin_lock(&dev->crtc_config.config_lock); + crtc->id = drm_mode_idr_get(dev, crtc); + DRM_DEBUG("crtc %p got id %d\n", crtc, crtc->id); + spin_lock(&dev->crtc_config.config_lock); list_add_tail(&crtc->head, &dev->crtc_config.crtc_list); dev->crtc_config.num_crtc++; - spin_unlock(&dev->crtc_config.config_lock); return crtc; @@ -71,7 +102,9 @@ void drm_crtc_destroy(struct drm_crtc *crtc) if (crtc->funcs->cleanup) (*crtc->funcs->cleanup)(crtc); + spin_lock(&dev->crtc_config.config_lock); + drm_mode_idr_put(dev, crtc->id); list_del(&crtc->head); dev->crtc_config.num_crtc--; spin_unlock(&dev->crtc_config.config_lock); @@ -257,6 +290,7 @@ bool drm_set_desired_modes(struct drm_device *dev) list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { output = NULL; + DRM_DEBUG("crtc is %d\n", crtc->id); list_for_each_entry(list_output, &dev->crtc_config.output_list, head) { if (list_output->crtc == crtc) { output = list_output; @@ -345,6 +379,7 @@ struct drm_output *drm_output_create(drm_device_t *dev, output->dev = dev; output->funcs = funcs; + output->id = drm_mode_idr_get(dev, output); if (name) strncpy(output->name, name, DRM_OUTPUT_LEN); output->name[DRM_OUTPUT_LEN - 1] = 0; @@ -382,6 +417,7 @@ void drm_output_destroy(struct drm_output *output) drm_mode_remove(output, mode); spin_lock(&dev->crtc_config.config_lock); + drm_mode_idr_put(dev, output->id); list_del(&output->head); spin_unlock(&dev->crtc_config.config_lock); kfree(output); @@ -411,28 +447,13 @@ struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev) if (!nmode) return NULL; -again: - if (idr_pre_get(&dev->crtc_config.mode_idr, GFP_KERNEL) == 0) { - DRM_ERROR("Ran out memory getting a mode number\n"); - kfree(nmode); - return NULL; - } - - spin_lock(&dev->crtc_config.config_lock); - - ret = idr_get_new(&dev->crtc_config.mode_idr, nmode, &nmode->mode_id); - if (ret == -EAGAIN) { - udelay(1); - spin_unlock(&dev->crtc_config.config_lock); - goto again; - } - spin_unlock(&dev->crtc_config.config_lock); + nmode->mode_id = drm_mode_idr_get(dev, nmode); return nmode; } void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) { - idr_remove(&dev->crtc_config.mode_idr, mode->mode_id); + drm_mode_idr_put(dev, mode->mode_id); kfree(mode); } @@ -443,7 +464,7 @@ void drm_crtc_config_init(drm_device_t *dev) INIT_LIST_HEAD(&dev->crtc_config.fb_list); INIT_LIST_HEAD(&dev->crtc_config.crtc_list); INIT_LIST_HEAD(&dev->crtc_config.output_list); - idr_init(&dev->crtc_config.mode_idr); + idr_init(&dev->crtc_config.crtc_idr); } EXPORT_SYMBOL(drm_crtc_config_init); @@ -502,6 +523,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { + DRM_DEBUG("crtc is %d\n", crtc->id); crtc->fb = fb; if (!vga_crtc) { vga_crtc = crtc; @@ -568,7 +590,6 @@ void drm_crtc_config_cleanup(drm_device_t *dev) drm_output_destroy(output); } - list_for_each_entry_safe(crtc, ct, &dev->crtc_config.crtc_list, head) { drm_crtc_destroy(crtc); } @@ -592,6 +613,8 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display out->vscan = in->vscan; out->flags = in->flags; + strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); + out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } @@ -605,15 +628,24 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, struct drm_mode_card_res card_res; struct list_head *lh; struct drm_output *output; + struct drm_crtc *crtc; struct drm_mode_modeinfo u_mode; struct drm_display_mode *mode; int retcode = 0; int mode_count= 0; + int output_count = 0; + int crtc_count = 0; + int copied = 0; memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); + + list_for_each(lh, &dev->crtc_config.crtc_list) + crtc_count++; + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + output_count++; list_for_each(lh, &output->modes) mode_count++; } @@ -621,8 +653,38 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, if (copy_from_user(&card_res, argp, sizeof(card_res))) return -EFAULT; + /* handle this in 3 parts */ + /* CRTCs */ + if (card_res.count_crtcs >= crtc_count) { + copied = 0; + list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head){ + DRM_DEBUG("CRTC ID is %d\n", crtc->id); + if (put_user(crtc->id, &card_res.crtc_id[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } + card_res.count_crtcs = crtc_count; + + + /* Outputs */ + if (card_res.count_outputs >= output_count) { + copied = 0; + list_for_each_entry(output, &dev->crtc_config.output_list, + head) { + DRM_DEBUG("OUTPUT ID is %d\n", output->id); + if (put_user(output->id, &card_res.output_id[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } + card_res.count_outputs = output_count; + + /* Modes */ if (card_res.count_modes >= mode_count) { - int copied = 0; + copied = 0; list_for_each_entry(output, &dev->crtc_config.output_list, head) { list_for_each_entry(mode, &output->modes, head) { @@ -634,19 +696,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, } } } - - else { - list_for_each(lh, &dev->crtc_config.crtc_list) - card_res.count_crtcs++; - - list_for_each_entry(output, &dev->crtc_config.output_list, - head) - { - list_for_each(lh, &output->modes) - card_res.count_modes++; - card_res.count_outputs++; - } - } + card_res.count_modes = mode_count; done: DRM_DEBUG("Counted %d %d %d\n", card_res.count_crtcs, @@ -658,3 +708,95 @@ done: return retcode; } + +int drm_mode_getcrtc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_crtc __user *argp = (void __user *)arg; + struct drm_mode_crtc crtc_resp; + struct drm_crtc *crtc; + struct drm_output *output; + int ocount; + int retcode = 0; + + if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp))) + return -EFAULT; + + crtc = idr_find(&dev->crtc_config.crtc_idr, crtc_resp.crtc_id); + if (!crtc || (crtc->id != crtc_resp.crtc_id)) + return -EINVAL; + crtc_resp.x = crtc->x; + crtc_resp.y = crtc->y; + crtc_resp.fb_id = 1; + + crtc_resp.outputs = 0; + if (crtc->enabled) { + + crtc_resp.mode = crtc->mode.mode_id; + ocount = 0; + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + if (output->crtc == crtc) + crtc_resp.outputs |= 1 << (ocount++); + } + } else { + crtc_resp.mode = 0; + } + + if (copy_to_user(argp, &crtc_resp, sizeof(crtc_resp))) + return -EFAULT; + + return retcode; +} + +int drm_mode_getoutput(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_get_output __user *argp = (void __user *)arg; + struct drm_mode_get_output out_resp; + struct drm_crtc *crtc; + struct drm_output *output; + struct drm_display_mode *mode; + int mode_count = 0; + int retcode = 0; + int copied = 0; + + if (copy_from_user(&out_resp, argp, sizeof(out_resp))) + return -EFAULT; + + output= idr_find(&dev->crtc_config.crtc_idr, out_resp.output); + if (!output || (output->id != out_resp.output)) + return -EINVAL; + + list_for_each_entry(mode, &output->modes, head) + mode_count++; + + out_resp.mm_width = output->mm_width; + out_resp.mm_height = output->mm_height; + out_resp.subpixel = output->subpixel_order; + out_resp.connection = output->status; + if (output->crtc) + out_resp.crtc = output->crtc->id; + else + out_resp.crtc = 0; + + if (out_resp.count_modes >= mode_count) { + copied = 0; + list_for_each_entry(mode, &output->modes, head) { + if (put_user(mode->mode_id, &out_resp.modes[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } + out_resp.count_modes = mode_count; + +done: + if (copy_to_user(argp, &out_resp, sizeof(out_resp))) + return -EFAULT; + + return retcode; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 003946bc..e608b462 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -74,8 +74,6 @@ enum drm_mode_status { #define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \ DRM_MODE_TYPE_CRTC_C) -#define DRM_DISPLAY_MODE_LEN 32 - #define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ .name = nm, .status = 0, .type = (t), .clock = (c), \ .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ @@ -173,6 +171,7 @@ enum subpixel_order { struct drm_framebuffer { struct drm_device *dev; struct list_head head; + int id; /* idr assigned */ unsigned int pitch; unsigned long offset; unsigned int width; @@ -259,6 +258,8 @@ struct drm_crtc { struct drm_device *dev; struct list_head head; + int id; /* idr assigned */ + /* framebuffer the CRTC is currently bound to */ struct drm_framebuffer *fb; @@ -350,6 +351,7 @@ struct drm_output { struct drm_device *dev; struct list_head head; struct drm_crtc *crtc; + int id; /* idr assigned */ unsigned long possible_crtcs; unsigned long possible_clones; bool interlace_allowed; @@ -394,7 +396,7 @@ struct drm_crtc_config_funcs { */ struct drm_crtc_config { spinlock_t config_lock; - struct idr mode_idr; + struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output, modes - just makes life easier */ /* this is limited to one for now */ int num_fb; struct list_head fb_list; @@ -437,5 +439,9 @@ extern void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mod extern int drm_mode_getresources(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int drm_mode_getcrtc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_getoutput(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 9877db13..7d436f8a 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -123,7 +123,9 @@ static drm_ioctl_desc_t drm_ioctls[] = { DRM_AUTH }, [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources, DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETCRTC)] = {drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETOUTPUT)] = {drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index 33194dcc..1af0be38 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -892,6 +892,8 @@ typedef union drm_mm_init_arg{ * Drm mode setting */ +#define DRM_DISPLAY_MODE_LEN 32 + struct drm_mode_modeinfo { unsigned int id; @@ -901,8 +903,8 @@ struct drm_mode_modeinfo { unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; unsigned int flags; -// int count_flag; -// unsigned int __user *modeFlags; + + char name[DRM_DISPLAY_MODE_LEN]; }; struct drm_mode_card_res { @@ -910,7 +912,11 @@ struct drm_mode_card_res { unsigned int fb_id; int count_crtcs; + unsigned int __user *crtc_id; + int count_outputs; + unsigned int __user *output_id; + int count_modes; struct drm_mode_modeinfo __user *modes; @@ -918,10 +924,10 @@ struct drm_mode_card_res { struct drm_mode_crtc { unsigned int crtc_id; /**< Id */ - unsigned int buffer_id; /**< Id of framebuffer */ + unsigned int fb_id; /**< Id of framebuffer */ int x, y; /**< Position on the frameuffer */ - unsigned int width, height; + unsigned int mode; /**< Current mode used */ int count_outputs; @@ -942,7 +948,7 @@ struct drm_mode_get_output { unsigned int crtc; /**< Id of crtc */ unsigned int connection; - unsigned int width, height; /**< HxW in millimeters */ + unsigned int mm_width, mm_height; /**< HxW in millimeters */ unsigned int subpixel; int count_crtcs; @@ -1028,8 +1034,8 @@ struct drm_mode_get_output { #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t) #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) -#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, drm_mode_crtc_t) -#define DRM_IOCTL_MODE_GETOUTPUT DRM_IOWR(0xA2, drm_mode_get_output_t) +#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_GETOUTPUT DRM_IOWR(0xA2, struct drm_mode_get_output) /*@}*/ -- cgit v1.2.3 From b4094864f188a1346cc3b51bcb457beeacefbf82 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Apr 2007 18:01:02 +1000 Subject: checkpoint commit: implement SetCrtc so modes can in theory be set from user This hooks up the userspace mode set it "seems" to work. --- libdrm/xf86drmMode.c | 9 ++-- linux-core/drm_crtc.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 4 +- linux-core/drm_drv.c | 1 + shared-core/drm.h | 2 +- 5 files changed, 133 insertions(+), 11 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index b48ca838..c4403b1c 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -286,7 +286,7 @@ err_allocs: return 0; } -#if 0 + int drmModeSetCrtc( int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t modeId, @@ -302,15 +302,16 @@ int drmModeSetCrtc( crtc.x = x; crtc.y = y; - crtc.crtcId = crtcId; - crtc.bufferId = bufferId; + crtc.crtc_id = crtcId; + crtc.fb_id = bufferId; crtc.set_outputs = outputs; crtc.count_outputs = count; crtc.mode = modeId; - // return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); + return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); } +#if 0 drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtc, int *count) { /* TODO impl */ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 2dbe6de1..8e03dd5f 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -302,10 +302,10 @@ bool drm_set_desired_modes(struct drm_device *dev) continue; memset(&crtc->mode, 0, sizeof(crtc->mode)); - if (!crtc->desired_mode.crtc_hdisplay) { + if (!crtc->desired_mode->crtc_hdisplay) { } - if (!drm_crtc_set_mode(crtc, &crtc->desired_mode, + if (!drm_crtc_set_mode(crtc, crtc->desired_mode, crtc->desired_x, crtc->desired_y)) return false; } @@ -556,7 +556,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) break; DRM_DEBUG("Setting desired mode for output %s\n", output->name); drm_mode_debug_printmodeline(dev, des_mode); - output->crtc->desired_mode = *des_mode; + output->crtc->desired_mode = des_mode; output->initial_x = 0; output->initial_y = 0; use_output = output; @@ -568,7 +568,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) break; DRM_DEBUG("Setting desired mode for output %s\n", output->name); drm_mode_debug_printmodeline(dev, des_mode); - output->crtc->desired_mode = *des_mode; + output->crtc->desired_mode = des_mode; #endif output->initial_x = 0; output->initial_y = 0; @@ -596,6 +596,68 @@ void drm_crtc_config_cleanup(drm_device_t *dev) } EXPORT_SYMBOL(drm_crtc_config_cleanup); +int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set) +{ + drm_device_t *dev = crtc->dev; + struct drm_crtc **save_crtcs, *new_crtc; + bool save_enabled = crtc->enabled; + bool changed; + struct drm_output *output; + int count = 0, ro; + + save_crtcs = kzalloc(dev->crtc_config.num_crtc * sizeof(struct drm_crtc *), GFP_KERNEL); + if (!save_crtcs) + return -ENOMEM; + + if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) + changed = true; + + if (crtc->mode.mode_id != new_mode->mode_id) + changed = true; + + list_for_each_entry(output, &dev->crtc_config.output_list, head) { + save_crtcs[count++] = output->crtc; + + if (output->crtc == crtc) + new_crtc = NULL; + else + new_crtc = output->crtc; + + for (ro = 0; ro < crtc_info->count_outputs; ro++) + { + if (output_set[ro] == output) + new_crtc = crtc; + } + if (new_crtc != output->crtc) { + changed = true; + output->crtc = new_crtc; + } + } + + if (changed) { + crtc->enabled = new_mode != NULL; + if (new_mode) { + DRM_DEBUG("attempting to set mode from userspace\n"); + drm_mode_debug_printmodeline(dev, new_mode); + if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x, + crtc_info->y)) { + crtc->enabled = save_enabled; + count = 0; + list_for_each_entry(output, &dev->crtc_config.output_list, head) + output->crtc = save_crtcs[count++]; + kfree(save_crtcs); + return -EINVAL; + } + crtc->desired_x = crtc_info->x; + crtc->desired_y = crtc_info->y; + crtc->desired_mode = new_mode; + } + drm_disable_unused_functions(dev); + } + kfree(save_crtcs); + return 0; +} + void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in) { @@ -757,7 +819,6 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, drm_device_t *dev = priv->head->dev; struct drm_mode_get_output __user *argp = (void __user *)arg; struct drm_mode_get_output out_resp; - struct drm_crtc *crtc; struct drm_output *output; struct drm_display_mode *mode; int mode_count = 0; @@ -800,3 +861,60 @@ done: return retcode; } + + +int drm_mode_setcrtc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_crtc __user *argp = (void __user *)arg; + struct drm_mode_crtc crtc_req; + struct drm_crtc *crtc; + struct drm_output **output_set = NULL, *output; + struct drm_display_mode *mode; + int retcode = 0; + int i; + + if (copy_from_user(&crtc_req, argp, sizeof(crtc_req))) + return -EFAULT; + + crtc = idr_find(&dev->crtc_config.crtc_idr, crtc_req.crtc_id); + if (!crtc || (crtc->id != crtc_req.crtc_id)) + return -EINVAL; + + if (crtc_req.mode) { + mode = idr_find(&dev->crtc_config.crtc_idr, crtc_req.mode); + if (!mode || (mode->mode_id != crtc_req.mode)) + return -EINVAL; + } else + mode = NULL; + + if (crtc_req.count_outputs == 0 && mode) + return -EINVAL; + + if (crtc_req.count_outputs > 0 && !mode) + return -EINVAL; + + if (crtc_req.count_outputs > 0) { + u32 out_id; + output_set = kmalloc(crtc_req.count_outputs * sizeof(struct drm_output *), GFP_KERNEL); + if (!output_set) + return -ENOMEM; + + for (i = 0; i < crtc_req.count_outputs; i++) + { + if (get_user(out_id, &crtc_req.set_outputs[i])) + return -EFAULT; + + output = idr_find(&dev->crtc_config.crtc_idr, out_id); + if (!output || (out_id != output->id)) + return -EINVAL; + + output_set[i] = output; + } + } + + retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set); + return retcode; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index e608b462..a2c552e6 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -272,7 +272,7 @@ struct drm_crtc { struct drm_display_mode mode; int x, y; - struct drm_display_mode desired_mode; + struct drm_display_mode *desired_mode; int desired_x, desired_y; const struct drm_crtc_funcs *funcs; void *driver_private; @@ -443,5 +443,7 @@ extern int drm_mode_getcrtc(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_mode_getoutput(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int drm_mode_setcrtc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 7d436f8a..c8ee054f 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -126,6 +126,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETRESOURCES)] = {drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETCRTC)] = {drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETOUTPUT)] = {drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_SETCRTC)] = {drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index 1af0be38..49bc41bc 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1036,7 +1036,7 @@ struct drm_mode_get_output { #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) #define DRM_IOCTL_MODE_GETOUTPUT DRM_IOWR(0xA2, struct drm_mode_get_output) - +#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc) /*@}*/ /** -- cgit v1.2.3 From 652bbb77f6c9efb7e0a67cc868dfda42b00fc5fb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Apr 2007 20:20:33 +1000 Subject: add back compat for bool --- linux-core/drm_compat.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index bc5fadc5..bada1fdf 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -60,6 +60,13 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) #undef DRM_IRQ_ARGS #define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs + +typedef _Bool bool; +enum { + false = 0, + true = 1 +}; + #endif #ifndef list_for_each_safe -- cgit v1.2.3 From 6f3534a13abb0c8afb157511d0871dbc35bc403d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 5 Apr 2007 09:21:31 -0700 Subject: Add copyrights before I forget --- linux-core/drm_edid.c | 13 +++++++++---- linux-core/intel_crt.c | 5 +++++ linux-core/intel_display.c | 4 ++++ linux-core/intel_drv.h | 5 +++++ linux-core/intel_i2c.c | 4 ++-- linux-core/intel_lvds.c | 4 ++-- linux-core/intel_modes.c | 6 ++++++ 7 files changed, 33 insertions(+), 8 deletions(-) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 3c123751..7e254eee 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2007 Intel Corporation + * Jesse Barnes + */ + #include #include #include "drmP.h" @@ -73,7 +78,7 @@ struct detailed_data_monitor_range { u16 sec_gtf_toggle; /* A000=use above, 20=use below */ u8 hfreq_start_khz; /* need to multiply by 2 */ u8 c; /* need to divide by 2 */ - u16 m; + u16 m; /* FIXME: byte order */ u8 k; u8 j; /* need to divide by 2 */ } __attribute__((packed)); @@ -126,9 +131,9 @@ struct detailed_timing { struct edid { u8 header[8]; /* Vendor & product info */ - u16 mfg_id; - u16 prod_code; - u32 serial; + u16 mfg_id; /* FIXME: byte order */ + u16 prod_code; /* FIXME: byte order */ + u32 serial; /* FIXME: byte order */ u8 mfg_week; u8 mfg_year; /* EDID version */ diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 5ff9f791..a251d986 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2006-2007 Intel Corporation + * Eric Anholt + */ + #include #include "drmP.h" #include "drm.h" diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 495f4704..67d7c7d5 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1,3 +1,7 @@ +/* + * Copyright (c) 2006-2007 Intel Corporation + * Eric Anholt + */ #include #include "drmP.h" #include "drm.h" diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 5b8bef69..7b02d35f 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2006 Dave Airlie + * Copyright (c) 2007 Intel Corporation + * Jesse Barnes + */ #ifndef __INTEL_DRV_H__ #define __INTEL_DRV_H__ diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c index acae28a0..702e1376 100644 --- a/linux-core/intel_i2c.c +++ b/linux-core/intel_i2c.c @@ -1,6 +1,6 @@ /* - * Copyright 2006 Dave Airlie - * Copyright © 2006 Intel Corporation + * Copyright (c) 2006 Dave Airlie + * Copyright (c) 2006-2007 Intel Corporation * Eric Anholt * Jesse Barnes */ diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index c2ac5679..a2ac13a0 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -1,6 +1,6 @@ /* - * Copyright 2006 Dave Airlie - * Copyright © 2006 Intel Corporation + * Copyright (c) 2006 Dave Airlie + * Copyright (c) 2006-2007 Intel Corporation * Eric Anholt * Jesse Barnes */ diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c index 0e56147d..601770e1 100644 --- a/linux-core/intel_modes.c +++ b/linux-core/intel_modes.c @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2007 Dave Airlie + * Copyright (c) 2007 Intel Corporation + * Jesse Barnes + */ + #include #include #include "drmP.h" -- cgit v1.2.3 From 1c9ba24c2f37ca78965f8aa57ece02ef5bdb9b06 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 5 Apr 2007 11:34:11 -0700 Subject: Add required permission notices for code copied from X.Org source. --- linux-core/drm_modes.c | 28 ++++++++++++++++++++++++++-- linux-core/intel_crt.c | 25 +++++++++++++++++++++++-- linux-core/intel_display.c | 26 ++++++++++++++++++++++++-- linux-core/intel_i2c.c | 27 +++++++++++++++++++++++++-- linux-core/intel_lvds.c | 27 +++++++++++++++++++++++++-- linux-core/intel_sdvo.c | 27 +++++++++++++++++++++++++-- linux-core/intel_sdvo_regs.h | 24 +++++++++++++++++++++++- 7 files changed, 171 insertions(+), 13 deletions(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 940fc981..eea2e754 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -1,7 +1,31 @@ +/* + * Copyright © 1997-2003 by The XFree86 Project, 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. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ /* * Copyright © 2007 Dave Airlie - * - * Based on code from X.org - Copyright (c) 1997-2003 by The XFree86 Project, Inc. */ #include diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index a251d986..55d987a6 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -1,6 +1,27 @@ /* - * Copyright (c) 2006-2007 Intel Corporation - * Eric Anholt + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt */ #include diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 67d7c7d5..58d66987 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1,7 +1,29 @@ /* - * Copyright (c) 2006-2007 Intel Corporation - * Eric Anholt + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt */ + #include #include "drmP.h" #include "drm.h" diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c index 702e1376..d4cf7eef 100644 --- a/linux-core/intel_i2c.c +++ b/linux-core/intel_i2c.c @@ -1,7 +1,30 @@ +/* + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + */ /* * Copyright (c) 2006 Dave Airlie - * Copyright (c) 2006-2007 Intel Corporation - * Eric Anholt * Jesse Barnes */ diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index a2ac13a0..a83f7d7a 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -1,7 +1,30 @@ +/* + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + */ /* * Copyright (c) 2006 Dave Airlie - * Copyright (c) 2006-2007 Intel Corporation - * Eric Anholt * Jesse Barnes */ diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 4094b788..0e870d15 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1,7 +1,30 @@ +/* + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + */ /* * Copyright 2006 Dave Airlie - * Copyright © 2006 Intel Corporation - * Eric Anholt * Jesse Barnes */ diff --git a/linux-core/intel_sdvo_regs.h b/linux-core/intel_sdvo_regs.h index b8cb1dc6..c8ab950b 100644 --- a/linux-core/intel_sdvo_regs.h +++ b/linux-core/intel_sdvo_regs.h @@ -1,5 +1,27 @@ /* - * Copyright © 2006 Intel Corporation + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt */ /** -- cgit v1.2.3 From a35ba455b27b72f1ee3e1136ca6659f672ada4fa Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 7 Apr 2007 19:22:39 -0700 Subject: make drmP.h include drm_crtc.h for CRTC related stuff. fixup drm_crtc.c so it matches VGA and other outputs properly. make drm_crtc.c less verbose. add function declarations in drm_crtc.h for other files. --- linux-core/drmP.h | 1 + linux-core/drm_crtc.c | 37 +++++++++++++++++++++---------------- linux-core/drm_crtc.h | 29 ++++++++++++++++++++--------- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index db62ab83..74f52854 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -75,6 +75,7 @@ #include #include #include "drm.h" +#include "drm_crtc.h" #include #define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 8e03dd5f..fe27e386 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -340,8 +340,6 @@ void drm_disable_unused_functions(struct drm_device *dev) */ void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode) { - printk(KERN_ERR "adding DDC mode %s to output %s\n", mode->name, - output->name); spin_lock(&output->modes_lock); list_add(&mode->head, &output->probed_modes); spin_unlock(&output->modes_lock); @@ -440,7 +438,6 @@ EXPORT_SYMBOL(drm_output_rename); struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev) { - int ret; struct drm_display_mode *nmode; nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL); @@ -506,7 +503,8 @@ EXPORT_SYMBOL(drm_framebuffer_set_object); bool drm_initial_config(drm_device_t *dev, bool can_grow) { /* do a hardcoded initial configuration here */ - struct drm_crtc *crtc, *vga_crtc = NULL, *dvi_crtc = NULL; + struct drm_crtc *crtc, *vga_crtc = NULL, *dvi_crtc = NULL, + *lvds_crtc = NULL;; struct drm_framebuffer *fb; struct drm_output *output, *use_output = NULL; @@ -523,14 +521,18 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { - DRM_DEBUG("crtc is %d\n", crtc->id); crtc->fb = fb; if (!vga_crtc) { vga_crtc = crtc; crtc->enabled = 1; crtc->desired_x = 0; crtc->desired_y = 0; - } + } else if (!lvds_crtc) { + lvds_crtc = crtc; + crtc->enabled = 1; + crtc->desired_x = 0; + crtc->desired_y = 0; + } #if 0 else if (!dvi_crtc) { dvi_crtc = crtc; @@ -549,29 +551,32 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) list_for_each_entry(output, &dev->crtc_config.output_list, head) { struct drm_display_mode *des_mode; - if (strncmp(output->name, "VGA", 3)) { - output->crtc = vga_crtc; - /* just pull the first mode out of that hat */ - list_for_each_entry(des_mode, &output->modes, head) + /* Get the first preferred moded */ + list_for_each_entry(des_mode, &output->modes, head) { + if (des_mode->flags & DRM_MODE_TYPE_PREFERRED) break; - DRM_DEBUG("Setting desired mode for output %s\n", output->name); + } + if (!strncmp(output->name, "VGA", 3)) { + output->crtc = vga_crtc; drm_mode_debug_printmodeline(dev, des_mode); output->crtc->desired_mode = des_mode; output->initial_x = 0; output->initial_y = 0; use_output = output; - } else if (strncmp(output->name, "TMDS", 4)) { + } else if (!strncmp(output->name, "TMDS", 4)) { output->crtc = vga_crtc; #if 0 - /* just pull the first mode out of that hat */ - list_for_each_entry(des_mode, &output->modes, head) - break; - DRM_DEBUG("Setting desired mode for output %s\n", output->name); drm_mode_debug_printmodeline(dev, des_mode); output->crtc->desired_mode = des_mode; #endif output->initial_x = 0; output->initial_y = 0; + } else if (!strncmp(output->name, "LVDS", 3)) { + output->crtc = lvds_crtc; + drm_mode_debug_printmodeline(dev, des_mode); + output->crtc->desired_mode = des_mode; + output->initial_x = 0; + output->initial_y = 0; } else output->crtc = NULL; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index a2c552e6..21908f0c 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -10,8 +10,6 @@ #include #include #include -#include "drmP.h" -#include "drm.h" struct drm_device; @@ -79,7 +77,7 @@ enum drm_mode_status { .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ - .vscan = (vs), .flags = (f) + .vscan = (vs), .flags = (f), .vrefresh = 0 struct drm_display_mode { /* Header */ @@ -128,7 +126,7 @@ struct drm_display_mode { int private_flags; int vrefresh; - float hsync;//, vrefresh; + float hsync; }; /* Video mode flags */ @@ -417,13 +415,13 @@ struct drm_crtc_config { struct drm_output *drm_output_create(struct drm_device *dev, const struct drm_output_funcs *funcs, const char *name); -void drm_output_destroy(struct drm_output *output); -bool drm_output_rename(struct drm_output *output, const char *name); +extern void drm_output_destroy(struct drm_output *output); +extern bool drm_output_rename(struct drm_output *output, const char *name); -int drm_add_edid_modes(struct drm_output *output, +extern int drm_add_edid_modes(struct drm_output *output, struct i2c_adapter *adapter); -void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode); -void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode); +extern void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode); +extern void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode); extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_debug_printmodeline(struct drm_device *dev, @@ -445,5 +443,18 @@ extern int drm_mode_getoutput(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_mode_setcrtc(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern void drm_mode_list_concat(struct list_head *head, + struct list_head *new); +extern void drm_mode_validate_size(struct drm_device *dev, + struct list_head *mode_list, + int maxX, int maxY, int maxPitch); +extern void drm_mode_prune_invalid(struct drm_device *dev, + struct list_head *mode_list, bool verbose); +extern void drm_mode_sort(struct list_head *mode_list); +extern int drm_mode_vrefresh(struct drm_display_mode *mode); +extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, + int adjust_flags); +extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); + #endif /* __DRM_CRTC_H__ */ -- cgit v1.2.3 From 13d4ea90c09fa834eb6eecaa082780aace78dac7 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 7 Apr 2007 19:24:09 -0700 Subject: various cleanups to EDID code: - pull in FB DDC code (we'll have to rewrite it anyway it appears) - add comments - note a few FIXMEs - make it less quiet, and more informative when it actually does print --- linux-core/drm_edid.c | 240 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 175 insertions(+), 65 deletions(-) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 33018da6..fcd97d67 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -1,18 +1,15 @@ /* * Copyright (c) 2007 Intel Corporation * Jesse Barnes + * + * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from + * FB layer. */ - #include -#include +#include #include "drmP.h" -#include "intel_drv.h" - -/* - * DDC/EDID probing rippped off from FB layer - */ -#include "edid.h" +#define EDID_LENGTH 128 #define DDC_ADDR 0x50 #ifdef BIG_ENDIAN @@ -75,7 +72,7 @@ struct detailed_data_monitor_range { u8 min_hfreq_khz; u8 max_hfreq_khz; u8 pixel_clock_mhz; /* need to multiply by 10 */ - u16 sec_gtf_toggle; /* A000=use above, 20=use below */ + u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */ u8 hfreq_start_khz; /* need to multiply by 2 */ u8 c; /* need to divide by 2 */ u16 m; /* FIXME: byte order */ @@ -114,14 +111,14 @@ struct detailed_non_pixel { } __attribute__((packed)); #define EDID_DETAIL_STD_MODES 0xfa -#define EDID_DETAIL_CPDATA 0xfb -#define EDID_DETAIL_NAME 0xfc -#define EDID_DETAIL_RANGE 0xfd -#define EDID_DETAIL_STRING 0xfe -#define EDID_DETAIL_SERIAL 0xff +#define EDID_DETAIL_MONITOR_CPDATA 0xfb +#define EDID_DETAIL_MONITOR_NAME 0xfc +#define EDID_DETAIL_MONITOR_RANGE 0xfd +#define EDID_DETAIL_MONITOR_STRING 0xfe +#define EDID_DETAIL_MONITOR_SERIAL 0xff struct detailed_timing { - u16 pixel_clock; /* need to multiply by 10 KHz */ + u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */ union { struct detailed_pixel_timing pixel_data; struct detailed_non_pixel other_data; @@ -184,6 +181,14 @@ struct edid { static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; +/** + * edid_valid - sanity check EDID data + * @edid: EDID data + * + * 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 + * valid. + */ static bool edid_valid(struct edid *edid) { int i; @@ -215,7 +220,8 @@ bad: * Take the standard timing params (in this case width, aspect, and refresh) * and convert them into a real mode using CVT. * - * Punts for now. + * Punts for now, but should eventually use the FB layer's CVT based mode + * generation code. */ struct drm_display_mode *drm_mode_std(struct drm_device *dev, struct std_timing *t) @@ -245,19 +251,28 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, return mode; } +/** + * drm_mode_detailed - create a new mode from an EDID detailed timing section + * @timing: EDID detailed timing info + * @preferred: is this a preferred mode? + * + * An EDID detailed timing block contains enough info for us to create and + * return a new struct drm_display_mode. The @preferred flag will be set + * if this is the display's preferred timing, and we'll use it to indicate + * to the other layers that this mode is desired. + */ struct drm_display_mode *drm_mode_detailed(drm_device_t *dev, - struct detailed_timing *timing, - bool preferred) + struct detailed_timing *timing) { struct drm_display_mode *mode; struct detailed_pixel_timing *pt = &timing->data.pixel_data; if (pt->stereo) { - printk(KERN_ERR "stereo mode not supported\n"); + printk(KERN_WARNING "stereo mode not supported\n"); return NULL; } if (!pt->separate_sync) { - printk(KERN_ERR "integrated sync not supported\n"); + printk(KERN_WARNING "integrated sync not supported\n"); return NULL; } @@ -266,7 +281,6 @@ struct drm_display_mode *drm_mode_detailed(drm_device_t *dev, return NULL; mode->type = DRM_MODE_TYPE_DRIVER; - mode->type |= preferred ? DRM_MODE_TYPE_PREFERRED : 0; mode->clock = timing->pixel_clock / 100; mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo; @@ -297,7 +311,10 @@ struct drm_display_mode *drm_mode_detailed(drm_device_t *dev, return mode; } -static struct drm_display_mode established_modes[] = { +/* + * Detailed mode info for the EDID "established modes" data to use. + */ +static struct drm_display_mode edid_est_modes[] = { { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC) }, /* 800x600@60Hz */ @@ -372,8 +389,9 @@ static int add_established_modes(struct drm_output *output, struct edid *edid) for (i = 0; i <= EDID_EST_TIMINGS; i++) if (est_bits & (1<dev; + int i, modes = 0; for (i = 0; i < EDID_STD_TIMINGS; i++) { struct std_timing *t = &edid->standard_timings[i]; + struct drm_display_mode *newmode; /* If std timings bytes are 1, 1 it's empty */ if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1) continue; - drm_mode_probed_add(output, - drm_mode_std(dev, &edid->standard_timings[i])); + newmode = drm_mode_std(dev, &edid->standard_timings[i]); + drm_mode_probed_add(output, newmode); modes++; } @@ -416,13 +435,13 @@ static int add_standard_modes(struct drm_output *output, struct edid *edid) */ static int add_detailed_info(struct drm_output *output, struct edid *edid) { - int i, j, modes = 0; - bool preferred = 0; struct drm_device *dev = output->dev; + int i, j, modes = 0; for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { struct detailed_timing *timing = &edid->detailed_timings[i]; struct detailed_non_pixel *data = &timing->data.other_data; + struct drm_display_mode *newmode; /* EDID up to and including 1.2 may put monitor info here */ if (edid->version == 1 && edid->revision < 3) @@ -430,33 +449,38 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) /* Detailed mode timing */ if (timing->pixel_clock) { + newmode = drm_mode_detailed(dev, timing); + /* First detailed mode is preferred */ if (i == 0 && edid->preferred_timing) - preferred = 1; - drm_mode_probed_add(output, - drm_mode_detailed(dev, timing, preferred)); + newmode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(output, newmode); + modes++; continue; } /* Other timing or info */ switch (data->type) { - case EDID_DETAIL_SERIAL: + case EDID_DETAIL_MONITOR_SERIAL: break; - case EDID_DETAIL_STRING: + case EDID_DETAIL_MONITOR_STRING: break; - case EDID_DETAIL_RANGE: + case EDID_DETAIL_MONITOR_RANGE: + /* Get monitor range data */ break; - case EDID_DETAIL_NAME: + case EDID_DETAIL_MONITOR_NAME: break; - case EDID_DETAIL_CPDATA: + case EDID_DETAIL_MONITOR_CPDATA: break; case EDID_DETAIL_STD_MODES: /* Five modes per detailed section */ for (j = 0; j < 5; i++) { struct std_timing *std; + struct drm_display_mode *newmode; std = &data->data.timings[j]; - drm_mode_probed_add(output, drm_mode_std(dev, std)); + newmode = drm_mode_std(dev, std); + drm_mode_probed_add(output, newmode); modes++; } break; @@ -468,6 +492,108 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) return modes; } +#define DDC_ADDR 0x50 + +static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) +{ + unsigned char start = 0x0; + unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + struct i2c_msg msgs[] = { + { + .addr = DDC_ADDR, + .flags = 0, + .len = 1, + .buf = &start, + }, { + .addr = DDC_ADDR, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + .buf = buf, + } + }; + + if (!buf) { + dev_warn(&adapter->dev, "unable to allocate memory for EDID " + "block.\n"); + return NULL; + } + + if (i2c_transfer(adapter, msgs, 2) == 2) + return buf; + + dev_info(&adapter->dev, "unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) +{ + struct i2c_algo_bit_data *algo_data = adapter->algo_data; + unsigned char *edid = NULL; + int i, j; + + /* + * Startup the bus: + * Set clock line high (but give it time to come up) + * Then set clock & data low + */ + algo_data->setscl(algo_data->data, 1); + udelay(550); /* startup delay */ + algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 0); + + for (i = 0; i < 3; i++) { + /* For some old monitors we need the + * following process to initialize/stop DDC + */ + algo_data->setsda(algo_data->data, 0); + msleep(13); + + algo_data->setscl(algo_data->data, 1); + for (j = 0; j < 5; j++) { + msleep(10); + if (algo_data->getscl(algo_data->data)) + break; + } + if (j == 5) + continue; + + algo_data->setsda(algo_data->data, 0); + msleep(15); + algo_data->setscl(algo_data->data, 0); + msleep(15); + algo_data->setsda(algo_data->data, 1); + msleep(15); + + /* Do the real work */ + edid = drm_do_probe_ddc_edid(adapter); + algo_data->setsda(algo_data->data, 0); + algo_data->setscl(algo_data->data, 0); + msleep(15); + + algo_data->setscl(algo_data->data, 1); + for (j = 0; j < 10; j++) { + msleep(10); + if (algo_data->getscl(algo_data->data)) + break; + } + + algo_data->setsda(algo_data->data, 1); + msleep(15); + algo_data->setscl(algo_data->data, 0); + if (edid) + break; + } + /* Release the DDC lines when done or the Apple Cinema HD display + * will switch off + */ + algo_data->setsda(algo_data->data, 0); + algo_data->setscl(algo_data->data, 0); + algo_data->setscl(algo_data->data, 1); + + return edid; +} + /** * drm_add_edid_modes - add modes from EDID data, if available * @output: output we're probing @@ -481,42 +607,26 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) int drm_add_edid_modes(struct drm_output *output, struct i2c_adapter *adapter) { struct edid *edid; - u8 *raw_edid; - int i, est_modes, std_modes, det_modes; - - edid = (struct edid *)fb_ddc_read(adapter); + int num_modes = 0; + edid = (struct edid *)drm_ddc_read(adapter); if (!edid) { - dev_warn(&output->dev->pdev->dev, "no EDID data\n"); + dev_warn(&output->dev->pdev->dev, "%s: no EDID data\n", + output->name); goto out_err; } if (!edid_valid(edid)) { - dev_warn(&output->dev->pdev->dev, "EDID invalid, ignoring.\n"); + dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", + output->name); goto out_err; } - est_modes = add_established_modes(output, edid); - std_modes = add_standard_modes(output, edid); - det_modes = add_detailed_info(output, edid); - printk(KERN_ERR "est modes: %d, std_modes: %d, det_modes: %d\n", - est_modes, std_modes, det_modes); - - raw_edid = (u8 *)edid; - printk(KERN_ERR "EDID:\n" KERN_ERR); - for (i = 0; i < EDID_LENGTH; i++) { - if (i != 0 && ((i % 16) == 0)) - printk("\n" KERN_ERR); - printk("%02x", raw_edid[i] & 0xff); - } - printk("\n"); - - printk(KERN_ERR "EDID info:\n"); - printk(KERN_ERR " mfg_id: 0x%04x\n", edid->mfg_id); - printk(KERN_ERR " digital? %s\n", edid->digital ? "Yes" : "No"); - printk(KERN_ERR " extensions: %d\n", edid->extensions); + num_modes += add_established_modes(output, edid); + num_modes += add_standard_modes(output, edid); + num_modes += add_detailed_info(output, edid); - return est_modes + std_modes + det_modes; + return num_modes; out_err: kfree(edid); -- cgit v1.2.3 From 491ed9e4c27da6b1b5a6a6921039a7bf3a98c290 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 7 Apr 2007 19:24:53 -0700 Subject: document drm_mode_duplicate and fix vrefresh calculation (off by 1000 error) --- linux-core/drm_modes.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index eea2e754..1ae43447 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -75,7 +75,7 @@ int drm_mode_vrefresh(struct drm_display_mode *mode) if (mode->vrefresh > 0) refresh = mode->vrefresh; else if (mode->htotal > 0 && mode->vtotal > 0) { - refresh = ((mode->clock * 1000) * 1000) / mode->htotal / mode->vtotal; + refresh = (mode->clock * 1000) / mode->htotal / mode->vtotal; if (mode->flags & V_INTERLACE) refresh *= 2; if (mode->flags & V_DBLSCAN) @@ -139,6 +139,13 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) EXPORT_SYMBOL(drm_mode_set_crtcinfo); +/** + * drm_mode_duplicate - allocate and duplicate an existing mode + * @m: mode to duplicate + * + * Just allocate a new mode, copy the existing mode into it, and return + * a pointer to it. Used to create new instances of established modes. + */ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *mode) { struct drm_display_mode *nmode; -- cgit v1.2.3 From 2430d0c3157ef20a3319a4f93dc44b28d0189868 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 7 Apr 2007 19:25:25 -0700 Subject: just codingstyle cleanups --- linux-core/intel_crt.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 55d987a6..e62aa8d3 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -109,10 +109,10 @@ static void intel_crt_mode_set(struct drm_output *output, * Disable separate mode multiplier used when cloning SDVO to CRT * XXX this needs to be adjusted when we really are cloning */ - if (IS_I965G(dev)) - { + if (IS_I965G(dev)) { dpll_md = I915_READ(dpll_md_reg); - I915_WRITE(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); + I915_WRITE(dpll_md_reg, + dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); } adpa = 0; @@ -143,8 +143,8 @@ static bool intel_crt_detect_hotplug(struct drm_output *output) // struct intel_output *intel_output = output->driver_private; drm_i915_private_t *dev_priv = dev->dev_private; u32 temp; - const int timeout_ms = 1000; - int starttime, curtime; +// const int timeout_ms = 1000; +// int starttime, curtime; temp = I915_READ(PORT_HOTPLUG_EN); @@ -180,7 +180,6 @@ static bool intel_crt_detect_ddc(struct drm_output *output) static enum drm_output_status intel_crt_detect(struct drm_output *output) { drm_device_t *dev = output->dev; - drm_i915_private_t *dev_priv = dev->dev_private; if (IS_I945G(dev)| IS_I945GM(dev) || IS_I965G(dev)) { if (intel_crt_detect_hotplug(output)) @@ -227,9 +226,8 @@ void intel_crt_init(drm_device_t *dev) { struct drm_output *output; struct intel_output *intel_output; - int modes; - output = drm_output_create (dev, &intel_crt_output_funcs, "VGA"); + output = drm_output_create(dev, &intel_crt_output_funcs, "VGA"); intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) { -- cgit v1.2.3 From ab7ee9c1af3bd844653a83b5160773db671bbcad Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 7 Apr 2007 19:26:55 -0700 Subject: remove a printk to make things less verbose --- linux-core/intel_lvds.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index a83f7d7a..a444f145 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -124,7 +124,6 @@ void intel_lvds_init(drm_device_t *dev) } modes = intel_ddc_get_modes(output); - printk(KERN_ERR "LVDS: added %d modes from EDID.\n", modes); intel_i2c_destroy(intel_output->ddc_bus); drm_output_destroy(output); } -- cgit v1.2.3 From 7e2b1a6cf55579c6f8b1fd56a97e9f41e34b88fc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 9 Apr 2007 08:52:53 -0700 Subject: Fix refresh calculation (mistakenly removed 1000 factor needed for integer calulations, fixed mode printout debugging routine instead). --- linux-core/drm_modes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 1ae43447..bedef163 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -37,7 +37,7 @@ void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode) { DRM_DEBUG("Modeline \"%s\" %d %d %d %d %d %d %d %d %d %d\n", - mode->name, mode->vrefresh, mode->clock, + mode->name, mode->vrefresh / 1000, mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->vdisplay, mode->vsync_start, @@ -75,7 +75,7 @@ int drm_mode_vrefresh(struct drm_display_mode *mode) if (mode->vrefresh > 0) refresh = mode->vrefresh; else if (mode->htotal > 0 && mode->vtotal > 0) { - refresh = (mode->clock * 1000) / mode->htotal / mode->vtotal; + refresh = ((mode->clock * 1000) * 1000) / mode->htotal / mode->vtotal; if (mode->flags & V_INTERLACE) refresh *= 2; if (mode->flags & V_DBLSCAN) -- cgit v1.2.3 From b50bda002b824efb24e18e8d514ff0ca763c15b9 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 10 Apr 2007 18:44:47 +1000 Subject: add addfb/rmfb ioctls Originally from Jakob, cleaned up by airlied. --- libdrm/xf86drmMode.c | 22 ++++++++++++ libdrm/xf86drmMode.h | 6 ++-- linux-core/drm_crtc.c | 95 +++++++++++++++++++++++++++++++++++++++++++------- linux-core/drm_crtc.h | 27 +++++++------- linux-core/drm_drv.c | 2 ++ shared-core/drm.h | 10 ++++++ shared-core/i915_dma.c | 2 -- 7 files changed, 135 insertions(+), 29 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index c4403b1c..55a9d91c 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -192,6 +192,28 @@ err_allocs: return 0; } +uint32_t drmModeAddFB(int fd, uint32_t width, uint32_t height, + uint8_t bpp, uint32_t pitch, drmBO *bo) +{ + struct drm_mode_fb_cmd f; + + f.width = width; + f.height = height; + f.pitch = pitch; + f.bpp = bpp; + f.handle = bo->handle; + + if (ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)) + return 0; + + return f.buffer_id; +} + +int drmModeRmFB(int fd, uint32_t bufferId) +{ + return ioctl(fd, DRM_IOCTL_MODE_RMFB, bufferId); +} + #if 0 int drmModeForceProbe(int fd, uint32_t outputId) { diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index c027a16d..45b157a8 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -77,8 +77,10 @@ typedef struct _drmModeRes { typedef struct _drmModeFrameBuffer { - uint32_t minWidth, maxWidth; - uint32_t minHeight, maxHeight; + uint32_t width; + uint32_t height; + uint32_t pitch; + uint8_t bpp; } drmModeFrameBuffer, *drmModeFrameBufferPtr; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fe27e386..a02124f3 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -465,18 +465,19 @@ void drm_crtc_config_init(drm_device_t *dev) } EXPORT_SYMBOL(drm_crtc_config_init); -void drm_framebuffer_set_object(drm_device_t *dev, unsigned long handle) +static int drm_get_buffer_object(drm_device_t *dev, struct drm_buffer_object **bo, unsigned long handle) { - struct drm_framebuffer *fb; drm_user_object_t *uo; drm_hash_item_t *hash; - drm_buffer_object_t *bo; int ret; + *bo = NULL; + mutex_lock(&dev->struct_mutex); ret = drm_ht_find_item(&dev->object_hash, handle, &hash); if (ret) { DRM_ERROR("Couldn't find handle.\n"); + ret = -EINVAL; goto out_err; } @@ -485,20 +486,13 @@ void drm_framebuffer_set_object(drm_device_t *dev, unsigned long handle) ret = -EINVAL; goto out_err; } - - bo = drm_user_object_entry(uo, drm_buffer_object_t, base); - - /* get the first fb */ - list_for_each_entry(fb, &dev->crtc_config.fb_list, head) { - fb->offset = bo->offset; - break; - } + + *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); ret = 0; out_err: mutex_unlock(&dev->struct_mutex); - return; + return ret; } -EXPORT_SYMBOL(drm_framebuffer_set_object); bool drm_initial_config(drm_device_t *dev, bool can_grow) { @@ -923,3 +917,78 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set); return retcode; } + +/* Add framebuffer ioctl */ +int drm_mode_addfb(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct drm_file *priv = filp->private_data; + struct drm_device *dev = priv->head->dev; + struct drm_mode_fb_cmd __user *argp = (void __user *)arg; + struct drm_mode_fb_cmd r; + struct drm_crtc_config *config = &dev->crtc_config; + struct drm_framebuffer *fb; + struct drm_buffer_object *bo; + int ret; + + if (!copy_from_user(&r, argp, sizeof(r))) + return -EFAULT; + + if (config->min_width > r.width || r.width > config->max_width) { + DRM_ERROR("mode new framebuffer width not within limits"); + return -EINVAL; + } + if (config->min_height > r.height || r.height > config->min_height) { + DRM_ERROR("mode new framebuffer height not within limits"); + return -EINVAL; + } + + /* TODO check limits are okay */ + ret = drm_get_buffer_object(dev, &bo, r.handle); + if (ret || !bo) + return -EINVAL; + + /* TODO check buffer is sufficently large */ + /* TODO setup destructor callback */ + + fb = drm_framebuffer_create(dev); + if(!fb) + return -EINVAL;; + + fb->width = r.width; + fb->height = r.height; + fb->pitch = r.pitch; + fb->bits_per_pixel = r.bpp; + fb->offset = bo->offset; + fb->bo = bo; + + r.buffer_id = fb->id; + if (!copy_to_user(argp, &r, sizeof(r))) + return -EFAULT; + + return 0; +} + +int drm_mode_rmfb(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_framebuffer *fb = 0; + uint32_t id = arg; + + fb = idr_find(&dev->crtc_config.crtc_idr, id); + /* TODO check that we realy get a framebuffer back. */ + if (!fb || (id != fb->id)) { + DRM_ERROR("mode invalid framebuffer id\n"); + return -EINVAL; + } + + /* TODO check if we own the buffer */ + /* TODO release all crtc connected to the framebuffer */ + /* TODO unhock the destructor from the buffer object */ + + drm_framebuffer_destroy(fb); + + return 0; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 21908f0c..36d5f316 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -178,6 +178,7 @@ struct drm_framebuffer { unsigned int depth; int bits_per_pixel; int flags; + struct drm_buffer_object *bo; }; struct drm_crtc; struct drm_output; @@ -432,17 +433,6 @@ extern void drm_disable_unused_functions(struct drm_device *dev); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); - -/* IOCTLs */ -extern int drm_mode_getresources(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); - -extern int drm_mode_getcrtc(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_mode_getoutput(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int drm_mode_setcrtc(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); extern void drm_mode_list_concat(struct list_head *head, struct list_head *new); extern void drm_mode_validate_size(struct drm_device *dev, @@ -454,7 +444,20 @@ extern void drm_mode_sort(struct list_head *mode_list); extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); -extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); +/* IOCTLs */ +extern int drm_mode_getresources(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int drm_mode_getcrtc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_getoutput(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_setcrtc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_addfb(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_rmfb(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index c8ee054f..80007170 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -127,6 +127,8 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETCRTC)] = {drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETOUTPUT)] = {drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MODE_SETCRTC)] = {drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB)] = {drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_RMFB)] = {drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index 49bc41bc..8329609f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -962,6 +962,14 @@ struct drm_mode_get_output { }; +struct drm_mode_fb_cmd { + unsigned int buffer_id; + unsigned int width, height; + unsigned int pitch; + unsigned int bpp; + unsigned int handle; +}; + /** * \name Ioctls Definitions */ @@ -1037,6 +1045,8 @@ struct drm_mode_get_output { #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) #define DRM_IOCTL_MODE_GETOUTPUT DRM_IOWR(0xA2, struct drm_mode_get_output) #define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xA4, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) /*@}*/ /** diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index a5f1473a..811e4bb9 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -171,8 +171,6 @@ static int i915_initialize(drm_device_t * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); - /* this probably doesn't belong here - TODO */ - drm_framebuffer_set_object(dev, dev_priv->sarea_priv->front_handle); drm_set_desired_modes(dev); return 0; -- cgit v1.2.3 From ed0ebd9d3da2e5c4e8053b6e7a7d2898b184f857 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 10 Apr 2007 18:56:02 +1000 Subject: make crtc_config be named mode_config X.org calls this crtc_config but this is a bad name and will confuse ppl later (and me now :-) --- linux-core/drmP.h | 2 +- linux-core/drm_crtc.c | 136 ++++++++++++++++++++++----------------------- linux-core/drm_crtc.h | 14 ++--- linux-core/intel_display.c | 16 +++--- 4 files changed, 84 insertions(+), 84 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 74f52854..25fc8733 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -832,7 +832,7 @@ typedef struct drm_device { /*@} */ /* DRM mode setting */ - struct drm_crtc_config crtc_config; + struct drm_mode_config mode_config; } drm_device_t; #if __OS_HAS_AGP diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a02124f3..4f8af001 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -8,39 +8,39 @@ int drm_mode_idr_get(struct drm_device *dev, void *ptr) int new_id = 0; int ret; again: - if (idr_pre_get(&dev->crtc_config.crtc_idr, GFP_KERNEL) == 0) { + if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) { DRM_ERROR("Ran out memory getting a mode number\n"); return 0; } - spin_lock(&dev->crtc_config.config_lock); + spin_lock(&dev->mode_config.config_lock); - ret = idr_get_new_above(&dev->crtc_config.crtc_idr, ptr, 1, &new_id); + ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id); if (ret == -EAGAIN) { - spin_unlock(&dev->crtc_config.config_lock); + spin_unlock(&dev->mode_config.config_lock); goto again; } - spin_unlock(&dev->crtc_config.config_lock); + spin_unlock(&dev->mode_config.config_lock); return new_id; } void drm_mode_idr_put(struct drm_device *dev, int id) { - idr_remove(&dev->crtc_config.crtc_idr, id); + idr_remove(&dev->mode_config.crtc_idr, id); } struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) { struct drm_framebuffer *fb; - spin_lock(&dev->crtc_config.config_lock); + spin_lock(&dev->mode_config.config_lock); /* Limit to single framebuffer for now */ - if (dev->crtc_config.num_fb > 1) { + if (dev->mode_config.num_fb > 1) { DRM_ERROR("Attempt to add multiple framebuffers failed\n"); return NULL; } - spin_unlock(&dev->crtc_config.config_lock); + spin_unlock(&dev->mode_config.config_lock); fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); if (!fb) { @@ -50,10 +50,10 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) fb->id = drm_mode_idr_get(dev, fb); fb->dev = dev; - spin_lock(&dev->crtc_config.config_lock); - dev->crtc_config.num_fb++; - list_add(&fb->head, &dev->crtc_config.fb_list); - spin_unlock(&dev->crtc_config.config_lock); + spin_lock(&dev->mode_config.config_lock); + dev->mode_config.num_fb++; + list_add(&fb->head, &dev->mode_config.fb_list); + spin_unlock(&dev->mode_config.config_lock); return fb; } @@ -62,11 +62,11 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) { drm_device_t *dev = fb->dev; - spin_lock(&dev->crtc_config.config_lock); + spin_lock(&dev->mode_config.config_lock); drm_mode_idr_put(dev, fb->id); list_del(&fb->head); - dev->crtc_config.num_fb--; - spin_unlock(&dev->crtc_config.config_lock); + dev->mode_config.num_fb--; + spin_unlock(&dev->mode_config.config_lock); kfree(fb); } @@ -86,10 +86,10 @@ struct drm_crtc *drm_crtc_create(drm_device_t *dev, crtc->id = drm_mode_idr_get(dev, crtc); DRM_DEBUG("crtc %p got id %d\n", crtc, crtc->id); - spin_lock(&dev->crtc_config.config_lock); - list_add_tail(&crtc->head, &dev->crtc_config.crtc_list); - dev->crtc_config.num_crtc++; - spin_unlock(&dev->crtc_config.config_lock); + spin_lock(&dev->mode_config.config_lock); + list_add_tail(&crtc->head, &dev->mode_config.crtc_list); + dev->mode_config.num_crtc++; + spin_unlock(&dev->mode_config.config_lock); return crtc; } @@ -103,11 +103,11 @@ void drm_crtc_destroy(struct drm_crtc *crtc) (*crtc->funcs->cleanup)(crtc); - spin_lock(&dev->crtc_config.config_lock); + spin_lock(&dev->mode_config.config_lock); drm_mode_idr_put(dev, crtc->id); list_del(&crtc->head); - dev->crtc_config.num_crtc--; - spin_unlock(&dev->crtc_config.config_lock); + dev->mode_config.num_crtc--; + spin_unlock(&dev->mode_config.config_lock); kfree(crtc); } EXPORT_SYMBOL(drm_crtc_destroy); @@ -116,7 +116,7 @@ bool drm_crtc_in_use(struct drm_crtc *crtc) { struct drm_output *output; drm_device_t *dev = crtc->dev; - list_for_each_entry(output, &dev->crtc_config.output_list, head) + list_for_each_entry(output, &dev->mode_config.output_list, head) if (output->crtc == crtc) return true; return false; @@ -131,7 +131,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) //if (maxX == 0 || maxY == 0) // TODO - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { list_for_each_entry_safe(mode, t, &output->modes, head) drm_mode_remove(output, mode); @@ -214,7 +214,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, * adjust it according to limitations or output properties, and also * a chance to reject the mode entirely. */ - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { if (output->crtc != crtc) continue; @@ -229,7 +229,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, } /* Prepare the outputs and CRTCs before setting the mode. */ - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { if (output->crtc != crtc) continue; @@ -244,14 +244,14 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, * on the DPLL. */ crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { if (output->crtc == crtc) output->funcs->mode_set(output, mode, adjusted_mode); } /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ crtc->funcs->commit(crtc); - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { if (output->crtc == crtc) { output->funcs->commit(output); @@ -287,11 +287,11 @@ bool drm_set_desired_modes(struct drm_device *dev) struct drm_crtc *crtc; struct drm_output *output, *list_output; - list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { output = NULL; DRM_DEBUG("crtc is %d\n", crtc->id); - list_for_each_entry(list_output, &dev->crtc_config.output_list, head) { + list_for_each_entry(list_output, &dev->mode_config.output_list, head) { if (list_output->crtc == crtc) { output = list_output; break; @@ -320,12 +320,12 @@ void drm_disable_unused_functions(struct drm_device *dev) struct drm_output *output; struct drm_crtc *crtc; - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { if (!output->crtc) (*output->funcs->dpms)(output, DPMSModeOff); } - list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->enabled) crtc->funcs->dpms(crtc, DPMSModeOff); } @@ -389,11 +389,11 @@ struct drm_output *drm_output_create(drm_device_t *dev, /* output_set_monitor(output)? */ /* check for output_ignored(output)? */ - spin_lock(&dev->crtc_config.config_lock); - list_add_tail(&output->head, &dev->crtc_config.output_list); - dev->crtc_config.num_output++; + spin_lock(&dev->mode_config.config_lock); + list_add_tail(&output->head, &dev->mode_config.output_list); + dev->mode_config.num_output++; - spin_unlock(&dev->crtc_config.config_lock); + spin_unlock(&dev->mode_config.config_lock); return output; @@ -414,10 +414,10 @@ void drm_output_destroy(struct drm_output *output) list_for_each_entry_safe(mode, t, &output->modes, head) drm_mode_remove(output, mode); - spin_lock(&dev->crtc_config.config_lock); + spin_lock(&dev->mode_config.config_lock); drm_mode_idr_put(dev, output->id); list_del(&output->head); - spin_unlock(&dev->crtc_config.config_lock); + spin_unlock(&dev->mode_config.config_lock); kfree(output); } EXPORT_SYMBOL(drm_output_destroy); @@ -455,15 +455,15 @@ void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode kfree(mode); } -void drm_crtc_config_init(drm_device_t *dev) +void drm_mode_config_init(drm_device_t *dev) { - spin_lock_init(&dev->crtc_config.config_lock); - INIT_LIST_HEAD(&dev->crtc_config.fb_list); - INIT_LIST_HEAD(&dev->crtc_config.crtc_list); - INIT_LIST_HEAD(&dev->crtc_config.output_list); - idr_init(&dev->crtc_config.crtc_idr); + spin_lock_init(&dev->mode_config.config_lock); + INIT_LIST_HEAD(&dev->mode_config.fb_list); + INIT_LIST_HEAD(&dev->mode_config.crtc_list); + INIT_LIST_HEAD(&dev->mode_config.output_list); + idr_init(&dev->mode_config.crtc_idr); } -EXPORT_SYMBOL(drm_crtc_config_init); +EXPORT_SYMBOL(drm_mode_config_init); static int drm_get_buffer_object(drm_device_t *dev, struct drm_buffer_object **bo, unsigned long handle) { @@ -514,7 +514,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ - list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { crtc->fb = fb; if (!vga_crtc) { vga_crtc = crtc; @@ -542,7 +542,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* hard bind the CRTCS */ /* bind analog output to one crtc */ - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { struct drm_display_mode *des_mode; /* Get the first preferred moded */ @@ -580,20 +580,20 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) } EXPORT_SYMBOL(drm_initial_config); -void drm_crtc_config_cleanup(drm_device_t *dev) +void drm_mode_config_cleanup(drm_device_t *dev) { struct drm_output *output, *ot; struct drm_crtc *crtc, *ct; - list_for_each_entry_safe(output, ot, &dev->crtc_config.output_list, head) { + list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_output_destroy(output); } - list_for_each_entry_safe(crtc, ct, &dev->crtc_config.crtc_list, head) { + list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { drm_crtc_destroy(crtc); } } -EXPORT_SYMBOL(drm_crtc_config_cleanup); +EXPORT_SYMBOL(drm_mode_config_cleanup); int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set) { @@ -604,7 +604,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_output *output; int count = 0, ro; - save_crtcs = kzalloc(dev->crtc_config.num_crtc * sizeof(struct drm_crtc *), GFP_KERNEL); + save_crtcs = kzalloc(dev->mode_config.num_crtc * sizeof(struct drm_crtc *), GFP_KERNEL); if (!save_crtcs) return -ENOMEM; @@ -614,7 +614,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, if (crtc->mode.mode_id != new_mode->mode_id) changed = true; - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { save_crtcs[count++] = output->crtc; if (output->crtc == crtc) @@ -642,7 +642,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, crtc_info->y)) { crtc->enabled = save_enabled; count = 0; - list_for_each_entry(output, &dev->crtc_config.output_list, head) + list_for_each_entry(output, &dev->mode_config.output_list, head) output->crtc = save_crtcs[count++]; kfree(save_crtcs); return -EINVAL; @@ -700,10 +700,10 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); - list_for_each(lh, &dev->crtc_config.crtc_list) + list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; - list_for_each_entry(output, &dev->crtc_config.output_list, + list_for_each_entry(output, &dev->mode_config.output_list, head) { output_count++; @@ -718,7 +718,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, /* CRTCs */ if (card_res.count_crtcs >= crtc_count) { copied = 0; - list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head){ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ DRM_DEBUG("CRTC ID is %d\n", crtc->id); if (put_user(crtc->id, &card_res.crtc_id[copied++])) { retcode = -EFAULT; @@ -732,7 +732,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, /* Outputs */ if (card_res.count_outputs >= output_count) { copied = 0; - list_for_each_entry(output, &dev->crtc_config.output_list, + list_for_each_entry(output, &dev->mode_config.output_list, head) { DRM_DEBUG("OUTPUT ID is %d\n", output->id); if (put_user(output->id, &card_res.output_id[copied++])) { @@ -746,7 +746,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, /* Modes */ if (card_res.count_modes >= mode_count) { copied = 0; - list_for_each_entry(output, &dev->crtc_config.output_list, + list_for_each_entry(output, &dev->mode_config.output_list, head) { list_for_each_entry(mode, &output->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); @@ -785,7 +785,7 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp))) return -EFAULT; - crtc = idr_find(&dev->crtc_config.crtc_idr, crtc_resp.crtc_id); + crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp.crtc_id); if (!crtc || (crtc->id != crtc_resp.crtc_id)) return -EINVAL; crtc_resp.x = crtc->x; @@ -797,7 +797,7 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, crtc_resp.mode = crtc->mode.mode_id; ocount = 0; - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { if (output->crtc == crtc) crtc_resp.outputs |= 1 << (ocount++); } @@ -827,7 +827,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, if (copy_from_user(&out_resp, argp, sizeof(out_resp))) return -EFAULT; - output= idr_find(&dev->crtc_config.crtc_idr, out_resp.output); + output= idr_find(&dev->mode_config.crtc_idr, out_resp.output); if (!output || (output->id != out_resp.output)) return -EINVAL; @@ -878,12 +878,12 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, if (copy_from_user(&crtc_req, argp, sizeof(crtc_req))) return -EFAULT; - crtc = idr_find(&dev->crtc_config.crtc_idr, crtc_req.crtc_id); + crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id); if (!crtc || (crtc->id != crtc_req.crtc_id)) return -EINVAL; if (crtc_req.mode) { - mode = idr_find(&dev->crtc_config.crtc_idr, crtc_req.mode); + mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode); if (!mode || (mode->mode_id != crtc_req.mode)) return -EINVAL; } else @@ -906,7 +906,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, if (get_user(out_id, &crtc_req.set_outputs[i])) return -EFAULT; - output = idr_find(&dev->crtc_config.crtc_idr, out_id); + output = idr_find(&dev->mode_config.crtc_idr, out_id); if (!output || (out_id != output->id)) return -EINVAL; @@ -926,7 +926,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, struct drm_device *dev = priv->head->dev; struct drm_mode_fb_cmd __user *argp = (void __user *)arg; struct drm_mode_fb_cmd r; - struct drm_crtc_config *config = &dev->crtc_config; + struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; struct drm_buffer_object *bo; int ret; @@ -977,7 +977,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, struct drm_framebuffer *fb = 0; uint32_t id = arg; - fb = idr_find(&dev->crtc_config.crtc_idr, id); + fb = idr_find(&dev->mode_config.crtc_idr, id); /* TODO check that we realy get a framebuffer back. */ if (!fb || (id != fb->id)) { DRM_ERROR("mode invalid framebuffer id\n"); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 36d5f316..19d7cf51 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -377,7 +377,7 @@ struct drm_output { }; /** - * struct drm_crtc_config_funcs - configure CRTCs for a given screen layout + * struct drm_mode_config_funcs - configure CRTCs for a given screen layout * @resize: adjust CRTCs as necessary for the proposed layout * * Currently only a resize hook is available. DRM will call back into the @@ -385,15 +385,15 @@ struct drm_output { * the proposed size, it can return false. Otherwise it should adjust * the CRTC<->output mappings as needed and update its view of the screen. */ -struct drm_crtc_config_funcs { +struct drm_mode_config_funcs { bool (*resize)(struct drm_device *dev, int width, int height); }; /** - * drm_crtc_config - CRTC configuration control structure + * drm_mode_config - Mode configuration control structure * */ -struct drm_crtc_config { +struct drm_mode_config { spinlock_t config_lock; struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output, modes - just makes life easier */ /* this is limited to one for now */ @@ -410,7 +410,7 @@ struct drm_crtc_config { int max_width, max_height; /* DamagePtr rotationDamage? */ /* DGA stuff? */ - struct drm_crtc_config_funcs *funcs; + struct drm_mode_config_funcs *funcs; }; struct drm_output *drm_output_create(struct drm_device *dev, @@ -427,8 +427,8 @@ extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode); -extern void drm_crtc_config_init(struct drm_device *dev); -extern void drm_crtc_config_cleanup(struct drm_device *dev); +extern void drm_mode_config_init(struct drm_device *dev); +extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_disable_unused_functions(struct drm_device *dev); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 58d66987..e8d15ce5 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -224,10 +224,10 @@ static void intel_clock(struct drm_device *dev, int refclk, bool intel_pipe_has_type (struct drm_crtc *crtc, int type) { struct drm_device *dev = crtc->dev; - struct drm_crtc_config *crtc_config = &dev->crtc_config; + struct drm_mode_config *mode_config = &dev->mode_config; struct drm_output *l_entry; - list_for_each_entry(l_entry, &crtc_config->output_list, head) { + list_for_each_entry(l_entry, &mode_config->output_list, head) { if (l_entry->crtc == crtc) { struct intel_output *intel_output = l_entry->driver_private; if (intel_output->type == type) @@ -681,10 +681,10 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, u32 dpll = 0, fp = 0, dspcntr, pipeconf; bool ok, is_sdvo = false, is_dvo = false; bool is_crt = false, is_lvds = false, is_tv = false; - struct drm_crtc_config *crtc_config = &dev->crtc_config; + struct drm_mode_config *mode_config = &dev->mode_config; struct drm_output *output; - list_for_each_entry(output, &crtc_config->output_list, head) { + list_for_each_entry(output, &mode_config->output_list, head) { struct intel_output *intel_output = output->driver_private; if (output->crtc != crtc) @@ -1023,7 +1023,7 @@ int intel_output_clones (drm_device_t *dev, int type_mask) struct drm_output *output; int entry = 0; - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { struct intel_output *intel_output = output->driver_private; if (type_mask & (1 << intel_output->type)) index_mask |= (1 << entry); @@ -1048,7 +1048,7 @@ static void intel_setup_outputs(drm_device_t *dev) intel_sdvo_init(dev, SDVOC); } - list_for_each_entry(output, &dev->crtc_config.output_list, head) { + list_for_each_entry(output, &dev->mode_config.output_list, head) { struct intel_output *intel_output = output->driver_private; int crtc_mask = 0, clone_mask = 0; @@ -1088,7 +1088,7 @@ void intel_modeset_init(drm_device_t *dev) int num_pipe; int i; - drm_crtc_config_init(dev); + drm_mode_config_init(dev); if (IS_MOBILE(dev) || IS_I9XX(dev)) @@ -1109,5 +1109,5 @@ void intel_modeset_init(drm_device_t *dev) void intel_modeset_cleanup(drm_device_t *dev) { - drm_crtc_config_cleanup(dev); + drm_mode_config_cleanup(dev); } -- cgit v1.2.3 From eb9bdc27879d1aa307b234bbdb0f81494dcf7095 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Tue, 10 Apr 2007 11:51:31 +1000 Subject: mode: fixup problems with framebuffer add function --- libdrm/xf86drmMode.c | 12 +++++++----- linux-core/drm_crtc.c | 14 ++++++++------ linux-core/intel_display.c | 7 ++++++- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 55a9d91c..5f480890 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -192,10 +192,11 @@ err_allocs: return 0; } -uint32_t drmModeAddFB(int fd, uint32_t width, uint32_t height, - uint8_t bpp, uint32_t pitch, drmBO *bo) +int drmModeAddFB(int fd, uint32_t width, uint32_t height, + uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id) { struct drm_mode_fb_cmd f; + int ret; f.width = width; f.height = height; @@ -203,10 +204,11 @@ uint32_t drmModeAddFB(int fd, uint32_t width, uint32_t height, f.bpp = bpp; f.handle = bo->handle; - if (ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)) - return 0; + if (ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)) + return ret; - return f.buffer_id; + *buf_id = f.buffer_id; + return 0; } int drmModeRmFB(int fd, uint32_t bufferId) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 4f8af001..ce2073d1 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -502,6 +502,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) struct drm_framebuffer *fb; struct drm_output *output, *use_output = NULL; +#if 0 fb = drm_framebuffer_create(dev); if (!fb) return false; @@ -512,6 +513,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) fb->depth = 24; fb->bits_per_pixel = 32; +#endif /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -931,15 +933,15 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, struct drm_buffer_object *bo; int ret; - if (!copy_from_user(&r, argp, sizeof(r))) + if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; - if (config->min_width > r.width || r.width > config->max_width) { - DRM_ERROR("mode new framebuffer width not within limits"); + if ((config->min_width > r.width) || (r.width > config->max_width)) { + DRM_ERROR("mode new framebuffer width not within limits\n"); return -EINVAL; } - if (config->min_height > r.height || r.height > config->min_height) { - DRM_ERROR("mode new framebuffer height not within limits"); + if ((config->min_height > r.height) || (r.height > config->max_height)) { + DRM_ERROR("mode new framebuffer height not within limits\n"); return -EINVAL; } @@ -963,7 +965,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, fb->bo = bo; r.buffer_id = fb->id; - if (!copy_to_user(argp, &r, sizeof(r))) + if (copy_to_user(argp, &r, sizeof(r))) return -EFAULT; return 0; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index e8d15ce5..fce0fafd 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1090,6 +1090,11 @@ void intel_modeset_init(drm_device_t *dev) drm_mode_config_init(dev); + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; if (IS_MOBILE(dev) || IS_I9XX(dev)) num_pipe = 2; @@ -1104,7 +1109,7 @@ void intel_modeset_init(drm_device_t *dev) intel_setup_outputs(dev); - drm_initial_config(dev, false); + //drm_initial_config(dev, false); } void intel_modeset_cleanup(drm_device_t *dev) -- cgit v1.2.3 From c446bf50e3ae730f272c6842f4ad04d523bd40c3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 9 Apr 2007 20:46:38 -0700 Subject: Slam in most of X.Org's i830_lvds (not quite done yet so removed from Makefile.kernel too). --- linux-core/Makefile.kernel | 2 +- linux-core/intel_lvds.c | 423 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 384 insertions(+), 41 deletions(-) diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index ac403f64..1b767b6a 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -20,7 +20,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ - i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \ + i915_buffer.o intel_display.o intel_crt.o \ intel_sdvo.o intel_modes.o intel_i2c.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o \ diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index a444f145..7527dfce 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -1,5 +1,6 @@ /* * Copyright © 2006-2007 Intel Corporation + * Copyright (c) 2006 Dave Airlie * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -22,10 +23,8 @@ * * Authors: * Eric Anholt - */ -/* - * Copyright (c) 2006 Dave Airlie - * Jesse Barnes + * Dave Airlie + * Jesse Barnes */ #include @@ -39,23 +38,22 @@ /** * Sets the backlight level. * - * \param level backlight level, from 0 to i830_lvds_get_max_backlight(). + * \param level backlight level, from 0 to intel_lvds_get_max_backlight(). */ -static void lvds_set_backlight(drm_device_t *dev, u32 level) +static void intel_lvds_set_backlight(struct drm_device *dev, int level) { drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long blc_pwm_ctl; + u32 blc_pwm_ctl; - level &= BACKLIGHT_DUTY_CYCLE_MASK; blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | - (level << BACKLIGHT_DUTY_CYCLE_SHIFT)); + I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | + (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); } /** * Returns the maximum level of the backlight duty cycle field. */ -static u32 lvds_get_max_backlight(drm_device_t *dev) +static u32 intel_lvds_get_max_backlight(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -63,30 +61,386 @@ static u32 lvds_get_max_backlight(drm_device_t *dev) BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; } -int lvds_backlight(DRM_IOCTL_ARGS) +/** + * Sets the power state for the panel. + */ +static void intel_lvds_set_power(struct drm_device *dev, bool on) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 pp_status; + + if (on) { + I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | + POWER_TARGET_ON); + do { + pp_status = I915_READ(PP_STATUS); + } while ((pp_status & PP_ON) == 0); + + intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); + } else { + intel_lvds_set_backlight(dev, 0); + + I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & + ~POWER_TARGET_ON); + do { + pp_status = I915_READ(PP_STATUS); + } while (pp_status & PP_ON); + } +} + +static void intel_lvds_dpms(struct drm_output *output, int mode) +{ + struct drm_device *dev = output->dev; + + if (mode == DPMSModeOn) + intel_lvds_set_power(dev, true); + else + intel_lvds_set_power(dev, false); + + /* XXX: We never power down the LVDS pairs. */ +} + +static void intel_lvds_save(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + dev_priv->savePP_ON = I915_READ(LVDSPP_ON); + dev_priv->savePP_OFF = I915_READ(LVDSPP_OFF); + dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); + dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); + dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & + BACKLIGHT_DUTY_CYCLE_MASK); + + /* + * If the light is off at server startup, just make it full brightness + */ + if (dev_priv->backlight_duty_cycle == 0) + dev_priv->backlight_duty_cycle = + intel_lvds_get_max_backlight(dev); +} + +static void intel_lvds_restore(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); + I915_WRITE(LVDSPP_ON, dev_priv->savePP_ON); + I915_WRITE(LVDSPP_OFF, dev_priv->savePP_OFF); + I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); + I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); + if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) + intel_lvds_set_power(dev, true); + else + intel_lvds_set_power(dev, false); +} + +static int intel_lvds_mode_valid(struct drm_output *output, + struct drm_display_mode *mode) +{ + struct drm_device *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; + + if (fixed_mode) { + if (mode->hdisplay > fixed_mode->hdisplay) + return MODE_PANEL; + if (mode->vdisplay > fixed_mode->vdisplay) + return MODE_PANEL; + } + + return MODE_OK; +} + +static bool intel_lvds_mode_fixup(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = output->crtc->driver_private; + struct drm_output *tmp_output; + + spin_lock(&dev->crtc_config.config_lock); + list_for_each_entry(tmp_output, &dev->crtc_config.output_list, head) { + if (tmp_output != output && tmp_output->crtc == output->crtc) { + printk(KERN_ERR "Can't enable LVDS and another " + "output on the same pipe\n"); + return false; + } + } + spin_lock(&dev->crtc_config.config_lock); + + if (intel_crtc->pipe == 0) { + printk(KERN_ERR "Can't support LVDS on pipe A\n"); + return false; + } + + /* + * If we have timings from the BIOS for the panel, put them in + * to the adjusted mode. The CRTC will be set up for this mode, + * with the panel scaling set up to source from the H/VDisplay + * of the original mode. + */ + if (dev_priv->panel_fixed_mode != NULL) { + adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; + adjusted_mode->hsync_start = + dev_priv->panel_fixed_mode->hsync_start; + adjusted_mode->hsync_end = + dev_priv->panel_fixed_mode->hsync_end; + adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; + adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; + adjusted_mode->vsync_start = + dev_priv->panel_fixed_mode->vsync_start; + adjusted_mode->vsync_end = + dev_priv->panel_fixed_mode->vsync_end; + adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; + adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; +// xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V); + } + + /* + * XXX: It would be nice to support lower refresh rates on the + * panels to reduce power consumption, and perhaps match the + * user's requested refresh rate. + */ + + return true; +} + +static void intel_lvds_mode_set(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = output->crtc->driver_private; + u32 pfit_control; + + /* + * The LVDS pin pair will already have been turned on in the + * intel_crtc_mode_set since it has a large impact on the DPLL + * settings. + */ + + /* + * Enable automatic panel scaling so that non-native modes fill the + * screen. Should be enabled before the pipe is enabled, according to + * register description and PRM. + */ + pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | + VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR); + + if (!IS_I965G(dev)) { + if (dev_priv->panel_wants_dither) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + } + else + pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT; + + I915_WRITE(PFIT_CONTROL, pfit_control); +} + +/** + * Detect the LVDS connection. + * + * This always returns OUTPUT_STATUS_CONNECTED. This output should only have + * been set up if the LVDS was actually connected anyway. + */ +static enum drm_output_status intel_lvds_detect(struct drm_output *output) +{ + return output_status_connected; +} + +/** + * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. + */ +static int intel_lvds_get_modes(struct drm_output *output) { - DRM_DEVICE; - unsigned long dvoa_enabled, dvob_enabled, dvoc_enabled, lvds_enabled; + struct intel_output *intel_output = output->driver_private; + struct drm_device *dev = output->dev; drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_monitor_info *edid_mon; + int ret = 0; + + intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return 0; + } + intel_i2c_destroy(intel_output->ddc_bus); + + ret = intel_ddc_get_modes(output); + if (ret) + return ret; +#if 0 + if (!output->monitor_info) { + edid_mon = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL); + if (edid_mon) { + /* Set wide sync ranges so we get all modes + * handed to valid_mode for checking + */ + edid_mon->det_mon[0].type = DS_RANGES; + edid_mon->det_mon[0].section.ranges.min_v = 0; + edid_mon->det_mon[0].section.ranges.max_v = 200; + edid_mon->det_mon[0].section.ranges.min_h = 0; + edid_mon->det_mon[0].section.ranges.max_h = 200; + + output->monitor_info = edid_mon; + } + } +#endif + if (dev_priv->panel_fixed_mode != NULL) { + struct drm_display_mode *mode = + drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); + drm_mode_probed_add(output, mode); + return 1; + } - printk(KERN_ERR "max backlight value: %d\n", - lvds_get_max_backlight(dev)); - dvoa_enabled = I915_READ(DVOA); - dvob_enabled = I915_READ(DVOB); - dvoc_enabled = I915_READ(DVOC); - lvds_enabled = I915_READ(LVDS); - - printk(KERN_ERR "dvoa_enabled: 0x%08lx\n", dvoa_enabled); - printk(KERN_ERR "dvob_enabled: 0x%08lx\n", dvob_enabled); - printk(KERN_ERR "dvoc_enabled: 0x%08lx\n", dvoc_enabled); - printk(KERN_ERR "lvds_enabled: 0x%08lx\n", lvds_enabled); - printk(KERN_ERR "BLC_PWM_CTL: 0x%08x\n", I915_READ(BLC_PWM_CTL)); - return 0; } -static const struct drm_output_funcs intel_lvds_output_funcs; +static void intel_lvds_destroy(struct drm_output *output) +{ + drm_output_destroy(output); +} + +static const struct drm_output_funcs intel_lvds_output_funcs = { + .dpms = intel_lvds_dpms, + .save = intel_lvds_save, + .restore = intel_lvds_restore, + .mode_valid = intel_lvds_mode_valid, + .mode_fixup = intel_lvds_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_lvds_mode_set, + .commit = intel_output_commit, + .detect = intel_lvds_detect, + .get_modes = intel_lvds_get_modes, + .cleanup = intel_lvds_destroy +}; + +void +intel_lvds_init(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_output *output; + struct intel_output *intel_output; + struct drm_display_mode *modes, scan, bios_mode; + + output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS"); + if (!output) + return; + + intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); + if (!intel_output) { + drm_output_destroy(output); + return; + } + + intel_output->type = INTEL_OUTPUT_LVDS; + output->driver_private = intel_output; + output->subpixel_order = SubPixelHorizontalRGB; + output->interlace_allowed = FALSE; + output->doublescan_allowed = FALSE; + + /* + * Attempt to get the fixed panel mode from DDC. Assume that the + * preferred mode is the right one. + */ + intel_ddc_get_modes(output); + list_for_each_entry(scan, &output->probed_modes, head) { + if (scan->type & DRM_MODE_TYPE_PREFERRED) + break; + } + + if (scan != NULL) + dev_priv->panel_fixed_mode = scan; + +#if 0 + /* + * If we didn't get EDID, try checking if the panel is already turned + * on. If so, assume that whatever is currently programmed is the + * correct mode. + */ + if (dev_priv->panel_fixed_mode == NULL) { + u32 lvds = I915_READ(LVDS); + int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; + struct drm_crtc_config *crtc_config = dev->crtc_config; + struct drm_crtc *crtc = crtc_config->crtc[pipe]; + + if (lvds & LVDS_PORT_EN) { + dev_priv->panel_fixed_mode = intel_crtc_mode_get(pScrn, crtc); + if (dev_priv->panel_fixed_mode != NULL) + dev_priv->panel_fixed_mode->type |= M_T_PREFERRED; + } + } + + /* Get the LVDS fixed mode out of the BIOS. We should support LVDS with + * the BIOS being unavailable or broken, but lack the configuration options + * for now. + */ + bios_mode = intel_bios_get_panel_mode(pScrn); + if (bios_mode != NULL) { + if (dev_priv->panel_fixed_mode != NULL) { + if (dev_priv->debug_modes && + !xf86ModesEqual(dev_priv->panel_fixed_mode, bios_mode)) + { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "BIOS panel mode data doesn't match probed data, " + "continuing with probed.\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode:\n"); + xf86PrintModeline(pScrn->scrnIndex, bios_mode); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "probed mode:\n"); + xf86PrintModeline(pScrn->scrnIndex, dev_priv->panel_fixed_mode); + xfree(bios_mode->name); + xfree(bios_mode); + } + } else { + dev_priv->panel_fixed_mode = bios_mode; + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Couldn't detect panel mode. Disabling panel\n"); + goto disable_exit; + } + + /* Blacklist machines with BIOSes that list an LVDS panel without actually + * having one. + */ + if (dev_priv->PciInfo->chipType == PCI_CHIP_I945_GM) { + if (dev_priv->PciInfo->subsysVendor == 0xa0a0) /* aopen mini pc */ + goto disable_exit; + + if ((dev_priv->PciInfo->subsysVendor == 0x8086) && + (dev_priv->PciInfo->subsysCard == 0x7270)) { + /* It's a Mac Mini or Macbook Pro. + * + * Apple hardware is out to get us. The macbook pro has a real + * LVDS panel, but the mac mini does not, and they have the same + * device IDs. We'll distinguish by panel size, on the assumption + * that Apple isn't about to make any machines with an 800x600 + * display. + */ + if (dev_priv->panel_fixed_mode != NULL && + dev_priv->panel_fixed_mode->HDisplay == 800 && + dev_priv->panel_fixed_mode->VDisplay == 600) + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Suspected Mac Mini, ignoring the LVDS\n"); + goto disable_exit; + } + } + } + +#endif + return; +} + +#if 0 /** * intel_lvds_init - setup LVDS outputs on this device * @dev: drm device @@ -115,16 +469,5 @@ void intel_lvds_init(drm_device_t *dev) output->subpixel_order = SubPixelHorizontalRGB; output->interlace_allowed = 0; output->doublescan_allowed = 0; - - intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); - if (!intel_output->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " - "failed.\n"); - return; - } - - modes = intel_ddc_get_modes(output); - intel_i2c_destroy(intel_output->ddc_bus); - drm_output_destroy(output); } - +#endif -- cgit v1.2.3 From 65f465ed5ad3caf773658bb2832785c963b987f6 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Tue, 10 Apr 2007 14:49:49 +1000 Subject: fixup numerous issues with adding framebuffer support This still isn't perfect but it fixes a few oopses and cleans up some of the tabs and bugs in the original fb limit code --- libdrm/xf86drmMode.c | 8 ++-- libdrm/xf86drmMode.h | 8 ++-- linux-core/drm_crtc.c | 101 ++++++++++++++++++++++++++++++++++--------------- linux-core/drm_crtc.h | 6 +-- linux-core/drm_modes.c | 4 +- shared-core/i915_dma.c | 2 +- 6 files changed, 83 insertions(+), 46 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 5f480890..df8ea8ee 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -311,11 +311,9 @@ err_allocs: } -int drmModeSetCrtc( - int fd, uint32_t crtcId, uint32_t bufferId, - uint32_t x, uint32_t y, uint32_t modeId, - uint32_t *outputs, int count - ) +int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t modeId, + uint32_t *outputs, int count) { struct drm_mode_crtc crtc; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 45b157a8..fadfdc5d 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -214,14 +214,12 @@ extern drmModeFrameBufferPtr drmModeGetFramebuffer(int fd, /** * Creates a new framebuffer with an buffer object as its scanout buffer. */ -extern uint32_t drmModeNewFrameBuffer(int fd, - uint32_t width, uint32_t height, - uint8_t bbp, uint32_t pitch, drmBO *bo); - +extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, + uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id); /** * Destroies the given framebuffer. */ -extern int drmModeDesFrameBuffer(int fd, uint32_t bufferId); +extern int drmModeRmFB(int fd, uint32_t bufferId); /** * Changes the scanout buffer to the given buffer object. diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ce2073d1..46b7f7ae 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -371,7 +371,7 @@ struct drm_output *drm_output_create(drm_device_t *dev, { struct drm_output *output = NULL; - output = kmalloc(sizeof(struct drm_output), GFP_KERNEL); + output = kzalloc(sizeof(struct drm_output), GFP_KERNEL); if (!output) return NULL; @@ -471,13 +471,13 @@ static int drm_get_buffer_object(drm_device_t *dev, struct drm_buffer_object **b drm_hash_item_t *hash; int ret; - *bo = NULL; + *bo = NULL; mutex_lock(&dev->struct_mutex); ret = drm_ht_find_item(&dev->object_hash, handle, &hash); if (ret) { DRM_ERROR("Couldn't find handle.\n"); - ret = -EINVAL; + ret = -EINVAL; goto out_err; } @@ -486,7 +486,7 @@ static int drm_get_buffer_object(drm_device_t *dev, struct drm_buffer_object **b ret = -EINVAL; goto out_err; } - + *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); ret = 0; out_err: @@ -517,7 +517,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - crtc->fb = fb; + // crtc->fb = fb; if (!vga_crtc) { vga_crtc = crtc; crtc->enabled = 1; @@ -699,15 +699,14 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, int output_count = 0; int crtc_count = 0; int copied = 0; - + memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; list_for_each_entry(output, &dev->mode_config.output_list, - head) - { + head) { output_count++; list_for_each(lh, &output->modes) mode_count++; @@ -716,6 +715,16 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, if (copy_from_user(&card_res, argp, sizeof(card_res))) return -EFAULT; + if (card_res.count_modes == 0) { + DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width, dev->mode_config.max_height); + drm_crtc_probe_output_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); + mode_count = 0; + list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each(lh, &output->modes) + mode_count++; + } + } + /* handle this in 3 parts */ /* CRTCs */ if (card_res.count_crtcs >= crtc_count) { @@ -829,13 +838,16 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, if (copy_from_user(&out_resp, argp, sizeof(out_resp))) return -EFAULT; + DRM_DEBUG("output id %d\n", out_resp.output); output= idr_find(&dev->mode_config.crtc_idr, out_resp.output); if (!output || (output->id != out_resp.output)) return -EINVAL; + DRM_DEBUG("about to count modes\n"); list_for_each_entry(mode, &output->modes, head) mode_count++; + DRM_DEBUG("about to count modes %d %d %p\n", mode_count, out_resp.count_modes, output->crtc); out_resp.mm_width = output->mm_width; out_resp.mm_height = output->mm_height; out_resp.subpixel = output->subpixel_order; @@ -845,7 +857,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, else out_resp.crtc = 0; - if (out_resp.count_modes >= mode_count) { + if ((out_resp.count_modes >= mode_count) && mode_count) { copied = 0; list_for_each_entry(mode, &output->modes, head) { if (put_user(mode->mode_id, &out_resp.modes[copied++])) { @@ -882,20 +894,40 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id); if (!crtc || (crtc->id != crtc_req.crtc_id)) + { + DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req.crtc_id); return -EINVAL; + } if (crtc_req.mode) { mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode); if (!mode || (mode->mode_id != crtc_req.mode)) + { + { + struct drm_output *output; + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(mode, &output->modes, head) { + drm_mode_debug_printmodeline(dev, mode); + } + } + } + + DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req.mode, mode); return -EINVAL; + } } else mode = NULL; - if (crtc_req.count_outputs == 0 && mode) + if (crtc_req.count_outputs == 0 && mode) { + DRM_DEBUG("Count outputs is 0 but mode set\n"); return -EINVAL; + } - if (crtc_req.count_outputs > 0 && !mode) + if (crtc_req.count_outputs > 0 && !mode) { + DRM_DEBUG("Count outputs is %d but no mode set\n", crtc_req.count_outputs); return -EINVAL; + } if (crtc_req.count_outputs > 0) { u32 out_id; @@ -903,14 +935,15 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, if (!output_set) return -ENOMEM; - for (i = 0; i < crtc_req.count_outputs; i++) - { + for (i = 0; i < crtc_req.count_outputs; i++) { if (get_user(out_id, &crtc_req.set_outputs[i])) return -EFAULT; output = idr_find(&dev->mode_config.crtc_idr, out_id); - if (!output || (out_id != output->id)) + if (!output || (out_id != output->id)) { + DRM_DEBUG("Output id %d unknown\n", out_id); return -EINVAL; + } output_set[i] = output; } @@ -922,16 +955,16 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, /* Add framebuffer ioctl */ int drm_mode_addfb(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { struct drm_file *priv = filp->private_data; struct drm_device *dev = priv->head->dev; struct drm_mode_fb_cmd __user *argp = (void __user *)arg; struct drm_mode_fb_cmd r; - struct drm_mode_config *config = &dev->mode_config; + struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; struct drm_buffer_object *bo; - int ret; + int ret; if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -939,16 +972,16 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, if ((config->min_width > r.width) || (r.width > config->max_width)) { DRM_ERROR("mode new framebuffer width not within limits\n"); return -EINVAL; - } + } if ((config->min_height > r.height) || (r.height > config->max_height)) { DRM_ERROR("mode new framebuffer height not within limits\n"); return -EINVAL; } /* TODO check limits are okay */ - ret = drm_get_buffer_object(dev, &bo, r.handle); - if (ret || !bo) - return -EINVAL; + ret = drm_get_buffer_object(dev, &bo, r.handle); + if (ret || !bo) + return -EINVAL; /* TODO check buffer is sufficently large */ /* TODO setup destructor callback */ @@ -957,22 +990,30 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, if(!fb) return -EINVAL;; - fb->width = r.width; - fb->height = r.height; - fb->pitch = r.pitch; + fb->width = r.width; + fb->height = r.height; + fb->pitch = r.pitch; fb->bits_per_pixel = r.bpp; - fb->offset = bo->offset; - fb->bo = bo; + fb->offset = bo->offset; + fb->bo = bo; - r.buffer_id = fb->id; - if (copy_to_user(argp, &r, sizeof(r))) - return -EFAULT; + r.buffer_id = fb->id; + + /* bind the fb to the crtc for now */ + { + struct drm_crtc *crtc; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + crtc->fb = fb; + } + } + if (copy_to_user(argp, &r, sizeof(r))) + return -EFAULT; return 0; } int drm_mode_rmfb(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 19d7cf51..142e0ecb 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -178,7 +178,7 @@ struct drm_framebuffer { unsigned int depth; int bits_per_pixel; int flags; - struct drm_buffer_object *bo; + struct drm_buffer_object *bo; }; struct drm_crtc; struct drm_output; @@ -456,8 +456,8 @@ extern int drm_mode_getoutput(struct inode *inode, struct file *filp, extern int drm_mode_setcrtc(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_mode_addfb(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); + unsigned int cmd, unsigned long arg); extern int drm_mode_rmfb(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); + unsigned int cmd, unsigned long arg); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index bedef163..0f2a612a 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -36,8 +36,8 @@ void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode) { - DRM_DEBUG("Modeline \"%s\" %d %d %d %d %d %d %d %d %d %d\n", - mode->name, mode->vrefresh / 1000, mode->clock, + DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d\n", + mode->mode_id, mode->name, mode->vrefresh / 1000, mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->vdisplay, mode->vsync_start, diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 811e4bb9..2c14cb5d 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -171,7 +171,7 @@ static int i915_initialize(drm_device_t * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); - drm_set_desired_modes(dev); +//drm_set_desired_modes(dev); return 0; } -- cgit v1.2.3 From 40bd6dcd86d554ca426deccd4fbada693c4be8a6 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Tue, 10 Apr 2007 15:20:50 +1000 Subject: set the base address of the CRTC correctly --- linux-core/intel_display.c | 3 ++- shared-core/i915_dma.c | 4 +++- shared-core/i915_drv.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index fce0fafd..92b39406 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -351,9 +351,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); - Start = crtc->fb->offset; + Start = crtc->fb->offset + dev_priv->baseaddr; Offset = ((y * crtc->fb->width + x) * (crtc->fb->bits_per_pixel / 8)); + DRM_DEBUG("Writing base %08X %08X %d %d\n", Start, Offset, x, y); if (IS_I965G(dev)) { I915_WRITE(dspbase, Offset); I915_READ(dspbase); diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 2c14cb5d..c2a6d863 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -877,11 +877,13 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) if (IS_I9XX(dev)) { dev_priv->mmiobase = drm_get_resource_start(dev, 0); dev_priv->mmiolen = drm_get_resource_len(dev, 0); + dev_priv->baseaddr = drm_get_resource_start(dev, 2) & 0xff000000; } else if (drm_get_resource_start(dev, 1)) { dev_priv->mmiobase = drm_get_resource_start(dev, 1); dev_priv->mmiolen = drm_get_resource_len(dev, 1); + dev_priv->baseaddr = drm_get_resource_start(dev, 0) & 0xff000000; } else { - DRM_ERROR("Unable to find MMIO registers\n"); + DRM_ERROR("Unable to find MMIO registers or FB\n"); return -ENODEV; } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index f37f5873..517d0bf6 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -92,6 +92,7 @@ typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; + unsigned long baseaddr; unsigned long mmiobase; unsigned long mmiolen; -- cgit v1.2.3 From 1e39dc43230ba1827eedc29ab422464281ec3e1b Mon Sep 17 00:00:00 2001 From: David Airlie Date: Tue, 10 Apr 2007 16:25:31 +1000 Subject: export output name to userspace --- libdrm/xf86drmMode.c | 4 +++- libdrm/xf86drmMode.h | 2 +- linux-core/drm_crtc.c | 7 +++++-- shared-core/drm.h | 3 ++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index df8ea8ee..c0444e65 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -40,6 +40,7 @@ #include "xf86drmMode.h" #include "xf86drm.h" #include +#include /* * Util functions @@ -385,7 +386,8 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) r->crtcs = out.crtcs; r->clones = out.clones; r->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(uint32_t)); - + strncpy(r->name, out.name, DRM_OUTPUT_NAME_LEN); + r->name[DRM_OUTPUT_NAME_LEN-1] = 0; return r; err_allocs: diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index fadfdc5d..594eb487 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -120,7 +120,7 @@ typedef enum { typedef struct _drmModeOutput { unsigned int crtc; /**< Crtc currently connected to */ - + unsigned char name[DRM_OUTPUT_NAME_LEN]; drmModeConnection connection; uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ drmModeSubPixel subpixel; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 46b7f7ae..cc082d91 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -838,16 +838,19 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, if (copy_from_user(&out_resp, argp, sizeof(out_resp))) return -EFAULT; - DRM_DEBUG("output id %d\n", out_resp.output); + DRM_DEBUG("output id %d:\n", out_resp.output); output= idr_find(&dev->mode_config.crtc_idr, out_resp.output); if (!output || (output->id != out_resp.output)) return -EINVAL; - DRM_DEBUG("about to count modes\n"); + DRM_DEBUG("about to count modes: %s\n", output->name); list_for_each_entry(mode, &output->modes, head) mode_count++; DRM_DEBUG("about to count modes %d %d %p\n", mode_count, out_resp.count_modes, output->crtc); + strncpy(out_resp.name, output->name, DRM_OUTPUT_NAME_LEN); + out_resp.name[DRM_OUTPUT_NAME_LEN-1] = 0; + out_resp.mm_width = output->mm_width; out_resp.mm_height = output->mm_height; out_resp.subpixel = output->subpixel_order; diff --git a/shared-core/drm.h b/shared-core/drm.h index 8329609f..f1afc049 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -891,7 +891,7 @@ typedef union drm_mm_init_arg{ /* * Drm mode setting */ - +#define DRM_OUTPUT_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 struct drm_mode_modeinfo { @@ -946,6 +946,7 @@ struct drm_mode_get_output { unsigned int output; /**< Id */ unsigned int crtc; /**< Id of crtc */ + unsigned char name[DRM_OUTPUT_NAME_LEN]; unsigned int connection; unsigned int mm_width, mm_height; /**< HxW in millimeters */ -- cgit v1.2.3 From f1476e4e5cefd4aa8c487b4e651a26056110e2f0 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Tue, 10 Apr 2007 16:25:52 +1000 Subject: re-tab and fixup the i915GM get core clock function to actually work --- linux-core/intel_display.c | 186 ++++++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 95 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 92b39406..75d7359f 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -583,8 +583,9 @@ static int intel_get_core_clock_speed(drm_device_t *dev) else if (IS_I945GM(dev) || IS_845G(dev)) return 200000; else if (IS_I915GM(dev)) { -#if 0 - u16 gcfgc = pciReadWord(dev->PciTag, I915_GCFGC); + u16 gcfgc = 0; + + pci_read_config_word(dev->pdev, I915_GCFGC, &gcfgc); if (gcfgc & I915_LOW_FREQUENCY_ENABLE) return 133000; @@ -597,7 +598,6 @@ static int intel_get_core_clock_speed(drm_device_t *dev) return 190000; } } -#endif } else if (IS_I865G(dev)) return 266000; else if (IS_I855(dev)) { @@ -835,106 +835,102 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, if (intel_panel_fitter_pipe(dev) == pipe) I915_WRITE(PFIT_CONTROL, 0); + DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + drm_mode_debug_printmodeline(dev, mode); + #if 0 - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); - xf86PrintModeline(pScrn->scrnIndex, mode); - if (!xf86ModesEqual(mode, adjusted_mode)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Adjusted mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); - xf86PrintModeline(pScrn->scrnIndex, mode); - } - i830PrintPll("chosen", &clock); + if (!xf86ModesEqual(mode, adjusted_mode)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Adjusted mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); + xf86PrintModeline(pScrn->scrnIndex, mode); + } + i830PrintPll("chosen", &clock); #endif - if (dpll & DPLL_VCO_ENABLE) - { + if (dpll & DPLL_VCO_ENABLE) { + I915_WRITE(fp_reg, fp); + I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); + I915_READ(dpll_reg); + udelay(150); + } + + /* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ + if (is_lvds) { + u32 lvds = I915_READ(LVDS); + + lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (clock.p2 == 7) + lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. + */ + + I915_WRITE(LVDS, lvds); + I915_READ(LVDS); + } + I915_WRITE(fp_reg, fp); - I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); + I915_WRITE(dpll_reg, dpll); I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ udelay(150); - } - - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (is_lvds) - { - u32 lvds = I915_READ(LVDS); - - lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; - /* Set the B0-B3 data pairs corresponding to whether we're going to - * set the DPLLs for dual-channel mode or not. - */ - if (clock.p2 == 7) - lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ - - I915_WRITE(LVDS, lvds); - I915_READ(LVDS); - } - - I915_WRITE(fp_reg, fp); - I915_WRITE(dpll_reg, dpll); - I915_READ(dpll_reg); - /* Wait for the clocks to stabilize. */ - udelay(150); - - if (IS_I965G(dev)) { - int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; - I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | - ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); - } else { - /* write it again -- the BIOS does, after all */ - I915_WRITE(dpll_reg, dpll); - } - I915_READ(dpll_reg); - /* Wait for the clocks to stabilize. */ - udelay(150); - - I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | - ((adjusted_mode->crtc_htotal - 1) << 16)); - I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | - ((adjusted_mode->crtc_hblank_end - 1) << 16)); - I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | - ((adjusted_mode->crtc_hsync_end - 1) << 16)); - I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | - ((adjusted_mode->crtc_vtotal - 1) << 16)); - I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | - ((adjusted_mode->crtc_vblank_end - 1) << 16)); - I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | - ((adjusted_mode->crtc_vsync_end - 1) << 16)); - I915_WRITE(dspstride_reg, crtc->fb->pitch * (crtc->fb->bits_per_pixel / 8)); - /* pipesrc and dspsize control the size that is scaled from, which should - * always be the user's requested size. - */ - I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); - I915_WRITE(dsppos_reg, 0); - I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); - I915_WRITE(pipeconf_reg, pipeconf); - I915_READ(pipeconf_reg); - - intel_wait_for_vblank(dev); - - I915_WRITE(dspcntr_reg, dspcntr); - - /* Flush the plane changes */ - intel_pipe_set_base(crtc, x, y); - + + if (IS_I965G(dev)) { + int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | + ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); + } else { + /* write it again -- the BIOS does, after all */ + I915_WRITE(dpll_reg, dpll); + } + I915_READ(dpll_reg); + /* Wait for the clocks to stabilize. */ + udelay(150); + + I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | + ((adjusted_mode->crtc_htotal - 1) << 16)); + I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | + ((adjusted_mode->crtc_hblank_end - 1) << 16)); + I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | + ((adjusted_mode->crtc_hsync_end - 1) << 16)); + I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | + ((adjusted_mode->crtc_vtotal - 1) << 16)); + I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | + ((adjusted_mode->crtc_vblank_end - 1) << 16)); + I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | + ((adjusted_mode->crtc_vsync_end - 1) << 16)); + I915_WRITE(dspstride_reg, crtc->fb->pitch * (crtc->fb->bits_per_pixel / 8)); + /* pipesrc and dspsize control the size that is scaled from, which should + * always be the user's requested size. + */ + I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); + I915_WRITE(dsppos_reg, 0); + I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + I915_WRITE(pipeconf_reg, pipeconf); + I915_READ(pipeconf_reg); + + intel_wait_for_vblank(dev); + + I915_WRITE(dspcntr_reg, dspcntr); + + /* Flush the plane changes */ + intel_pipe_set_base(crtc, x, y); + #ifdef XF86DRI // TODO // I830DRISetVBlankInterrupt (pScrn, TRUE); #endif - - intel_wait_for_vblank(dev); - - + + intel_wait_for_vblank(dev); } /** Loads the palette/gamma unit for the CRTC with the prepared values */ @@ -1002,7 +998,7 @@ void intel_crtc_init(drm_device_t *dev, int pipe) if (crtc == NULL) return; - intel_crtc = kmalloc(sizeof(struct intel_crtc), GFP_KERNEL); + intel_crtc = kzalloc(sizeof(struct intel_crtc), GFP_KERNEL); if (intel_crtc == NULL) { kfree(crtc); return; -- cgit v1.2.3 From 23a66fd506e71fdfde906d1679fb07c0df8bec4c Mon Sep 17 00:00:00 2001 From: David Airlie Date: Tue, 10 Apr 2007 16:26:07 +1000 Subject: fixup true/false in intel_sdvo.c --- linux-core/intel_sdvo.c | 72 ++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 0e870d15..4a954f9e 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -298,7 +298,7 @@ static bool intel_sdvo_get_trained_inputs(struct drm_output *output, bool *input *input_1 = response.input0_trained; *input_2 = response.input1_trained; - return TRUE; + return true; } static bool intel_sdvo_get_active_outputs(struct drm_output *output, @@ -363,13 +363,13 @@ static bool intel_sdvo_get_input_pixel_clock_range(struct drm_output *output, status = intel_sdvo_read_response(output, &clocks, sizeof(clocks)); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; /* Convert the values from units of 10 kHz to kHz. */ *clock_min = clocks.min * 10; *clock_max = clocks.max * 10; - return TRUE; + return true; } static bool intel_sdvo_set_target_output(struct drm_output *output, @@ -393,15 +393,15 @@ static bool intel_sdvo_get_timing(struct drm_output *output, u8 cmd, status = intel_sdvo_read_response(output, &dtd->part1, sizeof(dtd->part1)); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; intel_sdvo_write_cmd(output, cmd + 1, NULL, 0); status = intel_sdvo_read_response(output, &dtd->part2, sizeof(dtd->part2)); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; - return TRUE; + return true; } static bool intel_sdvo_get_input_timing(struct drm_output *output, @@ -426,14 +426,14 @@ static bool intel_sdvo_set_timing(struct drm_output *output, u8 cmd, intel_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1)); status = intel_sdvo_read_response(output, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; intel_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); status = intel_sdvo_read_response(output, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; - return TRUE; + return true; } static bool intel_sdvo_set_input_timing(struct drm_output *output, @@ -464,16 +464,16 @@ static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output, status = intel_sdvo_read_response(output, &dtd->part1, sizeof(dtd->part1)); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, NULL, 0); status = intel_sdvo_read_response(output, &dtd->part2, sizeof(dtd->part2)); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; - return TRUE; + return true; } #endif @@ -502,9 +502,9 @@ static bool intel_sdvo_set_clock_rate_mult(struct drm_output *output, u8 val) intel_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); status = intel_sdvo_read_response(output, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; - return TRUE; + return true; } static bool intel_sdvo_mode_fixup(struct drm_output *output, @@ -515,7 +515,7 @@ static bool intel_sdvo_mode_fixup(struct drm_output *output, * device will be told of the multiplier during mode_set. */ adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); - return TRUE; + return true; } static void intel_sdvo_mode_set(struct drm_output *output, @@ -584,7 +584,7 @@ static void intel_sdvo_mode_set(struct drm_output *output, intel_sdvo_set_output_timing(output, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(output, TRUE, FALSE); + intel_sdvo_set_target_input(output, true, false); /* We would like to use i830_sdvo_create_preferred_input_timing() to * provide the device with a timing it can support, if it supports that @@ -620,16 +620,20 @@ static void intel_sdvo_mode_set(struct drm_output *output, } /* Set the SDVO control regs. */ - sdvox = I915_READ(sdvo_priv->output_device); - switch (sdvo_priv->output_device) { - case SDVOB: - sdvox &= SDVOB_PRESERVE_MASK; - break; - case SDVOC: - sdvox &= SDVOC_PRESERVE_MASK; - break; - } - sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; + if (0/*IS_I965GM(dev)*/) { + sdvox = SDVO_BORDER_ENABLE; + } else { + sdvox = I915_READ(sdvo_priv->output_device); + switch (sdvo_priv->output_device) { + case SDVOB: + sdvox &= SDVOB_PRESERVE_MASK; + break; + case SDVOC: + sdvox &= SDVOC_PRESERVE_MASK; + break; + } + sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; + } if (intel_crtc->pipe == 1) sdvox |= SDVO_PIPE_B_SELECT; @@ -706,13 +710,13 @@ static void intel_sdvo_save(struct drm_output *output) intel_sdvo_get_active_outputs(output, &sdvo_priv->save_active_outputs); if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { - intel_sdvo_set_target_input(output, TRUE, FALSE); + intel_sdvo_set_target_input(output, true, false); intel_sdvo_get_input_timing(output, &sdvo_priv->save_input_dtd_1); } if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { - intel_sdvo_set_target_input(output, FALSE, TRUE); + intel_sdvo_set_target_input(output, false, true); intel_sdvo_get_input_timing(output, &sdvo_priv->save_input_dtd_2); } @@ -754,12 +758,12 @@ static void intel_sdvo_restore(struct drm_output *output) } if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { - intel_sdvo_set_target_input(output, TRUE, FALSE); + intel_sdvo_set_target_input(output, true, false); intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_1); } if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { - intel_sdvo_set_target_input(output, FALSE, TRUE); + intel_sdvo_set_target_input(output, false, true); intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_2); } @@ -805,9 +809,9 @@ static bool intel_sdvo_get_capabilities(struct drm_output *output, struct intel_ intel_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); status = intel_sdvo_read_response(output, caps, sizeof(*caps)); if (status != SDVO_CMD_STATUS_SUCCESS) - return FALSE; + return false; - return TRUE; + return true; } @@ -980,7 +984,7 @@ void intel_sdvo_init(drm_device_t *dev, int output_device) } else { - unsigned char bytes[2]; + unsigned char bytes[2]; memcpy (bytes, &sdvo_priv->caps.output_flags, 2); DRM_DEBUG("%s: No active TMDS outputs (0x%02x%02x)\n", @@ -997,7 +1001,7 @@ void intel_sdvo_init(drm_device_t *dev, int output_device) /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(output, TRUE, FALSE); + intel_sdvo_set_target_input(output, true, false); intel_sdvo_get_input_pixel_clock_range(output, &sdvo_priv->pixel_clock_min, -- cgit v1.2.3 From b9c7fa55e2c6685c4c533613ab14f305f033c353 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Tue, 10 Apr 2007 16:32:17 +1000 Subject: fixup sarea writes for set pipe base and dpms --- linux-core/intel_display.c | 63 ++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 75d7359f..9fb497dd 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -366,27 +366,22 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) } -#if 0 - drmI830Sarea *sPriv = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn->pScreen); - - if (!sPriv) + if (!dev_priv->sarea_priv) return; switch (pipe) { - case 0: - sPriv->pipeA_x = x; - sPriv->pipeA_y = y; - break; + case 0: + dev_priv->sarea_priv->pipeA_x = x; + dev_priv->sarea_priv->pipeA_y = y; + break; case 1: - sPriv->pipeB_x = x; - sPriv->pipeB_y = y; + dev_priv->sarea_priv->pipeB_x = x; + dev_priv->sarea_priv->pipeB_y = y; break; default: - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Can't update pipe %d in SAREA\n", pipe); + DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); break; } -#endif } /** @@ -406,6 +401,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE; int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; u32 temp; + bool enabled; /* XXX: When our outputs are all unaware of DPMS modes other than off * and on, we should map those modes to DPMSModeOff in the CRTC. @@ -494,30 +490,25 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) break; } -#if 0 //TODO - if (pI830->directRenderingEnabled) { - drmI830Sarea *sPriv = (drmI830Sarea *) DRIGetSAREAPrivate(pScrn->pScreen); - Bool enabled = crtc->enabled && mode != DPMSModeOff; - - if (!sPriv) - return; - - switch (pipe) { - case 0: - sPriv->pipeA_w = enabled ? crtc->mode.HDisplay : 0; - sPriv->pipeA_h = enabled ? crtc->mode.VDisplay : 0; - break; - case 1: - sPriv->pipeB_w = enabled ? crtc->mode.HDisplay : 0; - sPriv->pipeB_h = enabled ? crtc->mode.VDisplay : 0; - break; - default: - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Can't update pipe %d in SAREA\n", pipe); - break; - } + + if (!dev_priv->sarea_priv) + return; + + enabled = crtc->enabled && mode != DPMSModeOff; + + switch (pipe) { + case 0: + dev_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0; + dev_priv->sarea_priv->pipeA_h = enabled ? crtc->mode.vdisplay : 0; + break; + case 1: + dev_priv->sarea_priv->pipeB_w = enabled ? crtc->mode.hdisplay : 0; + dev_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0; + break; + default: + DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); + break; } -#endif } static bool intel_crtc_lock(struct drm_crtc *crtc) -- cgit v1.2.3 From 50672adb3142abca743535a8e60c360ef47b2a08 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Tue, 10 Apr 2007 16:49:36 +1000 Subject: add sdvo debugging output --- linux-core/intel_sdvo.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 4a954f9e..1b45afdb 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -209,11 +209,30 @@ static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd, void *args, int args_len) { struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; + if (1) { + printk("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); + for (i = 0; i < args_len; i++) + printk("%02X ", ((u8 *)args)[i]); + for (; i < 8; i++) + printk(" "); + for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { + if (cmd == sdvo_cmd_names[i].cmd) { + printk("(%s)", sdvo_cmd_names[i].name); + break; + } + } + if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) + printk("(%02X)",cmd); + printk("\n"); + } + for (i = 0; i < args_len; i++) { intel_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]); } + intel_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd); } @@ -230,6 +249,8 @@ static const char *cmd_status_names[] = { static u8 intel_sdvo_read_response(struct drm_output *output, void *response, int response_len) { + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; u8 status; @@ -242,6 +263,18 @@ static u8 intel_sdvo_read_response(struct drm_output *output, void *response, /* read the return status */ intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + if (1) { + printk("%s: R: ", SDVO_NAME(sdvo_priv)); + for (i = 0; i < response_len; i++) + printk("%02X ", ((u8 *)response)[i]); + for (; i < 8; i++) + printk(" "); + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) + printk("(%s)", cmd_status_names[status]); + else + printk("(??? %d)", status); + printk("\n"); + } return status; } -- cgit v1.2.3 From 183cbd92dd016f8935f9b58ef9345fde1391173e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 10 Apr 2007 09:47:37 -0700 Subject: Finish bringing in LVDS code, re-add to Makefile. Needed other changes too: - move EDID structures to drm_edid.h - add EDID info structure to drm_output - add a few routines to intel_display for getting current mode info - add some prototypes to intel_drv.h and drm_crtc.h --- linux-core/Makefile.kernel | 2 +- linux-core/drm_crtc.h | 5 ++ linux-core/drm_edid.c | 173 +------------------------------------------- linux-core/drm_edid.h | 176 +++++++++++++++++++++++++++++++++++++++++++++ linux-core/intel_display.c | 114 +++++++++++++++++++++++++++-- linux-core/intel_drv.h | 3 + linux-core/intel_lvds.c | 117 ++++++++++++++---------------- 7 files changed, 350 insertions(+), 240 deletions(-) create mode 100644 linux-core/drm_edid.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 1b767b6a..ac403f64 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -20,7 +20,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ - i915_buffer.o intel_display.o intel_crt.o \ + i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \ intel_sdvo.o intel_modes.o intel_i2c.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o \ diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 21908f0c..775d21e7 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -369,6 +369,7 @@ struct drm_output { /* xf86MonPtr MonInfo; */ enum subpixel_order subpixel_order; int mm_width, mm_height; + struct edid *monitor_info; char name[DRM_OUTPUT_LEN]; const struct drm_output_funcs *funcs; void *driver_private; @@ -455,6 +456,10 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); +extern bool drm_initial_config(struct drm_device *dev, bool cangrow); +extern void drm_framebuffer_set_object(struct drm_device *dev, + unsigned long handle); +extern bool drm_set_desired_modes(struct drm_device *dev); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index fcd97d67..b79bc2db 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -4,181 +4,14 @@ * * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from * FB layer. + * Copyright (C) 2006 Dennis Munsie */ #include #include #include "drmP.h" +#include "drm_edid.h" -#define EDID_LENGTH 128 -#define DDC_ADDR 0x50 - -#ifdef BIG_ENDIAN -#error "EDID structure is little endian, need big endian versions" -#endif - -struct est_timings { - u8 t1; - u8 t2; - u8 mfg_rsvd; -} __attribute__((packed)); - -struct std_timing { - u8 hsize; /* need to multiply by 8 then add 248 */ - u8 vfreq:6; /* need to add 60 */ - u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ -} __attribute__((packed)); - -/* If detailed data is pixel timing */ -struct detailed_pixel_timing { - u8 hactive_lo; - u8 hblank_lo; - u8 hblank_hi:4; - u8 hactive_hi:4; - u8 vactive_lo; - u8 vblank_lo; - u8 vblank_hi:4; - u8 vactive_hi:4; - u8 hsync_offset_lo; - u8 hsync_pulse_width_lo; - u8 vsync_pulse_width_lo:4; - u8 vsync_offset_lo:4; - u8 hsync_pulse_width_hi:2; - u8 hsync_offset_hi:2; - u8 vsync_pulse_width_hi:2; - u8 vsync_offset_hi:2; - u8 width_mm_lo; - u8 height_mm_lo; - u8 height_mm_hi:4; - u8 width_mm_hi:4; - u8 hborder; - u8 vborder; - u8 unknown0:1; - u8 vsync_positive:1; - u8 hsync_positive:1; - u8 separate_sync:2; - u8 stereo:1; - u8 unknown6:1; - u8 interlaced:1; -} __attribute__((packed)); - -/* If it's not pixel timing, it'll be one of the below */ -struct detailed_data_string { - u8 str[13]; -} __attribute__((packed)); - -struct detailed_data_monitor_range { - u8 min_vfreq; - u8 max_vfreq; - u8 min_hfreq_khz; - u8 max_hfreq_khz; - u8 pixel_clock_mhz; /* need to multiply by 10 */ - u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */ - u8 hfreq_start_khz; /* need to multiply by 2 */ - u8 c; /* need to divide by 2 */ - u16 m; /* FIXME: byte order */ - u8 k; - u8 j; /* need to divide by 2 */ -} __attribute__((packed)); - -struct detailed_data_wpindex { - u8 white_y_lo:2; - u8 white_x_lo:2; - u8 pad:4; - u8 white_x_hi; - u8 white_y_hi; - u8 gamma; /* need to divide by 100 then add 1 */ -} __attribute__((packed)); - -struct detailed_data_color_point { - u8 windex1; - u8 wpindex1[3]; - u8 windex2; - u8 wpindex2[3]; -} __attribute__((packed)); - -struct detailed_non_pixel { - u8 pad1; - u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name - fb=color point data, fa=standard timing data, - f9=undefined, f8=mfg. reserved */ - u8 pad2; - union { - struct detailed_data_string str; - struct detailed_data_monitor_range range; - struct detailed_data_wpindex color; - struct std_timing timings[5]; - } data; -} __attribute__((packed)); - -#define EDID_DETAIL_STD_MODES 0xfa -#define EDID_DETAIL_MONITOR_CPDATA 0xfb -#define EDID_DETAIL_MONITOR_NAME 0xfc -#define EDID_DETAIL_MONITOR_RANGE 0xfd -#define EDID_DETAIL_MONITOR_STRING 0xfe -#define EDID_DETAIL_MONITOR_SERIAL 0xff - -struct detailed_timing { - u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */ - union { - struct detailed_pixel_timing pixel_data; - struct detailed_non_pixel other_data; - } data; -} __attribute__((packed)); - -struct edid { - u8 header[8]; - /* Vendor & product info */ - u16 mfg_id; /* FIXME: byte order */ - u16 prod_code; /* FIXME: byte order */ - u32 serial; /* FIXME: byte order */ - u8 mfg_week; - u8 mfg_year; - /* EDID version */ - u8 version; - u8 revision; - /* Display info: */ - /* input definition */ - u8 serration_vsync:1; - u8 sync_on_green:1; - u8 composite_sync:1; - u8 separate_syncs:1; - u8 blank_to_black:1; - u8 video_level:2; - u8 digital:1; /* bits below must be zero if set */ - u8 width_cm; - u8 height_cm; - u8 gamma; - /* feature support */ - u8 default_gtf:1; - u8 preferred_timing:1; - u8 standard_color:1; - u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ - u8 pm_active_off:1; - u8 pm_suspend:1; - u8 pm_standby:1; - /* Color characteristics */ - u8 red_green_lo; - u8 black_white_lo; - u8 red_x; - u8 red_y; - u8 green_x; - u8 green_y; - u8 blue_x; - u8 blue_y; - u8 white_x; - u8 white_y; - /* Est. timings and mfg rsvd timings*/ - struct est_timings established_timings; - /* Standard timings 1-8*/ - struct std_timing standard_timings[8]; - /* Detailing timings 1-4 */ - struct detailed_timing detailed_timings[4]; - /* Number of 128 byte ext. blocks */ - u8 extensions; - /* Checksum */ - u8 checksum; -} __attribute__((packed)); - +/* Valid EDID header has these bytes */ static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; /** diff --git a/linux-core/drm_edid.h b/linux-core/drm_edid.h new file mode 100644 index 00000000..0d2eeaa1 --- /dev/null +++ b/linux-core/drm_edid.h @@ -0,0 +1,176 @@ +#ifndef __DRM_EDID_H__ +#define __DRM_EDID_H__ + +#include + +#define EDID_LENGTH 128 +#define DDC_ADDR 0x50 + +#ifdef BIG_ENDIAN +#error "EDID structure is little endian, need big endian versions" +#endif + +struct est_timings { + u8 t1; + u8 t2; + u8 mfg_rsvd; +} __attribute__((packed)); + +struct std_timing { + u8 hsize; /* need to multiply by 8 then add 248 */ + u8 vfreq:6; /* need to add 60 */ + u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ +} __attribute__((packed)); + +/* If detailed data is pixel timing */ +struct detailed_pixel_timing { + u8 hactive_lo; + u8 hblank_lo; + u8 hblank_hi:4; + u8 hactive_hi:4; + u8 vactive_lo; + u8 vblank_lo; + u8 vblank_hi:4; + u8 vactive_hi:4; + u8 hsync_offset_lo; + u8 hsync_pulse_width_lo; + u8 vsync_pulse_width_lo:4; + u8 vsync_offset_lo:4; + u8 hsync_pulse_width_hi:2; + u8 hsync_offset_hi:2; + u8 vsync_pulse_width_hi:2; + u8 vsync_offset_hi:2; + u8 width_mm_lo; + u8 height_mm_lo; + u8 height_mm_hi:4; + u8 width_mm_hi:4; + u8 hborder; + u8 vborder; + u8 unknown0:1; + u8 vsync_positive:1; + u8 hsync_positive:1; + u8 separate_sync:2; + u8 stereo:1; + u8 unknown6:1; + u8 interlaced:1; +} __attribute__((packed)); + +/* If it's not pixel timing, it'll be one of the below */ +struct detailed_data_string { + u8 str[13]; +} __attribute__((packed)); + +struct detailed_data_monitor_range { + u8 min_vfreq; + u8 max_vfreq; + u8 min_hfreq_khz; + u8 max_hfreq_khz; + u8 pixel_clock_mhz; /* need to multiply by 10 */ + u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */ + u8 hfreq_start_khz; /* need to multiply by 2 */ + u8 c; /* need to divide by 2 */ + u16 m; /* FIXME: byte order */ + u8 k; + u8 j; /* need to divide by 2 */ +} __attribute__((packed)); + +struct detailed_data_wpindex { + u8 white_y_lo:2; + u8 white_x_lo:2; + u8 pad:4; + u8 white_x_hi; + u8 white_y_hi; + u8 gamma; /* need to divide by 100 then add 1 */ +} __attribute__((packed)); + +struct detailed_data_color_point { + u8 windex1; + u8 wpindex1[3]; + u8 windex2; + u8 wpindex2[3]; +} __attribute__((packed)); + +struct detailed_non_pixel { + u8 pad1; + u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name + fb=color point data, fa=standard timing data, + f9=undefined, f8=mfg. reserved */ + u8 pad2; + union { + struct detailed_data_string str; + struct detailed_data_monitor_range range; + struct detailed_data_wpindex color; + struct std_timing timings[5]; + } data; +} __attribute__((packed)); + +#define EDID_DETAIL_STD_MODES 0xfa +#define EDID_DETAIL_MONITOR_CPDATA 0xfb +#define EDID_DETAIL_MONITOR_NAME 0xfc +#define EDID_DETAIL_MONITOR_RANGE 0xfd +#define EDID_DETAIL_MONITOR_STRING 0xfe +#define EDID_DETAIL_MONITOR_SERIAL 0xff + +struct detailed_timing { + u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */ + union { + struct detailed_pixel_timing pixel_data; + struct detailed_non_pixel other_data; + } data; +} __attribute__((packed)); + +struct edid { + u8 header[8]; + /* Vendor & product info */ + u16 mfg_id; /* FIXME: byte order */ + u16 prod_code; /* FIXME: byte order */ + u32 serial; /* FIXME: byte order */ + u8 mfg_week; + u8 mfg_year; + /* EDID version */ + u8 version; + u8 revision; + /* Display info: */ + /* input definition */ + u8 serration_vsync:1; + u8 sync_on_green:1; + u8 composite_sync:1; + u8 separate_syncs:1; + u8 blank_to_black:1; + u8 video_level:2; + u8 digital:1; /* bits below must be zero if set */ + u8 width_cm; + u8 height_cm; + u8 gamma; + /* feature support */ + u8 default_gtf:1; + u8 preferred_timing:1; + u8 standard_color:1; + u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ + u8 pm_active_off:1; + u8 pm_suspend:1; + u8 pm_standby:1; + /* Color characteristics */ + u8 red_green_lo; + u8 black_white_lo; + u8 red_x; + u8 red_y; + u8 green_x; + u8 green_y; + u8 blue_x; + u8 blue_y; + u8 white_x; + u8 white_y; + /* Est. timings and mfg rsvd timings*/ + struct est_timings established_timings; + /* Standard timings 1-8*/ + struct std_timing standard_timings[8]; + /* Detailing timings 1-4 */ + struct detailed_timing detailed_timings[4]; + /* Number of 128 byte ext. blocks */ + u8 extensions; + /* Checksum */ + u8 checksum; +} __attribute__((packed)); + +#endif /* __DRM_EDID_H__ */ diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 58d66987..90c894ee 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -26,8 +26,6 @@ #include #include "drmP.h" -#include "drm.h" -#include "drm_crtc.h" #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -973,10 +971,115 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, intel_crtc_load_lut(crtc); } +/* Returns the clock of the currently programmed mode of the given pipe. */ +static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B); + u32 fp; + intel_clock_t clock; + + if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) + fp = I915_READ((pipe == 0) ? FPA0 : FPB0); + else + fp = I915_READ((pipe == 0) ? FPA1 : FPB1); + + clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; + clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; + clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; + if (IS_I9XX(dev)) { + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + + switch (dpll & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? + 5 : 10; + break; + case DPLLB_MODE_LVDS: + clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? + 7 : 14; + break; + default: + DRM_DEBUG("Unknown DPLL mode %08x in programmed " + "mode\n", (int)(dpll & DPLL_MODE_MASK)); + return 0; + } + + /* XXX: Handle the 100Mhz refclk */ + i9xx_clock(96000, &clock); + } else { + bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); + + if (is_lvds) { + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + clock.p2 = 14; + + if ((dpll & PLL_REF_INPUT_MASK) == + PLLB_REF_INPUT_SPREADSPECTRUMIN) { + /* XXX: might not be 66MHz */ + i8xx_clock(66000, &clock); + } else + i8xx_clock(48000, &clock); + } else { + if (dpll & PLL_P1_DIVIDE_BY_TWO) + clock.p1 = 2; + else { + clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> + DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; + } + if (dpll & PLL_P2_DIVIDE_BY_4) + clock.p2 = 4; + else + clock.p2 = 2; + + i8xx_clock(48000, &clock); + } + } + + /* XXX: It would be nice to validate the clocks, but we can't reuse + * i830PllIsValid() because it relies on the xf86_config output + * configuration being accurate, which it isn't necessarily. + */ + + return clock.dot; +} + +/** Returns the currently programmed mode of the given pipe. */ struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, struct drm_crtc *crtc) { - return NULL; + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + struct drm_display_mode *mode; + int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); + int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B); + int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); + int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B); + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) + return NULL; + + mode->clock = intel_crtc_clock_get(dev, crtc); + mode->hdisplay = (htot & 0xffff) + 1; + mode->htotal = ((htot & 0xffff0000) >> 16) + 1; + mode->hsync_start = (hsync & 0xffff) + 1; + mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; + mode->vdisplay = (vtot & 0xffff) + 1; + mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; + mode->vsync_start = (vsync & 0xffff) + 1; + mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; + /* FIXME: pull name generation into a common routine */ + snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, + mode->vdisplay); + drm_mode_set_crtcinfo(mode, 0); + + return mode; } static const struct drm_crtc_funcs intel_crtc_funcs = { @@ -1017,7 +1120,7 @@ void intel_crtc_init(drm_device_t *dev, int pipe) crtc->driver_private = intel_crtc; } -int intel_output_clones (drm_device_t *dev, int type_mask) +int intel_output_clones(drm_device_t *dev, int type_mask) { int index_mask = 0; struct drm_output *output; @@ -1039,9 +1142,11 @@ static void intel_setup_outputs(drm_device_t *dev) intel_crt_init(dev); +#if 0 /* Set up integrated LVDS */ if (IS_MOBILE(dev) && !IS_I830(dev)) intel_lvds_init(dev); +#endif if (IS_I9XX(dev)) { intel_sdvo_init(dev, SDVOB); @@ -1105,6 +1210,7 @@ void intel_modeset_init(drm_device_t *dev) intel_setup_outputs(dev); drm_initial_config(dev, false); + drm_set_desired_modes(dev); } void intel_modeset_cleanup(drm_device_t *dev) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 7b02d35f..0675e069 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -71,4 +71,7 @@ extern void intel_lvds_init(drm_device_t *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_output_prepare (struct drm_output *output); extern void intel_output_commit (struct drm_output *output); +extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, + struct drm_crtc *crtc); + #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 7527dfce..4638fb30 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -31,6 +31,7 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" +#include "drm_edid.h" #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -262,7 +263,7 @@ static int intel_lvds_get_modes(struct drm_output *output) struct intel_output *intel_output = output->driver_private; struct drm_device *dev = output->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_monitor_info *edid_mon; + struct edid *edid_info; int ret = 0; intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); @@ -276,23 +277,29 @@ static int intel_lvds_get_modes(struct drm_output *output) ret = intel_ddc_get_modes(output); if (ret) return ret; -#if 0 + + /* Didn't get an EDID */ if (!output->monitor_info) { - edid_mon = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL); - if (edid_mon) { - /* Set wide sync ranges so we get all modes - * handed to valid_mode for checking - */ - edid_mon->det_mon[0].type = DS_RANGES; - edid_mon->det_mon[0].section.ranges.min_v = 0; - edid_mon->det_mon[0].section.ranges.max_v = 200; - edid_mon->det_mon[0].section.ranges.min_h = 0; - edid_mon->det_mon[0].section.ranges.max_h = 200; - - output->monitor_info = edid_mon; - } + struct detailed_data_monitor_range *edid_range; + edid_info = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL); + if (!edid_info) + goto out; + + edid_info->detailed_timings[0].data.other_data.type = + EDID_DETAIL_MONITOR_RANGE; + edid_range = &edid_info->detailed_timings[0].data.other_data.data.range; + + /* Set wide sync ranges so we get all modes + * handed to valid_mode for checking + */ + edid_range->min_vfreq = 0; + edid_range->max_vfreq = 200; + edid_range->min_hfreq_khz = 0; + edid_range->max_hfreq_khz = 200; + output->monitor_info = edid_info; } -#endif + +out: if (dev_priv->panel_fixed_mode != NULL) { struct drm_display_mode *mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); @@ -322,13 +329,19 @@ static const struct drm_output_funcs intel_lvds_output_funcs = { .cleanup = intel_lvds_destroy }; -void -intel_lvds_init(struct drm_device *dev) +/** + * intel_lvds_init - setup LVDS outputs on this device + * @dev: drm device + * + * Create the output, register the LVDS DDC bus, and try to figure out what + * modes we can display on the LVDS panel (if present). + */ +void intel_lvds_init(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_output *output; struct intel_output *intel_output; - struct drm_display_mode *modes, scan, bios_mode; + struct drm_display_mode *scan; /* *modes, *bios_mode; */ output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS"); if (!output) @@ -356,37 +369,43 @@ intel_lvds_init(struct drm_device *dev) break; } - if (scan != NULL) + if (scan) dev_priv->panel_fixed_mode = scan; -#if 0 /* * If we didn't get EDID, try checking if the panel is already turned * on. If so, assume that whatever is currently programmed is the * correct mode. */ - if (dev_priv->panel_fixed_mode == NULL) { + if (!dev_priv->panel_fixed_mode) { u32 lvds = I915_READ(LVDS); int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; - struct drm_crtc_config *crtc_config = dev->crtc_config; - struct drm_crtc *crtc = crtc_config->crtc[pipe]; - - if (lvds & LVDS_PORT_EN) { - dev_priv->panel_fixed_mode = intel_crtc_mode_get(pScrn, crtc); - if (dev_priv->panel_fixed_mode != NULL) - dev_priv->panel_fixed_mode->type |= M_T_PREFERRED; + struct drm_crtc_config *crtc_config = &dev->crtc_config; + struct drm_crtc *crtc; + /* FIXME: need drm_crtc_from_pipe */ + //crtc = drm_crtc_from_pipe(crtc_config, pipe); + + if (lvds & LVDS_PORT_EN && 0) { + dev_priv->panel_fixed_mode = + intel_crtc_mode_get(dev, crtc); + if (dev_priv->panel_fixed_mode) + dev_priv->panel_fixed_mode->type |= + DRM_MODE_TYPE_PREFERRED; } } - /* Get the LVDS fixed mode out of the BIOS. We should support LVDS with - * the BIOS being unavailable or broken, but lack the configuration options - * for now. +/* No BIOS poking yet... */ +#if 0 + /* Get the LVDS fixed mode out of the BIOS. We should support LVDS + * with the BIOS being unavailable or broken, but lack the + * configuration options for now. */ bios_mode = intel_bios_get_panel_mode(pScrn); if (bios_mode != NULL) { if (dev_priv->panel_fixed_mode != NULL) { if (dev_priv->debug_modes && - !xf86ModesEqual(dev_priv->panel_fixed_mode, bios_mode)) + !xf86ModesEqual(dev_priv->panel_fixed_mode, + bios_mode)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "BIOS panel mode data doesn't match probed data, " @@ -439,35 +458,3 @@ intel_lvds_init(struct drm_device *dev) #endif return; } - -#if 0 -/** - * intel_lvds_init - setup LVDS outputs on this device - * @dev: drm device - * - * Create the output, register the LVDS DDC bus, and try to figure out what - * modes we can display on the LVDS panel (if present). - */ -void intel_lvds_init(drm_device_t *dev) -{ - struct drm_output *output; - struct intel_output *intel_output; - int modes; - - output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS"); - if (!output) - return; - - intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); - if (!intel_output) { - drm_output_destroy(output); - return; - } - - intel_output->type = INTEL_OUTPUT_LVDS; - output->driver_private = intel_output; - output->subpixel_order = SubPixelHorizontalRGB; - output->interlace_allowed = 0; - output->doublescan_allowed = 0; -} -#endif -- cgit v1.2.3 From c0336989884e75bcd05284257e884754bb5f85b6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 10 Apr 2007 09:48:20 -0700 Subject: Remove some delays from Intel i2c code, we'll need a more comprehensive fix in the Linux i2c layer to make DDC reliable on old monitors. --- linux-core/intel_i2c.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c index d4cf7eef..e23283fb 100644 --- a/linux-core/intel_i2c.c +++ b/linux-core/intel_i2c.c @@ -80,8 +80,8 @@ static void set_clock(void *data, int state_high) else clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK; + I915_WRITE(chan->reg, reserved | clock_bits); - udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ } static void set_data(void *data, int state_high) @@ -103,7 +103,6 @@ static void set_data(void *data, int state_high) GPIO_DATA_VAL_MASK; I915_WRITE(chan->reg, reserved | data_bits); - udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ } /** @@ -147,7 +146,7 @@ struct intel_i2c_chan *intel_i2c_create(drm_device_t *dev, const u32 reg, chan->algo.setscl = set_clock; chan->algo.getsda = get_data; chan->algo.getscl = get_clock; - chan->algo.udelay = 20; + chan->algo.udelay = 20; /* between calls to (set|get)_(clock|data) */ chan->algo.timeout = usecs_to_jiffies(2200); chan->algo.data = chan; @@ -159,7 +158,6 @@ struct intel_i2c_chan *intel_i2c_create(drm_device_t *dev, const u32 reg, /* JJJ: raise SCL and SDA? */ set_data(chan, 1); set_clock(chan, 1); - udelay(20); return chan; -- cgit v1.2.3 From 8785679f893ef9257c589a70113ac731edba0194 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 10 Apr 2007 09:49:02 -0700 Subject: Remove some debug #if 0 codes and add a reminder to check locking around output enumeration stuff. --- linux-core/drm_crtc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fe27e386..6874265e 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -116,6 +116,7 @@ bool drm_crtc_in_use(struct drm_crtc *crtc) { struct drm_output *output; drm_device_t *dev = crtc->dev; + /* FIXME: Locking around list access? */ list_for_each_entry(output, &dev->crtc_config.output_list, head) if (output->crtc == crtc) return true; @@ -504,7 +505,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) { /* do a hardcoded initial configuration here */ struct drm_crtc *crtc, *vga_crtc = NULL, *dvi_crtc = NULL, - *lvds_crtc = NULL;; + *lvds_crtc = NULL; struct drm_framebuffer *fb; struct drm_output *output, *use_output = NULL; @@ -517,7 +518,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) fb->height = 768; fb->depth = 24; fb->bits_per_pixel = 32; - + /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ list_for_each_entry(crtc, &dev->crtc_config.crtc_list, head) { @@ -533,14 +534,12 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) crtc->desired_x = 0; crtc->desired_y = 0; } -#if 0 else if (!dvi_crtc) { dvi_crtc = crtc; crtc->enabled = 1; crtc->desired_x = 0; crtc->desired_y = 0; } -#endif } drm_crtc_probe_output_modes(dev, 1024, 768); @@ -565,10 +564,8 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) use_output = output; } else if (!strncmp(output->name, "TMDS", 4)) { output->crtc = vga_crtc; -#if 0 drm_mode_debug_printmodeline(dev, des_mode); output->crtc->desired_mode = des_mode; -#endif output->initial_x = 0; output->initial_y = 0; } else if (!strncmp(output->name, "LVDS", 3)) { -- cgit v1.2.3 From 5130918e2531b9a8f6f6b65cdfce81f4f0904329 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 10 Apr 2007 09:51:17 -0700 Subject: Add save/restore state for LVDS code, along with a few other LVDS related items to i915 private structure. --- shared-core/i915_drv.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index f37f5873..6e81f6f8 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -133,6 +133,67 @@ typedef struct drm_i915_private { spinlock_t swaps_lock; drm_i915_vbl_swap_t vbl_swaps; unsigned int swaps_pending; + + /* LVDS info */ + int backlight_duty_cycle; /* restore backlight to this value */ + bool panel_wants_dither; + struct drm_display_mode *panel_fixed_mode; + + /* Register state */ + u32 saveDSPACNTR; + u32 saveDSPBCNTR; + u32 savePIPEACONF; + u32 savePIPEBCONF; + u32 savePIPEASRC; + u32 savePIPEBSRC; + u32 saveFPA0; + u32 saveFPA1; + u32 saveDPLL_A; + u32 saveDPLL_A_MD; + u32 saveHTOTAL_A; + u32 saveHBLANK_A; + u32 saveHSYNC_A; + u32 saveVTOTAL_A; + u32 saveVBLANK_A; + u32 saveVSYNC_A; + u32 saveDSPASTRIDE; + u32 saveDSPASIZE; + u32 saveDSPAPOS; + u32 saveDSPABASE; + u32 saveDSPASURF; + u32 saveFPB0; + u32 saveFPB1; + u32 saveDPLL_B; + u32 saveDPLL_B_MD; + u32 saveHTOTAL_B; + u32 saveHBLANK_B; + u32 saveHSYNC_B; + u32 saveVTOTAL_B; + u32 saveVBLANK_B; + u32 saveVSYNC_B; + u32 saveDSPBSTRIDE; + u32 saveDSPBSIZE; + u32 saveDSPBPOS; + u32 saveDSPBBASE; + u32 saveDSPBSURF; + u32 saveVCLK_DIVISOR_VGA0; + u32 saveVCLK_DIVISOR_VGA1; + u32 saveVCLK_POST_DIV; + u32 saveVGACNTRL; + u32 saveADPA; + u32 saveLVDS; + u32 saveDVOA; + u32 saveDVOB; + u32 saveDVOC; + u32 savePP_ON; + u32 savePP_OFF; + u32 savePP_CONTROL; + u32 savePP_CYCLE; + u32 savePFIT_CONTROL; + u32 savePaletteA[256]; + u32 savePaletteB[256]; + u32 saveSWF[17]; + u32 saveBLC_PWM_CTL; } drm_i915_private_t; enum intel_chip_family { @@ -478,6 +539,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define PFIT_CONTROL 0x61230 # define PFIT_ENABLE (1 << 31) +# define PFIT_PIPE_MASK (3 << 29) +# define PFIT_PIPE_SHIFT 29 # define VERT_INTERP_DISABLE (0 << 10) # define VERT_INTERP_BILINEAR (1 << 10) # define VERT_INTERP_MASK (3 << 10) -- cgit v1.2.3 From b59285d738b1a832b12d9258bd6f1db8f7e61f08 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 10 Apr 2007 10:31:10 -0700 Subject: Move i915 init code to new file, i915_init.c, and create a new high level init routine that runs at driver load time. --- linux-core/i915_init.c | 1 + shared-core/i915_dma.c | 76 +---------------------- shared-core/i915_init.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 74 deletions(-) create mode 120000 linux-core/i915_init.c create mode 100644 shared-core/i915_init.c diff --git a/linux-core/i915_init.c b/linux-core/i915_init.c new file mode 120000 index 00000000..473ddf7b --- /dev/null +++ b/linux-core/i915_init.c @@ -0,0 +1 @@ +../shared-core/i915_init.c \ No newline at end of file diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index a5f1473a..0ba3048a 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -78,7 +78,7 @@ void i915_kernel_lost_context(drm_device_t * dev) dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; } -static int i915_dma_cleanup(drm_device_t * dev) +int i915_dma_cleanup(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* Make sure interrupts are disabled here because the uninstall ioctl @@ -855,78 +855,6 @@ static int i915_mmio(DRM_IOCTL_ARGS) return 0; } -int i915_driver_load(drm_device_t *dev, unsigned long flags) -{ - drm_i915_private_t *dev_priv; - int ret; - unsigned long mmiobase, mmiolen; - - dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); - if (dev_priv == NULL) - return DRM_ERR(ENOMEM); - - memset(dev_priv, 0, sizeof(drm_i915_private_t)); - dev->dev_private = (void *)dev_priv; -// dev_priv->flags = flags; - - /* i915 has 4 more counters */ - dev->counters += 4; - dev->types[6] = _DRM_STAT_IRQ; - dev->types[7] = _DRM_STAT_PRIMARY; - dev->types[8] = _DRM_STAT_SECONDARY; - dev->types[9] = _DRM_STAT_DMA; - - if (IS_I9XX(dev)) { - dev_priv->mmiobase = drm_get_resource_start(dev, 0); - dev_priv->mmiolen = drm_get_resource_len(dev, 0); - } else if (drm_get_resource_start(dev, 1)) { - dev_priv->mmiobase = drm_get_resource_start(dev, 1); - dev_priv->mmiolen = drm_get_resource_len(dev, 1); - } else { - DRM_ERROR("Unable to find MMIO registers\n"); - return -ENODEV; - } - - ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, - _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio_map); - if (ret != 0) { - DRM_ERROR("Cannot add mapping for MMIO registers\n"); - return ret; - } - - DRM_DEBUG("dev_priv->mmio map is %08X\n", dev_priv->mmio_map); - intel_modeset_init(dev); - return 0; -} - -int i915_driver_unload(drm_device_t *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - intel_modeset_cleanup(dev); - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); - - dev->dev_private = NULL; - return 0; -} - -void i915_driver_lastclose(drm_device_t * dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - i915_mem_takedown(&(dev_priv->agp_heap)); - - i915_dma_cleanup(dev); - - dev_priv->mmio_map = NULL; -} - -void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - i915_mem_release(dev, filp, dev_priv->agp_heap); -} - drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH}, @@ -981,7 +909,7 @@ int i915_driver_firstopen(struct drm_device *dev) } } - DRM_DEBUG("dev_priv->mmio map is %08X\n", dev_priv->mmio_map); + DRM_DEBUG("dev_priv->mmio map is %p\n", dev_priv->mmio_map); return 0; } diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c new file mode 100644 index 00000000..e03ed429 --- /dev/null +++ b/shared-core/i915_init.c @@ -0,0 +1,157 @@ +#include "drmP.h" +#include "drm.h" +#include "drm_sarea.h" +#include "i915_drm.h" +#include "i915_drv.h" + +int i915_driver_load(drm_device_t *dev, unsigned long flags) +{ + drm_i915_private_t *dev_priv; + drm_i915_init_t init; + int ret; + + dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return DRM_ERR(ENOMEM); + + memset(dev_priv, 0, sizeof(drm_i915_private_t)); + dev->dev_private = (void *)dev_priv; +// dev_priv->flags = flags; + + /* i915 has 4 more counters */ + dev->counters += 4; + dev->types[6] = _DRM_STAT_IRQ; + dev->types[7] = _DRM_STAT_PRIMARY; + dev->types[8] = _DRM_STAT_SECONDARY; + dev->types[9] = _DRM_STAT_DMA; + + if (IS_I9XX(dev)) { + dev_priv->mmiobase = drm_get_resource_start(dev, 0); + dev_priv->mmiolen = drm_get_resource_len(dev, 0); + } else if (drm_get_resource_start(dev, 1)) { + dev_priv->mmiobase = drm_get_resource_start(dev, 1); + dev_priv->mmiolen = drm_get_resource_len(dev, 1); + } else { + DRM_ERROR("Unable to find MMIO registers\n"); + return -ENODEV; + } + + ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, + _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio_map); + if (ret != 0) { + DRM_ERROR("Cannot add mapping for MMIO registers\n"); + return ret; + } + + + ret = drm_setup(dev); + if (ret) { + DRM_ERROR("drm_setup failed\n"); + return ret; + } + + DRM_GETSAREA(); + if (!dev_priv->sarea) { + DRM_ERROR("can not find sarea!\n"); + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + return DRM_ERR(EINVAL); + } + + /* FIXME: where does the sarea_priv really go? */ + dev_priv->sarea_priv = kmalloc(sizeof(drm_i915_sarea_t), GFP_KERNEL); + + /* FIXME: need real front buffer offset */ + dev_priv->sarea_priv->front_handle = 0xa0000000 + 1024*1024; + + drm_bo_driver_init(dev); + /* this probably doesn't belong here - TODO */ + drm_framebuffer_set_object(dev, dev_priv->sarea_priv->front_handle); + intel_modeset_init(dev); + drm_set_desired_modes(dev); + + /* FIXME: command ring needs AGP space, do we own it at this point? */ + dev_priv->ring.Start = 0xa0000000; + dev_priv->ring.End = 128*1024; + dev_priv->ring.Size = 128*1024; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + dev_priv->ring.map.offset = dev_priv->ring.Start; + dev_priv->ring.map.size = dev_priv->ring.Size; + dev_priv->ring.map.type = 0; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; + + drm_core_ioremap(&dev_priv->ring.map, dev); + + if (dev_priv->ring.map.handle == NULL) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return DRM_ERR(ENOMEM); + } + + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->cpp = 4; + dev_priv->sarea_priv->pf_current_page = 0; + + /* We are using separate values as placeholders for mechanisms for + * private backbuffer/depthbuffer usage. + */ + dev_priv->use_mi_batchbuffer_start = 0; + + /* Allow hardware batchbuffers unless told otherwise. + */ + dev_priv->allow_batchbuffer = 1; + + /* Program Hardware Status Page */ + dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, + 0xffffffff); + + if (!dev_priv->status_page_dmah) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return DRM_ERR(ENOMEM); + } + dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + + I915_WRITE(0x02080, dev_priv->dma_status_page); + DRM_DEBUG("Enabled hardware status page\n"); + + return 0; +} + +int i915_driver_unload(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + intel_modeset_cleanup(dev); + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + + dev->dev_private = NULL; + return 0; +} + +void i915_driver_lastclose(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + i915_mem_takedown(&(dev_priv->agp_heap)); + + i915_dma_cleanup(dev); + + dev_priv->mmio_map = NULL; +} + +void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + i915_mem_release(dev, filp, dev_priv->agp_heap); +} + -- cgit v1.2.3 From e114b981bc291049fa6996d487334a408acc1ce2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 10 Apr 2007 10:31:58 -0700 Subject: Export drm_setup for use by new driver init code. --- linux-core/drm_fops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index d400a4d5..6f0465fd 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -41,7 +41,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t * dev); -static int drm_setup(drm_device_t * dev) +int drm_setup(drm_device_t * dev) { drm_local_map_t *map; int i; @@ -121,6 +121,7 @@ static int drm_setup(drm_device_t * dev) return 0; } +EXPORT_SYMBOL(drm_setup); /** * Open file. -- cgit v1.2.3 From b62ffb8e91dafbe46b4daa5be13a867b149b0170 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Wed, 11 Apr 2007 09:56:09 +1000 Subject: fixup calculation to make sdvo work --- linux-core/drm_modes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 0f2a612a..14c7acd5 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -129,9 +129,9 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) } p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); - p->crtc_vblank_end = min(p->crtc_vsync_end, p->crtc_vtotal); + p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); - p->crtc_hblank_end = min(p->crtc_hsync_end, p->crtc_htotal); + p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal); p->crtc_hadjusted = false; p->crtc_vadjusted = false; -- cgit v1.2.3 From 3e994a56be1bfc633e49434c9e4a3e3262070248 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Wed, 11 Apr 2007 13:18:49 +1000 Subject: use fb pitch and fix up some whitespace --- linux-core/intel_display.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 1eed71f0..04a6e086 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -350,7 +350,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); Start = crtc->fb->offset + dev_priv->baseaddr; - Offset = ((y * crtc->fb->width + x) * (crtc->fb->bits_per_pixel / 8)); + Offset = ((y * crtc->fb->pitch + x) * (crtc->fb->bits_per_pixel / 8)); DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); if (IS_I965G(dev)) { @@ -530,24 +530,22 @@ static void intel_crtc_unlock (struct drm_crtc *crtc) static void intel_crtc_prepare (struct drm_crtc *crtc) { - crtc->funcs->dpms (crtc, DPMSModeOff); + crtc->funcs->dpms(crtc, DPMSModeOff); } static void intel_crtc_commit (struct drm_crtc *crtc) { - crtc->funcs->dpms (crtc, DPMSModeOn); -// if (crtc->scrn->pScreen != NULL) -// xf86_reload_cursors (crtc->scrn->pScreen); + crtc->funcs->dpms(crtc, DPMSModeOn); } void intel_output_prepare (struct drm_output *output) { - output->funcs->dpms (output, DPMSModeOff); + output->funcs->dpms(output, DPMSModeOff); } void intel_output_commit (struct drm_output *output) { - output->funcs->dpms (output, DPMSModeOn); + output->funcs->dpms(output, DPMSModeOn); } static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, -- cgit v1.2.3 From 44be9c9d5950d3b2ba4d5527189abec8dac0686f Mon Sep 17 00:00:00 2001 From: David Airlie Date: Wed, 11 Apr 2007 13:19:30 +1000 Subject: add an fb count + id get to the get resources code path --- libdrm/xf86drmMode.c | 25 +++++++++++-------------- libdrm/xf86drmMode.h | 15 ++++++++------- linux-core/drm_crtc.c | 40 +++++++++++++++++++++++++++++++--------- shared-core/drm.h | 3 ++- 4 files changed, 52 insertions(+), 31 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index c0444e65..7f0252ce 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -144,14 +144,13 @@ drmModeResPtr drmModeGetResources(int fd) int i; drmModeResPtr r = 0; - res.count_crtcs = 0; - res.count_outputs = 0; - res.count_modes = 0; - res.modes = 0; + memset(&res, 0, sizeof(struct drm_mode_card_res)); if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) return 0; + if (res.count_fbs) + res.fb_id = drmMalloc(res.count_fbs*sizeof(uint32_t)); if (res.count_crtcs) res.crtc_id = drmMalloc(res.count_crtcs*sizeof(uint32_t)); if (res.count_outputs) @@ -159,8 +158,10 @@ drmModeResPtr drmModeGetResources(int fd) if (res.count_modes) res.modes = drmMalloc(res.count_modes*sizeof(*res.modes)); - if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) + if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { + r = NULL; goto err_allocs; + } /* * return @@ -170,27 +171,23 @@ drmModeResPtr drmModeGetResources(int fd) if (!(r = drmMalloc(sizeof(*r)))) return 0; - r->frameBufferId = res.fb_id; + r->count_fbs = res.count_fbs; r->count_crtcs = res.count_crtcs; r->count_outputs = res.count_outputs; r->count_modes = res.count_modes; /* TODO we realy should test if these allocs fails. */ + r->fbs = drmAllocCpy(res.fb_id, res.count_fbs, sizeof(uint32_t)); r->crtcs = drmAllocCpy(res.crtc_id, res.count_crtcs, sizeof(uint32_t)); r->outputs = drmAllocCpy(res.output_id, res.count_outputs, sizeof(uint32_t)); r->modes = drmAllocCpy(res.modes, res.count_modes, sizeof(struct drm_mode_modeinfo)); - drmFree(res.crtc_id); - drmFree(res.output_id); - drmFree(res.modes); - - return r; - err_allocs: + drmFree(res.fb_id); drmFree(res.crtc_id); drmFree(res.output_id); drmFree(res.modes); - return 0; + return r; } int drmModeAddFB(int fd, uint32_t width, uint32_t height, @@ -214,7 +211,7 @@ int drmModeAddFB(int fd, uint32_t width, uint32_t height, int drmModeRmFB(int fd, uint32_t bufferId) { - return ioctl(fd, DRM_IOCTL_MODE_RMFB, bufferId); + return ioctl(fd, DRM_IOCTL_MODE_RMFB, bufferId); } #if 0 diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 594eb487..4ca9e407 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -62,7 +62,8 @@ typedef struct _drmModeGammaTriple { typedef struct _drmModeRes { - uint32_t frameBufferId; + int count_fbs; + uint32_t *fbs; int count_crtcs; uint32_t *crtcs; @@ -77,10 +78,10 @@ typedef struct _drmModeRes { typedef struct _drmModeFrameBuffer { - uint32_t width; - uint32_t height; - uint32_t pitch; - uint8_t bpp; + uint32_t width; + uint32_t height; + uint32_t pitch; + uint8_t bpp; } drmModeFrameBuffer, *drmModeFrameBufferPtr; @@ -208,14 +209,14 @@ extern int drmModeForceProbe(int fd, uint32_t outputId); /** * Retrive information about framebuffer bufferId */ -extern drmModeFrameBufferPtr drmModeGetFramebuffer(int fd, +extern drmModeFrameBufferPtr drmModeGetFB(int fd, uint32_t bufferId); /** * Creates a new framebuffer with an buffer object as its scanout buffer. */ extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, - uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id); + uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id); /** * Destroies the given framebuffer. */ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1899df2d..12705272 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -84,7 +84,6 @@ struct drm_crtc *drm_crtc_create(drm_device_t *dev, crtc->funcs = funcs; crtc->id = drm_mode_idr_get(dev, crtc); - DRM_DEBUG("crtc %p got id %d\n", crtc, crtc->id); spin_lock(&dev->mode_config.config_lock); list_add_tail(&crtc->head, &dev->mode_config.crtc_list); @@ -291,7 +290,6 @@ bool drm_set_desired_modes(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { output = NULL; - DRM_DEBUG("crtc is %d\n", crtc->id); list_for_each_entry(list_output, &dev->mode_config.output_list, head) { if (list_output->crtc == crtc) { output = list_output; @@ -610,7 +608,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) changed = true; - if (crtc->mode.mode_id != new_mode->mode_id) + if (new_mode && (crtc->mode.mode_id != new_mode->mode_id)) changed = true; list_for_each_entry(output, &dev->mode_config.output_list, head) { @@ -633,8 +631,8 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, } if (changed) { - crtc->enabled = new_mode != NULL; - if (new_mode) { + crtc->enabled = (new_mode != NULL); + if (new_mode != NULL) { DRM_DEBUG("attempting to set mode from userspace\n"); drm_mode_debug_printmodeline(dev, new_mode); if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x, @@ -648,7 +646,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, } crtc->desired_x = crtc_info->x; crtc->desired_y = crtc_info->y; - crtc->desired_mode = new_mode; + crtc->desired_mode = new_mode; } drm_disable_unused_functions(dev); } @@ -687,6 +685,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, struct drm_mode_card_res __user *argp = (void __user *)arg; struct drm_mode_card_res card_res; struct list_head *lh; + struct drm_framebuffer *fb; struct drm_output *output; struct drm_crtc *crtc; struct drm_mode_modeinfo u_mode; @@ -695,10 +694,14 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, int mode_count= 0; int output_count = 0; int crtc_count = 0; + int fb_count = 0; int copied = 0; memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); + list_for_each(lh, &dev->mode_config.fb_list) + fb_count++; + list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; @@ -722,7 +725,19 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, } } - /* handle this in 3 parts */ + /* handle this in 4 parts */ + /* FBs */ + if (card_res.count_fbs >= fb_count) { + copied = 0; + list_for_each_entry(fb, &dev->mode_config.fb_list, head) { + if (put_user(fb->id, &card_res.fb_id[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } + card_res.count_fbs = fb_count; + /* CRTCs */ if (card_res.count_crtcs >= crtc_count) { copied = 0; @@ -840,11 +855,9 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, if (!output || (output->id != out_resp.output)) return -EINVAL; - DRM_DEBUG("about to count modes: %s\n", output->name); list_for_each_entry(mode, &output->modes, head) mode_count++; - DRM_DEBUG("about to count modes %d %d %p\n", mode_count, out_resp.count_modes, output->crtc); strncpy(out_resp.name, output->name, DRM_OUTPUT_NAME_LEN); out_resp.name[DRM_OUTPUT_NAME_LEN-1] = 0; @@ -1029,9 +1042,18 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, /* TODO check if we own the buffer */ /* TODO release all crtc connected to the framebuffer */ + /* bind the fb to the crtc for now */ + { + struct drm_crtc *crtc; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->fb == fb) + crtc->fb = NULL; + } + } /* TODO unhock the destructor from the buffer object */ drm_framebuffer_destroy(fb); return 0; } + diff --git a/shared-core/drm.h b/shared-core/drm.h index f1afc049..a5330b28 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -909,7 +909,8 @@ struct drm_mode_modeinfo { struct drm_mode_card_res { - unsigned int fb_id; + int count_fbs; + unsigned int __user *fb_id; int count_crtcs; unsigned int __user *crtc_id; -- cgit v1.2.3 From 7e58276c76ff2297fdf9ba295d696338377d6e14 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 11 Apr 2007 13:40:50 +1000 Subject: Revert "Remove some delays from Intel i2c code, we'll need a more comprehensive fix" This reverts commit c0336989884e75bcd05284257e884754bb5f85b6. this break SDVO --- linux-core/intel_i2c.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c index e23283fb..d4cf7eef 100644 --- a/linux-core/intel_i2c.c +++ b/linux-core/intel_i2c.c @@ -80,8 +80,8 @@ static void set_clock(void *data, int state_high) else clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_VAL_MASK; - I915_WRITE(chan->reg, reserved | clock_bits); + udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ } static void set_data(void *data, int state_high) @@ -103,6 +103,7 @@ static void set_data(void *data, int state_high) GPIO_DATA_VAL_MASK; I915_WRITE(chan->reg, reserved | data_bits); + udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ } /** @@ -146,7 +147,7 @@ struct intel_i2c_chan *intel_i2c_create(drm_device_t *dev, const u32 reg, chan->algo.setscl = set_clock; chan->algo.getsda = get_data; chan->algo.getscl = get_clock; - chan->algo.udelay = 20; /* between calls to (set|get)_(clock|data) */ + chan->algo.udelay = 20; chan->algo.timeout = usecs_to_jiffies(2200); chan->algo.data = chan; @@ -158,6 +159,7 @@ struct intel_i2c_chan *intel_i2c_create(drm_device_t *dev, const u32 reg, /* JJJ: raise SCL and SDA? */ set_data(chan, 1); set_clock(chan, 1); + udelay(20); return chan; -- cgit v1.2.3 From b329f91502a20cc6def44b7bea6cbc8b016edd5e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 11 Apr 2007 14:04:18 +1000 Subject: use the baseaddr at least --- shared-core/i915_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index e454c9fc..038e3939 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -64,7 +64,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) dev_priv->sarea_priv = kmalloc(sizeof(drm_i915_sarea_t), GFP_KERNEL); /* FIXME: need real front buffer offset */ - dev_priv->sarea_priv->front_handle = 0xa0000000 + 1024*1024; + dev_priv->sarea_priv->front_handle = dev_priv->baseaddr + 1024*1024; drm_bo_driver_init(dev); /* this probably doesn't belong here - TODO */ @@ -73,7 +73,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_set_desired_modes(dev); /* FIXME: command ring needs AGP space, do we own it at this point? */ - dev_priv->ring.Start = 0xa0000000; + dev_priv->ring.Start = dev_priv->baseaddr; dev_priv->ring.End = 128*1024; dev_priv->ring.Size = 128*1024; dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; -- cgit v1.2.3 From 9d12da5917ec57605a2c4cd81c1753145f7e229c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 11 Apr 2007 14:34:22 +1000 Subject: only bo finish at driver unload --- linux-core/drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 80007170..b43af328 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -156,8 +156,6 @@ int drm_lastclose(drm_device_t * dev) * We can't do much about this function failing. */ - drm_bo_driver_finish(dev); - if (dev->driver->lastclose) dev->driver->lastclose(dev); DRM_DEBUG("driver lastclose completed\n"); @@ -400,6 +398,8 @@ static void drm_cleanup(drm_device_t * dev) DRM_DEBUG("mtrr_del=%d\n", retval); } + drm_bo_driver_finish(dev); + if (drm_core_has_AGP(dev) && dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); dev->agp = NULL; -- cgit v1.2.3 From 3dd5dc5728620cadec24ee5db323a20c3bb48bf0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 11 Apr 2007 14:34:43 +1000 Subject: only init at driver load --- shared-core/i915_dma.c | 1 - 1 file changed, 1 deletion(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 1c8a0d45..a7603405 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -896,7 +896,6 @@ int i915_driver_firstopen(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; int ret; DRM_DEBUG("\n"); - drm_bo_driver_init(dev); if (!dev_priv->mmio_map) { ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, -- cgit v1.2.3 From add7a928ad1819df17d5764d06fb81985b285d08 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 11 Apr 2007 14:43:02 +1000 Subject: comment out unworkable code --- shared-core/i915_init.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 038e3939..61c128cb 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -45,7 +45,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) return ret; } - +#if 0 ret = drm_setup(dev); if (ret) { DRM_ERROR("drm_setup failed\n"); @@ -61,17 +61,17 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) } /* FIXME: where does the sarea_priv really go? */ - dev_priv->sarea_priv = kmalloc(sizeof(drm_i915_sarea_t), GFP_KERNEL); + // dev_priv->sarea_priv = kmalloc(sizeof(drm_i915_sarea_t), GFP_KERNEL); /* FIXME: need real front buffer offset */ - dev_priv->sarea_priv->front_handle = dev_priv->baseaddr + 1024*1024; - + /// dev_priv->sarea_priv->front_handle = dev_priv->baseaddr + 1024*1024; +#endif drm_bo_driver_init(dev); /* this probably doesn't belong here - TODO */ //drm_framebuffer_set_object(dev, dev_priv->sarea_priv->front_handle); intel_modeset_init(dev); - drm_set_desired_modes(dev); - + // drm_set_desired_modes(dev); +#if 0 /* FIXME: command ring needs AGP space, do we own it at this point? */ dev_priv->ring.Start = dev_priv->baseaddr; dev_priv->ring.End = 128*1024; @@ -125,6 +125,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); +#endif return 0; } -- cgit v1.2.3 From 32f6a58db216f23a7c71ca9c7eda56aaa8293078 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 11 Apr 2007 16:33:03 +1000 Subject: add initial drm_fb framebuffer So far I can load fbcon, once I use my miniglx to add a framebuffer. fbcon doesn't show anything on screen but baby steps and all that. --- linux-core/Makefile.kernel | 2 +- linux-core/drm_crtc.c | 2 + linux-core/drm_crtc.h | 6 ++ linux-core/drm_fb.c | 160 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_init.c | 4 +- 5 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 linux-core/drm_fb.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index c767116a..b9684d68 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -14,7 +14,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ - drm_edid.o drm_modes.o + drm_edid.o drm_modes.o drm_fb.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 12705272..83f8e167 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1022,6 +1022,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, if (copy_to_user(argp, &r, sizeof(r))) return -EFAULT; + drmfb_probe(dev, fb); return 0; } @@ -1040,6 +1041,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, return -EINVAL; } + drmfb_remove(dev, fb); /* TODO check if we own the buffer */ /* TODO release all crtc connected to the framebuffer */ /* bind the fb to the crtc for now */ diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 57bfb10b..d5d256d4 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -11,6 +11,8 @@ #include #include +#include + struct drm_device; /* @@ -179,6 +181,9 @@ struct drm_framebuffer { int bits_per_pixel; int flags; struct drm_buffer_object *bo; + void *fbdev; + u32 pseudo_palette[17]; + void *virtual_base; }; struct drm_crtc; struct drm_output; @@ -412,6 +417,7 @@ struct drm_mode_config { /* DamagePtr rotationDamage? */ /* DGA stuff? */ struct drm_mode_config_funcs *funcs; + int fb_base; }; struct drm_output *drm_output_create(struct drm_device *dev, diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c new file mode 100644 index 00000000..9bf2187c --- /dev/null +++ b/linux-core/drm_fb.c @@ -0,0 +1,160 @@ + /* + * Modularization + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drmP.h" +struct drmfb_par { + struct drm_device *dev; + struct drm_framebuffer *fb; +}; + +static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct drmfb_par *par = info->par; + struct drm_framebuffer *fb = par->fb; + if (regno > 17) + return 1; + + printk(KERN_INFO "Got set col reg %d %d %d %d\n", red, green, blue, regno); + + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + + return 0; +} + +static struct fb_ops drmfb_ops = { + .owner = THIS_MODULE, + // .fb_open = drmfb_open, + // .fb_read = drmfb_read, + // .fb_write = drmfb_write, + // .fb_release = drmfb_release, + // .fb_ioctl = drmfb_ioctl, + .fb_setcolreg = drmfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) +{ + struct fb_info *info; + struct drmfb_par *par; + struct device *device = &dev->pdev->dev; + struct fb_var_screeninfo *var_info; + unsigned long base, size; + + info = framebuffer_alloc(sizeof(struct drmfb_par), device); + if (!info){ + return -EINVAL; + } + + fb->fbdev = info; + + par = info->par; + + par->dev = dev; + par->fb = fb; + + info->fbops = &drmfb_ops; + + strcpy(info->fix.id, "drmfb"); + info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_len = (8*1024*1024); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; + info->fix.type_aux = 0; + info->fix.mmio_start = 0; + info->fix.mmio_len = 0; + info->fix.line_length = fb->pitch; + + info->flags = FBINFO_DEFAULT; + + base = fb->bo->offset + dev->mode_config.fb_base; + size = (fb->bo->mem.num_pages * PAGE_SIZE); + + DRM_DEBUG("remapping %08X %d\n", base, size); + fb->virtual_base = ioremap_nocache(base, size); + + info->screen_base = fb->virtual_base; + info->screen_size = size; + info->pseudo_palette = fb->pseudo_palette; + info->var.xres = fb->width; + info->var.xres_virtual = fb->pitch; + info->var.yres = fb->height; + info->var.yres_virtual = fb->height; + info->var.bits_per_pixel = fb->bits_per_pixel; + info->var.xoffset = 0; + info->var.yoffset = 0; + + switch(fb->depth) { + case 8: + case 15: + case 16: + break; + case 24: + case 32: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 8; + if (fb->depth == 32) { + info->var.transp.offset = 24; + info->var.transp.length = 8; + } + break; + } + + if (register_framebuffer(info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} +EXPORT_SYMBOL(drmfb_probe); + +int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +{ + struct fb_info *info = fb->fbdev; + + if (info) { + iounmap(fb->virtual_base); + unregister_framebuffer(info); + framebuffer_release(info); + } + return 0; +} +EXPORT_SYMBOL(drmfb_remove); +MODULE_LICENSE("GPL"); diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 61c128cb..5af86f82 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -28,11 +28,11 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) if (IS_I9XX(dev)) { dev_priv->mmiobase = drm_get_resource_start(dev, 0); dev_priv->mmiolen = drm_get_resource_len(dev, 0); - dev_priv->baseaddr = drm_get_resource_start(dev, 2) & 0xff000000; + dev->mode_config.fb_base = dev_priv->baseaddr = drm_get_resource_start(dev, 2) & 0xff000000; } else if (drm_get_resource_start(dev, 1)) { dev_priv->mmiobase = drm_get_resource_start(dev, 1); dev_priv->mmiolen = drm_get_resource_len(dev, 1); - dev_priv->baseaddr = drm_get_resource_start(dev, 0) & 0xff000000; + dev->mode_config.fb_base = dev_priv->baseaddr = drm_get_resource_start(dev, 0) & 0xff000000; } else { DRM_ERROR("Unable to find MMIO registers\n"); return -ENODEV; -- cgit v1.2.3 From c582eaac194411f52a2c0527ffa093b5a422d7b9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 11 Apr 2007 16:34:40 +1000 Subject: add copyright statement --- linux-core/drm_fb.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 9bf2187c..1fe3e54b 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -1,3 +1,28 @@ +/* + * Copyright © 2007 David Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * David Airlie + */ /* * Modularization */ -- cgit v1.2.3 From a6cc6a778f8b2f86300a8ce87441d044fd67f930 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Wed, 11 Apr 2007 17:13:45 +1000 Subject: add support for setting a framebuffer depth --- libdrm/xf86drmMode.c | 3 ++- libdrm/xf86drmMode.h | 2 +- linux-core/drm_crtc.c | 11 ++++++----- shared-core/drm.h | 1 + 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 7f0252ce..04fb07dc 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -190,7 +190,7 @@ err_allocs: return r; } -int drmModeAddFB(int fd, uint32_t width, uint32_t height, +int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id) { struct drm_mode_fb_cmd f; @@ -200,6 +200,7 @@ int drmModeAddFB(int fd, uint32_t width, uint32_t height, f.height = height; f.pitch = pitch; f.bpp = bpp; + f.depth = depth; f.handle = bo->handle; if (ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 4ca9e407..cdc82f7d 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -215,7 +215,7 @@ extern drmModeFrameBufferPtr drmModeGetFB(int fd, /** * Creates a new framebuffer with an buffer object as its scanout buffer. */ -extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, +extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id); /** * Destroies the given framebuffer. diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 83f8e167..1c1c3006 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1003,12 +1003,13 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, if(!fb) return -EINVAL;; - fb->width = r.width; - fb->height = r.height; - fb->pitch = r.pitch; + fb->width = r.width; + fb->height = r.height; + fb->pitch = r.pitch; fb->bits_per_pixel = r.bpp; - fb->offset = bo->offset; - fb->bo = bo; + fb->depth = r.depth; + fb->offset = bo->offset; + fb->bo = bo; r.buffer_id = fb->id; diff --git a/shared-core/drm.h b/shared-core/drm.h index a5330b28..621b201c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -970,6 +970,7 @@ struct drm_mode_fb_cmd { unsigned int pitch; unsigned int bpp; unsigned int handle; + unsigned int depth; }; /** -- cgit v1.2.3 From 1147fefed8d1154482c9cc9a9785e6871cd6e6a1 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Wed, 11 Apr 2007 17:13:57 +1000 Subject: fixup framebuffer depth --- linux-core/drm_fb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 1fe3e54b..e404642f 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -53,8 +53,6 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno > 17) return 1; - printk(KERN_INFO "Got set col reg %d %d %d %d\n", red, green, blue, regno); - if (regno < 16) { switch (fb->depth) { case 15: @@ -118,6 +116,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) info->fix.smem_len = (8*1024*1024); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_DIRECTCOLOR; + info->fix.accel = FB_ACCEL_NONE; info->fix.type_aux = 0; info->fix.mmio_start = 0; info->fix.mmio_len = 0; @@ -141,12 +140,18 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) info->var.bits_per_pixel = fb->bits_per_pixel; info->var.xoffset = 0; info->var.yoffset = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + info->var.vmode = FB_VMODE_NONINTERLACED; + DRM_DEBUG("fb depth is %d\n", fb->depth); switch(fb->depth) { case 8: case 15: case 16: break; + default: case 24: case 32: info->var.red.offset = 16; -- cgit v1.2.3 From 0392badd84ec833ddd9e2b187844d246d860bbf7 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Wed, 11 Apr 2007 17:25:37 +1000 Subject: oops for 32 pitch.. hey I can see stuff on fbcon now.. it looks like text.. just a bit garbled --- linux-core/drm_fb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index e404642f..30b14188 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -66,6 +66,7 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, ((blue & 0xf800) >> 11); break; case 24: + case 32: fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | (green & 0xff00) | ((blue & 0xff00) >> 8); -- cgit v1.2.3 From 7e48d47fb51cc0f1a38a99acfe591821a45d7081 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Wed, 11 Apr 2007 17:35:00 +1000 Subject: line_length calculation was incorrect.. I now can get fbcon to run --- linux-core/drm_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 30b14188..1a0fb79c 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -121,7 +121,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) info->fix.type_aux = 0; info->fix.mmio_start = 0; info->fix.mmio_len = 0; - info->fix.line_length = fb->pitch; + info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8); info->flags = FBINFO_DEFAULT; -- cgit v1.2.3 From 78598fdaa8b23a199880a63b79f17cfd7f14cb0f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 07:07:54 -0700 Subject: Various changes for in-kernel modesetting: - allow drm_buffer_object_create to be called w/o dev_mapping - fixup i915 init code to allocate memory, fb and set modes right - pass fb to drm_initial_config for setup - change some debug output to make it easier to spot - fixup lvds code to use DDC probing correctly --- linux-core/drm_bo.c | 10 ++++--- linux-core/drm_crtc.c | 40 ++++++++++++++-------------- linux-core/drm_crtc.h | 5 +++- linux-core/intel_display.c | 2 -- linux-core/intel_lvds.c | 21 ++++++++++++--- shared-core/i915_init.c | 65 +++++++++++++++++++++++++++++++++++++++------- 6 files changed, 102 insertions(+), 41 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 17d6fbc0..2107a3a8 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1530,7 +1530,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, return ret; } -int drm_buffer_object_create(drm_file_t * priv, +int drm_buffer_object_create(drm_device_t *dev, unsigned long size, drm_bo_type_t type, uint32_t mask, @@ -1539,7 +1539,6 @@ int drm_buffer_object_create(drm_file_t * priv, unsigned long buffer_start, drm_buffer_object_t ** buf_obj) { - drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; drm_buffer_object_t *bo; int ret = 0; @@ -1615,6 +1614,7 @@ int drm_buffer_object_create(drm_file_t * priv, drm_bo_usage_deref_unlocked(bo); return ret; } +EXPORT_SYMBOL(drm_buffer_object_create); static int drm_bo_add_user_object(drm_file_t * priv, drm_buffer_object_t * bo, int shareable) @@ -1670,7 +1670,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) switch (req->op) { case drm_bo_create: rep.ret = - drm_buffer_object_create(priv, req->size, + drm_buffer_object_create(priv->head->dev, + req->size, req->type, req->mask, req->hint, @@ -2301,6 +2302,9 @@ void drm_bo_unmap_virtual(drm_buffer_object_t * bo) loff_t offset = ((loff_t) bo->map_list.hash.key) << PAGE_SHIFT; loff_t holelen = ((loff_t) bo->mem.num_pages) << PAGE_SHIFT; + if (!dev->dev_mapping) + return; + unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); } diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1c1c3006..b349527d 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -57,6 +57,7 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) return fb; } +EXPORT_SYMBOL(drm_framebuffer_create); void drm_framebuffer_destroy(struct drm_framebuffer *fb) { @@ -493,30 +494,28 @@ out_err: return ret; } -bool drm_initial_config(drm_device_t *dev, bool can_grow) +/** + * drm_initial_config - setup a sane initial output configuration + * @dev: DRM device + * @fb: framebuffer backing for new setup + * @can_grow: this configuration is growable + * + * Scan the CRTCs and outputs and try to put together an initial setup. + * At the moment, this is a cloned configuration across all heads with + * @fb as the backing store. + */ +bool drm_initial_config(drm_device_t *dev, struct drm_framebuffer *fb, + bool can_grow) { /* do a hardcoded initial configuration here */ struct drm_crtc *crtc, *vga_crtc = NULL, *dvi_crtc = NULL, *lvds_crtc = NULL; - struct drm_framebuffer *fb; struct drm_output *output, *use_output = NULL; -#if 0 - fb = drm_framebuffer_create(dev); - if (!fb) - return false; - - fb->pitch = 1024; - fb->width = 1024; - fb->height = 768; - fb->depth = 24; - fb->bits_per_pixel = 32; -#endif - /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - // crtc->fb = fb; + crtc->fb = fb; if (!vga_crtc) { vga_crtc = crtc; crtc->enabled = 1; @@ -527,8 +526,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) crtc->enabled = 1; crtc->desired_x = 0; crtc->desired_y = 0; - } - else if (!dvi_crtc) { + } else if (!dvi_crtc) { dvi_crtc = crtc; crtc->enabled = 1; crtc->desired_x = 0; @@ -536,7 +534,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) } } - drm_crtc_probe_output_modes(dev, 1024, 768); + drm_crtc_probe_output_modes(dev, 2048, 2048); /* hard bind the CRTCS */ @@ -551,20 +549,20 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) } if (!strncmp(output->name, "VGA", 3)) { output->crtc = vga_crtc; - drm_mode_debug_printmodeline(dev, des_mode); + DRM_DEBUG("VGA preferred mode: %s\n", des_mode->name); output->crtc->desired_mode = des_mode; output->initial_x = 0; output->initial_y = 0; use_output = output; } else if (!strncmp(output->name, "TMDS", 4)) { output->crtc = vga_crtc; - drm_mode_debug_printmodeline(dev, des_mode); + DRM_DEBUG("TMDS preferred mode: %s\n", des_mode->name); output->crtc->desired_mode = des_mode; output->initial_x = 0; output->initial_y = 0; } else if (!strncmp(output->name, "LVDS", 3)) { output->crtc = lvds_crtc; - drm_mode_debug_printmodeline(dev, des_mode); + DRM_DEBUG("LVDS preferred mode: %s\n", des_mode->name); output->crtc->desired_mode = des_mode; output->initial_x = 0; output->initial_y = 0; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d5d256d4..54c508c5 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -452,10 +452,13 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); -extern bool drm_initial_config(struct drm_device *dev, bool cangrow); +extern bool drm_initial_config(struct drm_device *dev, + struct drm_framebuffer *fb, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); extern bool drm_set_desired_modes(struct drm_device *dev); +extern int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb); +extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); /* IOCTLs */ extern int drm_mode_getresources(struct inode *inode, struct file *filp, diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 04a6e086..bb6f7f23 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1128,11 +1128,9 @@ static void intel_setup_outputs(drm_device_t *dev) intel_crt_init(dev); -#if 0 /* Set up integrated LVDS */ if (IS_MOBILE(dev) && !IS_I830(dev)) intel_lvds_init(dev); -#endif if (IS_I9XX(dev)) { intel_sdvo_init(dev, SDVOB); diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 90a26109..8ecb204c 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -164,6 +164,7 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, struct intel_crtc *intel_crtc = output->crtc->driver_private; struct drm_output *tmp_output; +#if 0 spin_lock(&dev->mode_config.config_lock); list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) { if (tmp_output != output && tmp_output->crtc == output->crtc) { @@ -173,6 +174,7 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, } } spin_lock(&dev->mode_config.config_lock); +#endif if (intel_crtc->pipe == 0) { printk(KERN_ERR "Can't support LVDS on pipe A\n"); @@ -199,7 +201,7 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, dev_priv->panel_fixed_mode->vsync_end; adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; -// xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V); + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); } /* @@ -272,11 +274,11 @@ static int intel_lvds_get_modes(struct drm_output *output) "failed.\n"); return 0; } - intel_i2c_destroy(intel_output->ddc_bus); ret = intel_ddc_get_modes(output); if (ret) return ret; + intel_i2c_destroy(intel_output->ddc_bus); /* Didn't get an EDID */ if (!output->monitor_info) { @@ -359,19 +361,31 @@ void intel_lvds_init(struct drm_device *dev) output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; + /* Set up the DDC bus. */ + intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return; + } + /* * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ intel_ddc_get_modes(output); + intel_i2c_destroy(intel_output->ddc_bus); list_for_each_entry(scan, &output->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) break; } - if (scan) + if (scan) { dev_priv->panel_fixed_mode = scan; + DRM_DEBUG("LVDS panel_fixed: %s\n", scan->name); + } +#if 0 /* * If we didn't get EDID, try checking if the panel is already turned * on. If so, assume that whatever is currently programmed is the @@ -395,7 +409,6 @@ void intel_lvds_init(struct drm_device *dev) } /* No BIOS poking yet... */ -#if 0 /* Get the LVDS fixed mode out of the BIOS. We should support LVDS * with the BIOS being unavailable or broken, but lack the * configuration options for now. diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 5af86f82..d9fb485b 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -4,10 +4,23 @@ #include "i915_drm.h" #include "i915_drv.h" +/** + * i915_driver_load - setup chip and create an initial config + * @dev: DRM device + * @flags: startup flags + * + * The driver load routine has to do several things: + * - drive output discovery via intel_modeset_init() + * - initialize the memory manager + * - allocate initial config memory + * - setup the DRM framebuffer with the allocated memory + */ int i915_driver_load(drm_device_t *dev, unsigned long flags) { drm_i915_private_t *dev_priv; drm_i915_init_t init; + drm_buffer_object_t *entry; + struct drm_framebuffer *fb; int ret; dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); @@ -45,7 +58,6 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) return ret; } -#if 0 ret = drm_setup(dev); if (ret) { DRM_ERROR("drm_setup failed\n"); @@ -60,17 +72,48 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) return DRM_ERR(EINVAL); } - /* FIXME: where does the sarea_priv really go? */ - // dev_priv->sarea_priv = kmalloc(sizeof(drm_i915_sarea_t), GFP_KERNEL); + /* FIXME: assume sarea_priv is right after SAREA */ + dev_priv->sarea_priv = dev_priv->sarea->handle + sizeof(drm_sarea_t); - /* FIXME: need real front buffer offset */ - /// dev_priv->sarea_priv->front_handle = dev_priv->baseaddr + 1024*1024; -#endif + /* + * Initialize the memory manager for local and AGP space + */ drm_bo_driver_init(dev); - /* this probably doesn't belong here - TODO */ - //drm_framebuffer_set_object(dev, dev_priv->sarea_priv->front_handle); + /* FIXME: initial stolen area 8M init */ +#define SCANOUT_SIZE 1024*1024*8 /* big enough for 2048x1024 32bpp */ + drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, dev->mode_config.fb_base, + SCANOUT_SIZE); + + /* Allocate scanout buffer and command ring */ + /* FIXME: types and other args correct? */ + drm_buffer_object_create(dev, SCANOUT_SIZE, drm_bo_type_dc, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, + 0, PAGE_SIZE, 0, + &entry); + + DRM_DEBUG("allocated bo, start: 0x%lx, offset: 0x%lx\n", + entry->buffer_start, entry->offset); intel_modeset_init(dev); - // drm_set_desired_modes(dev); + + fb = drm_framebuffer_create(dev); + if (!fb) { + DRM_ERROR("failed to allocate fb\n"); + return -EINVAL; + } + + fb->width = 1024; + fb->height = 768; + fb->pitch = 1024; + fb->bits_per_pixel = 32; + fb->depth = 32; + fb->offset = entry->offset; + fb->bo = entry; + + drm_initial_config(dev, fb, false); + drmfb_probe(dev, fb); + drm_set_desired_modes(dev); + #if 0 /* FIXME: command ring needs AGP space, do we own it at this point? */ dev_priv->ring.Start = dev_priv->baseaddr; @@ -133,8 +176,10 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) int i915_driver_unload(drm_device_t *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_framebuffer *fb; - intel_modeset_cleanup(dev); + /* FIXME: remove framebuffer */ + //intel_modeset_cleanup(dev); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; -- cgit v1.2.3 From f35db6690625ccd01fb61dc766e6380a9c14c331 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 07:08:29 -0700 Subject: Fixup DDC probing. We only have one DDC bus so we have to use it only on demand, and unregister when we're done. --- linux-core/intel_crt.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index e62aa8d3..ca7ae7b3 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -180,6 +180,7 @@ static bool intel_crt_detect_ddc(struct drm_output *output) static enum drm_output_status intel_crt_detect(struct drm_output *output) { drm_device_t *dev = output->dev; + struct intel_output *intel_output = output->driver_private; if (IS_I945G(dev)| IS_I945GM(dev) || IS_I965G(dev)) { if (intel_crt_detect_hotplug(output)) @@ -188,21 +189,47 @@ static enum drm_output_status intel_crt_detect(struct drm_output *output) return output_status_disconnected; } - if (intel_crt_detect_ddc(output)) + /* Set up the DDC bus. */ + intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return 0; + } + + if (intel_crt_detect_ddc(output)) { + intel_i2c_destroy(intel_output->ddc_bus); return output_status_connected; + } + intel_i2c_destroy(intel_output->ddc_bus); /* TODO use load detect */ return output_status_unknown; } static void intel_crt_destroy(struct drm_output *output) { + if (output->driver_private) + kfree(output->driver_private); +} + +static int intel_crt_get_modes(struct drm_output *output) +{ + struct drm_device *dev = output->dev; struct intel_output *intel_output = output->driver_private; + int ret; - intel_i2c_destroy(intel_output->ddc_bus); + /* Set up the DDC bus. */ + intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return 0; + } - if (output->driver_private) - kfree(output->driver_private); + ret = intel_ddc_get_modes(output); + intel_i2c_destroy(intel_output->ddc_bus); + return ret; } /* @@ -218,7 +245,7 @@ static const struct drm_output_funcs intel_crt_output_funcs = { .mode_set = intel_crt_mode_set, .commit = intel_output_commit, .detect = intel_crt_detect, - .get_modes = intel_ddc_get_modes, + .get_modes = intel_crt_get_modes, .cleanup = intel_crt_destroy, }; @@ -239,12 +266,4 @@ void intel_crt_init(drm_device_t *dev) output->driver_private = intel_output; output->interlace_allowed = 0; output->doublescan_allowed = 0; - - /* Set up the DDC bus. */ - intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); - if (!intel_output->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " - "failed.\n"); - return; - } } -- cgit v1.2.3 From dd00aa5851ca7c5590ae0b0825dd84c027cfd420 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 07:08:48 -0700 Subject: export vblank routine for use by intel_display.c and intel_sdvo.c. --- linux-core/intel_drv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 0675e069..f47e6233 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -73,5 +73,6 @@ extern void intel_output_prepare (struct drm_output *output); extern void intel_output_commit (struct drm_output *output); extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, struct drm_crtc *crtc); +extern void intel_wait_for_vblank(drm_device_t *dev); #endif /* __INTEL_DRV_H__ */ -- cgit v1.2.3 From cc7faa4de80a68d5a7a484046b9b42de961cdbef Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 07:21:24 -0700 Subject: fix modeset cleanup for LVDS and reenable it in i915. --- linux-core/intel_lvds.c | 3 ++- shared-core/i915_init.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 8ecb204c..ec693275 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -314,7 +314,8 @@ out: static void intel_lvds_destroy(struct drm_output *output) { - drm_output_destroy(output); + if (output->driver_private) + kfree(output->driver_private); } static const struct drm_output_funcs intel_lvds_output_funcs = { diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index d9fb485b..43c535d2 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -179,7 +179,7 @@ int i915_driver_unload(drm_device_t *dev) struct drm_framebuffer *fb; /* FIXME: remove framebuffer */ - //intel_modeset_cleanup(dev); + intel_modeset_cleanup(dev); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; -- cgit v1.2.3 From c731b68091aa7284ee3a89c8a7ea3fdabac45a54 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 11:42:00 -0700 Subject: Fix EDID pixel clock calculation. --- linux-core/drm_edid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index b79bc2db..9acdc8da 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -114,7 +114,7 @@ struct drm_display_mode *drm_mode_detailed(drm_device_t *dev, return NULL; mode->type = DRM_MODE_TYPE_DRIVER; - mode->clock = timing->pixel_clock / 100; + mode->clock = timing->pixel_clock * 10; mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo; mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) | -- cgit v1.2.3 From 425da42e95606fec19cc87fad9329d48f93dfe6b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 11:44:54 -0700 Subject: Whitespace cleanups. --- linux-core/intel_display.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index bb6f7f23..396f4cfa 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -168,18 +168,18 @@ static const intel_limit_t intel_limits[] = { }, }; -static const intel_limit_t *intel_limit (struct drm_crtc *crtc) +static const intel_limit_t *intel_limit(struct drm_crtc *crtc) { drm_device_t *dev = crtc->dev; const intel_limit_t *limit; if (IS_I9XX(dev)) { - if (intel_pipe_has_type (crtc, INTEL_OUTPUT_LVDS)) + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; else limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; } else { - if (intel_pipe_has_type (crtc, INTEL_OUTPUT_LVDS)) + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS]; else limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC]; @@ -280,18 +280,20 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target, { drm_device_t *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; - intel_clock_t clock; - const intel_limit_t *limit = intel_limit (crtc); + intel_clock_t clock; + const intel_limit_t *limit = intel_limit(crtc); int err = target; - if (IS_I9XX(dev)& intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && - (I915_READ(LVDS) & LVDS_PORT_EN) != 0) - { - /* For LVDS, if the panel is on, just rely on its current settings for - * dual-channel. We haven't figured out how to reliably set up - * different single/dual channel state, if we even can. - */ - if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && + (I915_READ(LVDS) & LVDS_PORT_EN) != 0) { + /* + * For LVDS, if the panel is on, just rely on its current + * settings for dual-channel. We haven't figured out how to + * reliably set up different single/dual channel state, if we + * even can. + */ + if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; @@ -304,17 +306,16 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target, memset (best_clock, 0, sizeof (*best_clock)); - for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) - { - for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && clock.m2 <= limit->m2.max; clock.m2++) - { - for (clock.n = limit->n.min; clock.n <= limit->n.max; clock.n++) - { - for (clock.p1 = limit->p1.min; clock.p1 <= limit->p1.max; clock.p1++) - { + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { + for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && + clock.m2 <= limit->m2.max; clock.m2++) { + for (clock.n = limit->n.min; clock.n <= limit->n.max; + clock.n++) { + for (clock.p1 = limit->p1.min; + clock.p1 <= limit->p1.max; clock.p1++) { int this_err; - intel_clock (dev, refclk, &clock); + intel_clock(dev, refclk, &clock); if (!intel_PLL_is_valid(crtc, &clock)) continue; @@ -328,6 +329,7 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target, } } } + return (err != target); } -- cgit v1.2.3 From 63d4d40463b04f1277470ccf5cc96dafd81e8687 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 11:46:37 -0700 Subject: Fix i2c unregistration, cleanup panel_fixed_mode assignment. --- linux-core/intel_lvds.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index ec693275..e8670adc 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -164,7 +164,7 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, struct intel_crtc *intel_crtc = output->crtc->driver_private; struct drm_output *tmp_output; -#if 0 +#if 0 /* FIXME: Check for other outputs on this pipe */ spin_lock(&dev->mode_config.config_lock); list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) { if (tmp_output != output && tmp_output->crtc == output->crtc) { @@ -274,11 +274,11 @@ static int intel_lvds_get_modes(struct drm_output *output) "failed.\n"); return 0; } - ret = intel_ddc_get_modes(output); + intel_i2c_destroy(intel_output->ddc_bus); + if (ret) return ret; - intel_i2c_destroy(intel_output->ddc_bus); /* Didn't get an EDID */ if (!output->monitor_info) { @@ -377,13 +377,11 @@ void intel_lvds_init(struct drm_device *dev) intel_ddc_get_modes(output); intel_i2c_destroy(intel_output->ddc_bus); list_for_each_entry(scan, &output->probed_modes, head) { - if (scan->type & DRM_MODE_TYPE_PREFERRED) + if (scan->type & DRM_MODE_TYPE_PREFERRED) { + dev_priv->panel_fixed_mode = + drm_mode_duplicate(dev, scan); break; - } - - if (scan) { - dev_priv->panel_fixed_mode = scan; - DRM_DEBUG("LVDS panel_fixed: %s\n", scan->name); + } } #if 0 -- cgit v1.2.3 From 8dd75bd601f5fbf9793afc7b869a278050aa17d5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 11:47:58 -0700 Subject: Add aperture size and preallocation probing (from intelfb), cleanup load code to be more general. --- shared-core/i915_drv.h | 21 ++++++++ shared-core/i915_init.c | 132 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 140 insertions(+), 13 deletions(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index b1bf0469..c22ab843 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -318,6 +318,27 @@ extern void intel_modeset_cleanup(drm_device_t *dev); extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); +/* + * The Bridge device's PCI config space has information about the + * fb aperture size and the amount of pre-reserved memory. + */ +#define INTEL_GMCH_CTRL 0x52 +#define INTEL_GMCH_ENABLED 0x4 +#define INTEL_GMCH_MEM_MASK 0x1 +#define INTEL_GMCH_MEM_64M 0x1 +#define INTEL_GMCH_MEM_128M 0 + +#define INTEL_855_GMCH_GMS_MASK (0x7 << 4) +#define INTEL_855_GMCH_GMS_DISABLED (0x0 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_1M (0x1 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_4M (0x2 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_8M (0x3 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_16M (0x4 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_32M (0x5 << 4) + +#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4) +#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4) + #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) #define CMD_REPORT_HEAD (7<<23) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 43c535d2..fba633fd 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -1,9 +1,108 @@ +/* + * Copyright (c) 2007 Intel Corporation + * Jesse Barnes + * + * Copyright © 2002, 2003 David Dawes + * 2004 Sylvain Meyer + * + * GPL/BSD dual license + */ #include "drmP.h" #include "drm.h" #include "drm_sarea.h" #include "i915_drm.h" #include "i915_drv.h" +/** + * i915_probe_agp - get AGP bootup configuration + * @pdev: PCI device + * @aperture_size: returns AGP aperture configured size + * @preallocated_size: returns size of BIOS preallocated AGP space + * + * Since Intel integrated graphics are UMA, the BIOS has to set aside + * some RAM for the framebuffer at early boot. This code figures out + * how much was set aside so we can use it for our own purposes. + */ +int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, + unsigned long *preallocated_size) +{ + struct pci_dev *bridge_dev; + u16 tmp = 0; + unsigned long overhead; + + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!bridge_dev) { + DRM_ERROR("bridge device not found\n"); + return -1; + } + + /* Get the fb aperture size and "stolen" memory amount. */ + pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); + pci_dev_put(bridge_dev); + + *aperture_size = 1024 * 1024; + *preallocated_size = 1024 * 1024; + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_82915G_IG: + case PCI_DEVICE_ID_INTEL_82915GM_IG: + case PCI_DEVICE_ID_INTEL_82945G_IG: + case PCI_DEVICE_ID_INTEL_82945GM_IG: + /* 915 and 945 chipsets support a 256MB aperture. + Aperture size is determined by inspected the + base address of the aperture. */ + if (pci_resource_start(pdev, 2) & 0x08000000) + *aperture_size *= 128; + else + *aperture_size *= 256; + break; + default: + if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) + *aperture_size *= 64; + else + *aperture_size *= 128; + break; + } + + /* + * Some of the preallocated space is taken by the GTT + * and popup. GTT is 1K per MB of aperture size, and popup is 4K. + */ + overhead = (*aperture_size / 1024) + 4096; + switch (tmp & INTEL_855_GMCH_GMS_MASK) { + case INTEL_855_GMCH_GMS_STOLEN_1M: + break; /* 1M already */ + case INTEL_855_GMCH_GMS_STOLEN_4M: + *preallocated_size *= 4; + break; + case INTEL_855_GMCH_GMS_STOLEN_8M: + *preallocated_size *= 8; + break; + case INTEL_855_GMCH_GMS_STOLEN_16M: + *preallocated_size *= 16; + break; + case INTEL_855_GMCH_GMS_STOLEN_32M: + *preallocated_size *= 32; + break; + case INTEL_915G_GMCH_GMS_STOLEN_48M: + *preallocated_size *= 48; + break; + case INTEL_915G_GMCH_GMS_STOLEN_64M: + *preallocated_size *= 64; + break; + case INTEL_855_GMCH_GMS_DISABLED: + DRM_ERROR("video memory is disabled\n"); + return -1; + default: + DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", + tmp & INTEL_855_GMCH_GMS_MASK); + return -1; + } + *preallocated_size -= overhead; + + return 0; +} + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -21,7 +120,8 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_i915_init_t init; drm_buffer_object_t *entry; struct drm_framebuffer *fb; - int ret; + unsigned long agp_size, prealloc_size; + int hsize, vsize, bytes_per_pixel, size, ret; dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) @@ -41,11 +141,13 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) if (IS_I9XX(dev)) { dev_priv->mmiobase = drm_get_resource_start(dev, 0); dev_priv->mmiolen = drm_get_resource_len(dev, 0); - dev->mode_config.fb_base = dev_priv->baseaddr = drm_get_resource_start(dev, 2) & 0xff000000; + dev->mode_config.fb_base = dev_priv->baseaddr = + drm_get_resource_start(dev, 2) & 0xff000000; } else if (drm_get_resource_start(dev, 1)) { dev_priv->mmiobase = drm_get_resource_start(dev, 1); dev_priv->mmiolen = drm_get_resource_len(dev, 1); - dev->mode_config.fb_base = dev_priv->baseaddr = drm_get_resource_start(dev, 0) & 0xff000000; + dev->mode_config.fb_base = dev_priv->baseaddr = + drm_get_resource_start(dev, 0) & 0xff000000; } else { DRM_ERROR("Unable to find MMIO registers\n"); return -ENODEV; @@ -79,14 +181,18 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) * Initialize the memory manager for local and AGP space */ drm_bo_driver_init(dev); - /* FIXME: initial stolen area 8M init */ -#define SCANOUT_SIZE 1024*1024*8 /* big enough for 2048x1024 32bpp */ - drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, dev->mode_config.fb_base, - SCANOUT_SIZE); + + i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); + drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, dev_priv->baseaddr, + prealloc_size); /* Allocate scanout buffer and command ring */ /* FIXME: types and other args correct? */ - drm_buffer_object_create(dev, SCANOUT_SIZE, drm_bo_type_dc, + hsize = 1280; + vsize = 800; + bytes_per_pixel = 4; + size = hsize * vsize * bytes_per_pixel; + drm_buffer_object_create(dev, size, drm_bo_type_dc, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, 0, PAGE_SIZE, 0, @@ -102,11 +208,11 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) return -EINVAL; } - fb->width = 1024; - fb->height = 768; - fb->pitch = 1024; - fb->bits_per_pixel = 32; - fb->depth = 32; + fb->width = hsize; + fb->height = vsize; + fb->pitch = hsize; + fb->bits_per_pixel = bytes_per_pixel * 8; + fb->depth = bytes_per_pixel * 8; fb->offset = entry->offset; fb->bo = entry; -- cgit v1.2.3 From 2e21779992bd5026d8ec4dea52466377dbe5a0ed Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 12:51:52 -0700 Subject: Add new buffer object type for kernel allocations that don't initially have a user mapping. --- linux-core/drm_bo.c | 17 ++++++++++++++--- shared-core/drm.h | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 2107a3a8..a379c741 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -89,6 +89,9 @@ static int drm_bo_vm_pre_move(drm_buffer_object_t * bo, int old_is_pci) #ifdef DRM_ODD_MM_COMPAT int ret; + if (!bo->map_list.map) + return 0; + ret = drm_bo_lock_kmm(bo); if (ret) return ret; @@ -96,6 +99,9 @@ static int drm_bo_vm_pre_move(drm_buffer_object_t * bo, int old_is_pci) if (old_is_pci) drm_bo_finish_unmap(bo); #else + if (!bo->map_list.map) + return 0; + drm_bo_unmap_virtual(bo); #endif return 0; @@ -106,6 +112,9 @@ static void drm_bo_vm_post_move(drm_buffer_object_t * bo) #ifdef DRM_ODD_MM_COMPAT int ret; + if (!bo->map_list.map) + return; + ret = drm_bo_remap_bound(bo); if (ret) { DRM_ERROR("Failed to remap a bound buffer object.\n" @@ -131,6 +140,11 @@ static int drm_bo_add_ttm(drm_buffer_object_t * bo) if (!bo->ttm) ret = -ENOMEM; break; + case drm_bo_type_kernel: + bo->ttm = drm_ttm_init(dev, bo->mem.num_pages << PAGE_SHIFT); + if (!bo->ttm) + ret = -ENOMEM; + break; case drm_bo_type_user: case drm_bo_type_fake: break; @@ -2302,9 +2316,6 @@ void drm_bo_unmap_virtual(drm_buffer_object_t * bo) loff_t offset = ((loff_t) bo->map_list.hash.key) << PAGE_SHIFT; loff_t holelen = ((loff_t) bo->mem.num_pages) << PAGE_SHIFT; - if (!dev->dev_mapping) - return; - unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); } diff --git a/shared-core/drm.h b/shared-core/drm.h index 621b201c..698f851b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -795,6 +795,7 @@ typedef struct drm_fence_arg { typedef enum { drm_bo_type_dc, + drm_bo_type_kernel, /* for initial kernel allocations */ drm_bo_type_user, drm_bo_type_fake }drm_bo_type_t; -- cgit v1.2.3 From 9d7160c43a7475b9d2ab06c5c353acb9456efa12 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 12:52:57 -0700 Subject: Use new kernel buffer object type and cleanup agp probing. --- shared-core/i915_init.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index fba633fd..b942b70f 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -44,24 +44,19 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, *preallocated_size = 1024 * 1024; switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_82915G_IG: - case PCI_DEVICE_ID_INTEL_82915GM_IG: - case PCI_DEVICE_ID_INTEL_82945G_IG: - case PCI_DEVICE_ID_INTEL_82945GM_IG: - /* 915 and 945 chipsets support a 256MB aperture. - Aperture size is determined by inspected the - base address of the aperture. */ - if (pci_resource_start(pdev, 2) & 0x08000000) - *aperture_size *= 128; - else - *aperture_size *= 256; - break; - default: + case PCI_DEVICE_ID_INTEL_82830_CGC: + case PCI_DEVICE_ID_INTEL_82845G_HB: + case PCI_DEVICE_ID_INTEL_82855GM_IG: + case PCI_DEVICE_ID_INTEL_82865_IG: if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) *aperture_size *= 64; else *aperture_size *= 128; break; + default: + /* 9xx supports large sizes, just look at the length */ + *aperture_size = pci_resource_len(pdev, 2); + break; } /* @@ -192,7 +187,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) vsize = 800; bytes_per_pixel = 4; size = hsize * vsize * bytes_per_pixel; - drm_buffer_object_create(dev, size, drm_bo_type_dc, + drm_buffer_object_create(dev, size, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, 0, PAGE_SIZE, 0, -- cgit v1.2.3 From a81558d8b3ee17fbf46e32b10732e22fcd997858 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Apr 2007 08:45:40 +1000 Subject: add getfb ioctl --- libdrm/xf86drmMode.c | 52 +++++++++++++++++---------------------------------- libdrm/xf86drmMode.h | 15 ++++----------- linux-core/drm_crtc.c | 30 +++++++++++++++++++++++++++++ linux-core/drm_crtc.h | 2 ++ linux-core/drm_drv.c | 1 + shared-core/drm.h | 1 + 6 files changed, 55 insertions(+), 46 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 04fb07dc..6070ec6f 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -215,51 +215,33 @@ int drmModeRmFB(int fd, uint32_t bufferId) return ioctl(fd, DRM_IOCTL_MODE_RMFB, bufferId); } -#if 0 -int drmModeForceProbe(int fd, uint32_t outputId) -{ - /* TODO impl/keep? */ -} - -drmModeFrameBufferPtr drmModeGetFrameBuffer(int fd, uint32_t buf) +drmModeFrameBufferPtr drmModeGetFB(int fd, uint32_t buf) { -// struct drm_mode_fb_cmd info; + struct drm_mode_fb_cmd info; drmModeFrameBufferPtr r; - // if (ioctl(fd, DRM_IOCTL_MODE_GETFRAMEBUFFER, &info)) - return 0; + info.buffer_id = buf; + + if (ioctl(fd, DRM_IOCTL_MODE_GETFB, &info)) + return NULL; if (!(r = drmMalloc(sizeof(*r)))) - return 0; + return NULL; - /* TODO change to new code - r->minWidth = info.minWidth; - r->maxWidth = info.maxWidth; - r->minHeight = info.minHeight; - r->maxHeight = info.maxHeight;*/ + r->buffer_id = info.buffer_id; + r->width = info.width; + r->height = info.height; + r->pitch = info.pitch; + r->bpp = info.bpp; + r->handle = info.handle; + r->depth = info.depth; return r; } - -uint32_t drmModeNewFrameBuffer(int fd, uint32_t width, uint32_t height, - uint8_t bpp, uint32_t pitch, drmBO *bo) -{ - drm_mode_fb_cmd_t f; - - f.handle = bo->handle; - f.width = width; - f.height = height; - f.pitch = pitch; - - // if (ioctl(fd, DRM_IOCTL_MODE_NEWFRAMEBUFFER, &f)) - return 0; - - return f.bufferId; -} - -int drmModeDesFrameBuffer(int fd, uint32_t bufferId) +#if 0 +int drmModeForceProbe(int fd, uint32_t outputId) { - // return ioctl(fd, DRM_IOCTL_MODE_DESFRAMEBUFFER, bufferId); + /* TODO impl/keep? */ } #endif diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index cdc82f7d..6a566c4d 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -76,14 +76,7 @@ typedef struct _drmModeRes { } drmModeRes, *drmModeResPtr; -typedef struct _drmModeFrameBuffer { - - uint32_t width; - uint32_t height; - uint32_t pitch; - uint8_t bpp; - -} drmModeFrameBuffer, *drmModeFrameBufferPtr; +typedef struct drm_mode_fb_cmd drmModeFrameBuffer, *drmModeFrameBufferPtr; typedef struct _drmModeCrtc { @@ -209,14 +202,14 @@ extern int drmModeForceProbe(int fd, uint32_t outputId); /** * Retrive information about framebuffer bufferId */ -extern drmModeFrameBufferPtr drmModeGetFB(int fd, - uint32_t bufferId); +extern drmModeFrameBufferPtr drmModeGetFB(int fd, uint32_t bufferId); /** * Creates a new framebuffer with an buffer object as its scanout buffer. */ extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, - uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id); + uint8_t bpp, uint32_t pitch, drmBO *bo, + uint32_t *buf_id); /** * Destroies the given framebuffer. */ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index b349527d..d1f3c077 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1058,3 +1058,33 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, return 0; } +int drm_mode_getfb(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_fb_cmd __user *argp = (void __user *)arg; + struct drm_mode_fb_cmd r; + struct drm_framebuffer *fb; + + if (copy_from_user(&r, argp, sizeof(r))) + return -EFAULT; + + fb = idr_find(&dev->mode_config.crtc_idr, r.buffer_id); + if (!fb || (r.buffer_id != fb->id)) { + DRM_ERROR("invalid framebuffer id\n"); + return -EINVAL; + } + + r.height = fb->height; + r.width = fb->width; + r.depth = fb->depth; + r.bpp = fb->bits_per_pixel; + r.handle = fb->bo->base.hash.key; + r.pitch = fb->pitch; + + if (copy_to_user(argp, &r, sizeof(r))) + return -EFAULT; + + return 0; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 54c508c5..c02dcedc 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -474,5 +474,7 @@ extern int drm_mode_addfb(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_mode_rmfb(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int drm_mode_getfb(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index b43af328..b7a7aded 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -129,6 +129,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_MODE_SETCRTC)] = {drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB)] = {drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MODE_RMFB)] = {drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETFB)] = {drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index 698f851b..b5b0aa52 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1051,6 +1051,7 @@ struct drm_mode_fb_cmd { #define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc) #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xA4, struct drm_mode_fb_cmd) #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) +#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) /*@}*/ /** -- cgit v1.2.3 From 981f8156de0c5ec6387f659fbcac031d663d943c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Apr 2007 08:54:31 +1000 Subject: allow framebuffer changes on the crtc setup --- libdrm/xf86drmMode.c | 2 +- libdrm/xf86drmMode.h | 2 +- linux-core/drm_crtc.c | 22 ++++++++++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 6070ec6f..cb534678 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -276,7 +276,7 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) r->mode = crtc.mode; // r->width = crtc.width; // r->height = crtc.height; - r->bufferId = crtc.fb_id; + r->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; r->count_outputs = crtc.count_outputs; r->count_possibles = crtc.count_possibles; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 6a566c4d..c87a95da 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -80,7 +80,7 @@ typedef struct drm_mode_fb_cmd drmModeFrameBuffer, *drmModeFrameBufferPtr; typedef struct _drmModeCrtc { - unsigned int bufferId; /**< Buffer currently connected to */ + unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/ uint32_t x, y; /**< Position on the frameuffer */ uint32_t width, height; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index d1f3c077..21d7012e 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -590,7 +590,7 @@ void drm_mode_config_cleanup(drm_device_t *dev) } EXPORT_SYMBOL(drm_mode_config_cleanup); -int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set) +int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set, struct drm_framebuffer *fb) { drm_device_t *dev = crtc->dev; struct drm_crtc **save_crtcs, *new_crtc; @@ -603,6 +603,9 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, if (!save_crtcs) return -ENOMEM; + if (crtc->fb != fb) + changed = true; + if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) changed = true; @@ -629,6 +632,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, } if (changed) { + crtc->fb = fb; crtc->enabled = (new_mode != NULL); if (new_mode != NULL) { DRM_DEBUG("attempting to set mode from userspace\n"); @@ -897,6 +901,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, struct drm_crtc *crtc; struct drm_output **output_set = NULL, *output; struct drm_display_mode *mode; + struct drm_framebuffer *fb = NULL; int retcode = 0; int i; @@ -911,6 +916,15 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, } if (crtc_req.mode) { + + /* if we have a mode we need a framebuffer */ + if (crtc_req.fb_id) { + fb = idr_find(&dev->mode_config.crtc_idr, crtc_req.fb_id); + if (!fb || (fb->id != crtc_req.fb_id)) { + DRM_DEBUG("Unknown FB ID%d\n", crtc_req.fb_id); + return -EINVAL; + } + } mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode); if (!mode || (mode->mode_id != crtc_req.mode)) { @@ -935,8 +949,8 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, return -EINVAL; } - if (crtc_req.count_outputs > 0 && !mode) { - DRM_DEBUG("Count outputs is %d but no mode set\n", crtc_req.count_outputs); + if (crtc_req.count_outputs > 0 && !mode && !fb) { + DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req.count_outputs); return -EINVAL; } @@ -960,7 +974,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, } } - retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set); + retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb); return retcode; } -- cgit v1.2.3 From a5cf4cc369fcc2cf7b84bbaef1e458250ecb91ee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Apr 2007 11:28:55 +1000 Subject: fix unbalanced lock and make sure mode list has modes so lvds code doesn't crash --- linux-core/drm_crtc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 21d7012e..63ad829d 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -37,6 +37,7 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) spin_lock(&dev->mode_config.config_lock); /* Limit to single framebuffer for now */ if (dev->mode_config.num_fb > 1) { + spin_unlock(&dev->mode_config.config_lock); DRM_ERROR("Attempt to add multiple framebuffers failed\n"); return NULL; } @@ -542,6 +543,9 @@ bool drm_initial_config(drm_device_t *dev, struct drm_framebuffer *fb, list_for_each_entry(output, &dev->mode_config.output_list, head) { struct drm_display_mode *des_mode; + if (list_empty(&output->modes)) + continue; + /* Get the first preferred moded */ list_for_each_entry(des_mode, &output->modes, head) { if (des_mode->flags & DRM_MODE_TYPE_PREFERRED) -- cgit v1.2.3 From b49b3ba4c1aad0d3f34f06013f2ffa67fc8d82c9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Apr 2007 11:43:13 +1000 Subject: set bracing style like Linux --- linux-core/drm_crtc.c | 24 +++++++++--------------- linux-core/intel_display.c | 21 +++++++-------------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 63ad829d..259ea1b8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -254,8 +254,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ crtc->funcs->commit(crtc); list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == crtc) - { + if (output->crtc == crtc) { output->funcs->commit(output); #if 0 // TODO def RANDR_12_INTERFACE if (output->randr_output) @@ -624,8 +623,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, else new_crtc = output->crtc; - for (ro = 0; ro < crtc_info->count_outputs; ro++) - { + for (ro = 0; ro < crtc_info->count_outputs; ro++) { if (output_set[ro] == output) new_crtc = crtc; } @@ -913,8 +911,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, return -EFAULT; crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id); - if (!crtc || (crtc->id != crtc_req.crtc_id)) - { + if (!crtc || (crtc->id != crtc_req.crtc_id)) { DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req.crtc_id); return -EINVAL; } @@ -930,15 +927,12 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, } } mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode); - if (!mode || (mode->mode_id != crtc_req.mode)) - { - { - struct drm_output *output; - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - list_for_each_entry(mode, &output->modes, head) { - drm_mode_debug_printmodeline(dev, mode); - } + if (!mode || (mode->mode_id != crtc_req.mode)) { + struct drm_output *output; + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(mode, &output->modes, head) { + drm_mode_debug_printmodeline(dev, mode); } } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 396f4cfa..aed86231 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -412,8 +412,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) case DPMSModeSuspend: /* Enable the DPLL */ temp = I915_READ(dpll_reg); - if ((temp & DPLL_VCO_ENABLE) == 0) - { + if ((temp & DPLL_VCO_ENABLE) == 0) { I915_WRITE(dpll_reg, temp); I915_READ(dpll_reg); /* Wait for the clocks to stabilize. */ @@ -435,8 +434,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) /* Enable the plane */ temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) - { + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); /* Flush the plane changes */ I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); @@ -456,8 +454,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) /* Disable display plane */ temp = I915_READ(dspcntr_reg); - if ((temp & DISPLAY_PLANE_ENABLE) != 0) - { + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); /* Flush the plane changes */ I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); @@ -719,11 +716,9 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLLB_MODE_LVDS; else dpll |= DPLLB_MODE_DAC_SERIAL; - if (is_sdvo) - { + if (is_sdvo) { dpll |= DPLL_DVO_HIGH_SPEED; - if (IS_I945G(dev) || IS_I945GM(dev)) - { + if (IS_I945G(dev) || IS_I945GM(dev)) { int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; } @@ -760,8 +755,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, } } - if (is_tv) - { + if (is_tv) { /* XXX: just matching BIOS for now */ /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ dpll |= 3; @@ -801,8 +795,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, dspcntr |= DISPPLANE_SEL_PIPE_B; pipeconf = I915_READ(pipeconf_reg); - if (pipe == 0 && !IS_I965G(dev)) - { + if (pipe == 0 && !IS_I965G(dev)) { /* Enable pixel doubling when the dot clock is > 90% of the (display) * core speed. * -- cgit v1.2.3 From fb6c5aacb9955248300e0c62f68a5a65b40e15e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Apr 2007 11:54:49 +1000 Subject: only initialise modes when fbcon or fbset asks for it --- linux-core/drm_fb.c | 10 ++++++++++ shared-core/i915_init.c | 2 -- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 1a0fb79c..a70e4d52 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -77,6 +77,15 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +/* this will let fbcon do the mode init */ +static int drmfb_set_par(struct fb_info *info) +{ + struct drmfb_par *par = info->par; + struct drm_device *dev = par->dev; + + drm_set_desired_modes(dev); +} + static struct fb_ops drmfb_ops = { .owner = THIS_MODULE, // .fb_open = drmfb_open, @@ -84,6 +93,7 @@ static struct fb_ops drmfb_ops = { // .fb_write = drmfb_write, // .fb_release = drmfb_release, // .fb_ioctl = drmfb_ioctl, + .fb_set_par = drmfb_set_par, .fb_setcolreg = drmfb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index b942b70f..ebe73815 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -213,8 +213,6 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_initial_config(dev, fb, false); drmfb_probe(dev, fb); - drm_set_desired_modes(dev); - #if 0 /* FIXME: command ring needs AGP space, do we own it at this point? */ dev_priv->ring.Start = dev_priv->baseaddr; -- cgit v1.2.3 From 1bba3cb3b37ca9bc302d83377c1e9d5441653d0d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Apr 2007 11:55:10 +1000 Subject: cleanup framebuffers on drm unload --- linux-core/drm_crtc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 259ea1b8..2f140dbd 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -582,7 +582,7 @@ void drm_mode_config_cleanup(drm_device_t *dev) { struct drm_output *output, *ot; struct drm_crtc *crtc, *ct; - + struct drm_crtc *fb, *fbt; list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_output_destroy(output); } @@ -590,6 +590,11 @@ void drm_mode_config_cleanup(drm_device_t *dev) list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { drm_crtc_destroy(crtc); } + + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { + drmfb_remove(dev, fb); + drm_framebuffer_destroy(fb); + } } EXPORT_SYMBOL(drm_mode_config_cleanup); -- cgit v1.2.3 From b1f0fd6dfbd1495aa08c6358e936582eeca042c8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Apr 2007 12:11:58 +1000 Subject: use FB everywhere --- libdrm/xf86drmMode.c | 6 +++--- libdrm/xf86drmMode.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index cb534678..b695467b 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -106,7 +106,7 @@ void drmModeFreeResources(drmModeResPtr ptr) } -void drmModeFreeFrameBuffer(drmModeFrameBufferPtr ptr) +void drmModeFreeFB(drmModeFBPtr ptr) { if (!ptr) return; @@ -215,10 +215,10 @@ int drmModeRmFB(int fd, uint32_t bufferId) return ioctl(fd, DRM_IOCTL_MODE_RMFB, bufferId); } -drmModeFrameBufferPtr drmModeGetFB(int fd, uint32_t buf) +drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) { struct drm_mode_fb_cmd info; - drmModeFrameBufferPtr r; + drmModeFBPtr r; info.buffer_id = buf; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index c87a95da..6aa104a9 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -76,7 +76,7 @@ typedef struct _drmModeRes { } drmModeRes, *drmModeResPtr; -typedef struct drm_mode_fb_cmd drmModeFrameBuffer, *drmModeFrameBufferPtr; +typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr; typedef struct _drmModeCrtc { @@ -180,7 +180,7 @@ typedef struct _drmModeOutput { extern void drmModeFreeModeInfo( struct drm_mode_modeinfo *ptr ); extern void drmModeFreeResources( drmModeResPtr ptr ); -extern void drmModeFreeFrameBuffer( drmModeFrameBufferPtr ptr ); +extern void drmModeFreeFB( drmModeFBPtr ptr ); extern void drmModeFreeCrtc( drmModeCrtcPtr ptr ); extern void drmModeFreeOutput( drmModeOutputPtr ptr ); @@ -202,7 +202,7 @@ extern int drmModeForceProbe(int fd, uint32_t outputId); /** * Retrive information about framebuffer bufferId */ -extern drmModeFrameBufferPtr drmModeGetFB(int fd, uint32_t bufferId); +extern drmModeFBPtr drmModeGetFB(int fd, uint32_t bufferId); /** * Creates a new framebuffer with an buffer object as its scanout buffer. -- cgit v1.2.3 From 0430a80fc7861a3397a3f2649dfeb9eff14359a5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2007 20:41:27 -0700 Subject: Remove debug statement about buffer objects --- shared-core/i915_init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index b942b70f..7616b33e 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -193,8 +193,6 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) 0, PAGE_SIZE, 0, &entry); - DRM_DEBUG("allocated bo, start: 0x%lx, offset: 0x%lx\n", - entry->buffer_start, entry->offset); intel_modeset_init(dev); fb = drm_framebuffer_create(dev); -- cgit v1.2.3 From a85440c8a6cac3de4b0e50805fa30cdce40e311b Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 12 Apr 2007 15:11:38 +0100 Subject: Remove extraneous drm_crtc.h include --- linux-core/drmP.h | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index ac0bd767..0d0ec992 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -75,7 +75,6 @@ #include #include #include "drm.h" -#include "drm_crtc.h" #include #define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) -- cgit v1.2.3 From cf016891435a0aa74dc4909ed4125c7ed906b7d1 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 12 Apr 2007 15:12:00 +0100 Subject: Use drm_framebuffer instead of drm_crtc for fb & fbt --- linux-core/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 2f140dbd..ef025922 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -582,7 +582,7 @@ void drm_mode_config_cleanup(drm_device_t *dev) { struct drm_output *output, *ot; struct drm_crtc *crtc, *ct; - struct drm_crtc *fb, *fbt; + struct drm_framebuffer *fb, *fbt; list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_output_destroy(output); } -- cgit v1.2.3 From f2e3d790ac05b2792e795f47fee32fe896a096cc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 08:53:03 -0700 Subject: Revert "Export drm_setup for use by new driver init code.", we don't really want to use this function This reverts commit e114b981bc291049fa6996d487334a408acc1ce2. --- linux-core/drm_fops.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 6f0465fd..d400a4d5 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -41,7 +41,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t * dev); -int drm_setup(drm_device_t * dev) +static int drm_setup(drm_device_t * dev) { drm_local_map_t *map; int i; @@ -121,7 +121,6 @@ int drm_setup(drm_device_t * dev) return 0; } -EXPORT_SYMBOL(drm_setup); /** * Open file. -- cgit v1.2.3 From 258e1cf70345198209e6d49a428efc3de8ce8238 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 08:56:34 -0700 Subject: Whitespace cleanup --- linux-core/drm_modes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 14c7acd5..df34fc27 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -146,7 +146,8 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo); * Just allocate a new mode, copy the existing mode into it, and return * a pointer to it. Used to create new instances of established modes. */ -struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *mode) +struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, + struct drm_display_mode *mode) { struct drm_display_mode *nmode; int new_id; -- cgit v1.2.3 From c2fce380c26d72f2d7971a4d08076da33c41f5ae Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 08:57:58 -0700 Subject: Move i2c init back to where it belongs and add i2c unregistration in *_destroy. --- linux-core/intel_crt.c | 36 +++++++++++++----------------------- linux-core/intel_lvds.c | 20 ++++++++++++-------- 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index ca7ae7b3..fe846eb8 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -189,26 +189,19 @@ static enum drm_output_status intel_crt_detect(struct drm_output *output) return output_status_disconnected; } - /* Set up the DDC bus. */ - intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); - if (!intel_output->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " - "failed.\n"); - return 0; - } - - if (intel_crt_detect_ddc(output)) { - intel_i2c_destroy(intel_output->ddc_bus); + if (intel_crt_detect_ddc(output)) return output_status_connected; - } - intel_i2c_destroy(intel_output->ddc_bus); /* TODO use load detect */ return output_status_unknown; } static void intel_crt_destroy(struct drm_output *output) { + struct intel_output *intel_output = output->driver_private; + + intel_i2c_destroy(intel_output->ddc_bus); + if (output->driver_private) kfree(output->driver_private); } @@ -219,17 +212,7 @@ static int intel_crt_get_modes(struct drm_output *output) struct intel_output *intel_output = output->driver_private; int ret; - /* Set up the DDC bus. */ - intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); - if (!intel_output->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " - "failed.\n"); - return 0; - } - - ret = intel_ddc_get_modes(output); - intel_i2c_destroy(intel_output->ddc_bus); - return ret; + return intel_ddc_get_modes(output); } /* @@ -261,6 +244,13 @@ void intel_crt_init(drm_device_t *dev) drm_output_destroy(output); return; } + /* Set up the DDC bus. */ + intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (!intel_output->ddc_bus) { + dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " + "failed.\n"); + return; + } intel_output->type = INTEL_OUTPUT_ANALOG; output->driver_private = intel_output; diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index e8670adc..d2725e21 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -268,14 +268,7 @@ static int intel_lvds_get_modes(struct drm_output *output) struct edid *edid_info; int ret = 0; - intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); - if (!intel_output->ddc_bus) { - dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " - "failed.\n"); - return 0; - } ret = intel_ddc_get_modes(output); - intel_i2c_destroy(intel_output->ddc_bus); if (ret) return ret; @@ -312,8 +305,19 @@ out: return 0; } +/** + * intel_lvds_destroy - unregister and free LVDS structures + * @output: output to free + * + * Unregister the DDC bus for this output then free the driver private + * structure. + */ static void intel_lvds_destroy(struct drm_output *output) { + struct intel_output *intel_output = output->driver_private; + + intel_i2c_destroy(intel_output->ddc_bus); + if (output->driver_private) kfree(output->driver_private); } @@ -375,7 +379,7 @@ void intel_lvds_init(struct drm_device *dev) * preferred mode is the right one. */ intel_ddc_get_modes(output); - intel_i2c_destroy(intel_output->ddc_bus); + list_for_each_entry(scan, &output->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { dev_priv->panel_fixed_mode = -- cgit v1.2.3 From 2160e267ff3e1a503ab7666b60ffe21f4a90b803 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 09:01:53 -0700 Subject: Don't use drm_setup, do SAREA allocation and mapping directly instead. --- shared-core/i915_init.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 1a8af0ab..687eaa4b 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -114,8 +114,10 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_i915_private_t *dev_priv; drm_i915_init_t init; drm_buffer_object_t *entry; + drm_local_map_t *map; struct drm_framebuffer *fb; unsigned long agp_size, prealloc_size; + unsigned long sareapage; int hsize, vsize, bytes_per_pixel, size, ret; dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); @@ -155,9 +157,12 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) return ret; } - ret = drm_setup(dev); + /* prebuild the SAREA */ + sareapage = max(SAREA_MAX, PAGE_SIZE); + ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, + &map); if (ret) { - DRM_ERROR("drm_setup failed\n"); + DRM_ERROR("SAREA setup failed\n"); return ret; } -- cgit v1.2.3 From e183a091ff44e5b03ec521696830c45b2ce9ce87 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 11:40:12 -0700 Subject: Initialize the hw lock waitqueue so we don't hang in drm_lastclose. --- shared-core/i915_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 687eaa4b..f0ab4574 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -173,6 +173,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) i915_dma_cleanup(dev); return DRM_ERR(EINVAL); } + init_waitqueue_head(&dev->lock.lock_queue); /* FIXME: assume sarea_priv is right after SAREA */ dev_priv->sarea_priv = dev_priv->sarea->handle + sizeof(drm_sarea_t); @@ -280,7 +281,6 @@ int i915_driver_unload(drm_device_t *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_framebuffer *fb; - /* FIXME: remove framebuffer */ intel_modeset_cleanup(dev); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); -- cgit v1.2.3 From fb3c82f1d8362a0b7d64cb3bce75be8c72328e1c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 11:50:57 -0700 Subject: Don't need a NULL check prior to calling kfree. --- linux-core/intel_crt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index fe846eb8..ebf6e469 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -201,9 +201,7 @@ static void intel_crt_destroy(struct drm_output *output) struct intel_output *intel_output = output->driver_private; intel_i2c_destroy(intel_output->ddc_bus); - - if (output->driver_private) - kfree(output->driver_private); + kfree(output->driver_private); } static int intel_crt_get_modes(struct drm_output *output) -- cgit v1.2.3 From 9e5d61d5b8c052b4dc126b155dca1f0d2e4e5ad9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 12:40:51 -0700 Subject: Fix 945+ hotplug detection, remove some unused variables. --- linux-core/intel_crt.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index ebf6e469..86eaff54 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -140,30 +140,25 @@ static void intel_crt_mode_set(struct drm_output *output, static bool intel_crt_detect_hotplug(struct drm_output *output) { drm_device_t *dev = output->dev; -// struct intel_output *intel_output = output->driver_private; drm_i915_private_t *dev_priv = dev->dev_private; u32 temp; -// const int timeout_ms = 1000; -// int starttime, curtime; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); temp = I915_READ(PORT_HOTPLUG_EN); - I915_WRITE(PORT_HOTPLUG_EN, temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5)); -#if 0 - for (curtime = starttime = GetTimeInMillis(); - (curtime - starttime) < timeout_ms; curtime = GetTimeInMillis()) - { - if ((I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT) == 0) + I915_WRITE(PORT_HOTPLUG_EN, + temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5)); + + do { + if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT)) break; - } -#endif + } while (time_after(timeout, jiffies)); + if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) == CRT_HOTPLUG_MONITOR_COLOR) - { return true; - } else { - return false; - } + + return false; } static bool intel_crt_detect_ddc(struct drm_output *output) @@ -180,7 +175,6 @@ static bool intel_crt_detect_ddc(struct drm_output *output) static enum drm_output_status intel_crt_detect(struct drm_output *output) { drm_device_t *dev = output->dev; - struct intel_output *intel_output = output->driver_private; if (IS_I945G(dev)| IS_I945GM(dev) || IS_I965G(dev)) { if (intel_crt_detect_hotplug(output)) @@ -206,10 +200,6 @@ static void intel_crt_destroy(struct drm_output *output) static int intel_crt_get_modes(struct drm_output *output) { - struct drm_device *dev = output->dev; - struct intel_output *intel_output = output->driver_private; - int ret; - return intel_ddc_get_modes(output); } -- cgit v1.2.3 From 6b229c1e59e8d070e1822030f8f0c1d61140508d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 12:41:56 -0700 Subject: Add new function for getting a CRTC pointer given a pipe number. --- linux-core/intel_display.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index aed86231..e58b31b0 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1101,6 +1101,18 @@ void intel_crtc_init(drm_device_t *dev, int pipe) crtc->driver_private = intel_crtc; } +struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe) +{ + struct drm_crtc *crtc = NULL; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = crtc->driver_private; + if (intel_crtc->pipe == pipe) + break; + } + return crtc; +} + int intel_output_clones(drm_device_t *dev, int type_mask) { int index_mask = 0; -- cgit v1.2.3 From 9a39cb9b9a51516abcaf795fa6e38cbeb22d7db9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 12:43:47 -0700 Subject: Use crtc_from_pipe call in intel_lvds.c and add get_mode panel mode detection. Also fix up error case for when LVDS mode can't be determined. Leave placeholder code in place for BIOS mode probing and platform quirks. --- linux-core/intel_drv.h | 1 + linux-core/intel_lvds.c | 71 +++++++++++++++++++++++++++---------------------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index f47e6233..aa33437d 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -74,5 +74,6 @@ extern void intel_output_commit (struct drm_output *output); extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, struct drm_crtc *crtc); extern void intel_wait_for_vblank(drm_device_t *dev); +extern struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe); #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index d2725e21..4020ec6e 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -164,8 +164,6 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, struct intel_crtc *intel_crtc = output->crtc->driver_private; struct drm_output *tmp_output; -#if 0 /* FIXME: Check for other outputs on this pipe */ - spin_lock(&dev->mode_config.config_lock); list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) { if (tmp_output != output && tmp_output->crtc == output->crtc) { printk(KERN_ERR "Can't enable LVDS and another " @@ -173,8 +171,6 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, return false; } } - spin_lock(&dev->mode_config.config_lock); -#endif if (intel_crtc->pipe == 0) { printk(KERN_ERR "Can't support LVDS on pipe A\n"); @@ -262,7 +258,6 @@ static enum drm_output_status intel_lvds_detect(struct drm_output *output) */ static int intel_lvds_get_modes(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; struct drm_device *dev = output->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct edid *edid_info; @@ -317,9 +312,7 @@ static void intel_lvds_destroy(struct drm_output *output) struct intel_output *intel_output = output->driver_private; intel_i2c_destroy(intel_output->ddc_bus); - - if (output->driver_private) - kfree(output->driver_private); + kfree(output->driver_private); } static const struct drm_output_funcs intel_lvds_output_funcs = { @@ -349,6 +342,9 @@ void intel_lvds_init(struct drm_device *dev) struct drm_output *output; struct intel_output *intel_output; struct drm_display_mode *scan; /* *modes, *bios_mode; */ + struct drm_crtc *crtc; + u32 lvds; + int pipe; output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS"); if (!output) @@ -384,34 +380,34 @@ void intel_lvds_init(struct drm_device *dev) if (scan->type & DRM_MODE_TYPE_PREFERRED) { dev_priv->panel_fixed_mode = drm_mode_duplicate(dev, scan); - break; + goto out; /* FIXME: check for quirks */ } } -#if 0 /* * If we didn't get EDID, try checking if the panel is already turned * on. If so, assume that whatever is currently programmed is the * correct mode. */ - if (!dev_priv->panel_fixed_mode) { - u32 lvds = I915_READ(LVDS); - int pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_crtc *crtc; - /* FIXME: need drm_crtc_from_pipe */ - //crtc = drm_crtc_from_pipe(mode_config, pipe); + lvds = I915_READ(LVDS); + pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; + crtc = intel_get_crtc_from_pipe(dev, pipe); - if (lvds & LVDS_PORT_EN && 0) { - dev_priv->panel_fixed_mode = - intel_crtc_mode_get(dev, crtc); - if (dev_priv->panel_fixed_mode) - dev_priv->panel_fixed_mode->type |= - DRM_MODE_TYPE_PREFERRED; + if (crtc && (lvds & LVDS_PORT_EN)) { + dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc); + if (dev_priv->panel_fixed_mode) { + dev_priv->panel_fixed_mode->type |= + DRM_MODE_TYPE_PREFERRED; + goto out; /* FIXME: check for quirks */ } } -/* No BIOS poking yet... */ + /* If we still don't have a mode after all that, give up. */ + if (!dev_priv->panel_fixed_mode) + goto failed; + + /* FIXME: probe the BIOS for modes and check for LVDS quirks */ +#if 0 /* Get the LVDS fixed mode out of the BIOS. We should support LVDS * with the BIOS being unavailable or broken, but lack the * configuration options for now. @@ -442,22 +438,25 @@ void intel_lvds_init(struct drm_device *dev) goto disable_exit; } - /* Blacklist machines with BIOSes that list an LVDS panel without actually - * having one. + /* + * Blacklist machines with BIOSes that list an LVDS panel without + * actually having one. */ if (dev_priv->PciInfo->chipType == PCI_CHIP_I945_GM) { - if (dev_priv->PciInfo->subsysVendor == 0xa0a0) /* aopen mini pc */ + /* aopen mini pc */ + if (dev_priv->PciInfo->subsysVendor == 0xa0a0) goto disable_exit; if ((dev_priv->PciInfo->subsysVendor == 0x8086) && (dev_priv->PciInfo->subsysCard == 0x7270)) { /* It's a Mac Mini or Macbook Pro. * - * Apple hardware is out to get us. The macbook pro has a real - * LVDS panel, but the mac mini does not, and they have the same - * device IDs. We'll distinguish by panel size, on the assumption - * that Apple isn't about to make any machines with an 800x600 - * display. + * Apple hardware is out to get us. The macbook pro + * has a real LVDS panel, but the mac mini does not, + * and they have the same device IDs. We'll + * distinguish by panel size, on the assumption + * that Apple isn't about to make any machines with an + * 800x600 display. */ if (dev_priv->panel_fixed_mode != NULL && @@ -472,5 +471,13 @@ void intel_lvds_init(struct drm_device *dev) } #endif + +out: return; + +failed: + DRM_DEBUG("No LVDS modes found, disabling.\n"); + intel_i2c_destroy(intel_output->ddc_bus); + kfree(output->driver_private); + drm_output_destroy(output); } -- cgit v1.2.3 From 79b7a588bb685459d51527e7ac6877696fe392a3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 14:57:07 -0700 Subject: Oops, forgot to push the msleep() in the hotplug test. Wouldn't want to spin in the kernel for a whole second w/o it... --- linux-core/intel_crt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 86eaff54..cdfb314f 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -152,6 +152,7 @@ static bool intel_crt_detect_hotplug(struct drm_output *output) do { if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT)) break; + msleep(1); } while (time_after(timeout, jiffies)); if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) == -- cgit v1.2.3 From 9f0f6509f5278b5d46a282acf40e7b69790892a6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Apr 2007 18:30:36 -0700 Subject: Move driver load call to after AGP init, in case the load routine needs AGP stuff. --- linux-core/drm_stub.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index f4da7dac..13652ebd 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -113,10 +113,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, dev->driver = driver; - if (dev->driver->load) - if ((retcode = dev->driver->load(dev, ent->driver_data))) - goto error_out_unreg; - if (drm_core_has_AGP(dev)) { if (drm_device_is_agp(dev)) dev->agp = drm_agp_init(dev); @@ -136,6 +132,11 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, } } + + if (dev->driver->load) + if ((retcode = dev->driver->load(dev, ent->driver_data))) + goto error_out_unreg; + retcode = drm_ctxbitmap_init(dev); if (retcode) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); -- cgit v1.2.3 From a890d596fc22a3dca9d390f96f0f739cf90de5e1 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Fri, 13 Apr 2007 14:30:44 +1000 Subject: revert LVDS destroy - this oops on sysfs on sdvo init of i2c bus --- linux-core/intel_lvds.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 4020ec6e..db025417 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -476,8 +476,7 @@ out: return; failed: - DRM_DEBUG("No LVDS modes found, disabling.\n"); - intel_i2c_destroy(intel_output->ddc_bus); - kfree(output->driver_private); - drm_output_destroy(output); + DRM_DEBUG("No LVDS modes found, disabling.\n"); + // intel_lvds_destroy(output); + // drm_output_destroy(output); } -- cgit v1.2.3 From 27598bacfd8e086832753a8b931f0fce18989f8d Mon Sep 17 00:00:00 2001 From: David Airlie Date: Fri, 13 Apr 2007 14:31:10 +1000 Subject: export drm_bo_driver_finish symbol --- linux-core/drm_bo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index a379c741..045d5fdc 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2125,6 +2125,7 @@ int drm_bo_driver_finish(drm_device_t * dev) mutex_unlock(&dev->bm.init_mutex); return ret; } +EXPORT_SYMBOL(drm_bo_driver_finish); int drm_bo_driver_init(drm_device_t * dev) { -- cgit v1.2.3 From cc471a361fc7058df4fb8d15d9c9a8b5cdd3dd77 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Fri, 13 Apr 2007 14:33:52 +1000 Subject: i915/drm: clean up a lot of the i915/drm startup/teardown sequences When the kernel driver is loaded it sets up a lot of stuff.. it tears down the same stuff on unload. This add a new map type called DRM_DRIVER which means the driver will clean the mapping up and fix up the map cleaner --- linux-core/drm_bufs.c | 3 +- linux-core/drm_drv.c | 30 +++++------ linux-core/drm_stub.c | 1 - linux-core/i915_drv.c | 1 - shared-core/drm.h | 3 +- shared-core/i915_dma.c | 106 -------------------------------------- shared-core/i915_drv.h | 3 ++ shared-core/i915_init.c | 132 +++++++++++++++++++++++++++--------------------- 8 files changed, 95 insertions(+), 184 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 8793ba0e..1ba53c8f 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -57,7 +57,7 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, drm_map_list_t *entry = list_entry(list, drm_map_list_t, head); if (entry->map && map->type == entry->map->type && ((entry->map->offset == map->offset) || - (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { + ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) { return entry; } } @@ -417,6 +417,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) break; case _DRM_SHM: vfree(map->handle); + dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ break; case _DRM_AGP: case _DRM_SCATTER_GATHER: diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index b7a7aded..7bb8c659 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -147,7 +147,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { int drm_lastclose(drm_device_t * dev) { drm_magic_entry_t *pt, *next; - drm_map_list_t *r_list; + drm_map_list_t *r_list, *r_list_tmp; drm_vma_entry_t *vma, *vma_next; int i; @@ -238,10 +238,9 @@ int drm_lastclose(drm_device_t * dev) } if (dev->maplist) { - while (!list_empty(&dev->maplist->head)) { - struct list_head *list = dev->maplist->head.next; - r_list = list_entry(list, drm_map_list_t, head); - drm_rmmap_locked(dev, r_list->map); + list_for_each_entry_safe(r_list, r_list_tmp, &dev->maplist->head, head) { + if (!(r_list->map->flags & _DRM_DRIVER)) + drm_rmmap_locked(dev, r_list->map); } } @@ -265,8 +264,7 @@ int drm_lastclose(drm_device_t * dev) if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) drm_dma_takedown(dev); - if (dev->lock.hw_lock) { - dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ + if (dev->lock.filp) { dev->lock.filp = NULL; wake_up_interruptible(&dev->lock.lock_queue); } @@ -377,14 +375,6 @@ static void drm_cleanup(drm_device_t * dev) drm_lastclose(dev); drm_fence_manager_takedown(dev); - if (dev->maplist) { - drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); - dev->maplist = NULL; - drm_ht_remove(&dev->map_hash); - drm_mm_takedown(&dev->offset_manager); - drm_ht_remove(&dev->object_hash); - } - if (!drm_fb_loaded) pci_disable_device(dev->pdev); @@ -399,7 +389,7 @@ static void drm_cleanup(drm_device_t * dev) DRM_DEBUG("mtrr_del=%d\n", retval); } - drm_bo_driver_finish(dev); + // drm_bo_driver_finish(dev); if (drm_core_has_AGP(dev) && dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); @@ -408,6 +398,14 @@ static void drm_cleanup(drm_device_t * dev) if (dev->driver->unload) dev->driver->unload(dev); + if (dev->maplist) { + drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); + dev->maplist = NULL; + drm_ht_remove(&dev->map_hash); + drm_mm_takedown(&dev->offset_manager); + drm_ht_remove(&dev->object_hash); + } + drm_put_head(&dev->primary); if (drm_put_dev(dev)) DRM_ERROR("Cannot unload module\n"); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 13652ebd..417e5095 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -132,7 +132,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, } } - if (dev->driver->load) if ((retcode = dev->driver->load(dev, ent->driver_data))) goto error_out_unreg; diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index b9e624f9..50ff9771 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -80,7 +80,6 @@ static struct drm_driver driver = { DRIVER_IRQ_VBL2, .load = i915_driver_load, .unload = i915_driver_unload, - .firstopen = i915_driver_firstopen, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .device_is_agp = i915_driver_device_is_agp, diff --git a/shared-core/drm.h b/shared-core/drm.h index b5b0aa52..6c626f66 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -289,7 +289,8 @@ typedef enum drm_map_flags { _DRM_KERNEL = 0x08, /**< kernel requires access */ _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */ _DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */ - _DRM_REMOVABLE = 0x40 /**< Removable mapping */ + _DRM_REMOVABLE = 0x40, /**< Removable mapping */ + _DRM_DRIVER = 0x80 /**< Driver will take care of it */ } drm_map_flags_t; typedef struct drm_ctx_priv_map { diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index cf729c6f..2b29dbe2 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -88,16 +88,6 @@ int i915_dma_cleanup(drm_device_t * dev) if (dev->irq) drm_irq_uninstall(dev); - if (dev_priv->status_page_dmah) { - drm_pci_free(dev, dev_priv->status_page_dmah); - dev_priv->status_page_dmah = NULL; - dev_priv->hw_status_page = NULL; - dev_priv->dma_status_page = 0; - /* Need to rewrite hardware status page */ - I915_WRITE(0x02080, 0x1ffff000); - } - - dev_priv->sarea_priv = NULL; return 0; } @@ -106,39 +96,6 @@ static int i915_initialize(drm_device_t * dev, drm_i915_private_t * dev_priv, drm_i915_init_t * init) { - DRM_GETSAREA(); - if (!dev_priv->sarea) { - DRM_ERROR("can not find sarea!\n"); - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - return DRM_ERR(EINVAL); - } - - dev_priv->sarea_priv = (drm_i915_sarea_t *) - ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); - - dev_priv->ring.Start = init->ring_start; - dev_priv->ring.End = init->ring_end; - dev_priv->ring.Size = init->ring_size; - dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - - dev_priv->ring.map.offset = init->ring_start; - dev_priv->ring.map.size = init->ring_size; - dev_priv->ring.map.type = 0; - dev_priv->ring.map.flags = 0; - dev_priv->ring.map.mtrr = 0; - - drm_core_ioremap(&dev_priv->ring.map, dev); - - if (dev_priv->ring.map.handle == NULL) { - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - DRM_ERROR("can not ioremap virtual address for" - " ring buffer\n"); - return DRM_ERR(ENOMEM); - } - - dev_priv->ring.virtual_start = dev_priv->ring.map.handle; dev_priv->cpp = init->cpp; dev_priv->sarea_priv->pf_current_page = 0; @@ -152,27 +109,6 @@ static int i915_initialize(drm_device_t * dev, */ dev_priv->allow_batchbuffer = 1; - /* Program Hardware Status Page */ - dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, - 0xffffffff); - - if (!dev_priv->status_page_dmah) { - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - DRM_ERROR("Can not allocate hardware status page\n"); - return DRM_ERR(ENOMEM); - } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); - - I915_WRITE(0x02080, dev_priv->dma_status_page); - DRM_DEBUG("Enabled hardware status page\n"); - -//drm_set_desired_modes(dev); - return 0; } @@ -182,29 +118,6 @@ static int i915_dma_resume(drm_device_t * dev) DRM_DEBUG("%s\n", __FUNCTION__); - if (!dev_priv->sarea) { - DRM_ERROR("can not find sarea!\n"); - return DRM_ERR(EINVAL); - } - - if (!dev_priv->mmio_map) { - DRM_ERROR("can not find mmio map!\n"); - return DRM_ERR(EINVAL); - } - - if (dev_priv->ring.map.handle == NULL) { - DRM_ERROR("can not ioremap virtual address for" - " ring buffer\n"); - return DRM_ERR(ENOMEM); - } - - /* Program Hardware Status Page */ - if (!dev_priv->hw_status_page) { - DRM_ERROR("Can not find hardware status page\n"); - return DRM_ERR(EINVAL); - } - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); - I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); @@ -889,23 +802,4 @@ int i915_driver_device_is_agp(drm_device_t * dev) return 1; } -int i915_driver_firstopen(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int ret; - DRM_DEBUG("\n"); - - if (!dev_priv->mmio_map) { - ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, - _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio_map); - if (ret != 0) { - DRM_ERROR("Cannot add mapping for MMIO registers\n"); - return ret; - } - } - - DRM_DEBUG("dev_priv->mmio map is %p\n", dev_priv->mmio_map); - - return 0; -} diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index c22ab843..f4343014 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -89,6 +89,7 @@ typedef struct _drm_i915_vbl_swap { } drm_i915_vbl_swap_t; typedef struct drm_i915_private { + drm_buffer_object_t *ring_buffer; drm_local_map_t *sarea; drm_local_map_t *mmio_map; @@ -922,4 +923,6 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810) || IS_I915GM(pI810) || IS_I945GM(pI810)) +#define PRIMARY_RINGBUFFER_SIZE (128*1024) + #endif diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index f0ab4574..be702624 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -151,7 +151,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) } ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, - _DRM_REGISTERS, _DRM_READ_ONLY, &dev_priv->mmio_map); + _DRM_REGISTERS, _DRM_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map); if (ret != 0) { DRM_ERROR("Cannot add mapping for MMIO registers\n"); return ret; @@ -159,20 +159,13 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) /* prebuild the SAREA */ sareapage = max(SAREA_MAX, PAGE_SIZE); - ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, - &map); + ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, + &dev_priv->sarea); if (ret) { DRM_ERROR("SAREA setup failed\n"); return ret; } - DRM_GETSAREA(); - if (!dev_priv->sarea) { - DRM_ERROR("can not find sarea!\n"); - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - return DRM_ERR(EINVAL); - } init_waitqueue_head(&dev->lock.lock_queue); /* FIXME: assume sarea_priv is right after SAREA */ @@ -187,61 +180,34 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, dev_priv->baseaddr, prealloc_size); - /* Allocate scanout buffer and command ring */ - /* FIXME: types and other args correct? */ - hsize = 1280; - vsize = 800; - bytes_per_pixel = 4; - size = hsize * vsize * bytes_per_pixel; - drm_buffer_object_create(dev, size, drm_bo_type_kernel, - DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, - 0, PAGE_SIZE, 0, - &entry); - - intel_modeset_init(dev); - - fb = drm_framebuffer_create(dev); - if (!fb) { - DRM_ERROR("failed to allocate fb\n"); + size = PRIMARY_RINGBUFFER_SIZE; + ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_PRIV0 | + DRM_BO_FLAG_NO_MOVE, + DRM_BO_HINT_DONT_FENCE, 0x1, 0, + &dev_priv->ring_buffer); + if (ret < 0) { + DRM_ERROR("Unable to allocate ring buffer\n"); return -EINVAL; } - fb->width = hsize; - fb->height = vsize; - fb->pitch = hsize; - fb->bits_per_pixel = bytes_per_pixel * 8; - fb->depth = bytes_per_pixel * 8; - fb->offset = entry->offset; - fb->bo = entry; - - drm_initial_config(dev, fb, false); - drmfb_probe(dev, fb); -#if 0 - /* FIXME: command ring needs AGP space, do we own it at this point? */ - dev_priv->ring.Start = dev_priv->baseaddr; - dev_priv->ring.End = 128*1024; - dev_priv->ring.Size = 128*1024; + /* remap the buffer object properly */ + dev_priv->ring.Start = dev_priv->ring_buffer->offset + dev_priv->baseaddr; + dev_priv->ring.End = dev_priv->ring.Start + size; + dev_priv->ring.Size = size; dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - dev_priv->ring.map.offset = dev_priv->ring.Start; - dev_priv->ring.map.size = dev_priv->ring.Size; - dev_priv->ring.map.type = 0; - dev_priv->ring.map.flags = 0; - dev_priv->ring.map.mtrr = 0; + dev_priv->ring.virtual_start = ioremap((dev_priv->ring.Start), (dev_priv->ring_buffer->mem.num_pages * PAGE_SIZE)); - drm_core_ioremap(&dev_priv->ring.map, dev); - if (dev_priv->ring.map.handle == NULL) { - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - DRM_ERROR("can not ioremap virtual address for" - " ring buffer\n"); - return DRM_ERR(ENOMEM); - } + DRM_DEBUG("ring start %08X, %08X, %08X\n", dev_priv->ring.Start, dev_priv->ring.virtual_start, dev_priv->ring.Size); + I915_WRITE(LP_RING + RING_HEAD, 0); + I915_WRITE(LP_RING + RING_TAIL, 0); + I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); + I915_WRITE(LP_RING + RING_LEN, ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | + (RING_NO_REPORT | RING_VALID)); - dev_priv->ring.virtual_start = dev_priv->ring.map.handle; - dev_priv->cpp = 4; dev_priv->sarea_priv->pf_current_page = 0; /* We are using separate values as placeholders for mechanisms for @@ -271,8 +237,40 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); + +#if 1 + /* Allocate scanout buffer and command ring */ + /* FIXME: types and other args correct? */ + hsize = 1280; + vsize = 800; + bytes_per_pixel = 4; + size = hsize * vsize * bytes_per_pixel; + drm_buffer_object_create(dev, size, drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, + 0, PAGE_SIZE, 0, + &entry); #endif + intel_modeset_init(dev); + +#if 1 + fb = drm_framebuffer_create(dev); + if (!fb) { + DRM_ERROR("failed to allocate fb\n"); + return -EINVAL; + } + fb->width = hsize; + fb->height = vsize; + fb->pitch = hsize; + fb->bits_per_pixel = bytes_per_pixel * 8; + fb->depth = bytes_per_pixel * 8; + fb->offset = entry->offset; + fb->bo = entry; + + drm_initial_config(dev, fb, false); + drmfb_probe(dev, fb); +#endif return 0; } @@ -281,7 +279,26 @@ int i915_driver_unload(drm_device_t *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct drm_framebuffer *fb; + if (dev_priv->status_page_dmah) { + drm_pci_free(dev, dev_priv->status_page_dmah); + dev_priv->status_page_dmah = NULL; + dev_priv->hw_status_page = NULL; + dev_priv->dma_status_page = 0; + /* Need to rewrite hardware status page */ + I915_WRITE(0x02080, 0x1ffff000); + } + + I915_WRITE(LP_RING + RING_LEN, 0); + + iounmap(dev_priv->ring.virtual_start); + + drm_bo_driver_finish(dev); + intel_modeset_cleanup(dev); + DRM_DEBUG("%p, %p\n", dev_priv->mmio_map, dev_priv->sarea); + drm_rmmap(dev, dev_priv->mmio_map); + drm_rmmap(dev, dev_priv->sarea); + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; @@ -296,7 +313,6 @@ void i915_driver_lastclose(drm_device_t * dev) i915_dma_cleanup(dev); - dev_priv->mmio_map = NULL; } void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) -- cgit v1.2.3 From c4e944182db3002101c330453ebb3f454637743e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 13 Apr 2007 02:23:42 +0200 Subject: Added debug messages so we know which output we are dealing with --- linux-core/drm_crtc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ef025922..adea0309 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -134,13 +134,14 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) // TODO list_for_each_entry(output, &dev->mode_config.output_list, head) { - + list_for_each_entry_safe(mode, t, &output->modes, head) drm_mode_remove(output, mode); output->status = (*output->funcs->detect)(output); if (output->status == output_status_disconnected) { + DRM_DEBUG("%s is disconnected\n", output->name); /* TODO set EDID to NULL */ continue; } @@ -164,8 +165,10 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) drm_mode_prune_invalid(dev, &output->modes, TRUE); - if (list_empty(&output->modes)) + if (list_empty(&output->modes)) { + DRM_DEBUG("No valid modes found on %s\n", output->name); continue; + } drm_mode_sort(&output->modes); @@ -429,9 +432,12 @@ bool drm_output_rename(struct drm_output *output, const char *name) strncpy(output->name, name, DRM_OUTPUT_LEN); output->name[DRM_OUTPUT_LEN - 1] = 0; + + DRM_DEBUG("Changed name to %s\n", output->name); // drm_output_set_monitor(output); // if (drm_output_ignored(output)) // return FALSE; + return TRUE; } EXPORT_SYMBOL(drm_output_rename); -- cgit v1.2.3 From 65619cab276ba1f00014f9701b8347e2b834abe4 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 14 Apr 2007 15:35:21 -0700 Subject: Fix PRIV0 memory initialization (mm_init takes pages, not bytes), align fb allocation correctly, and use drm_mem_reg_iomap to map ring buffer object. --- linux-core/drm_bo_move.c | 1 + shared-core/i915_init.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 4f752065..415e4bed 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -128,6 +128,7 @@ int drm_mem_reg_ioremap(drm_device_t * dev, drm_bo_mem_reg_t * mem, *virtual = addr; return 0; } +EXPORT_SYMBOL(drm_mem_reg_ioremap); /** * \c Unmap mapping obtained using drm_bo_ioremap diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index be702624..273a1116 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -177,8 +177,9 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_bo_driver_init(dev); i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); + DRM_DEBUG("setting up %d bytes of PRIV0 space\n", prealloc_size); drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, dev_priv->baseaddr, - prealloc_size); + prealloc_size >> PAGE_SHIFT); size = PRIMARY_RINGBUFFER_SIZE; ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, @@ -198,8 +199,11 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) dev_priv->ring.Size = size; dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - dev_priv->ring.virtual_start = ioremap((dev_priv->ring.Start), (dev_priv->ring_buffer->mem.num_pages * PAGE_SIZE)); + ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, + &dev_priv->ring.virtual_start); + if (ret) + DRM_ERROR("error mapping ring buffer: %d\n", ret); DRM_DEBUG("ring start %08X, %08X, %08X\n", dev_priv->ring.Start, dev_priv->ring.virtual_start, dev_priv->ring.Size); I915_WRITE(LP_RING + RING_HEAD, 0); @@ -248,7 +252,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_buffer_object_create(dev, size, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, - 0, PAGE_SIZE, 0, + 0, 0, 0, &entry); #endif intel_modeset_init(dev); -- cgit v1.2.3 From 2aa183db1ff0fb6044d24eae51854ff128da9a0f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 14 Apr 2007 15:35:38 -0700 Subject: Use drm_mem_reg_ioremap to map buffer object. --- linux-core/drm_fb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index a70e4d52..df979cd1 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -107,6 +107,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) struct device *device = &dev->pdev->dev; struct fb_var_screeninfo *var_info; unsigned long base, size; + int ret; info = framebuffer_alloc(sizeof(struct drmfb_par), device); if (!info){ @@ -139,7 +140,9 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) size = (fb->bo->mem.num_pages * PAGE_SIZE); DRM_DEBUG("remapping %08X %d\n", base, size); - fb->virtual_base = ioremap_nocache(base, size); + ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); + if (ret) + DRM_ERROR("error mapping fb: %d\n", ret); info->screen_base = fb->virtual_base; info->screen_size = size; -- cgit v1.2.3 From cd5769c3b563048357535b24dc40783775adb227 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 16 Apr 2007 20:54:24 +0200 Subject: Fix offset should from pci device address --- linux-core/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index e58b31b0..48239329 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -350,8 +350,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) unsigned long Start, Offset; int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); - - Start = crtc->fb->offset + dev_priv->baseaddr; + + Start = crtc->fb->offset; Offset = ((y * crtc->fb->pitch + x) * (crtc->fb->bits_per_pixel / 8)); DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); -- cgit v1.2.3 From 79aa1d54746f33c33ffbf98fb96ccbf88c3cb390 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 17 Apr 2007 18:16:38 +1000 Subject: another large overhaul of interactions with userspace... We need to keep a list of user created fbs to nuke on master exit. We also need to use the bo properly. --- linux-core/drmP.h | 2 ++ linux-core/drm_bo_move.c | 1 + linux-core/drm_crtc.c | 33 +++++++++++++++++++++++++-------- linux-core/drm_crtc.h | 1 + linux-core/drm_fb.c | 7 ++----- linux-core/drm_fops.c | 4 +++- linux-core/drm_objects.h | 5 +++++ linux-core/drm_stub.c | 13 +++++++------ shared-core/i915_dma.c | 12 ++++++++++++ shared-core/i915_drv.h | 1 - shared-core/i915_init.c | 35 ++++++++++++++++++++++------------- 11 files changed, 80 insertions(+), 34 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 0d0ec992..326565cb 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -431,6 +431,8 @@ typedef struct drm_file { drm_open_hash_t refd_object_hash[_DRM_NO_REF_TYPES]; void *driver_priv; + + struct list_head fbs; } drm_file_t; /** Wait queue */ diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 415e4bed..eaeef1b0 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -151,6 +151,7 @@ void drm_mem_reg_iounmap(drm_device_t * dev, drm_bo_mem_reg_t * mem, iounmap(virtual); } } +EXPORT_SYMBOL(drm_mem_reg_iounmap); static int drm_copy_io_page(void *dst, void *src, unsigned long page) { diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index adea0309..bf019df3 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -64,6 +64,15 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) { drm_device_t *dev = fb->dev; + /* remove from any CRTC */ + { + struct drm_crtc *crtc; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->fb == fb) + crtc->fb = NULL; + } + } + spin_lock(&dev->mode_config.config_lock); drm_mode_idr_put(dev, fb->id); list_del(&fb->head); @@ -1034,6 +1043,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, r.buffer_id = fb->id; + list_add(&fb->filp_head, &priv->fbs); /* bind the fb to the crtc for now */ { struct drm_crtc *crtc; @@ -1049,7 +1059,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, } int drm_mode_rmfb(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; @@ -1067,13 +1077,6 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, /* TODO check if we own the buffer */ /* TODO release all crtc connected to the framebuffer */ /* bind the fb to the crtc for now */ - { - struct drm_crtc *crtc; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb == fb) - crtc->fb = NULL; - } - } /* TODO unhock the destructor from the buffer object */ drm_framebuffer_destroy(fb); @@ -1111,3 +1114,17 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, return 0; } + +void drm_fb_release(struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_framebuffer *fb, *tfb; + + list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { + list_del(&fb->filp_head); + drmfb_remove(dev, fb); + drm_framebuffer_destroy(fb); + + } +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index c02dcedc..584788ee 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -184,6 +184,7 @@ struct drm_framebuffer { void *fbdev; u32 pseudo_palette[17]; void *virtual_base; + struct list_head filp_head; }; struct drm_crtc; struct drm_output; diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index df979cd1..ef05341a 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -84,6 +84,7 @@ static int drmfb_set_par(struct fb_info *info) struct drm_device *dev = par->dev; drm_set_desired_modes(dev); + return 0; } static struct fb_ops drmfb_ops = { @@ -136,10 +137,6 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) info->flags = FBINFO_DEFAULT; - base = fb->bo->offset + dev->mode_config.fb_base; - size = (fb->bo->mem.num_pages * PAGE_SIZE); - - DRM_DEBUG("remapping %08X %d\n", base, size); ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); if (ret) DRM_ERROR("error mapping fb: %d\n", ret); @@ -194,7 +191,7 @@ int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) struct fb_info *info = fb->fbdev; if (info) { - iounmap(fb->virtual_base); + drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); unregister_framebuffer(info); framebuffer_release(info); } diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index d400a4d5..e4748978 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -86,7 +86,7 @@ static int drm_setup(drm_device_t * dev) INIT_LIST_HEAD(&dev->ctxlist->head); dev->vmalist = NULL; - dev->sigdata.lock = NULL; + // dev->sigdata.lock = NULL; init_waitqueue_head(&dev->lock.lock_queue); dev->queue_count = 0; dev->queue_reserved = 0; @@ -270,6 +270,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, INIT_LIST_HEAD(&priv->user_objects); INIT_LIST_HEAD(&priv->refd_objects); + INIT_LIST_HEAD(&priv->fbs); for (i=0; i<_DRM_NO_REF_TYPES; ++i) { ret = drm_ht_create(&priv->refd_object_hash[i], DRM_FILE_HASH_ORDER); @@ -501,6 +502,7 @@ int drm_release(struct inode *inode, struct file *filp) mutex_unlock(&dev->ctxlist_mutex); mutex_lock(&dev->struct_mutex); + drm_fb_release(filp); drm_object_release(filp); if (priv->remove_auth_on_close == 1) { drm_file_t *temp = dev->file_first; diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index b3155af1..401fd0ed 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -467,4 +467,9 @@ extern int drm_bo_move_accel_cleanup(drm_buffer_object_t * bo, uint32_t fence_flags, drm_bo_mem_reg_t * new_mem); +extern int drm_mem_reg_ioremap(struct drm_device *dev, drm_bo_mem_reg_t * mem, + void **virtual); +extern void drm_mem_reg_iounmap(struct drm_device *dev, drm_bo_mem_reg_t * mem, + void *virtual); + #endif diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 417e5095..01ffe679 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -79,27 +79,28 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, #endif dev->irq = pdev->irq; - if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) { - drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); + if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) return -ENOMEM; - } + if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START, DRM_FILE_PAGE_OFFSET_SIZE)) { - drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); drm_ht_remove(&dev->map_hash); return -ENOMEM; } if (drm_ht_create(&dev->object_hash, DRM_OBJECT_HASH_ORDER)) { - drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); drm_ht_remove(&dev->map_hash); drm_mm_takedown(&dev->offset_manager); return -ENOMEM; } dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS); - if (dev->maplist == NULL) + if (dev->maplist == NULL) { + drm_ht_remove(&dev->object_hash); + drm_ht_remove(&dev->map_hash); + drm_mm_takedown(&dev->offset_manager); return -ENOMEM; + } INIT_LIST_HEAD(&dev->maplist->head); /* the DRM has 6 counters */ diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 2b29dbe2..25172c1b 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -85,6 +85,8 @@ int i915_dma_cleanup(drm_device_t * dev) * may not have been called from userspace and after dev_private * is freed, it's too late. */ + I915_WRITE(LP_RING + RING_LEN, 0); + if (dev->irq) drm_irq_uninstall(dev); @@ -97,6 +99,16 @@ static int i915_initialize(drm_device_t * dev, drm_i915_init_t * init) { + /* reset ring pointers */ + I915_WRITE(LP_RING + RING_LEN, 0); + mb(); + + memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); + + I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); + I915_WRITE(LP_RING + RING_LEN, ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | (RING_NO_REPORT | RING_VALID)); + + dev_priv->cpp = init->cpp; dev_priv->sarea_priv->pf_current_page = 0; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index f4343014..8c2b4817 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -93,7 +93,6 @@ typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; - unsigned long baseaddr; unsigned long mmiobase; unsigned long mmiolen; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 273a1116..2ed7a822 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -138,12 +138,12 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) if (IS_I9XX(dev)) { dev_priv->mmiobase = drm_get_resource_start(dev, 0); dev_priv->mmiolen = drm_get_resource_len(dev, 0); - dev->mode_config.fb_base = dev_priv->baseaddr = + dev->mode_config.fb_base = drm_get_resource_start(dev, 2) & 0xff000000; } else if (drm_get_resource_start(dev, 1)) { dev_priv->mmiobase = drm_get_resource_start(dev, 1); dev_priv->mmiolen = drm_get_resource_len(dev, 1); - dev->mode_config.fb_base = dev_priv->baseaddr = + dev->mode_config.fb_base = drm_get_resource_start(dev, 0) & 0xff000000; } else { DRM_ERROR("Unable to find MMIO registers\n"); @@ -178,14 +178,18 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); DRM_DEBUG("setting up %d bytes of PRIV0 space\n", prealloc_size); - drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, dev_priv->baseaddr, + drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, 0, prealloc_size >> PAGE_SHIFT); + I915_WRITE(LP_RING + RING_LEN, 0); + I915_WRITE(LP_RING + RING_HEAD, 0); + I915_WRITE(LP_RING + RING_TAIL, 0); + size = PRIMARY_RINGBUFFER_SIZE; ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MEM_PRIV0 | - DRM_BO_FLAG_NO_MOVE, + DRM_BO_FLAG_NO_EVICT, DRM_BO_HINT_DONT_FENCE, 0x1, 0, &dev_priv->ring_buffer); if (ret < 0) { @@ -194,23 +198,17 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) } /* remap the buffer object properly */ - dev_priv->ring.Start = dev_priv->ring_buffer->offset + dev_priv->baseaddr; + dev_priv->ring.Start = dev_priv->ring_buffer->offset; dev_priv->ring.End = dev_priv->ring.Start + size; dev_priv->ring.Size = size; dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, &dev_priv->ring.virtual_start); if (ret) DRM_ERROR("error mapping ring buffer: %d\n", ret); DRM_DEBUG("ring start %08X, %08X, %08X\n", dev_priv->ring.Start, dev_priv->ring.virtual_start, dev_priv->ring.Size); - I915_WRITE(LP_RING + RING_HEAD, 0); - I915_WRITE(LP_RING + RING_TAIL, 0); - I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); - I915_WRITE(LP_RING + RING_LEN, ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | - (RING_NO_REPORT | RING_VALID)); dev_priv->sarea_priv->pf_current_page = 0; @@ -294,11 +292,22 @@ int i915_driver_unload(drm_device_t *dev) I915_WRITE(LP_RING + RING_LEN, 0); - iounmap(dev_priv->ring.virtual_start); + intel_modeset_cleanup(dev); + + drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, + dev_priv->ring.virtual_start); + + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(dev_priv->ring_buffer); + mutex_unlock(&dev->struct_mutex); + + if (drm_bo_clean_mm(dev, DRM_BO_MEM_PRIV0)) { + DRM_ERROR("Memory manager type 3 not clean. " + "Delaying takedown\n"); + } drm_bo_driver_finish(dev); - intel_modeset_cleanup(dev); DRM_DEBUG("%p, %p\n", dev_priv->mmio_map, dev_priv->sarea); drm_rmmap(dev, dev_priv->mmio_map); drm_rmmap(dev, dev_priv->sarea); -- cgit v1.2.3 From 56ef1ab8acc0c68b66c4f781107b605f9dd79657 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 17 Apr 2007 18:18:25 +1000 Subject: add some missing export symbols --- linux-core/drm_bo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 045d5fdc..343cc1ef 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -494,6 +494,7 @@ void drm_bo_usage_deref_locked(drm_buffer_object_t * bo) drm_bo_destroy_locked(bo); } } +EXPORT_SYMBOL(drm_bo_usage_deref_locked); static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo) { @@ -1993,6 +1994,7 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) return ret; } +EXPORT_SYMBOL(drm_bo_clean_mm); /** *Evict all buffers of a particular mem_type, but leave memory manager -- cgit v1.2.3 From 1a5e647f63f083788a7fe43c2367d2e022c48588 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 17 Apr 2007 18:18:42 +1000 Subject: I don't think this dec is necessary and my stuff all works without .. with it everything falls over --- linux-core/drm_bo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 343cc1ef..d6dce10a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1740,7 +1740,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) entry = drm_user_object_entry(uo, drm_buffer_object_t, base); - atomic_dec(&entry->usage); + /* I don't think this is needed - D.A. */ + // atomic_dec(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); drm_bo_fill_rep_arg(entry, &rep); -- cgit v1.2.3 From 32b5616cc681e404f671b4bc3b030ee24b753d4a Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 17 Apr 2007 16:08:26 +0100 Subject: Correct PCI ID for i845 --- shared-core/i915_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 2ed7a822..5872aeb3 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -45,7 +45,7 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, switch (pdev->device) { case PCI_DEVICE_ID_INTEL_82830_CGC: - case PCI_DEVICE_ID_INTEL_82845G_HB: + case PCI_DEVICE_ID_INTEL_82845G_IG: case PCI_DEVICE_ID_INTEL_82855GM_IG: case PCI_DEVICE_ID_INTEL_82865_IG: if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) -- cgit v1.2.3 From ecd9801c3cf08082b4aaa7e23f1f94a5e1d47a75 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 17 Apr 2007 16:09:40 +0100 Subject: Fix SDVO outputs --- linux-core/intel_sdvo_regs.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-core/intel_sdvo_regs.h b/linux-core/intel_sdvo_regs.h index c8ab950b..a9d16711 100644 --- a/linux-core/intel_sdvo_regs.h +++ b/linux-core/intel_sdvo_regs.h @@ -37,7 +37,11 @@ #define SDVO_OUTPUT_SCART0 (1 << 5) #define SDVO_OUTPUT_LVDS0 (1 << 6) #define SDVO_OUTPUT_TMDS1 (1 << 8) -#define SDVO_OUTPUT_RGB1 (1 << 13) +#define SDVO_OUTPUT_RGB1 (1 << 9) +#define SDVO_OUTPUT_CVBS1 (1 << 10) +#define SDVO_OUTPUT_SVID1 (1 << 11) +#define SDVO_OUTPUT_YPRPB1 (1 << 12) +#define SDVO_OUTPUT_SCART1 (1 << 13) #define SDVO_OUTPUT_LVDS1 (1 << 14) #define SDVO_OUTPUT_LAST (14) -- cgit v1.2.3 From b729b919baed250313caf3f0bbd4044e084de8bf Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 17 Apr 2007 16:11:00 +0100 Subject: Fix a register read that was swapped SDVOB/SDVOC Check for the PENDING message when reading the attached displays. Ensures the command has completed before continuing. (probably need to check PENDING in other SDVO calls too) --- linux-core/intel_sdvo.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 1b45afdb..6f592f8a 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -29,6 +29,7 @@ */ #include +#include #include "drmP.h" #include "drm.h" #include "drm_crtc.h" @@ -69,9 +70,9 @@ static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) int i; if (sdvo_priv->output_device == SDVOB) - cval = I915_READ(SDVOC); - else bval = I915_READ(SDVOB); + else + cval = I915_READ(SDVOC); /* * Write the registers twice for luck. Sometimes, @@ -869,12 +870,21 @@ static enum drm_output_status intel_sdvo_detect(struct drm_output *output) { u8 response[2]; u8 status; + u8 retry = 50; intel_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); - status = intel_sdvo_read_response(output, &response, 2); - if (status != SDVO_CMD_STATUS_SUCCESS) - return output_status_unknown; + while (retry--) { + status = intel_sdvo_read_response(output, &response, 2); + + if (status == SDVO_CMD_STATUS_SUCCESS) + break; + + if (status != SDVO_CMD_STATUS_PENDING) + return output_status_unknown; + + mdelay(50); + } DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); if ((response[0] != 0) || (response[1] != 0)) -- cgit v1.2.3 From 5e6c34539694c58cd7e9dd60541fc6e2bde1a79d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 17 Apr 2007 09:57:08 -0700 Subject: Add prototypes for drm_bo_init_mm and drm_buffer_object_create for use by in-kernel code. --- linux-core/drm_objects.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index b3155af1..cbc0e610 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -423,7 +423,13 @@ typedef struct drm_bo_driver { /* * buffer objects (drm_bo.c) */ - +extern int drm_bo_init_mm(struct drm_device * dev, unsigned type, + unsigned long p_offset, unsigned long p_size); +extern int drm_buffer_object_create(struct drm_device *dev, unsigned long size, + drm_bo_type_t type, uint32_t mask, + uint32_t hint, uint32_t page_alignment, + unsigned long buffer_start, + drm_buffer_object_t ** buf_obj); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_driver_finish(struct drm_device *dev); -- cgit v1.2.3 From eeb5de059401361871e34e29c456a1feebac0b1e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 17 Apr 2007 09:59:21 -0700 Subject: Cleanup whitespace, rename macro argument. --- shared-core/i915_drv.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index f4343014..b0d70124 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -908,8 +908,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define IS_I855(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82855GM_IG) #define IS_I865G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82865_IG) -#define IS_I915G(pI810) (dev->pci_device == PCI_DEVICE_ID_INTEL_82915G_IG)/* || dev->pci_device == PCI_DEVICE_ID_INTELPCI_CHIP_E7221_G)*/ -#define IS_I915GM(pI810) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82915GM_IG) +#define IS_I915G(dev) (dev->pci_device == PCI_DEVICE_ID_INTEL_82915G_IG)/* || dev->pci_device == PCI_DEVICE_ID_INTELPCI_CHIP_E7221_G)*/ +#define IS_I915GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82915GM_IG) #define IS_I945G(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82945G_IG) #define IS_I945GM(dev) ((dev)->pci_device == PCI_DEVICE_ID_INTEL_82945GM_IG) @@ -919,9 +919,11 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); (dev)->pci_device == 0x29A2) -#define IS_I9XX(pI810) (IS_I915G(pI810) || IS_I915GM(pI810) || IS_I945G(pI810) || IS_I945GM(pI810) || IS_I965G(pI810)) +#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \ + IS_I945GM(dev) || IS_I965G(dev)) -#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810) || IS_I915GM(pI810) || IS_I945GM(pI810)) +#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ + IS_I945GM(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) -- cgit v1.2.3 From 4e4d9cbeb3f52b605e46aad8ae1a947ca236079f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 17 Apr 2007 10:00:37 -0700 Subject: Move initial framebuffer allocation and configuration to drm_initial_config, remove i915_driver_load fb related stuff. Add a small helper for setting up outputs. --- linux-core/drm_crtc.c | 73 +++++++++++++++++++++++++++++++++++-------------- linux-core/drm_crtc.h | 3 +- shared-core/i915_init.c | 48 ++++++-------------------------- 3 files changed, 61 insertions(+), 63 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index adea0309..ff989265 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1,6 +1,6 @@ #include -#include "drmP.h" #include "drm.h" +#include "drmP.h" #include "drm_crtc.h" int drm_mode_idr_get(struct drm_device *dev, void *ptr) @@ -500,6 +500,15 @@ out_err: return ret; } +static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + output->crtc = crtc; + output->crtc->desired_mode = mode; + output->initial_x = 0; + output->initial_y = 0; +} + /** * drm_initial_config - setup a sane initial output configuration * @dev: DRM device @@ -510,13 +519,21 @@ out_err: * At the moment, this is a cloned configuration across all heads with * @fb as the backing store. */ -bool drm_initial_config(drm_device_t *dev, struct drm_framebuffer *fb, - bool can_grow) +bool drm_initial_config(drm_device_t *dev, bool can_grow) { /* do a hardcoded initial configuration here */ - struct drm_crtc *crtc, *vga_crtc = NULL, *dvi_crtc = NULL, + struct drm_crtc *crtc, *vga_crtc = NULL, *tmds_crtc = NULL, *lvds_crtc = NULL; - struct drm_output *output, *use_output = NULL; + struct drm_output *output; + struct drm_framebuffer *fb; + drm_buffer_object_t *fbo; + unsigned long size, bytes_per_pixel; + + fb = drm_framebuffer_create(dev); + if (!fb) { + DRM_ERROR("failed to allocate fb.\n"); + return true; + } /* bind both CRTCs to this fb */ /* only initialise one crtc to enabled state */ @@ -532,8 +549,8 @@ bool drm_initial_config(drm_device_t *dev, struct drm_framebuffer *fb, crtc->enabled = 1; crtc->desired_x = 0; crtc->desired_y = 0; - } else if (!dvi_crtc) { - dvi_crtc = crtc; + } else if (!tmds_crtc) { + tmds_crtc = crtc; crtc->enabled = 1; crtc->desired_x = 0; crtc->desired_y = 0; @@ -557,29 +574,43 @@ bool drm_initial_config(drm_device_t *dev, struct drm_framebuffer *fb, break; } if (!strncmp(output->name, "VGA", 3)) { - output->crtc = vga_crtc; DRM_DEBUG("VGA preferred mode: %s\n", des_mode->name); - output->crtc->desired_mode = des_mode; - output->initial_x = 0; - output->initial_y = 0; - use_output = output; + drm_setup_output(output, vga_crtc, des_mode); } else if (!strncmp(output->name, "TMDS", 4)) { - output->crtc = vga_crtc; DRM_DEBUG("TMDS preferred mode: %s\n", des_mode->name); - output->crtc->desired_mode = des_mode; - output->initial_x = 0; - output->initial_y = 0; + drm_setup_output(output, tmds_crtc, des_mode); } else if (!strncmp(output->name, "LVDS", 3)) { - output->crtc = lvds_crtc; DRM_DEBUG("LVDS preferred mode: %s\n", des_mode->name); - output->crtc->desired_mode = des_mode; - output->initial_x = 0; - output->initial_y = 0; + drm_setup_output(output, lvds_crtc, des_mode); } else output->crtc = NULL; - + + /* FB config is max of above desired resolutions */ + /* FIXME: per-output FBs/CRTCs */ + if (des_mode->hdisplay > fb->width) { + fb->width = des_mode->hdisplay; + fb->pitch = fb->width; + } + if (des_mode->vdisplay > fb->height) + fb->height = des_mode->vdisplay; } + /* FIXME: multiple depths */ + bytes_per_pixel = 4; + fb->bits_per_pixel = bytes_per_pixel * 8; + fb->depth = bytes_per_pixel * 8; + size = fb->width * fb->height * bytes_per_pixel; + drm_buffer_object_create(dev, size, drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, + 0, 0, 0, + &fbo); + DRM_DEBUG("allocated %dx%d fb: 0x%08lx\n", fb->width, fb->height, + fbo->offset); + fb->offset = fbo->offset; + fb->bo = fbo; + drmfb_probe(dev, fb); + return false; } EXPORT_SYMBOL(drm_initial_config); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index c02dcedc..560c38f4 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -452,8 +452,7 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); -extern bool drm_initial_config(struct drm_device *dev, - struct drm_framebuffer *fb, bool cangrow); +extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); extern bool drm_set_desired_modes(struct drm_device *dev); diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 273a1116..b98f155b 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -112,13 +112,9 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, int i915_driver_load(drm_device_t *dev, unsigned long flags) { drm_i915_private_t *dev_priv; - drm_i915_init_t init; - drm_buffer_object_t *entry; - drm_local_map_t *map; - struct drm_framebuffer *fb; unsigned long agp_size, prealloc_size; unsigned long sareapage; - int hsize, vsize, bytes_per_pixel, size, ret; + int size, ret; dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) @@ -150,6 +146,8 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) return -ENODEV; } + DRM_DEBUG("fb_base: 0x%08lx\n", dev_priv->baseaddr); + ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, _DRM_REGISTERS, _DRM_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map); if (ret != 0) { @@ -177,7 +175,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_bo_driver_init(dev); i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); - DRM_DEBUG("setting up %d bytes of PRIV0 space\n", prealloc_size); + DRM_DEBUG("setting up %ld bytes of PRIV0 space\n", prealloc_size); drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, dev_priv->baseaddr, prealloc_size >> PAGE_SHIFT); @@ -199,13 +197,14 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) dev_priv->ring.Size = size; dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - + /* FIXME: need wrapper with PCI mem checks */ ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, &dev_priv->ring.virtual_start); if (ret) DRM_ERROR("error mapping ring buffer: %d\n", ret); - DRM_DEBUG("ring start %08X, %08X, %08X\n", dev_priv->ring.Start, dev_priv->ring.virtual_start, dev_priv->ring.Size); + DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start, + dev_priv->ring.virtual_start, dev_priv->ring.Size); I915_WRITE(LP_RING + RING_HEAD, 0); I915_WRITE(LP_RING + RING_TAIL, 0); I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); @@ -242,46 +241,15 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); -#if 1 - /* Allocate scanout buffer and command ring */ - /* FIXME: types and other args correct? */ - hsize = 1280; - vsize = 800; - bytes_per_pixel = 4; - size = hsize * vsize * bytes_per_pixel; - drm_buffer_object_create(dev, size, drm_bo_type_kernel, - DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, - 0, 0, 0, - &entry); -#endif intel_modeset_init(dev); + drm_initial_config(dev, false); -#if 1 - fb = drm_framebuffer_create(dev); - if (!fb) { - DRM_ERROR("failed to allocate fb\n"); - return -EINVAL; - } - - fb->width = hsize; - fb->height = vsize; - fb->pitch = hsize; - fb->bits_per_pixel = bytes_per_pixel * 8; - fb->depth = bytes_per_pixel * 8; - fb->offset = entry->offset; - fb->bo = entry; - - drm_initial_config(dev, fb, false); - drmfb_probe(dev, fb); -#endif return 0; } int i915_driver_unload(drm_device_t *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_framebuffer *fb; if (dev_priv->status_page_dmah) { drm_pci_free(dev, dev_priv->status_page_dmah); -- cgit v1.2.3 From a45fa264f2b60185ae797f85d2084d57de49bbca Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 17 Apr 2007 22:27:46 +0200 Subject: Lvds now power up backlight on commit Now saves previous power level in prepare and sets that power level in commit, should power level be 0 it will set maximum level. --- linux-core/intel_display.c | 2 ++ linux-core/intel_lvds.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 48239329..d0a3a465 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -539,11 +539,13 @@ static void intel_crtc_commit (struct drm_crtc *crtc) void intel_output_prepare (struct drm_output *output) { + /* lvds has its own version of prepare see intel_lvds_prepare */ output->funcs->dpms(output, DPMSModeOff); } void intel_output_commit (struct drm_output *output) { + /* lvds has its own version of commit see intel_lvds_commit */ output->funcs->dpms(output, DPMSModeOn); } diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index db025417..8454bbcf 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -209,6 +209,30 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, return true; } +static void intel_lvds_prepare(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & + BACKLIGHT_DUTY_CYCLE_MASK); + + intel_lvds_set_power(dev, false); +} + +static void intel_lvds_commit( struct drm_output *output) +{ + struct drm_device *dev = output->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + if (dev_priv->backlight_duty_cycle == 0) + dev_priv->backlight_duty_cycle = + intel_lvds_get_max_backlight(dev); + + intel_lvds_set_power(dev, true); +} + static void intel_lvds_mode_set(struct drm_output *output, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -321,9 +345,9 @@ static const struct drm_output_funcs intel_lvds_output_funcs = { .restore = intel_lvds_restore, .mode_valid = intel_lvds_mode_valid, .mode_fixup = intel_lvds_mode_fixup, - .prepare = intel_output_prepare, + .prepare = intel_lvds_prepare, .mode_set = intel_lvds_mode_set, - .commit = intel_output_commit, + .commit = intel_lvds_commit, .detect = intel_lvds_detect, .get_modes = intel_lvds_get_modes, .cleanup = intel_lvds_destroy -- cgit v1.2.3 From 73b031df613b58c4462a65818b88200bed0a97de Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 17 Apr 2007 17:30:46 -0700 Subject: Add framebuffer bo freeing to drm_mode_config_cleanup (seems like the best place for now). --- linux-core/drm_crtc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1adae0d2..0fb5b9ae 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -614,8 +614,8 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, 0, 0, 0, &fbo); - DRM_DEBUG("allocated %dx%d fb: 0x%08lx\n", fb->width, fb->height, - fbo->offset); + DRM_DEBUG("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, + fb->height, fbo->offset, fbo); fb->offset = fbo->offset; fb->bo = fbo; drmfb_probe(dev, fb); @@ -639,6 +639,12 @@ void drm_mode_config_cleanup(drm_device_t *dev) list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { drmfb_remove(dev, fb); + /* If this FB was the kernel one, free it */ + if (fb->bo->type == drm_bo_type_kernel) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(fb->bo); + mutex_unlock(&dev->struct_mutex); + } drm_framebuffer_destroy(fb); } } -- cgit v1.2.3 From 7c9e19ba55dcdf212845253648194115639fe7b6 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Fri, 13 Apr 2007 16:43:55 +1000 Subject: clean up ring buffer and TTM in i915_driver_unload I've commented out the framebuffer for now --- linux-core/drm_drv.c | 15 ++++++++------- shared-core/i915_init.c | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 7bb8c659..5aa7137b 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -375,9 +375,6 @@ static void drm_cleanup(drm_device_t * dev) drm_lastclose(dev); drm_fence_manager_takedown(dev); - if (!drm_fb_loaded) - pci_disable_device(dev->pdev); - drm_ctxbitmap_cleanup(dev); if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && dev->agp @@ -389,15 +386,16 @@ static void drm_cleanup(drm_device_t * dev) DRM_DEBUG("mtrr_del=%d\n", retval); } - // drm_bo_driver_finish(dev); - + if (dev->driver->unload) + dev->driver->unload(dev); + if (drm_core_has_AGP(dev) && dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); dev->agp = NULL; } - if (dev->driver->unload) - dev->driver->unload(dev); + + // drm_bo_driver_finish(dev); if (dev->maplist) { drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; @@ -406,6 +404,9 @@ static void drm_cleanup(drm_device_t * dev) drm_ht_remove(&dev->object_hash); } + if (!drm_fb_loaded) + pci_disable_device(dev->pdev); + drm_put_head(&dev->primary); if (drm_put_dev(dev)) DRM_ERROR("Cannot unload module\n"); diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 3e44dd54..0c9ef4d4 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -265,6 +265,7 @@ int i915_driver_unload(drm_device_t *dev) drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, dev_priv->ring.virtual_start); + DRM_DEBUG("usage is %d\n", dev_priv->ring_buffer->usage); mutex_lock(&dev->struct_mutex); drm_bo_usage_deref_locked(dev_priv->ring_buffer); mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 2352ec9bfab20761cc898ea40db2a7c6d53e81f3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 18 Apr 2007 10:39:58 +1000 Subject: backout alanh's broken commit --- linux-core/intel_sdvo.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 6f592f8a..5dbfb8eb 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -70,10 +70,9 @@ static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) int i; if (sdvo_priv->output_device == SDVOB) - bval = I915_READ(SDVOB); - else cval = I915_READ(SDVOC); - + else + bval = I915_READ(SDVOB); /* * Write the registers twice for luck. Sometimes, * writing them only once doesn't appear to 'stick'. -- cgit v1.2.3 From d20aaf485893ed11dd0d68daf63ccadd77b02213 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 18 Apr 2007 10:41:39 +1000 Subject: don't crash if no desired mode --- linux-core/drm_crtc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 0fb5b9ae..437259d5 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -572,7 +572,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* bind analog output to one crtc */ list_for_each_entry(output, &dev->mode_config.output_list, head) { - struct drm_display_mode *des_mode; + struct drm_display_mode *des_mode = NULL; if (list_empty(&output->modes)) continue; @@ -582,6 +582,10 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) if (des_mode->flags & DRM_MODE_TYPE_PREFERRED) break; } + + if (!des_mode) + continue; + if (!strncmp(output->name, "VGA", 3)) { DRM_DEBUG("VGA preferred mode: %s\n", des_mode->name); drm_setup_output(output, vga_crtc, des_mode); -- cgit v1.2.3 From 4f0841a31cbed315a3e891557eadc55cab0dfd23 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 17 Apr 2007 18:03:14 -0700 Subject: Just use drm_output_destroy to cleanup LVDS failures. It'll call our cleanup routine, which will take care of freeing our dev_priv and i2c ddc bus. --- linux-core/intel_lvds.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 8454bbcf..34ed6a9d 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -501,6 +501,5 @@ out: failed: DRM_DEBUG("No LVDS modes found, disabling.\n"); - // intel_lvds_destroy(output); - // drm_output_destroy(output); + drm_output_destroy(output); /* calls intel_lvds_destroy above */ } -- cgit v1.2.3 From 20b2949e3738bc900407d6aeddc6338f05b0b169 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 18 Apr 2007 14:55:43 +1000 Subject: make sure TMDS gets a crtc --- linux-core/drm_crtc.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 437259d5..e8f42feb 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -553,16 +553,19 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) crtc->enabled = 1; crtc->desired_x = 0; crtc->desired_y = 0; - } else if (!lvds_crtc) { - lvds_crtc = crtc; - crtc->enabled = 1; - crtc->desired_x = 0; - crtc->desired_y = 0; - } else if (!tmds_crtc) { - tmds_crtc = crtc; - crtc->enabled = 1; - crtc->desired_x = 0; - crtc->desired_y = 0; + } else { + if (!lvds_crtc) { + lvds_crtc = crtc; + crtc->enabled = 1; + crtc->desired_x = 0; + crtc->desired_y = 0; + } + if (!tmds_crtc) { + tmds_crtc = crtc; + crtc->enabled = 1; + crtc->desired_x = 0; + crtc->desired_y = 0; + } } } -- cgit v1.2.3 From dc03e07f236ea5716d271155dcbbc54a218732c6 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 18 Apr 2007 11:46:04 +0100 Subject: Move SDVO PENDING check to read_response so all SDVO commands benefit from the spin loop. --- linux-core/intel_sdvo.c | 60 +++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 6f592f8a..edc27016 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -254,30 +254,38 @@ static u8 intel_sdvo_read_response(struct drm_output *output, void *response, struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; u8 status; + u8 retry = 50; - /* Read the command response */ - for (i = 0; i < response_len; i++) { - intel_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i, + while (retry--) { + /* Read the command response */ + for (i = 0; i < response_len; i++) { + intel_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i]); - } + } - /* read the return status */ - intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + /* read the return status */ + intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + + if (1) { + printk("%s: R: ", SDVO_NAME(sdvo_priv)); + for (i = 0; i < response_len; i++) + printk("%02X ", ((u8 *)response)[i]); + for (; i < 8; i++) + printk(" "); + if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) + printk("(%s)", cmd_status_names[status]); + else + printk("(??? %d)", status); + printk("\n"); + } - if (1) { - printk("%s: R: ", SDVO_NAME(sdvo_priv)); - for (i = 0; i < response_len; i++) - printk("%02X ", ((u8 *)response)[i]); - for (; i < 8; i++) - printk(" "); - if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - printk("(%s)", cmd_status_names[status]); - else - printk("(??? %d)", status); - printk("\n"); - } - return status; + if (status != SDVO_CMD_STATUS_PENDING) + return status; + + mdelay(50); + } + return SDVO_CMD_STATUS_SUCCESS; } int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) @@ -870,21 +878,9 @@ static enum drm_output_status intel_sdvo_detect(struct drm_output *output) { u8 response[2]; u8 status; - u8 retry = 50; intel_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); - - while (retry--) { - status = intel_sdvo_read_response(output, &response, 2); - - if (status == SDVO_CMD_STATUS_SUCCESS) - break; - - if (status != SDVO_CMD_STATUS_PENDING) - return output_status_unknown; - - mdelay(50); - } + status = intel_sdvo_read_response(output, &response, 2); DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); if ((response[0] != 0) || (response[1] != 0)) -- cgit v1.2.3 From ea8bcb466bca82081816ca3d83a420f09a62870c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 18 Apr 2007 11:47:21 +0100 Subject: Check status after SDVO command for sdvo_set_control_bus_switch --- linux-core/intel_sdvo.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index edc27016..e7618e11 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -298,9 +298,14 @@ int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) return 4; } -static void intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target) +static bool intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target) { + u8 status; + intel_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); + status = intel_sdvo_read_response(output, NULL, 0); + + return (status == SDVO_CMD_STATUS_SUCCESS); } static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0, bool target_1) -- cgit v1.2.3 From 51e867c57880c85c87e187af0a667e9b99413206 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 18 Apr 2007 11:53:25 +0100 Subject: Support the RGB outputs of SDVO cards, which are essentially VGA outs. The drm_initial_config path has specific handling code to name match for VGA, TMDS or LVDS. This is pretty restrictive and should probably be dealt with to be more generic. --- linux-core/intel_sdvo.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index e7618e11..67c3329d 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1014,7 +1014,28 @@ void intel_sdvo_init(drm_device_t *dev, int output_device) memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); - if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) + /* TODO, CVBS, SVID, YPRPB & SCART outputs. + * drm_initial_config probably wants tweaking too to support the + * above. But has fixed VGA, TMDS and LVDS checking code. That should + * be dealt with. + */ + if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) + { + sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; + output->subpixel_order = SubPixelHorizontalRGB; + /* drm_initial_config wants this name, but should be RGB */ + /* Use this for now.... */ + name_prefix="VGA"; + } + else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) + { + sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; + output->subpixel_order = SubPixelHorizontalRGB; + /* drm_initial_config wants this name, but should be RGB */ + /* Use this for now.... */ + name_prefix="VGA"; + } + else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; output->subpixel_order = SubPixelHorizontalRGB; @@ -1031,7 +1052,7 @@ void intel_sdvo_init(drm_device_t *dev, int output_device) unsigned char bytes[2]; memcpy (bytes, &sdvo_priv->caps.output_flags, 2); - DRM_DEBUG("%s: No active TMDS outputs (0x%02x%02x)\n", + DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", SDVO_NAME(sdvo_priv), bytes[0], bytes[1]); } @@ -1063,8 +1084,11 @@ void intel_sdvo_init(drm_device_t *dev, int output_device) sdvo_priv->pixel_clock_max / 1000, (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', - sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0 ? 'Y' : 'N', - sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1 ? 'Y' : 'N'); + /* check currently supported outputs */ + sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', + sdvo_priv->caps.output_flags & + (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); intel_output->ddc_bus = i2cbus; } -- cgit v1.2.3 From 191594ebd5fbe3ac3615247c4e2cd50e1b099635 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 18 Apr 2007 12:07:55 +0100 Subject: When no valid EDID modes are available, we bail. This snippet adds a standard 640x480 @ 60Hz mode when that occurs, so we can continue with a basic mode. Should we do this here though ??? --- linux-core/drm_crtc.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e8f42feb..f6c675c5 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -134,6 +134,15 @@ bool drm_crtc_in_use(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_in_use); +/* + * Detailed mode info for a standard 640x480@60Hz monitor + */ +static struct drm_display_mode std_mode[] = { + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ +}; + void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) { struct drm_output *output; @@ -175,8 +184,22 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) drm_mode_prune_invalid(dev, &output->modes, TRUE); if (list_empty(&output->modes)) { + struct drm_display_mode *newmode; + DRM_DEBUG("No valid modes found on %s\n", output->name); - continue; + + /* Should we do this here ??? + * When no valid EDID modes are available we end up + * here and bailed in the past, now we add a standard + * 640x480@60Hz mode and carry on. + */ + newmode = drm_mode_duplicate(dev, &std_mode[0]); + drm_mode_probed_add(output, newmode); + drm_mode_list_concat(&output->probed_modes, + &output->modes); + + DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", + output->name); } drm_mode_sort(&output->modes); @@ -310,13 +333,11 @@ bool drm_set_desired_modes(struct drm_device *dev) } } /* Skip disabled crtcs */ - if (!output) + if (!output) { + DRM_DEBUG("skipping disabled crtc\n"); continue; - - memset(&crtc->mode, 0, sizeof(crtc->mode)); - if (!crtc->desired_mode->crtc_hdisplay) { - } + if (!drm_crtc_set_mode(crtc, crtc->desired_mode, crtc->desired_x, crtc->desired_y)) return false; -- cgit v1.2.3 From 87b46bd436074572b3a62e2fb7ec85a1db8df892 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 18 Apr 2007 12:10:06 +0100 Subject: free the duplicated mode. --- linux-core/drm_crtc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f6c675c5..16bbd9b6 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -184,7 +184,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) drm_mode_prune_invalid(dev, &output->modes, TRUE); if (list_empty(&output->modes)) { - struct drm_display_mode *newmode; + struct drm_display_mode *stdmode; DRM_DEBUG("No valid modes found on %s\n", output->name); @@ -193,10 +193,11 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) * here and bailed in the past, now we add a standard * 640x480@60Hz mode and carry on. */ - newmode = drm_mode_duplicate(dev, &std_mode[0]); + stdmode = drm_mode_duplicate(dev, &std_mode[0]); drm_mode_probed_add(output, newmode); drm_mode_list_concat(&output->probed_modes, &output->modes); + drm_crtc_mode_destroy(dev, stdmode); DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", output->name); -- cgit v1.2.3 From 0207b51acce0382b2e3cf55ed7dbbe02e48c73b2 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 18 Apr 2007 12:19:16 +0100 Subject: Fix build problem --- linux-core/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 16bbd9b6..02325520 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -194,7 +194,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) * 640x480@60Hz mode and carry on. */ stdmode = drm_mode_duplicate(dev, &std_mode[0]); - drm_mode_probed_add(output, newmode); + drm_mode_probed_add(output, stdmode); drm_mode_list_concat(&output->probed_modes, &output->modes); drm_crtc_mode_destroy(dev, stdmode); -- cgit v1.2.3 From b642ced0830d4e91785ba94677abe637c7cb3791 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 18 Apr 2007 13:52:46 +0100 Subject: Fix return status --- linux-core/intel_sdvo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index c9bc692e..f004c766 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -284,7 +284,7 @@ static u8 intel_sdvo_read_response(struct drm_output *output, void *response, mdelay(50); } - return SDVO_CMD_STATUS_SUCCESS; + return status; } int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) -- cgit v1.2.3 From dfc02547ff5f35bfa5cffd6a0dcb56402db59f33 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 18 Apr 2007 14:18:56 +0100 Subject: Shouldn't free the mode here. It's done later on. --- linux-core/drm_crtc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 02325520..38d596ba 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -197,7 +197,6 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) drm_mode_probed_add(output, stdmode); drm_mode_list_concat(&output->probed_modes, &output->modes); - drm_crtc_mode_destroy(dev, stdmode); DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", output->name); -- cgit v1.2.3 From 5587961cfeff86d8368ff03867a1f0667e4a64d4 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Apr 2007 11:49:42 -0700 Subject: Document main drm_crtc.c functions, and rename drm_crtc_mode_create to drm_mode_create to be consistent with the other functions. Also document where we need locking fixes and what the locks are for. --- linux-core/drm_crtc.c | 520 ++++++++++++++++++++++++++++++++++++++++++++++--- linux-core/drm_crtc.h | 8 +- linux-core/drm_edid.c | 4 +- linux-core/drm_modes.c | 4 +- 4 files changed, 498 insertions(+), 38 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 38d596ba..a099a6dc 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1,9 +1,55 @@ +/* + * Copyright (c) 2006-2007 Intel Corporation + * Copyright (c) 2007 Dave Airlie + * + * DRM core CRTC related functions + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Authors: + * Keith Packard + * Eric Anholt + * Dave Airlie + * Jesse Barnes + */ #include #include "drm.h" #include "drmP.h" #include "drm_crtc.h" -int drm_mode_idr_get(struct drm_device *dev, void *ptr) +/** + * drm_idr_get - allocate a new identifier + * @dev: DRM device + * @ptr: object pointer, used to generate unique ID + * + * LOCKING: + * Process context (either init or calling process). Must take DRM mode_config + * lock around IDR allocation. + * + * Create a unique identifier based on @ptr in @dev's identifier space. Used + * for tracking modes, CRTCs and outputs. + * + * RETURNS: + * New unique (relative to other objects in @dev) integer identifier for the + * object. + */ +int drm_idr_get(struct drm_device *dev, void *ptr) { int new_id = 0; int ret; @@ -25,11 +71,34 @@ again: return new_id; } -void drm_mode_idr_put(struct drm_device *dev, int id) +/** + * drm_idr_put - free an identifer + * @dev: DRM device + * @id: ID to free + * + * LOCKING: + * Caller must hold DRM mode_config lock. + * + * Free @id from @dev's unique identifier pool. + */ +void drm_idr_put(struct drm_device *dev, int id) { idr_remove(&dev->mode_config.crtc_idr, id); } +/** + * drm_framebuffer_create - create a new framebuffer object + * @dev: DRM device + * + * LOCKING: + * Process context (either init or calling process). Must take DRM mode_config + * lock around mode_config manipulation. + * + * Creates a new framebuffer objects and adds it to @dev's DRM mode_config. + * + * RETURNS: + * Pointer to new framebuffer or NULL on error. + */ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) { struct drm_framebuffer *fb; @@ -49,7 +118,7 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) return NULL; } - fb->id = drm_mode_idr_get(dev, fb); + fb->id = drm_idr_get(dev, fb); fb->dev = dev; spin_lock(&dev->mode_config.config_lock); dev->mode_config.num_fb++; @@ -60,21 +129,30 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) } EXPORT_SYMBOL(drm_framebuffer_create); +/** + * drm_framebuffer_destroy - remove a framebuffer object + * @fb: framebuffer to remove + * + * LOCKING: + * Process context (either init or calling process). Must take DRM mode_config + * lock around mode_config manipulation. + * + * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes + * it, setting it to NULL. + */ void drm_framebuffer_destroy(struct drm_framebuffer *fb) { drm_device_t *dev = fb->dev; + struct drm_crtc *crtc; /* remove from any CRTC */ - { - struct drm_crtc *crtc; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb == fb) - crtc->fb = NULL; - } + spin_lock(&dev->mode_config.config_lock); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->fb == fb) + crtc->fb = NULL; } - spin_lock(&dev->mode_config.config_lock); - drm_mode_idr_put(dev, fb->id); + drm_idr_put(dev, fb->id); list_del(&fb->head); dev->mode_config.num_fb--; spin_unlock(&dev->mode_config.config_lock); @@ -82,6 +160,20 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) kfree(fb); } +/** + * drm_crtc_create - create a new CRTC object + * @dev: DRM device + * @funcs: callbacks for the new CRTC + * + * LOCKING: + * Process context (either init or calling process). Must take DRM mode_config + * lock around mode_config manipulation. + * + * Creates a new CRTC object and adds it to @dev's mode_config structure. + * + * RETURNS: + * Pointer to new CRTC object or NULL on error. + */ struct drm_crtc *drm_crtc_create(drm_device_t *dev, const struct drm_crtc_funcs *funcs) { @@ -94,7 +186,7 @@ struct drm_crtc *drm_crtc_create(drm_device_t *dev, crtc->dev = dev; crtc->funcs = funcs; - crtc->id = drm_mode_idr_get(dev, crtc); + crtc->id = drm_idr_get(dev, crtc); spin_lock(&dev->mode_config.config_lock); list_add_tail(&crtc->head, &dev->mode_config.crtc_list); @@ -105,6 +197,17 @@ struct drm_crtc *drm_crtc_create(drm_device_t *dev, } EXPORT_SYMBOL(drm_crtc_create); +/** + * drm_crtc_destroy - remove a CRTC object + * @crtc: CRTC to remove + * + * LOCKING: + * Process context (either init or calling process). Must take DRM mode_config + * lock around mode_config traversal. + * + * Cleanup @crtc. Calls @crtc's cleanup function, then removes @crtc from + * its associated DRM device's mode_config. Frees it afterwards. + */ void drm_crtc_destroy(struct drm_crtc *crtc) { drm_device_t *dev = crtc->dev; @@ -112,9 +215,8 @@ void drm_crtc_destroy(struct drm_crtc *crtc) if (crtc->funcs->cleanup) (*crtc->funcs->cleanup)(crtc); - spin_lock(&dev->mode_config.config_lock); - drm_mode_idr_put(dev, crtc->id); + drm_idr_put(dev, crtc->id); list_del(&crtc->head); dev->mode_config.num_crtc--; spin_unlock(&dev->mode_config.config_lock); @@ -122,6 +224,18 @@ void drm_crtc_destroy(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_destroy); +/** + * drm_crtc_in_use - check if a given CRTC is in a mode_config + * @crtc: CRTC to check + * + * LOCKING: + * Caller? (FIXME) + * + * Walk @crtc's DRM device's mode_config and see if it's in use. + * + * RETURNS: + * True if @crtc is part of the mode_config, false otherwise. + */ bool drm_crtc_in_use(struct drm_crtc *crtc) { struct drm_output *output; @@ -143,6 +257,25 @@ static struct drm_display_mode std_mode[] = { V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ }; +/** + * drm_crtc_probe_output_modes - get complete set of display modes + * @dev: DRM device + * @maxX: max width for modes + * @maxY: max height for modes + * + * LOCKING: + * Caller? (FIXME) + * + * Based on @dev's mode_config layout, scan all the outputs and try to detect + * modes on them. Modes will first be added to the output's probed_modes + * list, then culled (based on validity and the @maxX, @maxY parameters) and + * put into the normal modes list. + * + * Intended to be used either at bootup time or when major configuration + * changes have occurred. + * + * FIXME: take into account monitor limits + */ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) { struct drm_output *output; @@ -186,7 +319,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) if (list_empty(&output->modes)) { struct drm_display_mode *stdmode; - DRM_DEBUG("No valid modes found on %s\n", output->name); + DRM_DEBUG("No valid modes on %s\n", output->name); /* Should we do this here ??? * When no valid EDID modes are available we end up @@ -214,6 +347,22 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) } } +/** + * drm_crtc_set_mode - set a mode + * @crtc: CRTC to program + * @mode: mode to use + * @x: width of mode + * @y: height of mode + * + * LOCKING: + * Caller? (FIXME) + * + * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance + * to fixup or reject the mode prior to trying to set it. + * + * RETURNS: + * True if the mode was set successfully, or false otherwise. + */ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y) { @@ -299,7 +448,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, } /* XXX free adjustedmode */ - drm_crtc_mode_destroy(dev, adjusted_mode); + drm_mode_destroy(dev, adjusted_mode); ret = TRUE; /* TODO */ // if (scrn->pScreen) @@ -318,6 +467,20 @@ done: return ret; } +/** + * drm_set_desired_modes - set a good mode on every CRTC & output + * @dev: DRM device + * + * LOCKING: + * Caller? (FIXME) + * + * Each CRTC may have a desired mode associated with it. This routine simply + * walks @dev's mode_config and sets the desired mode on every CRTC. Intended + * for use at startup time. + * + * RETURNS: + * True if modes were set, false otherwise. + */ bool drm_set_desired_modes(struct drm_device *dev) { struct drm_crtc *crtc; @@ -326,7 +489,8 @@ bool drm_set_desired_modes(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { output = NULL; - list_for_each_entry(list_output, &dev->mode_config.output_list, head) { + list_for_each_entry(list_output, &dev->mode_config.output_list, + head) { if (list_output->crtc == crtc) { output = list_output; break; @@ -348,6 +512,16 @@ bool drm_set_desired_modes(struct drm_device *dev) } EXPORT_SYMBOL(drm_set_desired_modes); +/** + * drm_disable_unused_functions - disable unused objects + * @dev: DRM device + * + * LOCKING: + * Caller? (FIXME) + * + * If an output or CRTC isn't part of @dev's mode_config, it can be disabled + * by calling its dpms function, which should power it off. + */ void drm_disable_unused_functions(struct drm_device *dev) { struct drm_output *output; @@ -369,9 +543,14 @@ void drm_disable_unused_functions(struct drm_device *dev) * @output: output the new mode * @mode: mode data * + * LOCKING: + * Process context (either init or calling process). Must take @output's + * mode_lock around mode list manipulation. + * * Add @mode to @output's mode list for later use. */ -void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode) +void drm_mode_probed_add(struct drm_output *output, + struct drm_display_mode *mode) { spin_lock(&output->modes_lock); list_add(&mode->head, &output->probed_modes); @@ -384,6 +563,10 @@ EXPORT_SYMBOL(drm_mode_probed_add); * @output: output list to modify * @mode: mode to remove * + * LOCKING: + * Process context (either init or calling process). Must take @output's + * mode_lock around mode list manipulation. + * * Remove @mode from @output's mode list, then free it. */ void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) @@ -395,8 +578,21 @@ void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_remove); -/* - * Probably belongs in the DRM device structure +/** + * drm_output_create - create a new output + * @dev: DRM device + * @funcs: callbacks for this output + * @name: user visible name of the output + * + * LOCKING: + * Process context (either init or calling process). Must take @dev's + * mode_config lock around mode list manipulation. + * + * Creates a new drm_output structure and adds it to @dev's mode_config + * structure. + * + * RETURNS: + * Pointer to the new output or NULL on error. */ struct drm_output *drm_output_create(drm_device_t *dev, const struct drm_output_funcs *funcs, @@ -410,7 +606,7 @@ struct drm_output *drm_output_create(drm_device_t *dev, output->dev = dev; output->funcs = funcs; - output->id = drm_mode_idr_get(dev, output); + output->id = drm_idr_get(dev, output); if (name) strncpy(output->name, name, DRM_OUTPUT_LEN); output->name[DRM_OUTPUT_LEN - 1] = 0; @@ -433,6 +629,18 @@ struct drm_output *drm_output_create(drm_device_t *dev, } EXPORT_SYMBOL(drm_output_create); +/** + * drm_output_destroy - remove an output + * @output: output to remove + * + * LOCKING: + * Process context (either init or calling process). Must take @dev's + * mode_config lock around mode list manipulation. Caller must hold + * modes lock? (FIXME) + * + * Call @output's cleanup function, then remove the output from the DRM + * mode_config after freeing @output's modes. + */ void drm_output_destroy(struct drm_output *output) { struct drm_device *dev = output->dev; @@ -448,13 +656,26 @@ void drm_output_destroy(struct drm_output *output) drm_mode_remove(output, mode); spin_lock(&dev->mode_config.config_lock); - drm_mode_idr_put(dev, output->id); + drm_idr_put(dev, output->id); list_del(&output->head); spin_unlock(&dev->mode_config.config_lock); kfree(output); } EXPORT_SYMBOL(drm_output_destroy); +/** + * drm_output_rename - rename an output + * @output: output to rename + * @name: new user visible name + * + * LOCKING: + * None. + * + * Simply stuff a new name into @output's name field, based on @name. + * + * RETURNS: + * True if the name was changed, false otherwise. + */ bool drm_output_rename(struct drm_output *output, const char *name) { if (!name) @@ -472,7 +693,19 @@ bool drm_output_rename(struct drm_output *output, const char *name) } EXPORT_SYMBOL(drm_output_rename); -struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev) +/** + * drm_mode_create - create a new display mode + * @dev: DRM device + * + * LOCKING: + * None. + * + * Create a new drm_display_mode, give it an ID, and return it. + * + * RETURNS: + * Pointer to new mode on success, NULL on error. + */ +struct drm_display_mode *drm_mode_create(struct drm_device *dev) { struct drm_display_mode *nmode; @@ -480,17 +713,37 @@ struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev) if (!nmode) return NULL; - nmode->mode_id = drm_mode_idr_get(dev, nmode); + nmode->mode_id = drm_idr_get(dev, nmode); return nmode; } -void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) +/** + * drm_mode_destroy - remove a mode + * @dev: DRM device + * @mode: mode to remove + * + * LOCKING: + * None. + * + * Free @mode's unique identifier, then free it. + */ +void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) { - drm_mode_idr_put(dev, mode->mode_id); + drm_idr_put(dev, mode->mode_id); kfree(mode); } +/** + * drm_mode_config_init - initialize DRM mode_configuration structure + * @dev: DRM device + * + * LOCKING: + * None, should happen single threaded at init time. + * + * Initialize @dev's mode_config structure, used for tracking the graphics + * configuration of @dev. + */ void drm_mode_config_init(drm_device_t *dev) { spin_lock_init(&dev->mode_config.config_lock); @@ -501,6 +754,21 @@ void drm_mode_config_init(drm_device_t *dev) } EXPORT_SYMBOL(drm_mode_config_init); +/** + * drm_get_buffer_object - find the buffer object for a given handle + * @dev: DRM device + * @bo: pointer to caller's buffer_object pointer + * @handle: handle to lookup + * + * LOCKING: + * Must take @dev's struct_mutex to protect buffer object lookup. + * + * Given @handle, lookup the buffer object in @dev and put it in the caller's + * @bo pointer. + * + * RETURNS: + * Zero on success, -EINVAL if the handle couldn't be found. + */ static int drm_get_buffer_object(drm_device_t *dev, struct drm_buffer_object **bo, unsigned long handle) { drm_user_object_t *uo; @@ -530,6 +798,18 @@ out_err: return ret; } +/** + * drm_setup_output - setup an output structure + * @output: output to setup + * @crtc: CRTC this output belongs to + * @mode: desired mode for this output + * + * LOCKING: + * None. + * + * Setup @output with the parameters given, with its initial coordinates set + * at the origin. + */ static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc, struct drm_display_mode *mode) { @@ -542,12 +822,19 @@ static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc, /** * drm_initial_config - setup a sane initial output configuration * @dev: DRM device - * @fb: framebuffer backing for new setup * @can_grow: this configuration is growable * + * LOCKING: + * Must take various locks. (FIXME) + * * Scan the CRTCs and outputs and try to put together an initial setup. * At the moment, this is a cloned configuration across all heads with - * @fb as the backing store. + * a new framebuffer object as the backing store. + * + * FIXME: return value and better initial config. + * + * RETURNS: + * Zero if everything went ok, nonzero otherwise. */ bool drm_initial_config(drm_device_t *dev, bool can_grow) { @@ -652,6 +939,18 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) } EXPORT_SYMBOL(drm_initial_config); +/** + * drm_mode_config_cleanup - free up DRM mode_config info + * @dev: DRM device + * + * LOCKING: + * Caller? (FIXME) + * + * Free up all the outputs and CRTCs associated with this DRM device, then + * free up the framebuffers and associated buffer objects. + * + * FIXME: cleanup any dangling user buffer objects too + */ void drm_mode_config_cleanup(drm_device_t *dev) { struct drm_output *output, *ot; @@ -678,6 +977,23 @@ void drm_mode_config_cleanup(drm_device_t *dev) } EXPORT_SYMBOL(drm_mode_config_cleanup); +/** + * drm_crtc_set_config - set a new config from userspace + * @crtc: CRTC to setup + * @crtc_info: user provided configuration + * @new_mode: new mode to set + * @output_set: set of outputs for the new config + * @fb: new framebuffer + * + * LOCKING: + * Caller? (FIXME) + * + * Setup a new configuration, provided by the user in @crtc_info, and enable + * it. + * + * RETURNS: + * Zero. (FIXME) + */ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set, struct drm_framebuffer *fb) { drm_device_t *dev = crtc->dev; @@ -743,6 +1059,17 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, return 0; } +/** + * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo + * @out: drm_mode_modeinfo struct to return to the user + * @in: drm_display_mode to use + * + * LOCKING: + * None. + * + * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to + * the user. + */ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in) { @@ -765,7 +1092,24 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display } -/* IOCTL code from userspace */ +/** + * drm_mode_getresources - get graphics configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Construct a set of configuration description structures and return + * them to the user, including CRTC, output and framebuffer configuration. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ int drm_mode_getresources(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -882,6 +1226,23 @@ done: return retcode; } +/** + * drm_mode_getcrtc - get CRTC configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Construct a CRTC configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ int drm_mode_getcrtc(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -923,6 +1284,23 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, return retcode; } +/** + * drm_mode_getoutput - get output configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Construct a output configuration structure to return to the user. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ int drm_mode_getoutput(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -977,7 +1355,23 @@ done: return retcode; } - +/** + * drm_mode_setcrtc - set CRTC configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Build a new CRTC configuration based on user request. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ int drm_mode_setcrtc(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1061,7 +1455,23 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, return retcode; } -/* Add framebuffer ioctl */ +/** + * drm_mode_addfb - add an FB to the graphics configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Add a new FB to the specified CRTC, given a user request. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ int drm_mode_addfb(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1123,6 +1533,23 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, return 0; } +/** + * drm_mode_rmfb - remove an FB from the configuration + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Remove the FB specified by the user. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ int drm_mode_rmfb(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1149,6 +1576,23 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, return 0; } +/** + * drm_mode_getfb - get FB info + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Lookup the FB given its ID and return info about it. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ int drm_mode_getfb(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1180,6 +1624,20 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, return 0; } +/** + * drm_fb_release - remove and free the FBs on this file + * @filp: file * from the ioctl + * + * LOCKING: + * Caller? (FIXME) + * + * Destroy all the FBs associated with @filp. + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ void drm_fb_release(struct file *filp) { drm_file_t *priv = filp->private_data; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index f8d7da26..7128afe1 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -361,7 +361,7 @@ struct drm_output { unsigned long possible_clones; bool interlace_allowed; bool doublescan_allowed; - spinlock_t modes_lock; + spinlock_t modes_lock; /* protects modes and probed_modes lists */ struct list_head modes; /* list of modes on this output */ /* OptionInfoPtr options; @@ -401,7 +401,7 @@ struct drm_mode_config_funcs { * */ struct drm_mode_config { - spinlock_t config_lock; + spinlock_t config_lock; /* protects configuration and IDR */ struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output, modes - just makes life easier */ /* this is limited to one for now */ int num_fb; @@ -439,8 +439,8 @@ extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_disable_unused_functions(struct drm_device *dev); -extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); -extern void drm_crtc_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); +extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); +extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_list_concat(struct list_head *head, struct list_head *new); extern void drm_mode_validate_size(struct drm_device *dev, diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 9acdc8da..a9cf23a1 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -66,7 +66,7 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, struct drm_display_mode *mode; int hsize = t->hsize * 8 + 248, vsize; - mode = drm_crtc_mode_create(dev); + mode = drm_mode_create(dev); if (!mode) return NULL; @@ -109,7 +109,7 @@ struct drm_display_mode *drm_mode_detailed(drm_device_t *dev, return NULL; } - mode = drm_crtc_mode_create(dev); + mode = drm_mode_create(dev); if (!mode) return NULL; diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index df34fc27..7d976d9f 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -152,7 +152,7 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *nmode; int new_id; - nmode = drm_crtc_mode_create(dev); + nmode = drm_mode_create(dev); if (!nmode) return NULL; @@ -184,6 +184,7 @@ bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mod } EXPORT_SYMBOL(drm_mode_equal); +/* caller must hold modes lock */ void drm_mode_validate_size(struct drm_device *dev, struct list_head *mode_list, int maxX, int maxY, int maxPitch) @@ -224,6 +225,7 @@ void drm_mode_validate_clocks(struct drm_device *dev, } EXPORT_SYMBOL(drm_mode_validate_clocks); +/* caller must hold modes lock */ void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose) { -- cgit v1.2.3 From 8d893e49ec35905a3718c565ec56c21d76dc745c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 19 Apr 2007 09:43:46 +1000 Subject: backout SDVO control bus check and comment why this is a bad idea --- linux-core/intel_sdvo.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index f004c766..507b0f5e 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -297,14 +297,14 @@ int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) return 4; } -static bool intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target) +/** + * Don't check status code from this as it switches the bus back to the + * SDVO chips which defeats the purpose of doing a bus switch in the first + * place. + */ +void intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target) { - u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); - status = intel_sdvo_read_response(output, NULL, 0); - - return (status == SDVO_CMD_STATUS_SUCCESS); } static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0, bool target_1) -- cgit v1.2.3 From 6238ebee21f800cec6c77b6bf90d7916ca945931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 20 Apr 2007 16:52:04 -0400 Subject: Clean up and return if no outputs are found. --- linux-core/intel_sdvo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 507b0f5e..98c4034d 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1054,6 +1054,8 @@ void intel_sdvo_init(drm_device_t *dev, int output_device) DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", SDVO_NAME(sdvo_priv), bytes[0], bytes[1]); + drm_output_destroy(output); + return; } strcpy (name, name_prefix); strcat (name, name_suffix); -- cgit v1.2.3 From 2d1de1fc6b9ab3524a1247f56ddeea7238c04ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 20 Apr 2007 18:06:31 -0400 Subject: Initialize rwlock using rwlock_init to appease lockdep validator. --- linux-core/drm_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index be075bb3..6be6f218 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -495,7 +495,7 @@ void drm_fence_manager_init(drm_device_t * dev) int i; - fm->lock = RW_LOCK_UNLOCKED; + rwlock_init(&fm->lock); write_lock(&fm->lock); fm->initialized = 0; if (!fed) -- cgit v1.2.3 From 9ca4932054a5bde5dda500ea346ad101bb5c80a0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 20 Apr 2007 16:32:58 -0700 Subject: Add a mode name generation wrapper to make name format changes easier. --- linux-core/drm_crtc.h | 1 + linux-core/drm_edid.c | 5 ++--- linux-core/drm_modes.c | 7 +++++++ linux-core/intel_display.c | 5 ++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 7128afe1..e5a89b17 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -437,6 +437,7 @@ extern void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); +extern void drm_mode_set_name(struct drm_display_mode *mode); extern void drm_disable_unused_functions(struct drm_device *dev); extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index a9cf23a1..0d067929 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -79,7 +79,7 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, else vsize = (hsize * 9) / 16; - snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", hsize, vsize); + drm_mode_set_name(mode); return mode; } @@ -132,8 +132,7 @@ struct drm_display_mode *drm_mode_detailed(drm_device_t *dev, pt->vsync_pulse_width_lo); mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo); - snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, - mode->vdisplay); + drm_mode_set_name(mode); if (pt->interlaced) mode->flags |= V_INTERLACE; diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 7d976d9f..44498c5e 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -45,6 +45,13 @@ void drm_mode_debug_printmodeline(struct drm_device *dev, } EXPORT_SYMBOL(drm_mode_debug_printmodeline); +void drm_mode_set_name(struct drm_display_mode *mode) +{ + snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, + mode->vdisplay); +} +EXPORT_SYMBOL(drm_mode_set_name); + void drm_mode_list_concat(struct list_head *head, struct list_head *new) { diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index d0a3a465..a6f94fb1 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1057,9 +1057,8 @@ struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; mode->vsync_start = (vsync & 0xffff) + 1; mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; - /* FIXME: pull name generation into a common routine */ - snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, - mode->vdisplay); + + drm_mode_set_name(mode); drm_mode_set_crtcinfo(mode, 0); return mode; -- cgit v1.2.3 From a21ff375c697fc7560c16d0f88335a6db2c9c37a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 20 Apr 2007 17:03:50 -0700 Subject: Document drm_modes.c functions. --- linux-core/drm_modes.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 166 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 44498c5e..648e85e5 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -33,6 +33,16 @@ #include "drm.h" #include "drm_crtc.h" +/** + * drm_mode_debug_printmodeline - debug print a mode + * @dev: DRM device + * @mode: mode to print + * + * LOCKING: + * None. + * + * Describe @mode using DRM_DEBUG. + */ void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode) { @@ -45,6 +55,15 @@ void drm_mode_debug_printmodeline(struct drm_device *dev, } EXPORT_SYMBOL(drm_mode_debug_printmodeline); +/** + * drm_mode_set_name - set the name on a mode + * @mode: name will be set in this mode + * + * LOCKING: + * None. + * + * Set the name of @mode to a standard format. + */ void drm_mode_set_name(struct drm_display_mode *mode) { snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay, @@ -52,6 +71,16 @@ void drm_mode_set_name(struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_set_name); +/** + * drm_mode_list_concat - move modes from one list to another + * @head: source list + * @new: dst list + * + * LOCKING: + * Caller must ensure both lists are locked. + * + * Move all the modes from @head to @new. + */ void drm_mode_list_concat(struct list_head *head, struct list_head *new) { @@ -62,6 +91,20 @@ void drm_mode_list_concat(struct list_head *head, struct list_head *new) } } +/** + * drm_mode_width - get the width of a mode + * @mode: mode + * + * LOCKING: + * None. + * + * Return @mode's width (hdisplay) value. + * + * FIXME: is this needed? + * + * RETURNS: + * @mode->hdisplay + */ int drm_mode_width(struct drm_display_mode *mode) { return mode->hdisplay; @@ -69,12 +112,40 @@ int drm_mode_width(struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_width); +/** + * drm_mode_height - get the height of a mode + * @mode: mode + * + * LOCKING: + * None. + * + * Return @mode's height (vdisplay) value. + * + * FIXME: is this needed? + * + * RETURNS: + * @mode->vdisplay + */ int drm_mode_height(struct drm_display_mode *mode) { return mode->vdisplay; } EXPORT_SYMBOL(drm_mode_height); +/** + * drm_mode_vrefresh - get the vrefresh of a mode + * @mode: mode + * + * LOCKING: + * None. + * + * Return @mode's vrefresh rate or calculate it if necessary. + * + * FIXME: why is this needed? + * + * RETURNS: + * Vertical refresh rate of @mode. + */ int drm_mode_vrefresh(struct drm_display_mode *mode) { int refresh = 0; @@ -94,7 +165,16 @@ int drm_mode_vrefresh(struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_vrefresh); - +/** + * drm_mode_set_crtcinfo - set CRTC modesetting parameters + * @p: mode + * @adjust_flags: unused? (FIXME) + * + * LOCKING: + * None. + * + * Setup the CRTC modesetting parameters for @p, adjusting if necessary. + */ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) { if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) @@ -150,6 +230,9 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo); * drm_mode_duplicate - allocate and duplicate an existing mode * @m: mode to duplicate * + * LOCKING: + * None. + * * Just allocate a new mode, copy the existing mode into it, and return * a pointer to it. Used to create new instances of established modes. */ @@ -171,6 +254,19 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, } EXPORT_SYMBOL(drm_mode_duplicate); +/** + * drm_mode_equal - test modes for equality + * @mode1: first mode + * @mode2: second mode + * + * LOCKING: + * None. + * + * Check to see if @mode1 and @mode2 are equivalent. + * + * RETURNS: + * True if the modes are equal, false otherwise. + */ bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2) { if (mode1->clock == mode2->clock && @@ -191,7 +287,21 @@ bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mod } EXPORT_SYMBOL(drm_mode_equal); -/* caller must hold modes lock */ +/** + * drm_mode_validate_size - make sure modes adhere to size constraints + * @dev: DRM device + * @mode_list: list of modes to check + * @maxX: maximum width + * @maxY: maximum height + * @maxPitch: max pitch + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * The DRM device (@dev) has size and pitch limits. Here we validate the + * modes we probed for @dev against those limits and set their status as + * necessary. + */ void drm_mode_validate_size(struct drm_device *dev, struct list_head *mode_list, int maxX, int maxY, int maxPitch) @@ -211,6 +321,22 @@ void drm_mode_validate_size(struct drm_device *dev, } EXPORT_SYMBOL(drm_mode_validate_size); +/** + * drm_mode_validate_clocks - validate modes against clock limits + * @dev: DRM device + * @mode_list: list of modes to check + * @min: minimum clock rate array + * @max: maximum clock rate array + * @n_ranges: number of clock ranges (size of arrays) + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * Some code may need to check a mode list against the clock limits of the + * device in question. This function walks the mode list, testing to make + * sure each mode falls within a given range (defined by @min and @max + * arrays) and sets @mode->status as needed. + */ void drm_mode_validate_clocks(struct drm_device *dev, struct list_head *mode_list, int *min, int *max, int n_ranges) @@ -232,7 +358,19 @@ void drm_mode_validate_clocks(struct drm_device *dev, } EXPORT_SYMBOL(drm_mode_validate_clocks); -/* caller must hold modes lock */ +/** + * drm_mode_prune_invalid - remove invalid modes from mode list + * @dev: DRM device + * @mode_list: list of modes to check + * @verbose: be verbose about it + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * Once mode list generation is complete, a caller can use this routine to + * remove invalid modes from a mode list. If any of the modes have a + * status other than %MODE_OK, they are removed from @mode_list and freed. + */ void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose) { @@ -248,6 +386,21 @@ void drm_mode_prune_invalid(struct drm_device *dev, } } +/** + * drm_mode_compare - compare modes for favorability + * @lh_a: list_head for first mode + * @lh_b: list_head for second mode + * + * LOCKING: + * None. + * + * Compare two modes, given by @lh_a and @lh_b, returning a value indicating + * which is better. + * + * RETURNS: + * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or + * positive if @lh_b is better than @lh_a. + */ static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b) { struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head); @@ -265,6 +418,7 @@ static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b) return diff; } +/* FIXME: what we don't have a list sort function? */ /* list sort from Mark J Roberts (mjr@znex.org) */ void list_sort(struct list_head *head, int (*cmp)(struct list_head *a, struct list_head *b)) { @@ -342,6 +496,15 @@ void list_sort(struct list_head *head, int (*cmp)(struct list_head *a, struct li list->prev = head; } +/** + * drm_mode_sort - sort mode list + * @mode_list: list to sort + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * Sort @mode_list by favorability, putting good modes first. + */ void drm_mode_sort(struct list_head *mode_list) { list_sort(mode_list, drm_mode_compare); -- cgit v1.2.3 From eb892fb09dc2e5206f2461e8b258495c7cef904a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 20 Apr 2007 17:59:30 -0700 Subject: Add a monitor information structure separate from the EDID data for tracking monitor limits, etc. --- linux-core/drm_crtc.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++- linux-core/intel_lvds.c | 21 +++++++------------ shared-core/drm.h | 1 + 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index e5a89b17..e3e97ad8 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -168,6 +168,59 @@ enum subpixel_order { SubPixelNone, }; +/* + * Describes a given display (e.g. CRT or flat panel) and its limitations. + */ +struct drm_display_info { + char name[DRM_DISPLAY_INFO_LEN]; + /* Input info */ + bool serration_vsync; + bool sync_on_green; + bool composite_sync; + bool separate_syncs; + bool blank_to_black; + unsigned char video_level; + bool digital; + /* Physical size */ + unsigned int width_mm; + unsigned int height_mm; + + /* Display parameters */ + unsigned char gamma; /* FIXME: storage format */ + bool gtf_supported; + bool standard_color; + enum { + monochrome, + rgb, + other, + unknown, + } display_type; + bool active_off_supported; + bool suspend_supported; + bool standby_supported; + + /* Color info FIXME: storage format */ + unsigned short redx, redy; + unsigned short greenx, greeny; + unsigned short bluex, bluey; + unsigned short whitex, whitey; + + /* Clock limits FIXME: storage format */ + unsigned int min_vfreq, max_vfreq; + unsigned int min_hfreq, max_hfreq; + unsigned int pixel_clock; + + /* White point indices FIXME: storage format */ + unsigned int wpx1, wpy1; + unsigned int wpgamma1; + unsigned int wpx2, wpy2; + unsigned int wpgamma2; + + /* Preferred mode (if any) */ + struct drm_display_mode *preferred_mode; + struct edid *raw_edid; /* if any */ +}; + struct drm_framebuffer { struct drm_device *dev; struct list_head head; @@ -376,7 +429,7 @@ struct drm_output { /* xf86MonPtr MonInfo; */ enum subpixel_order subpixel_order; int mm_width, mm_height; - struct edid *monitor_info; + struct drm_display_info *monitor_info; /* if any */ char name[DRM_OUTPUT_LEN]; const struct drm_output_funcs *funcs; void *driver_private; diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 34ed6a9d..74b040ba 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -284,7 +284,6 @@ static int intel_lvds_get_modes(struct drm_output *output) { struct drm_device *dev = output->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct edid *edid_info; int ret = 0; ret = intel_ddc_get_modes(output); @@ -294,23 +293,19 @@ static int intel_lvds_get_modes(struct drm_output *output) /* Didn't get an EDID */ if (!output->monitor_info) { - struct detailed_data_monitor_range *edid_range; - edid_info = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL); - if (!edid_info) + struct drm_display_info *dspinfo; + dspinfo = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL); + if (!dspinfo) goto out; - edid_info->detailed_timings[0].data.other_data.type = - EDID_DETAIL_MONITOR_RANGE; - edid_range = &edid_info->detailed_timings[0].data.other_data.data.range; - /* Set wide sync ranges so we get all modes * handed to valid_mode for checking */ - edid_range->min_vfreq = 0; - edid_range->max_vfreq = 200; - edid_range->min_hfreq_khz = 0; - edid_range->max_hfreq_khz = 200; - output->monitor_info = edid_info; + dspinfo->min_vfreq = 0; + dspinfo->max_vfreq = 200; + dspinfo->min_hfreq = 0; + dspinfo->max_hfreq = 200; + output->monitor_info = dspinfo; } out: diff --git a/shared-core/drm.h b/shared-core/drm.h index 6c626f66..b55640e1 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -893,6 +893,7 @@ typedef union drm_mm_init_arg{ /* * Drm mode setting */ +#define DRM_DISPLAY_INFO_LEN 32 #define DRM_OUTPUT_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 -- cgit v1.2.3 From 97b5599982c76915b0750c6ef0a270639b02a6f2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 20 Apr 2007 18:00:44 -0700 Subject: Oops, edid data should just be a char *, as edid.h is private to edid.c (we can just recombine them now). --- linux-core/drm_crtc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index e3e97ad8..149bc31f 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -218,7 +218,7 @@ struct drm_display_info { /* Preferred mode (if any) */ struct drm_display_mode *preferred_mode; - struct edid *raw_edid; /* if any */ + char *raw_edid; /* if any */ }; struct drm_framebuffer { -- cgit v1.2.3 From 0f3c5148f02bd98411095fdc8059207fa17b4a7d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 23 Apr 2007 09:10:46 +1000 Subject: fixup vrefresh reporting, it should now be *1000 in userspace --- linux-core/drm_crtc.c | 2 +- linux-core/drm_modes.c | 14 +++++++++++--- shared-core/drm.h | 2 ++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a099a6dc..f95facce 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1085,7 +1085,7 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display out->vsync_end = in->vsync_end; out->vtotal = in->vtotal; out->vscan = in->vscan; - + out->vrefresh = in->vrefresh; out->flags = in->flags; strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 648e85e5..54c25137 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -47,7 +47,7 @@ void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode) { DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d\n", - mode->mode_id, mode->name, mode->vrefresh / 1000, mode->clock, + mode->mode_id, mode->name, mode->vrefresh, mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->vdisplay, mode->vsync_start, @@ -144,16 +144,24 @@ EXPORT_SYMBOL(drm_mode_height); * FIXME: why is this needed? * * RETURNS: - * Vertical refresh rate of @mode. + * Vertical refresh rate of @mode x 1000. For precision reasons. */ int drm_mode_vrefresh(struct drm_display_mode *mode) { int refresh = 0; + unsigned int calc_val; if (mode->vrefresh > 0) refresh = mode->vrefresh; else if (mode->htotal > 0 && mode->vtotal > 0) { - refresh = ((mode->clock * 1000) * 1000) / mode->htotal / mode->vtotal; + /* work out vrefresh the value will be x1000 */ + calc_val = (mode->clock * 1000); + + calc_val /= mode->htotal; + calc_val *= 1000; + calc_val /= mode->vtotal; + + refresh = calc_val; if (mode->flags & V_INTERLACE) refresh *= 2; if (mode->flags & V_DBLSCAN) diff --git a/shared-core/drm.h b/shared-core/drm.h index b55640e1..d42bf73a 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -905,6 +905,8 @@ struct drm_mode_modeinfo { unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; + unsigned int vrefresh; /* vertical refresh * 1000 */ + unsigned int flags; char name[DRM_DISPLAY_MODE_LEN]; -- cgit v1.2.3 From ceb44021ad7755721acc3c0307c54009b666442e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 23 Apr 2007 11:42:29 +1000 Subject: drm: make mode numbers no change by comparing probed modes The mode list sets all the output modes to UNVERIFIED, then probes a new list, If a mode is on the new list and not on the old, it adds it to the old, if a mode is on the new list and old, it just updates the status to the new mode status. If a mode is on the old list and not on the new, prune invalid modes should remove all UNVERIFIED modes --- linux-core/drm_crtc.c | 7 +++---- linux-core/drm_crtc.h | 1 + linux-core/drm_modes.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f95facce..16cf62a7 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -286,8 +286,9 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) list_for_each_entry(output, &dev->mode_config.output_list, head) { + /* set all modes to the unverified state */ list_for_each_entry_safe(mode, t, &output->modes, head) - drm_mode_remove(output, mode); + mode->status = MODE_UNVERIFIED; output->status = (*output->funcs->detect)(output); @@ -300,9 +301,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) ret = (*output->funcs->get_modes)(output); if (ret) { - /* move the modes over to the main mode list */ - drm_mode_list_concat(&output->probed_modes, - &output->modes); + drm_mode_output_list_update(output); } if (maxX && maxY) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 149bc31f..a15ce0cf 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -59,6 +59,7 @@ enum drm_mode_status { MODE_ONE_HEIGHT, /* only one height is supported */ MODE_ONE_SIZE, /* only one resolution is supported */ MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ + MODE_UNVERIFIED = -3, /* mode needs to reverified */ MODE_BAD = -2, /* unspecified reason */ MODE_ERROR = -1 /* error condition */ }; diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 54c25137..3293f91d 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -517,3 +517,42 @@ void drm_mode_sort(struct list_head *mode_list) { list_sort(mode_list, drm_mode_compare); } + + +/** + * drm_mode_output_list_update - update the mode list for the output + * @output: the output to update + * + * LOCKING: + * Caller must hold a lock protecting @mode_list. + * + * This moves the modes from the @output probed_modes list + * to the actual mode list. It compares the probed mode against the current + * list and only adds different modes. All modes unverified after this point + * will be removed by the prune invalid modes. + */ +void drm_mode_output_list_update(struct drm_output *output) +{ + struct drm_display_mode *mode, *t; + struct drm_display_mode *pmode, *pt; + int found_it; + list_for_each_entry_safe(pmode, pt, &output->probed_modes, + head) { + found_it = 0; + /* go through current modes checking for the new probed mode */ + list_for_each_entry(mode, &output->modes, head) { + if (drm_mode_equal(pmode, mode)) { + found_it = 1; + /* if equal delete the probed mode */ + mode->status = pmode->status; + list_del(&pmode->head); + kfree(pmode); + break; + } + } + + if (!found_it) { + list_move_tail(&pmode->head, &output->modes); + } + } +} -- cgit v1.2.3 From 34be91fe4e9f0ad73b7c4354aea0c8ce10f45f68 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 26 Apr 2007 14:50:00 +1000 Subject: i915: fix vblank pipe setup --- linux-core/intel_display.c | 24 ++++++++++++++++++++---- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index a6f94fb1..7d581175 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -333,6 +333,24 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target, return (err != target); } +void +intel_set_vblank(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + int vbl_pipe = 0; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + intel_crtc = crtc->driver_private; + + if (crtc->enabled) + vbl_pipe |= (1<pipe); + } + + dev_priv->vblank_pipe = vbl_pipe; + i915_enable_interrupt(dev); +} void intel_wait_for_vblank(drm_device_t *dev) { @@ -910,10 +928,8 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, /* Flush the plane changes */ intel_pipe_set_base(crtc, x, y); -#ifdef XF86DRI // TODO -// I830DRISetVBlankInterrupt (pScrn, TRUE); -#endif - + intel_set_vblank(dev); + intel_wait_for_vblank(dev); } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 2dd76d30..946e464f 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -237,6 +237,7 @@ extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); extern int i915_emit_irq(drm_device_t * dev); extern void i915_user_irq_on(drm_i915_private_t *dev_priv); extern void i915_user_irq_off(drm_i915_private_t *dev_priv); +extern void i915_enable_interrupt (drm_device_t *dev); extern int i915_vblank_swap(DRM_IOCTL_ARGS); /* i915_mem.c */ diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4047e77e..870fe402 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -489,7 +489,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } -static void i915_enable_interrupt (drm_device_t *dev) +void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -- cgit v1.2.3 From 8e8e37515eafbd75b971f57f767ef01344361256 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 1 May 2007 13:15:41 +1000 Subject: fix unusued variable --- linux-core/drm_modes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 3293f91d..97f7607d 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -533,7 +533,7 @@ void drm_mode_sort(struct list_head *mode_list) */ void drm_mode_output_list_update(struct drm_output *output) { - struct drm_display_mode *mode, *t; + struct drm_display_mode *mode; struct drm_display_mode *pmode, *pt; int found_it; list_for_each_entry_safe(pmode, pt, &output->probed_modes, -- cgit v1.2.3 From 89231953d108e74ee7b0eb99494ead1dd795d640 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 1 May 2007 13:16:29 +1000 Subject: Add support for user defined modes This allows userspace to specify modes and add them to the modesetting system and attach modes to outputs --- libdrm/xf86drmMode.c | 33 +++---- libdrm/xf86drmMode.h | 16 ++-- linux-core/drm_crtc.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++- linux-core/drm_crtc.h | 19 +++- linux-core/drm_drv.c | 4 + shared-core/drm.h | 12 ++- 6 files changed, 312 insertions(+), 29 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index b695467b..93b0af76 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -376,37 +376,38 @@ err_allocs: return 0; } -#if 0 -uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo) +uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *mode_info) { - /* TODO impl */ + if (ioctl(fd, DRM_IOCTL_MODE_ADDMODE, mode_info)) + return 0; + + return mode_info->id; } -int drmModeDesMode(int fd, uint32_t modeId) +int drmModeRmMode(int fd, uint32_t mode_id) { - // return ioctl(fd, DRM_IOCTL_MODE_DESMODE, modeId); + return ioctl(fd, DRM_IOCTL_MODE_RMMODE, mode_id); } -int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId) +int drmModeAttachMode(int fd, uint32_t output_id, uint32_t mode_id) { - drm_mode_outputmode_t res; + struct drm_mode_mode_cmd res; - res.outputId = outputId; - res.modeId = modeId; + res.output_id = output_id; + res.mode_id = mode_id; - // return ioctl(fd, DRM_IOCTL_MODE_ADDMODE, &res); + return ioctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res); } -int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId) +int drmModeDetachMode(int fd, uint32_t output_id, uint32_t mode_id) { - drm_mode_outputmode_t res; + struct drm_mode_mode_cmd res; - res.outputId = outputId; - res.modeId = modeId; + res.output_id = output_id; + res.mode_id = mode_id; - // return ioctl(fd, DRM_IOCTL_MODE_DELMODE, &res); + return ioctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res); } -#endif diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 6aa104a9..60e919ae 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -261,24 +261,24 @@ extern drmModeOutputPtr drmModeGetOutput(int fd, uint32_t outputId); /** - * Creates a new mode from the given mode info. + * Adds a new mode from the given mode info. * Name must be unique. */ -extern uint32_t drmModeNewMode(int fd, struct drm_mode_modeinfo *modeInfo); +extern uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *modeInfo); /** - * Destroys a mode created with CreateMode, must be unused. + * Removes a mode created with AddMode, must be unused. */ -extern int drmModeDesMode(int fd, uint32_t modeId); +extern int drmModeRmMode(int fd, uint32_t modeId); /** - * Adds the given mode to an output. + * Attaches the given mode to an output. */ -extern int drmModeAddMode(int fd, uint32_t outputId, uint32_t modeId); +extern int drmModeAttachMode(int fd, uint32_t outputId, uint32_t modeId); /** - * Deletes a mode Added with AddOutputMode from the output, + * Detaches a mode from the output * must be unused, by the given mode. */ -extern int drmModeDelMode(int fd, uint32_t outputId, uint32_t modeId); +extern int drmModeDetachMode(int fd, uint32_t outputId, uint32_t modeId); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 16cf62a7..201137db 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -749,6 +749,7 @@ void drm_mode_config_init(drm_device_t *dev) INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); + INIT_LIST_HEAD(&dev->mode_config.usermode_list); idr_init(&dev->mode_config.crtc_idr); } EXPORT_SYMBOL(drm_mode_config_init); @@ -1090,6 +1091,35 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } +/** + * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode + * @out: drm_display_mode to return to the user + * @in: drm_mode_modeinfo to use + * + * LOCKING: + * None. + * + * Convert a drmo_mode_modeinfo into a drm_display_mode structure to return to + * the caller. + */ +void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modeinfo *in) +{ + out->clock = in->clock; + out->hdisplay = in->hdisplay; + out->hsync_start = in->hsync_start; + out->hsync_end = in->hsync_end; + out->htotal = in->htotal; + out->hskew = in->hskew; + out->vdisplay = in->vdisplay; + out->vsync_start = in->vsync_start; + out->vsync_end = in->vsync_end; + out->vtotal = in->vtotal; + out->vscan = in->vscan; + out->vrefresh = in->vrefresh; + out->flags = in->flags; + strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); + out->name[DRM_DISPLAY_MODE_LEN-1] = 0; +} /** * drm_mode_getresources - get graphics configuration @@ -1143,6 +1173,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each(lh, &output->modes) mode_count++; } + list_for_each(lh, &dev->mode_config.usermode_list) + mode_count++; if (copy_from_user(&card_res, argp, sizeof(card_res))) return -EFAULT; @@ -1155,6 +1187,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each(lh, &output->modes) mode_count++; } + list_for_each(lh, &dev->mode_config.usermode_list) + mode_count++; } /* handle this in 4 parts */ @@ -1211,6 +1245,14 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, } } } + /* add in user modes */ + list_for_each_entry(mode, &dev->mode_config.usermode_list, head) { + drm_crtc_convert_to_umode(&u_mode, mode); + if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { + retcode = -EFAULT; + goto done; + } + } } card_res.count_modes = mode_count; @@ -1312,6 +1354,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, int mode_count = 0; int retcode = 0; int copied = 0; + int i; if (copy_from_user(&out_resp, argp, sizeof(out_resp))) return -EFAULT; @@ -1323,6 +1366,10 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, list_for_each_entry(mode, &output->modes, head) mode_count++; + + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) + if (output->user_mode_ids[i] != 0) + mode_count++; strncpy(out_resp.name, output->name, DRM_OUTPUT_NAME_LEN); out_resp.name[DRM_OUTPUT_NAME_LEN-1] = 0; @@ -1344,6 +1391,14 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, goto done; } } + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { + if (output->user_mode_ids[i] != 0) + if (put_user(output->user_mode_ids[i], &out_resp.modes[copied++])) { + retcode = -EFAULT; + goto done; + } + } + } out_resp.count_modes = mode_count; @@ -1408,9 +1463,13 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, if (!mode || (mode->mode_id != crtc_req.mode)) { struct drm_output *output; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - list_for_each_entry(mode, &output->modes, head) { - drm_mode_debug_printmodeline(dev, mode); + list_for_each_entry(output, + &dev->mode_config.output_list, + head) { + list_for_each_entry(mode, &output->modes, + head) { + drm_mode_debug_printmodeline(dev, + mode); } } @@ -1650,3 +1709,195 @@ void drm_fb_release(struct file *filp) } } + +/** + * drm_fb_newmode - adds a user defined mode + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * Adds a user specified mode to the kernel. + * + * Called by the user via ioctl. + * + * RETURNS: + * writes new mode id into arg. + * Zero on success, errno on failure. + */ +int drm_mode_addmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_modeinfo __user *argp = (void __user *)arg; + struct drm_mode_modeinfo new_mode; + struct drm_display_mode *user_mode; + + if (copy_from_user(&new_mode, argp, sizeof(new_mode))) + return -EFAULT; + + user_mode = drm_mode_create(dev); + if (!user_mode) + return -ENOMEM; + + drm_crtc_convert_umode(user_mode, &new_mode); + user_mode->type |= DRM_MODE_TYPE_USERDEF; + + user_mode->output_count = 0; + + spin_lock(&dev->mode_config.config_lock); + list_add(&user_mode->head, &dev->mode_config.usermode_list); + spin_unlock(&dev->mode_config.config_lock); + + new_mode.id = user_mode->mode_id; + if (copy_to_user(argp, &new_mode, sizeof(new_mode))) + return -EFAULT; + + return 0; +} + +/** + * drm_fb_rmmode - removes a user defined mode + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * Remove the user defined mode specified by the user. + * + * Called by the user via ioctl + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_rmmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + uint32_t id = arg; + struct drm_display_mode *mode, *t; + int retcode = -EINVAL; + + mode = idr_find(&dev->mode_config.crtc_idr, id); + if (!mode || (id != mode->mode_id)) + return -EINVAL; + + if (!(mode->type & DRM_MODE_TYPE_USERDEF)) + return -EINVAL; + + if (mode->output_count) + return -EINVAL; + + spin_lock(&dev->mode_config.config_lock); + list_for_each_entry(t, &dev->mode_config.usermode_list, head) { + if (t == mode) { + list_del(&mode->head); + drm_mode_destroy(dev, mode); + retcode = 0; + break; + } + } + spin_unlock(&dev->mode_config.config_lock); + return retcode; +} + +/** + * drm_fb_attachmode - Attach a user mode to an output + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * This attaches a user specified mode to an output. + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_attachmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_mode_cmd __user *argp = (void __user *)arg; + struct drm_mode_mode_cmd mode_cmd; + struct drm_output *output; + struct drm_display_mode *mode; + int i; + + if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) + return -EFAULT; + + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); + if (!mode || (mode->mode_id != mode_cmd.mode_id)) + return -EINVAL; + + output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); + if (!output || (output->id != mode_cmd.output_id)) + return -EINVAL; + + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { + if (output->user_mode_ids[i] == 0) { + output->user_mode_ids[i] = mode->mode_id; + mode->output_count++; + break; + } + } + + if (i == DRM_OUTPUT_MAX_UMODES) + return -ENOSPC; + + return 0; +} + + +/** + * drm_fb_detachmode - Detach a user specified mode from an output + * @inode: inode from the ioctl + * @filp: file * from the ioctl + * @cmd: cmd from ioctl + * @arg: arg from ioctl + * + * Called by the user via ioctl. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_mode_detachmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->head->dev; + struct drm_mode_mode_cmd __user *argp = (void __user *)arg; + struct drm_mode_mode_cmd mode_cmd; + struct drm_output *output; + struct drm_display_mode *mode; + int i, found = 0; + + if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) + return -EFAULT; + + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); + if (!mode || (mode->mode_id != mode_cmd.mode_id)) + return -EINVAL; + + output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); + if (!output || (output->id != mode_cmd.output_id)) + return -EINVAL; + + + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { + if (output->user_mode_ids[i] == mode->mode_id) { + output->user_mode_ids[i] = 0; + mode->output_count--; + found = 1; + } + } + + if (!found) + return -EINVAL; + + return 0; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index a15ce0cf..12c7eef1 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -87,6 +87,7 @@ struct drm_display_mode { struct list_head head; char name[DRM_DISPLAY_MODE_LEN]; int mode_id; + int output_count; enum drm_mode_status status; int type; @@ -382,6 +383,7 @@ struct drm_output_funcs { void (*cleanup)(struct drm_output *output); }; +#define DRM_OUTPUT_MAX_UMODES 16 #define DRM_OUTPUT_LEN 32 /** * drm_output - central DRM output control structure @@ -417,6 +419,7 @@ struct drm_output { bool doublescan_allowed; spinlock_t modes_lock; /* protects modes and probed_modes lists */ struct list_head modes; /* list of modes on this output */ + /* OptionInfoPtr options; XF86ConfMonitorPtr conf_monitor; @@ -434,7 +437,8 @@ struct drm_output { char name[DRM_OUTPUT_LEN]; const struct drm_output_funcs *funcs; void *driver_private; - /* RROutputPtr randr_output? */ + + u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES]; }; /** @@ -467,6 +471,7 @@ struct drm_mode_config { int num_crtc; struct list_head crtc_list; + struct list_head usermode_list; int min_width, min_height; int max_width, max_height; /* DamagePtr rotationDamage? */ @@ -480,6 +485,7 @@ struct drm_output *drm_output_create(struct drm_device *dev, const char *name); extern void drm_output_destroy(struct drm_output *output); extern bool drm_output_rename(struct drm_output *output, const char *name); +extern void drm_fb_release(struct file *filp); extern int drm_add_edid_modes(struct drm_output *output, struct i2c_adapter *adapter); @@ -507,6 +513,8 @@ extern void drm_mode_sort(struct list_head *mode_list); extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); +extern void drm_mode_output_list_update(struct drm_output *output); + extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, @@ -531,5 +539,14 @@ extern int drm_mode_rmfb(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_mode_getfb(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int drm_mode_addmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_rmmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_attachmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_mode_detachmode(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5aa7137b..dc52f302 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -130,6 +130,10 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDFB)] = {drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MODE_RMFB)] = {drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MODE_GETFB)] = {drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_ADDMODE)] = {drm_mode_addmode, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_RMMODE)] = {drm_mode_rmmode, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_ATTACHMODE)] = {drm_mode_attachmode, DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_MODE_DETACHMODE)] = {drm_mode_detachmode, DRM_MASTER|DRM_ROOT_ONLY}, }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index d42bf73a..890dcf88 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -978,6 +978,11 @@ struct drm_mode_fb_cmd { unsigned int depth; }; +struct drm_mode_mode_cmd { + unsigned int output_id; + unsigned int mode_id; +}; + /** * \name Ioctls Definitions */ @@ -1055,7 +1060,12 @@ struct drm_mode_fb_cmd { #define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc) #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xA4, struct drm_mode_fb_cmd) #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) -#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) + +#define DRM_IOCTL_MODE_ADDMODE DRM_IOWR(0xA7, struct drm_mode_modeinfo) +#define DRM_IOCTL_MODE_RMMODE DRM_IOWR(0xA8, unsigned int) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) /*@}*/ /** -- cgit v1.2.3 From 3a69e2484a4a392c8fc8542fc44f9c6552589c46 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 1 May 2007 14:20:22 +1000 Subject: cleanup usermodes on drm mode setting shutdown --- linux-core/drm_crtc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 201137db..a8f14e17 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -956,6 +956,7 @@ void drm_mode_config_cleanup(drm_device_t *dev) struct drm_output *output, *ot; struct drm_crtc *crtc, *ct; struct drm_framebuffer *fb, *fbt; + struct drm_display_mode *mode, *mt; list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_output_destroy(output); } @@ -964,6 +965,10 @@ void drm_mode_config_cleanup(drm_device_t *dev) drm_crtc_destroy(crtc); } + list_for_each_entry_safe(mode, mt, &dev->mode_config.usermode_list, head) { + drm_mode_destroy(dev, mode); + } + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { drmfb_remove(dev, fb); /* If this FB was the kernel one, free it */ -- cgit v1.2.3 From 45e09ea3cf85b76c18fb92a593ca7c40681052a7 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Sat, 5 May 2007 16:08:27 +0200 Subject: Cleaned up userspace interface for modesetting. --- libdrm/xf86drmMode.c | 30 ++++-------------- libdrm/xf86drmMode.h | 88 ++++------------------------------------------------ 2 files changed, 12 insertions(+), 106 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 93b0af76..a7241ffd 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -238,15 +238,10 @@ drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) return r; } -#if 0 -int drmModeForceProbe(int fd, uint32_t outputId) -{ - /* TODO impl/keep? */ -} -#endif + /* - * Crtc function. + * Crtc functions */ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) @@ -274,9 +269,7 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) r->x = crtc.x; r->y = crtc.y; r->mode = crtc.mode; -// r->width = crtc.width; -// r->height = crtc.height; - r->buffer_id = crtc.fb_id; + r->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; r->count_outputs = crtc.count_outputs; r->count_possibles = crtc.count_possibles; @@ -305,8 +298,8 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, crtc.x = x; crtc.y = y; - crtc.crtc_id = crtcId; - crtc.fb_id = bufferId; + crtc.crtc_id = crtcId; + crtc.fb_id = bufferId; crtc.set_outputs = outputs; crtc.count_outputs = count; crtc.mode = modeId; @@ -314,22 +307,11 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); } -#if 0 -drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtc, int *count) -{ - /* TODO impl */ -} -int drmModeSetCrtcGamma(int fd, uint32_t crtcId, - drmModeGammaTriplePtr ptr, int count) -{ - /* TODO impl */ -} - -#endif /* * Output manipulation */ + drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) { struct drm_mode_get_output out; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 60e919ae..b25a6610 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -40,25 +40,17 @@ * In order to use this interface you must include either or another * header defining uint32_t, int32_t and uint16_t. * - * It aims to provide a randr compatible interface for modesettings in the + * It aims to provide a randr1.2 compatible interface for modesettings in the * kernel, the interface is also ment to be used by libraries like EGL. * * More information can be found in randrproto.txt which can be found here: * http://gitweb.freedesktop.org/?p=xorg/proto/randrproto.git * - * All framebuffer, crtc and output ids start at 1 while 0 is either an invalid - * parameter or used to indicate that the command should disconnect from the - * currently bound target, as with drmModeMapOutput. - * - * Currently only one framebuffer exist and has a id of 1, which is also the - * default framebuffer and should allways be avaible to the client, unless - * it is locked/used or any other limiting state is applied on it. - * + * There are some major diffrences to be noted. Unlike the randr1.2 proto you + * need to create the memory object of the framebuffer yourself with the ttm + * buffer object interface. This object needs to be pinned. */ -typedef struct _drmModeGammaTriple { - uint16_t r, g, b; -} drmModeGammaTriple, *drmModeGammaTriplePtr; typedef struct _drmModeRes { @@ -130,53 +122,7 @@ typedef struct _drmModeOutput { } drmModeOutput, *drmModeOutputPtr; -/* - * RRSetScreenConfig o - * RRGetScreenInfo o - * - * RRGetScreenSizeRange - see frameBuffer info - * RRSetScreenSize - * RRGetScreenResources - * - * RRGetOutputInfo - * - * RRListOutputProperties * - * RRQueryOutputProperty * - * RRConfigureOutputProperty * - * RRChangeOutputProperty * - * RRDeleteOutputProperty * - * RRGetOutputProperty * - * - * RRCreateMode - * RRDestroyMode - * RRAddOutputMode - * RRDeleteOutputMode - * - * RRGetCrtcInfo - * RRSetCrtcConfig - * - * RRGetCrtcGammaSize - see crtc info - * RRGetCrtcGamma - * RRSetCrtcGamma - * - * drmModeGetResources - * drmModeForceProbe - * - * drmModeGetFrameBufferInfo - * drmModeSetFrameBufferSize - * - * drmModeGetCrtcInfo - * drmModeSetCrtcConfig - * drmModeGetCrtcGamma - * drmModeSetCrtcGamma - * - * drmModeGetOutputInfo - * - * drmModeAddMode - * drmModeDestroyMode - * drmModeAddOutputMode - * drmModeDeleteOutputMode - */ + extern void drmModeFreeModeInfo( struct drm_mode_modeinfo *ptr ); extern void drmModeFreeResources( drmModeResPtr ptr ); @@ -189,11 +135,6 @@ extern void drmModeFreeOutput( drmModeOutputPtr ptr ); */ extern drmModeResPtr drmModeGetResources(int fd); -/** - * Forces a probe of the give output outputId, on 0 all will be probed. - */ -extern int drmModeForceProbe(int fd, uint32_t outputId); - /* * FrameBuffer manipulation. @@ -215,13 +156,9 @@ extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, */ extern int drmModeRmFB(int fd, uint32_t bufferId); -/** - * Changes the scanout buffer to the given buffer object. - */ -extern int drmModeFlipFrameBuffer(int fd, uint32_t bufferId, drmBO *bo); /* - * Crtc function. + * Crtc functions */ /** @@ -236,19 +173,6 @@ extern int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t modeId, uint32_t *outputs, int count); -/** - * Gets the gamma from a crtc - */ -extern drmModeGammaTriplePtr drmModeGetCrtcGamma(int fd, uint32_t crtcId, - int *count); - -/** - * Sets the gamma on a crtc - */ -extern int drmModeSetCrtcGamma(int fd, uint32_t crtcId, - drmModeGammaTriplePtr ptr, int count); - - /* * Output manipulation -- cgit v1.2.3 From eba00df1203040905d38bf0ef449d25d6dbdb72c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 10 May 2007 13:16:05 +0100 Subject: Just some minor cleanups. --- linux-core/drm_fb.c | 5 ++--- linux-core/intel_sdvo.c | 3 --- shared-core/i915_drv.h | 1 + shared-core/i915_init.c | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index ef05341a..c0453258 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -106,8 +106,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) struct fb_info *info; struct drmfb_par *par; struct device *device = &dev->pdev->dev; - struct fb_var_screeninfo *var_info; - unsigned long base, size; + unsigned long size = (8*1024*1024); /* FIXME */ int ret; info = framebuffer_alloc(sizeof(struct drmfb_par), device); @@ -126,7 +125,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) strcpy(info->fix.id, "drmfb"); info->fix.smem_start = fb->offset + dev->mode_config.fb_base; - info->fix.smem_len = (8*1024*1024); + info->fix.smem_len = size; info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_DIRECTCOLOR; info->fix.accel = FB_ACCEL_NONE; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 98c4034d..58aa432c 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -525,7 +525,6 @@ static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output, static int intel_sdvo_get_clock_rate_mult(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; u8 response, status; intel_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); @@ -895,8 +894,6 @@ static enum drm_output_status intel_sdvo_detect(struct drm_output *output) static int intel_sdvo_get_modes(struct drm_output *output) { - struct drm_display_mode *modes; - /* set the bus switch and get the modes */ intel_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2); intel_ddc_get_modes(output); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 946e464f..0513eed8 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -221,6 +221,7 @@ extern void i915_emit_breadcrumb(drm_device_t *dev); extern void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync); extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush); extern int i915_driver_firstopen(struct drm_device *dev); +extern int i915_dma_cleanup(drm_device_t * dev); /* i915_irq.c */ extern int i915_irq_emit(DRM_IOCTL_ARGS); diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 0c9ef4d4..43040e6e 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -202,7 +202,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) /* FIXME: need wrapper with PCI mem checks */ ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, - &dev_priv->ring.virtual_start); + (void **) &dev_priv->ring.virtual_start); if (ret) DRM_ERROR("error mapping ring buffer: %d\n", ret); -- cgit v1.2.3 From 5ce8aaae7251e60c078eda0a21894aae0e1d7a45 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 May 2007 12:46:36 +0100 Subject: Large changes for fbdev support. Change from DIRECTCOLOR to TRUECOLOR, and enable support for PSEUDOCOLOR. DIRECTCOLOR support needs more work. Add the ability to change the mode on the fbdev device. Support depth 8, 15, 16 and 24 (and 32). Add a /dev/fbX device per CRTC, but there's some code which doesn't allocate the fbX device unless the output is actually enabled. Read the code on this as it impacts the fbcon map flags. Pick CRTC's based on the available outputs. More work could be done here to match modes, so cloning could be achieved on outputs. This fits more inline with what the X code does. --- linux-core/drm_crtc.c | 234 +++++++++++++++++---------------------- linux-core/drm_crtc.h | 11 +- linux-core/drm_fb.c | 267 +++++++++++++++++++++++++++++++++++++++++---- linux-core/intel_display.c | 23 ++-- linux-core/intel_drv.h | 2 +- linux-core/intel_lvds.c | 12 +- linux-core/intel_sdvo.c | 14 +-- 7 files changed, 375 insertions(+), 188 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a8f14e17..d710a4e7 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -466,51 +466,6 @@ done: return ret; } -/** - * drm_set_desired_modes - set a good mode on every CRTC & output - * @dev: DRM device - * - * LOCKING: - * Caller? (FIXME) - * - * Each CRTC may have a desired mode associated with it. This routine simply - * walks @dev's mode_config and sets the desired mode on every CRTC. Intended - * for use at startup time. - * - * RETURNS: - * True if modes were set, false otherwise. - */ -bool drm_set_desired_modes(struct drm_device *dev) -{ - struct drm_crtc *crtc; - struct drm_output *output, *list_output; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - output = NULL; - - list_for_each_entry(list_output, &dev->mode_config.output_list, - head) { - if (list_output->crtc == crtc) { - output = list_output; - break; - } - } - /* Skip disabled crtcs */ - if (!output) { - DRM_DEBUG("skipping disabled crtc\n"); - continue; - } - - if (!drm_crtc_set_mode(crtc, crtc->desired_mode, - crtc->desired_x, crtc->desired_y)) - return false; - } - - drm_disable_unused_functions(dev); - return true; -} -EXPORT_SYMBOL(drm_set_desired_modes); - /** * drm_disable_unused_functions - disable unused objects * @dev: DRM device @@ -799,26 +754,82 @@ out_err: } /** - * drm_setup_output - setup an output structure - * @output: output to setup - * @crtc: CRTC this output belongs to - * @mode: desired mode for this output + * drm_pick_crtcs - pick crtcs for output devices + * @dev: DRM device * * LOCKING: * None. - * - * Setup @output with the parameters given, with its initial coordinates set - * at the origin. */ -static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc, - struct drm_display_mode *mode) +static void drm_pick_crtcs (drm_device_t *dev) { - output->crtc = crtc; - output->crtc->desired_mode = mode; - output->initial_x = 0; - output->initial_y = 0; + int c, o; + struct drm_output *output, *output_equal; + struct drm_crtc *crtc; + struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + output->crtc = NULL; + + /* Don't hook up outputs that are disconnected ?? + * + * This is debateable. Do we want fixed /dev/fbX or + * dynamic on hotplug (need mode code for that though) ? + * + * If we don't hook up outputs now, then we only create + * /dev/fbX for the output that's enabled, that's good as + * the users console will be on that output. + * + * If we do hook up outputs that are disconnected now, then + * the user may end up having to muck about with the fbcon + * map flags to assign his console to the enabled output. Ugh. + */ + if (output->status != output_status_connected) + continue; + + des_mode = NULL; + list_for_each_entry(des_mode, &output->modes, head) { + if (des_mode->flags & DRM_MODE_TYPE_PREFERRED) + break; + } + + c = -1; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + c++; + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + +#if 0 /* should we try and clone ?? - code not tested - FIXME */ + o = -1; + list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { + o++; + if (output->id == output_equal->id) + continue; + + list_for_each_entry(modes, &output->modes, head) { + list_for_each_entry(modes_equal, &output_equal->modes, head) { + if (drm_mode_equal (modes, modes_equal)) { + if ((output->possible_clones & (1 << o))) { + goto clone; + } + } + } + } + } + +clone: +#endif + /* Found a CRTC to attach to, do it ! */ + output->crtc = crtc; + output->crtc->desired_mode = des_mode; + output->initial_x = 0; + output->initial_y = 0; + DRM_DEBUG("Desired mode for CRTC %d is %dx%x\n",c,des_mode->hdisplay,des_mode->vdisplay); + break; + } + } } + /** * drm_initial_config - setup a sane initial output configuration * @dev: DRM device @@ -831,109 +842,61 @@ static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc, * At the moment, this is a cloned configuration across all heads with * a new framebuffer object as the backing store. * - * FIXME: return value and better initial config. - * * RETURNS: * Zero if everything went ok, nonzero otherwise. */ bool drm_initial_config(drm_device_t *dev, bool can_grow) { /* do a hardcoded initial configuration here */ - struct drm_crtc *crtc, *vga_crtc = NULL, *tmds_crtc = NULL, - *lvds_crtc = NULL; + struct drm_display_mode *des_mode = NULL; struct drm_output *output; struct drm_framebuffer *fb; drm_buffer_object_t *fbo; unsigned long size, bytes_per_pixel; - fb = drm_framebuffer_create(dev); - if (!fb) { - DRM_ERROR("failed to allocate fb.\n"); - return true; - } - - /* bind both CRTCs to this fb */ - /* only initialise one crtc to enabled state */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - crtc->fb = fb; - if (!vga_crtc) { - vga_crtc = crtc; - crtc->enabled = 1; - crtc->desired_x = 0; - crtc->desired_y = 0; - } else { - if (!lvds_crtc) { - lvds_crtc = crtc; - crtc->enabled = 1; - crtc->desired_x = 0; - crtc->desired_y = 0; - } - if (!tmds_crtc) { - tmds_crtc = crtc; - crtc->enabled = 1; - crtc->desired_x = 0; - crtc->desired_y = 0; - } - } - } - drm_crtc_probe_output_modes(dev, 2048, 2048); - /* hard bind the CRTCS */ + drm_pick_crtcs(dev); - /* bind analog output to one crtc */ list_for_each_entry(output, &dev->mode_config.output_list, head) { - struct drm_display_mode *des_mode = NULL; - if (list_empty(&output->modes)) + /* can't setup the output if there's no assigned crtc or mode */ + if (!output->crtc || !output->crtc->desired_mode) continue; - /* Get the first preferred moded */ - list_for_each_entry(des_mode, &output->modes, head) { - if (des_mode->flags & DRM_MODE_TYPE_PREFERRED) - break; + fb = drm_framebuffer_create(dev); + if (!fb) { + DRM_ERROR("failed to allocate fb.\n"); + return true; } + output->crtc->fb = fb; + des_mode = output->crtc->desired_mode; - if (!des_mode) - continue; - - if (!strncmp(output->name, "VGA", 3)) { - DRM_DEBUG("VGA preferred mode: %s\n", des_mode->name); - drm_setup_output(output, vga_crtc, des_mode); - } else if (!strncmp(output->name, "TMDS", 4)) { - DRM_DEBUG("TMDS preferred mode: %s\n", des_mode->name); - drm_setup_output(output, tmds_crtc, des_mode); - } else if (!strncmp(output->name, "LVDS", 3)) { - DRM_DEBUG("LVDS preferred mode: %s\n", des_mode->name); - drm_setup_output(output, lvds_crtc, des_mode); - } else - output->crtc = NULL; - - /* FB config is max of above desired resolutions */ - /* FIXME: per-output FBs/CRTCs */ if (des_mode->hdisplay > fb->width) { fb->width = des_mode->hdisplay; fb->pitch = fb->width; } if (des_mode->vdisplay > fb->height) fb->height = des_mode->vdisplay; - } - /* FIXME: multiple depths */ - bytes_per_pixel = 4; - fb->bits_per_pixel = bytes_per_pixel * 8; - fb->depth = bytes_per_pixel * 8; - size = fb->width * fb->height * bytes_per_pixel; - drm_buffer_object_create(dev, size, drm_bo_type_kernel, + /* FIXME: multiple depths */ + bytes_per_pixel = 4; + fb->bits_per_pixel = 32; + fb->depth = 24; + size = fb->pitch * fb->height * bytes_per_pixel; + /* FIXME - what about resizeable objects ??? */ + drm_buffer_object_create(dev, size, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE, 0, 0, 0, &fbo); - DRM_DEBUG("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, - fb->height, fbo->offset, fbo); - fb->offset = fbo->offset; - fb->bo = fbo; - drmfb_probe(dev, fb); + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, + fb->height, fbo->offset, fbo); + fb->offset = fbo->offset; + fb->bo = fbo; + drmfb_probe(dev, output->crtc); + } + drm_disable_unused_functions(dev); return false; } @@ -1582,17 +1545,20 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, r.buffer_id = fb->id; list_add(&fb->filp_head, &priv->fbs); + + if (copy_to_user(argp, &r, sizeof(r))) + return -EFAULT; + /* bind the fb to the crtc for now */ { struct drm_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { crtc->fb = fb; + + drmfb_probe(dev, crtc); } } - if (copy_to_user(argp, &r, sizeof(r))) - return -EFAULT; - drmfb_probe(dev, fb); return 0; } @@ -1629,6 +1595,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, } drmfb_remove(dev, fb); + /* TODO check if we own the buffer */ /* TODO release all crtc connected to the framebuffer */ /* bind the fb to the crtc for now */ @@ -1711,7 +1678,6 @@ void drm_fb_release(struct file *filp) list_del(&fb->filp_head); drmfb_remove(dev, fb); drm_framebuffer_destroy(fb); - } } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 12c7eef1..fa143e6e 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -294,8 +294,8 @@ struct drm_crtc_funcs { void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y); /* Set gamma on the CRTC */ - void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, - int size); + void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b, + int regno); /* Driver cleanup routine */ void (*cleanup)(struct drm_crtc *crtc); }; @@ -320,7 +320,7 @@ struct drm_crtc { int id; /* idr assigned */ - /* framebuffer the CRTC is currently bound to */ + /* framebuffer the output is currently bound to */ struct drm_framebuffer *fb; bool enabled; @@ -439,6 +439,7 @@ struct drm_output { void *driver_private; u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES]; + }; /** @@ -498,6 +499,7 @@ extern void drm_mode_debug_printmodeline(struct drm_device *dev, extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_set_name(struct drm_display_mode *mode); +extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); extern void drm_disable_unused_functions(struct drm_device *dev); extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); @@ -519,8 +521,7 @@ extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); -extern bool drm_set_desired_modes(struct drm_device *dev); -extern int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb); +extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); /* IOCTLs */ diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index c0453258..8fd0f620 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -39,9 +39,11 @@ #include #include "drmP.h" +#include "drm_crtc.h" + struct drmfb_par { struct drm_device *dev; - struct drm_framebuffer *fb; + struct drm_crtc *crtc; }; static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -49,11 +51,20 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct drmfb_par *par = info->par; - struct drm_framebuffer *fb = par->fb; - if (regno > 17) + struct drm_framebuffer *fb = par->crtc->fb; + struct drm_crtc *crtc = par->crtc; + + if (regno > 255) return 1; - if (regno < 16) { + if (fb->depth == 8) { + if (crtc->funcs->gamma_set) { + crtc->funcs->gamma_set(crtc, red, green, blue, regno); + } + return 0; + } + + if (regno < 16) { switch (fb->depth) { case 15: fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | @@ -72,8 +83,118 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, ((blue & 0xff00) >> 8); break; } + } + + return 0; +} + +static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct drmfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_display_mode *drm_mode; + struct drm_output *output; + int depth; + + if (!var->pixclock) + return -EINVAL; + + /* Need to resize the fb object !!! */ + if (var->xres > fb->width || var->yres > fb->height) { + DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); + DRM_ERROR("Need resizing code.\n"); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + depth = var->bits_per_pixel; + break; + } + + switch (depth) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 15: + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.length = 1; + var->transp.offset = 15; + break; + case 16: + var->red.offset = 11; + var->green.offset = 6; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 24; + break; + default: + return -EINVAL; + } + +#if 0 + /* Here we walk the output mode list and look for modes. If we haven't + * got it, then bail. Not very nice, so this is disabled. + * In the set_par code, we create our mode based on the incoming + * parameters. Nicer, but may not be desired by some. + */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } + + list_for_each_entry(drm_mode, &output->modes, head) { + if (drm_mode->hdisplay == var->xres && + drm_mode->vdisplay == var->yres && + drm_mode->clock != 0) + break; } + if (!drm_mode) + return -EINVAL; +#endif + return 0; } @@ -81,9 +202,74 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, static int drmfb_set_par(struct fb_info *info) { struct drmfb_par *par = info->par; + struct drm_framebuffer *fb = par->crtc->fb; struct drm_device *dev = par->dev; + struct drm_display_mode *drm_mode; + struct fb_var_screeninfo *var = &info->var; + struct drm_output *output; + + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + fb->depth = var->bits_per_pixel; + break; + } + + fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8); + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + info->screen_size = info->fix.smem_len; /* ??? */ + + /* Should we walk the output's modelist or just create our own ??? + * For now, we create and destroy a mode based on the incoming + * parameters. But there's commented out code below which scans + * the output list too. + */ +#if 0 + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } + + list_for_each_entry(drm_mode, &output->modes, head) { + if (drm_mode->hdisplay == var->xres && + drm_mode->vdisplay == var->yres && + drm_mode->clock != 0) + break; + } +#else + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode_set_name(drm_mode); +#endif + + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + return -EINVAL; + + /* Have to destroy our created mode if we're not searching the mode + * list for it. + */ +#if 1 + drm_mode_destroy(dev, drm_mode); +#endif - drm_set_desired_modes(dev); return 0; } @@ -94,6 +280,7 @@ static struct fb_ops drmfb_ops = { // .fb_write = drmfb_write, // .fb_release = drmfb_release, // .fb_ioctl = drmfb_ioctl, + .fb_check_var = drmfb_check_var, .fb_set_par = drmfb_set_par, .fb_setcolreg = drmfb_setcolreg, .fb_fillrect = cfb_fillrect, @@ -101,12 +288,13 @@ static struct fb_ops drmfb_ops = { .fb_imageblit = cfb_imageblit, }; -int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) +int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) { struct fb_info *info; + struct drm_framebuffer *fb = crtc->fb; struct drmfb_par *par; struct device *device = &dev->pdev->dev; - unsigned long size = (8*1024*1024); /* FIXME */ + struct drm_display_mode *mode = crtc->desired_mode; int ret; info = framebuffer_alloc(sizeof(struct drmfb_par), device); @@ -119,20 +307,20 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) par = info->par; par->dev = dev; - par->fb = fb; + par->crtc = crtc; info->fbops = &drmfb_ops; strcpy(info->fix.id, "drmfb"); - info->fix.smem_start = fb->offset + dev->mode_config.fb_base; - info->fix.smem_len = size; info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = FB_VISUAL_DIRECTCOLOR; + info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.accel = FB_ACCEL_NONE; info->fix.type_aux = 0; info->fix.mmio_start = 0; info->fix.mmio_len = 0; info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8); + info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; @@ -141,11 +329,9 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) DRM_ERROR("error mapping fb: %d\n", ret); info->screen_base = fb->virtual_base; - info->screen_size = size; + info->screen_size = info->fix.smem_len; /* ??? */ info->pseudo_palette = fb->pseudo_palette; - info->var.xres = fb->width; info->var.xres_virtual = fb->pitch; - info->var.yres = fb->height; info->var.yres_virtual = fb->height; info->var.bits_per_pixel = fb->bits_per_pixel; info->var.xoffset = 0; @@ -155,24 +341,67 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) info->var.width = -1; info->var.vmode = FB_VMODE_NONINTERLACED; + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = 10000000 / mode->htotal * 1000 / + mode->vtotal * 100000 / mode->vrefresh; + DRM_DEBUG("fb depth is %d\n", fb->depth); switch(fb->depth) { case 8: + info->var.red.offset = 0; + info->var.green.offset = 0; + info->var.blue.offset = 0; + info->var.red.length = 8; /* 8bit DAC */ + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; case 15: + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 5; + info->var.transp.offset = 15; + info->var.transp.length = 1; + break; case 16: + info->var.red.offset = 11; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 6; + info->var.blue.length = 5; + info->var.transp.offset = 0; + info->var.transp.length = 0; break; - default: case 24: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; case 32: info->var.red.offset = 16; info->var.green.offset = 8; info->var.blue.offset = 0; info->var.red.length = info->var.green.length = info->var.blue.length = 8; - if (fb->depth == 32) { - info->var.transp.offset = 24; - info->var.transp.length = 8; - } + info->var.transp.offset = 24; + info->var.transp.length = 8; + break; + default: break; } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 7d581175..7879965e 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -787,6 +787,9 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, else dpll |= PLL_REF_INPUT_DREFCLK; + /* setup pipeconf */ + pipeconf = I915_READ(pipeconf_reg); + /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; @@ -814,7 +817,6 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, else dspcntr |= DISPPLANE_SEL_PIPE_B; - pipeconf = I915_READ(pipeconf_reg); if (pipe == 0 && !IS_I965G(dev)) { /* Enable pixel doubling when the dot clock is > 90% of the (display) * core speed. @@ -955,19 +957,14 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } /** Sets the color ramps on behalf of RandR */ -static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, - u16 *blue, int size) +static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno) { struct intel_crtc *intel_crtc = crtc->driver_private; - int i; - for (i = 0; i < 256; i++) { - intel_crtc->lut_r[i] = red[i] >> 8; - intel_crtc->lut_g[i] = green[i] >> 8; - intel_crtc->lut_b[i] = blue[i] >> 8; - } - - intel_crtc_load_lut(crtc); + intel_crtc->lut_r[regno] = red >> 8; + intel_crtc->lut_g[regno] = green >> 8; + intel_crtc->lut_b[regno] = blue >> 8; } /* Returns the clock of the currently programmed mode of the given pipe. */ @@ -1176,7 +1173,8 @@ static void intel_setup_outputs(drm_device_t *dev) (1 << INTEL_OUTPUT_SDVO)); break; case INTEL_OUTPUT_ANALOG: - crtc_mask = ((1 << 0)); + crtc_mask = ((1 << 0)| + (1 << 1)); clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_SDVO)); @@ -1223,7 +1221,6 @@ void intel_modeset_init(drm_device_t *dev) intel_setup_outputs(dev); //drm_initial_config(dev, false); - //drm_set_desired_modes(dev); } void intel_modeset_cleanup(drm_device_t *dev) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index aa33437d..fdf260e9 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -72,7 +72,7 @@ extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_output_prepare (struct drm_output *output); extern void intel_output_commit (struct drm_output *output); extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, - struct drm_crtc *crtc); + struct drm_crtc *crtc); extern void intel_wait_for_vblank(drm_device_t *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe); diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 74b040ba..942eb2ab 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -164,6 +164,13 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, struct intel_crtc *intel_crtc = output->crtc->driver_private; struct drm_output *tmp_output; + /* Should never happen!! */ + if (!IS_I965G(dev) && intel_crtc->pipe == 0) { + printk(KERN_ERR "Can't support LVDS on pipe A\n"); + return false; + } + + /* Should never happen!! */ list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) { if (tmp_output != output && tmp_output->crtc == output->crtc) { printk(KERN_ERR "Can't enable LVDS and another " @@ -172,11 +179,6 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, } } - if (intel_crtc->pipe == 0) { - printk(KERN_ERR "Can't support LVDS on pipe A\n"); - return false; - } - /* * If we have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 58aa432c..c02fd958 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1010,26 +1010,18 @@ void intel_sdvo_init(drm_device_t *dev, int output_device) memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); - /* TODO, CVBS, SVID, YPRPB & SCART outputs. - * drm_initial_config probably wants tweaking too to support the - * above. But has fixed VGA, TMDS and LVDS checking code. That should - * be dealt with. - */ + /* TODO, CVBS, SVID, YPRPB & SCART outputs. */ if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; output->subpixel_order = SubPixelHorizontalRGB; - /* drm_initial_config wants this name, but should be RGB */ - /* Use this for now.... */ - name_prefix="VGA"; + name_prefix="RGB"; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; output->subpixel_order = SubPixelHorizontalRGB; - /* drm_initial_config wants this name, but should be RGB */ - /* Use this for now.... */ - name_prefix="VGA"; + name_prefix="RGB"; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) { -- cgit v1.2.3 From 2222bd767f9fc02d05ebd0f35a8ceeff2f032c94 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 13:19:56 +0100 Subject: Fix build problem --- linux-core/drm_fb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 8fd0f620..27d80d7a 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -92,6 +92,7 @@ static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct drmfb_par *par = info->par; struct drm_device *dev = par->dev; + struct drm_framebuffer *fb = par->crtc->fb; struct drm_display_mode *drm_mode; struct drm_output *output; int depth; -- cgit v1.2.3 From a18b4befb9b76c4b2662ff6caa0e4f0975eb8e9c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 17 May 2007 09:00:06 -0700 Subject: Fix FB pitch value (we had it wrong and were working around it in a few places). Add new FB hooks to the drm driver structure and make i915 use them for an Intel specific FB driver. This will allow acceleration and better handling of the command stream. --- linux-core/Makefile.kernel | 4 +- linux-core/drmP.h | 4 + linux-core/drm_crtc.c | 15 +- linux-core/drm_fb.c | 6 +- linux-core/i915_drv.c | 3 + linux-core/intel_display.c | 4 +- linux-core/intel_drv.h | 3 + linux-core/intel_fb.c | 358 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_dma.c | 2 +- shared-core/i915_drv.h | 9 ++ shared-core/i915_init.c | 11 +- 11 files changed, 400 insertions(+), 19 deletions(-) create mode 100644 linux-core/intel_fb.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index b9684d68..b4fe7fa8 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -14,14 +14,14 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ - drm_edid.o drm_modes.o drm_fb.o + drm_edid.o drm_modes.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \ - intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o + intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o \ nv04_timer.o \ diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 377f447a..2417181d 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -661,6 +661,10 @@ struct drm_driver { unsigned long (*get_reg_ofs) (struct drm_device * dev); void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); + /* FB routines, if present */ + int (*fb_probe)(struct drm_device *dev, struct drm_framebuffer *fb); + int (*fb_remove)(struct drm_device *dev, struct drm_framebuffer *fb); + struct drm_fence_driver *fence_driver; struct drm_bo_driver *bo_driver; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 16cf62a7..26a1cf2f 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -910,10 +910,8 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* FB config is max of above desired resolutions */ /* FIXME: per-output FBs/CRTCs */ - if (des_mode->hdisplay > fb->width) { + if (des_mode->hdisplay > fb->width) fb->width = des_mode->hdisplay; - fb->pitch = fb->width; - } if (des_mode->vdisplay > fb->height) fb->height = des_mode->vdisplay; } @@ -921,6 +919,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) /* FIXME: multiple depths */ bytes_per_pixel = 4; fb->bits_per_pixel = bytes_per_pixel * 8; + fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); fb->depth = bytes_per_pixel * 8; size = fb->width * fb->height * bytes_per_pixel; drm_buffer_object_create(dev, size, drm_bo_type_kernel, @@ -932,7 +931,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) fb->height, fbo->offset, fbo); fb->offset = fbo->offset; fb->bo = fbo; - drmfb_probe(dev, fb); + dev->driver->fb_probe(dev, fb); return false; } @@ -964,7 +963,7 @@ void drm_mode_config_cleanup(drm_device_t *dev) } list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { - drmfb_remove(dev, fb); + dev->driver->fb_remove(dev, fb); /* If this FB was the kernel one, free it */ if (fb->bo->type == drm_bo_type_kernel) { mutex_lock(&dev->struct_mutex); @@ -1528,7 +1527,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, if (copy_to_user(argp, &r, sizeof(r))) return -EFAULT; - drmfb_probe(dev, fb); + dev->driver->fb_probe(dev, fb); return 0; } @@ -1564,7 +1563,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, return -EINVAL; } - drmfb_remove(dev, fb); + dev->driver->fb_remove(dev, fb); /* TODO check if we own the buffer */ /* TODO release all crtc connected to the framebuffer */ /* bind the fb to the crtc for now */ @@ -1645,7 +1644,7 @@ void drm_fb_release(struct file *filp) list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { list_del(&fb->filp_head); - drmfb_remove(dev, fb); + dev->driver->fb_remove(dev, fb); drm_framebuffer_destroy(fb); } diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index ef05341a..1eb31952 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -106,8 +106,6 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) struct fb_info *info; struct drmfb_par *par; struct device *device = &dev->pdev->dev; - struct fb_var_screeninfo *var_info; - unsigned long base, size; int ret; info = framebuffer_alloc(sizeof(struct drmfb_par), device); @@ -126,7 +124,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) strcpy(info->fix.id, "drmfb"); info->fix.smem_start = fb->offset + dev->mode_config.fb_base; - info->fix.smem_len = (8*1024*1024); + info->fix.smem_len = fb->bo->mem.size; info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_DIRECTCOLOR; info->fix.accel = FB_ACCEL_NONE; @@ -142,7 +140,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) DRM_ERROR("error mapping fb: %d\n", ret); info->screen_base = fb->virtual_base; - info->screen_size = size; + info->screen_size = fb->bo->mem.size; info->pseudo_palette = fb->pseudo_palette; info->var.xres = fb->width; info->var.xres_virtual = fb->pitch; diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 50ff9771..ecf42771 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -30,6 +30,7 @@ #include "drmP.h" #include "drm.h" #include "i915_drm.h" +#include "intel_drv.h" #include "i915_drv.h" #include "drm_pciids.h" @@ -92,6 +93,8 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, + .fb_probe = intelfb_probe, + .fb_remove = intelfb_remove, .ioctls = i915_ioctls, .fops = { .owner = THIS_MODULE, diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 7d581175..be2db912 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -370,7 +370,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); Start = crtc->fb->offset; - Offset = ((y * crtc->fb->pitch + x) * (crtc->fb->bits_per_pixel / 8)); + Offset = y * crtc->fb->pitch + x; DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); if (IS_I965G(dev)) { @@ -911,7 +911,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, ((adjusted_mode->crtc_vblank_end - 1) << 16)); I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); - I915_WRITE(dspstride_reg, crtc->fb->pitch * (crtc->fb->bits_per_pixel / 8)); + I915_WRITE(dspstride_reg, crtc->fb->pitch); /* pipesrc and dspsize control the size that is scaled from, which should * always be the user's requested size. */ diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index aa33437d..91112ff5 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -76,4 +76,7 @@ extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, extern void intel_wait_for_vblank(drm_device_t *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe); +extern int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb); +extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); + #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c new file mode 100644 index 00000000..267b4fd6 --- /dev/null +++ b/linux-core/intel_fb.c @@ -0,0 +1,358 @@ +/* + * Copyright © 2007 David Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * David Airlie + */ + /* + * Modularization + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +struct intelfb_par { + struct drm_device *dev; + struct drm_framebuffer *fb; +}; + +static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct intelfb_par *par = info->par; + struct drm_framebuffer *fb = par->fb; + if (regno > 17) + return 1; + + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + + return 0; +} + +/* this will let fbcon do the mode init */ +static int intelfb_set_par(struct fb_info *info) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + + drm_set_desired_modes(dev); + return 0; +} + +static void intelfb_copyarea(struct fb_info *info, + const struct fb_copyarea *region) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset; + u32 cmd, rop_depth_pitch, src_pitch; + RING_LOCALS; + + cmd = XY_SRC_COPY_BLT_CMD; + src_x1 = region->sx; + src_y1 = region->sy; + dst_x1 = region->dx; + dst_y1 = region->dy; + dst_x2 = region->dx + region->width; + dst_y2 = region->dy + region->height; + offset = par->fb->offset; + rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch; + src_pitch = par->fb->pitch; + + switch (par->fb->bits_per_pixel) { + case 16: + rop_depth_pitch |= BLT_DEPTH_16_565; + break; + case 32: + rop_depth_pitch |= BLT_DEPTH_32; + cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; + break; + } + + BEGIN_LP_RING(8); + OUT_RING(cmd); + OUT_RING(rop_depth_pitch); + OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); + OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); + OUT_RING(offset); + OUT_RING((src_y1 << 16) | (src_x1 & 0xffff)); + OUT_RING(src_pitch); + OUT_RING(offset); + ADVANCE_LP_RING(); +} + +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) +#define ROUND_DOWN_TO(x, y) ((x) / (y) * (y)) + +void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 cmd, rop_pitch_depth, tmp; + int nbytes, ndwords, pad; + u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg; + int dat, ix, iy, iw; + int i, j; + RING_LOCALS; + + /* size in bytes of a padded scanline */ + nbytes = ROUND_UP_TO(image->width, 16) / 8; + + /* Total bytes of padded scanline data to write out. */ + nbytes *= image->height; + + /* + * Check if the glyph data exceeds the immediate mode limit. + * It would take a large font (1K pixels) to hit this limit. + */ + if (nbytes > 128 || image->depth != 1) + return cfb_imageblit(info, image); + + /* Src data is packaged a dword (32-bit) at a time. */ + ndwords = ROUND_UP_TO(nbytes, 4) / 4; + + /* + * Ring has to be padded to a quad word. But because the command starts + with 7 bytes, pad only if there is an even number of ndwords + */ + pad = !(ndwords % 2); + + DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width, + image->height, image->depth, image->dx, image->dy); + DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad); + + tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords; + cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp; + offset = par->fb->offset; + dst_x1 = image->dx; + dst_y1 = image->dy; + dst_x2 = image->dx + image->width; + dst_y2 = image->dy + image->height; + rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch; + + switch (par->fb->bits_per_pixel) { + case 8: + rop_pitch_depth |= BLT_DEPTH_8; + fg = image->fg_color; + bg = image->bg_color; + break; + case 16: + rop_pitch_depth |= BLT_DEPTH_16_565; + fg = par->fb->pseudo_palette[image->fg_color]; + bg = par->fb->pseudo_palette[image->bg_color]; + break; + case 32: + rop_pitch_depth |= BLT_DEPTH_32; + cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; + fg = par->fb->pseudo_palette[image->fg_color]; + bg = par->fb->pseudo_palette[image->bg_color]; + break; + default: + DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel); + break; + } + + BEGIN_LP_RING(8 + ndwords); + OUT_RING(cmd); + OUT_RING(rop_pitch_depth); + OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); + OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); + OUT_RING(offset); + OUT_RING(bg); + OUT_RING(fg); + ix = iy = 0; + iw = ROUND_UP_TO(image->width, 8) / 8; + while (ndwords--) { + dat = 0; + for (j = 0; j < 2; ++j) { + for (i = 0; i < 2; ++i) { + if (ix != iw || i == 0) + dat |= image->data[iy*iw + ix++] << (i+j*2)*8; + } + if (ix == iw && iy != (image->height - 1)) { + ix = 0; + ++iy; + } + } + OUT_RING(dat); + } + if (pad) + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); +} + +static struct fb_ops intelfb_ops = { + .owner = THIS_MODULE, + // .fb_open = intelfb_open, + // .fb_read = intelfb_read, + // .fb_write = intelfb_write, + // .fb_release = intelfb_release, + // .fb_ioctl = intelfb_ioctl, + .fb_set_par = intelfb_set_par, + .fb_setcolreg = intelfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, //intelfb_copyarea, + .fb_imageblit = intelfb_imageblit, +}; + +int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) +{ + struct fb_info *info; + struct intelfb_par *par; + struct device *device = &dev->pdev->dev; + int ret; + + info = framebuffer_alloc(sizeof(struct intelfb_par), device); + if (!info){ + return -EINVAL; + } + + fb->fbdev = info; + + par = info->par; + + par->dev = dev; + par->fb = fb; + + info->fbops = &intelfb_ops; + + strcpy(info->fix.id, "intelfb"); + info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_len = fb->bo->mem.size; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.type_aux = 0; + info->fix.xpanstep = 8; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; + info->fix.accel = FB_ACCEL_I830; + info->fix.type_aux = 0; + info->fix.mmio_start = 0; + info->fix.mmio_len = 0; + info->fix.line_length = fb->pitch; + + info->flags = FBINFO_DEFAULT; + + ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); + if (ret) + DRM_ERROR("error mapping fb: %d\n", ret); + + info->screen_base = fb->virtual_base; + info->screen_size = fb->bo->mem.size; + info->pseudo_palette = fb->pseudo_palette; + info->var.xres = fb->width; + info->var.xres_virtual = fb->width; + info->var.yres = fb->height; + info->var.yres_virtual = fb->height; + info->var.bits_per_pixel = fb->bits_per_pixel; + info->var.xoffset = 0; + info->var.yoffset = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + info->var.vmode = FB_VMODE_NONINTERLACED; + + info->pixmap.size = 64*1024; + info->pixmap.buf_align = 8; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + info->pixmap.scan_align = 1; + + DRM_DEBUG("fb depth is %d\n", fb->depth); + DRM_DEBUG(" pitch is %d\n", fb->pitch); + switch(fb->depth) { + case 8: + case 15: + case 16: + break; + default: + case 24: + case 32: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 8; + if (fb->depth == 32) { + info->var.transp.offset = 24; + info->var.transp.length = 8; + } + break; + } + + if (register_framebuffer(info) < 0) + return -EINVAL; + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} +EXPORT_SYMBOL(intelfb_probe); + +int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +{ + struct fb_info *info = fb->fbdev; + + if (info) { + unregister_framebuffer(info); + framebuffer_release(info); + drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + } + return 0; +} +EXPORT_SYMBOL(intelfb_remove); +MODULE_LICENSE("GPL"); diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 25172c1b..f4761da9 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -130,7 +130,7 @@ static int i915_dma_resume(drm_device_t * dev) DRM_DEBUG("%s\n", __FUNCTION__); - I915_WRITE(0x02080, dev_priv->dma_status_page); + I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); return 0; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 946e464f..a99beaa9 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -317,6 +317,8 @@ extern void intel_modeset_cleanup(drm_device_t *dev); I915_WRITE(LP_RING + RING_TAIL, outring); \ } while(0) +#define MI_NOOP (0x00 << 23) + extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); /* @@ -356,6 +358,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define BB1_UNPROTECTED (0<<0) #define BB2_END_ADDR_MASK (~0x7) +#define I915REG_HWS_PGA 0x02080 #define I915REG_HWSTAM 0x02098 #define I915REG_INT_IDENTITY_R 0x020a4 #define I915REG_INT_MASK_R 0x020a8 @@ -460,8 +463,14 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) #define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5) #define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) #define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) +#define BLT_DEPTH_8 (0<<24) +#define BLT_DEPTH_16_565 (1<<24) +#define BLT_DEPTH_16_1555 (2<<24) +#define BLT_DEPTH_32 (3<<24) +#define BLT_ROP_GXCOPY (0xcc<<16) #define MI_BATCH_BUFFER ((0x30<<23)|1) #define MI_BATCH_BUFFER_START (0x31<<23) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 0c9ef4d4..510e853b 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -211,6 +211,13 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) dev_priv->sarea_priv->pf_current_page = 0; + memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); + + I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); + I915_WRITE(LP_RING + RING_LEN, + ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | + (RING_NO_REPORT | RING_VALID)); + /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. */ @@ -236,7 +243,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) memset(dev_priv->hw_status_page, 0, PAGE_SIZE); DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); - I915_WRITE(0x02080, dev_priv->dma_status_page); + I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); intel_modeset_init(dev); @@ -255,7 +262,7 @@ int i915_driver_unload(drm_device_t *dev) dev_priv->hw_status_page = NULL; dev_priv->dma_status_page = 0; /* Need to rewrite hardware status page */ - I915_WRITE(0x02080, 0x1ffff000); + I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); } I915_WRITE(LP_RING + RING_LEN, 0); -- cgit v1.2.3 From fd63ea971322246734fca5977a800c3ef51cc3fe Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 17:00:11 +0100 Subject: Grab the default mode if the preferred mode isn't available. Fix an overflow problem. --- linux-core/drm_crtc.c | 16 ++++++++++++++-- linux-core/drm_fb.c | 4 +++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index d710a4e7..13a01fee 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -252,7 +252,7 @@ EXPORT_SYMBOL(drm_crtc_in_use); * Detailed mode info for a standard 640x480@60Hz monitor */ static struct drm_display_mode std_mode[] = { - { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, + { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ }; @@ -792,6 +792,18 @@ static void drm_pick_crtcs (drm_device_t *dev) break; } + + /* No preferred mode, let's select another which should pick + * the default 640x480 if nothing else is here. + * + */ + if (!des_mode || !(des_mode->flags & DRM_MODE_TYPE_PREFERRED)) { + list_for_each_entry(des_mode, &output->modes, head) { + if (des_mode->flags & DRM_MODE_TYPE_DEFAULT) + break; + } + } + c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { c++; @@ -823,7 +835,7 @@ clone: output->crtc->desired_mode = des_mode; output->initial_x = 0; output->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is %dx%x\n",c,des_mode->hdisplay,des_mode->vdisplay); + DRM_DEBUG("Desired mode for CRTC %d is %s\n",c,des_mode->name); break; } } diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 27d80d7a..118967bf 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -351,7 +351,9 @@ int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; info->var.pixclock = 10000000 / mode->htotal * 1000 / - mode->vtotal * 100000 / mode->vrefresh; + mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; DRM_DEBUG("fb depth is %d\n", fb->depth); switch(fb->depth) { -- cgit v1.2.3 From 07a5fbaa612a777de37b5dc0112f6f3f3f84c486 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 19:28:03 +0100 Subject: Move destruction of crtc as intelfb_remove uses the crtc to locate the fb. --- linux-core/drm_crtc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ab8b4688..7544eac4 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -971,10 +971,6 @@ void drm_mode_config_cleanup(drm_device_t *dev) drm_output_destroy(output); } - list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { - drm_crtc_destroy(crtc); - } - list_for_each_entry_safe(mode, mt, &dev->mode_config.usermode_list, head) { drm_mode_destroy(dev, mode); } @@ -989,6 +985,11 @@ void drm_mode_config_cleanup(drm_device_t *dev) } drm_framebuffer_destroy(fb); } + + list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { + drm_crtc_destroy(crtc); + } + } EXPORT_SYMBOL(drm_mode_config_cleanup); -- cgit v1.2.3 From c0479dad8e34a51efebfaa05b0d329aa7d2b95d1 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 19:32:46 +0100 Subject: bring in change from drm_fb.c --- linux-core/intel_fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 7126c16c..9d7b7327 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -504,7 +504,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; info->var.pixclock = 10000000 / mode->htotal * 1000 / - mode->vtotal * 100000 / mode->vrefresh; + mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; -- cgit v1.2.3 From f3beabedc36b7bc2d45ca9c7f64d2c54e291e32b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 17 May 2007 13:48:46 -0700 Subject: Remove unused edid.h header from X.Org. --- linux-core/edid.h | 138 ------------------------------------------------------ 1 file changed, 138 deletions(-) delete mode 100644 linux-core/edid.h diff --git a/linux-core/edid.h b/linux-core/edid.h deleted file mode 100644 index bd89fb3b..00000000 --- a/linux-core/edid.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * drivers/video/edid.h - EDID/DDC Header - * - * Based on: - * 1. XFree86 4.3.0, edid.h - * Copyright 1998 by Egbert Eich - * - * 2. John Fremlin and - * Ani Joshi - * - * DDC is a Trademark of VESA (Video Electronics Standard Association). - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. -*/ - -#ifndef __EDID_H__ -#define __EDID_H__ - -#define EDID_LENGTH 0x80 -#define EDID_HEADER 0x00 -#define EDID_HEADER_END 0x07 - -#define ID_MANUFACTURER_NAME 0x08 -#define ID_MANUFACTURER_NAME_END 0x09 -#define ID_MODEL 0x0a - -#define ID_SERIAL_NUMBER 0x0c - -#define MANUFACTURE_WEEK 0x10 -#define MANUFACTURE_YEAR 0x11 - -#define EDID_STRUCT_VERSION 0x12 -#define EDID_STRUCT_REVISION 0x13 - -#define EDID_STRUCT_DISPLAY 0x14 - -#define DPMS_FLAGS 0x18 -#define ESTABLISHED_TIMING_1 0x23 -#define ESTABLISHED_TIMING_2 0x24 -#define MANUFACTURERS_TIMINGS 0x25 - -/* standard timings supported */ -#define STD_TIMING 8 -#define STD_TIMING_DESCRIPTION_SIZE 2 -#define STD_TIMING_DESCRIPTIONS_START 0x26 - -#define DETAILED_TIMING_DESCRIPTIONS_START 0x36 -#define DETAILED_TIMING_DESCRIPTION_SIZE 18 -#define NO_DETAILED_TIMING_DESCRIPTIONS 4 - -#define DETAILED_TIMING_DESCRIPTION_1 0x36 -#define DETAILED_TIMING_DESCRIPTION_2 0x48 -#define DETAILED_TIMING_DESCRIPTION_3 0x5a -#define DETAILED_TIMING_DESCRIPTION_4 0x6c - -#define DESCRIPTOR_DATA 5 - -#define UPPER_NIBBLE( x ) \ - (((128|64|32|16) & (x)) >> 4) - -#define LOWER_NIBBLE( x ) \ - ((1|2|4|8) & (x)) - -#define COMBINE_HI_8LO( hi, lo ) \ - ( (((unsigned)hi) << 8) | (unsigned)lo ) - -#define COMBINE_HI_4LO( hi, lo ) \ - ( (((unsigned)hi) << 4) | (unsigned)lo ) - -#define PIXEL_CLOCK_LO (unsigned)block[ 0 ] -#define PIXEL_CLOCK_HI (unsigned)block[ 1 ] -#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*10000) -#define H_ACTIVE_LO (unsigned)block[ 2 ] -#define H_BLANKING_LO (unsigned)block[ 3 ] -#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] ) -#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO ) -#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] ) -#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO ) - -#define V_ACTIVE_LO (unsigned)block[ 5 ] -#define V_BLANKING_LO (unsigned)block[ 6 ] -#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] ) -#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO ) -#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] ) -#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO ) - -#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ] -#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ] - -#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] ) -#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] ) - -#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2)) -#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2) - -#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4) -#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6) - -#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO ) -#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO ) - -#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO ) -#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO ) - -#define H_SIZE_LO (unsigned)block[ 12 ] -#define V_SIZE_LO (unsigned)block[ 13 ] - -#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] ) -#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] ) - -#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO ) -#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO ) - -#define H_BORDER (unsigned)block[ 15 ] -#define V_BORDER (unsigned)block[ 16 ] - -#define FLAGS (unsigned)block[ 17 ] - -#define INTERLACED (FLAGS&128) -#define SYNC_TYPE (FLAGS&3<<3) /* bits 4,3 */ -#define SYNC_SEPARATE (3<<3) -#define HSYNC_POSITIVE (FLAGS & 4) -#define VSYNC_POSITIVE (FLAGS & 2) - -#define V_MIN_RATE block[ 5 ] -#define V_MAX_RATE block[ 6 ] -#define H_MIN_RATE block[ 7 ] -#define H_MAX_RATE block[ 8 ] -#define MAX_PIXEL_CLOCK (((int)block[ 9 ]) * 10) -#define GTF_SUPPORT block[10] - -#define DPMS_ACTIVE_OFF (1 << 5) -#define DPMS_SUSPEND (1 << 6) -#define DPMS_STANDBY (1 << 7) - -#endif /* __EDID_H__ */ -- cgit v1.2.3 From 95945bbf226610ba4f41381fd0436722082397ec Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 23:33:48 +0100 Subject: Set crtcinfo on temporary mode --- linux-core/drm_fb.c | 1 + linux-core/intel_fb.c | 1 + 2 files changed, 2 insertions(+) diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 5f2b1cea..173864d0 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -259,6 +259,7 @@ static int drmfb_set_par(struct fb_info *info) drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); #endif if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 9d7b7327..3c865a2f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -262,6 +262,7 @@ static int intelfb_set_par(struct fb_info *info) drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); #endif if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) -- cgit v1.2.3 From 3851600b3450697e20286b1937f3e51397f1965a Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 18 May 2007 13:59:46 +0100 Subject: Fix merge problem. --- shared-core/drm.h | 1 - 1 file changed, 1 deletion(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index 64536690..0f4a878b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -789,7 +789,6 @@ typedef struct drm_fence_arg { typedef enum { drm_bo_type_dc, - drm_bo_type_kernel, /* for initial kernel allocations */ drm_bo_type_user, drm_bo_type_fake, drm_bo_type_kernel, /* for initial kernel allocations */ -- cgit v1.2.3 From 0c33a2cd2ec81478403d39b1b92aaa4431e7cf0a Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 18 May 2007 14:16:10 +0100 Subject: Move fbo creation to the specified fb driver which gives it a chance to allocate the memory from whichever buffer it wants to. --- linux-core/drm_crtc.c | 45 +-------------------------------------------- linux-core/drm_crtc.h | 4 ++++ linux-core/drm_fb.c | 3 ++- linux-core/intel_drv.h | 4 ++-- linux-core/intel_fb.c | 39 +++++++++++++++++++++++++++++++++++++-- 5 files changed, 46 insertions(+), 49 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 7544eac4..1586eb1a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -184,6 +184,7 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) kfree(fb); } +EXPORT_SYMBOL(drm_framebuffer_destroy); /** * drm_crtc_create - create a new CRTC object @@ -820,10 +821,8 @@ static void drm_pick_crtcs (drm_device_t *dev) break; } - /* No preferred mode, let's select another which should pick * the default 640x480 if nothing else is here. - * */ if (!des_mode || !(des_mode->flags & DRM_MODE_TYPE_PREFERRED)) { list_for_each_entry(des_mode, &output->modes, head) { @@ -887,13 +886,7 @@ clone: */ bool drm_initial_config(drm_device_t *dev, bool can_grow) { - /* do a hardcoded initial configuration here */ - struct drm_display_mode *des_mode = NULL; struct drm_output *output; - struct drm_framebuffer *fb; - drm_buffer_object_t *fbo; - unsigned long size, bytes_per_pixel; - int ret; drm_crtc_probe_output_modes(dev, 2048, 2048); @@ -905,42 +898,6 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) if (!output->crtc || !output->crtc->desired_mode) continue; - fb = drm_framebuffer_create(dev); - if (!fb) { - DRM_ERROR("failed to allocate fb.\n"); - return true; - } - output->crtc->fb = fb; - des_mode = output->crtc->desired_mode; - - if (des_mode->hdisplay > fb->width) - fb->width = des_mode->hdisplay; - if (des_mode->vdisplay > fb->height) - fb->height = des_mode->vdisplay; - - /* FIXME: multiple depths */ - bytes_per_pixel = 4; - fb->bits_per_pixel = 32; - fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); - fb->depth = 24; - size = fb->width * fb->height * bytes_per_pixel; - /* FIXME - what about resizeable objects ??? */ - ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_PRIV0 | - DRM_BO_FLAG_NO_MOVE, - 0, 0, 0, - &fbo); - if (ret) { - printk(KERN_ERR "failed to allocate framebuffer\n"); - drm_framebuffer_destroy(fb); - continue; - } - fb->offset = fbo->offset; - fb->bo = fbo; - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, - fb->height, fbo->offset, fbo); dev->driver->fb_probe(dev, output->crtc); } drm_disable_unused_functions(dev); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index fa143e6e..8dfd2e2b 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -521,8 +521,12 @@ extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); +extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); +extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); +extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y); /* IOCTLs */ extern int drm_mode_getresources(struct inode *inode, struct file *filp, diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 173864d0..1531e96c 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -418,9 +418,10 @@ int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(drmfb_probe); -int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +int drmfb_remove(struct drm_device *dev, struct drm_crtc *crtc) { struct fb_info *info = fb->fbdev; + struct drm_framebuffer *fb = crtc->fb; if (info) { drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 9205b99b..0a03e37b 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -76,7 +76,7 @@ extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev, extern void intel_wait_for_vblank(drm_device_t *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe); -extern int intelfb_probe(struct drm_device *dev, struct drm_framebuffer *fb); -extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); +extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc); +extern int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc); #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 3c865a2f..ceeefc8c 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -210,7 +210,6 @@ static int intelfb_set_par(struct fb_info *info) struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode; struct fb_var_screeninfo *var = &info->var; - struct drm_output *output; switch (var->bits_per_pixel) { case 16: @@ -444,8 +443,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) struct fb_info *info; struct intelfb_par *par; struct device *device = &dev->pdev->dev; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb; struct drm_display_mode *mode = crtc->desired_mode; + drm_buffer_object_t *fbo = NULL; int ret; info = framebuffer_alloc(sizeof(struct intelfb_par), device); @@ -453,6 +453,41 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; } + fb = drm_framebuffer_create(dev); + if (!fb) { + framebuffer_release(info); + DRM_ERROR("failed to allocate fb.\n"); + return -EINVAL; + } + crtc->fb = fb; + + fb->width = crtc->desired_mode->hdisplay; + fb->height = crtc->desired_mode->vdisplay; + + fb->bits_per_pixel = 32; + fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); + fb->depth = 24; + ret = drm_buffer_object_create(dev, + fb->width * fb->height * 4, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_PRIV0 | /* FIXME! */ + DRM_BO_FLAG_NO_MOVE, + 0, 0, 0, + &fbo); + if (ret || !fbo) { + printk(KERN_ERR "failed to allocate framebuffer\n"); + drm_framebuffer_destroy(fb); + framebuffer_release(info); + return -EINVAL; + } + fb->offset = fbo->offset; + fb->bo = fbo; + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, + fb->height, fbo->offset, fbo); + + fb->fbdev = info; par = info->par; -- cgit v1.2.3 From d42c1de3fb05405820b03ec9bb12f0b9a7eb0a7b Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 18 May 2007 14:16:27 +0100 Subject: Change some printk's to DRM_DEBUG's --- linux-core/intel_sdvo.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index c02fd958..196298ff 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -213,20 +213,20 @@ static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd, int i; if (1) { - printk("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); + DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); for (i = 0; i < args_len; i++) - printk("%02X ", ((u8 *)args)[i]); + DRM_DEBUG("%02X ", ((u8 *)args)[i]); for (; i < 8; i++) - printk(" "); + DRM_DEBUG(" "); for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - printk("(%s)", sdvo_cmd_names[i].name); + DRM_DEBUG("(%s)", sdvo_cmd_names[i].name); break; } } if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) - printk("(%02X)",cmd); - printk("\n"); + DRM_DEBUG("(%02X)",cmd); + DRM_DEBUG("\n"); } for (i = 0; i < args_len; i++) { @@ -266,16 +266,16 @@ static u8 intel_sdvo_read_response(struct drm_output *output, void *response, intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); if (1) { - printk("%s: R: ", SDVO_NAME(sdvo_priv)); + DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv)); for (i = 0; i < response_len; i++) - printk("%02X ", ((u8 *)response)[i]); + DRM_DEBUG("%02X ", ((u8 *)response)[i]); for (; i < 8; i++) - printk(" "); + DRM_DEBUG(" "); if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - printk("(%s)", cmd_status_names[status]); + DRM_DEBUG("(%s)", cmd_status_names[status]); else - printk("(??? %d)", status); - printk("\n"); + DRM_DEBUG("(??? %d)", status); + DRM_DEBUG("\n"); } if (status != SDVO_CMD_STATUS_PENDING) -- cgit v1.2.3 From f89458722173b364b8c3c27788b6c61889da554c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 18 May 2007 09:40:01 -0700 Subject: Add locking. The main lock is dev->mode_config.config_lock. It should be held across any operations that modify mode lists, crtc config, output config, etc. It should be taken at high level entry points (currently just initial config and user IOCTL). Seems to work ok on my system, but needs more testing (with lockdep) and review from some fresh eyes. --- linux-core/drm_crtc.c | 343 ++++++++++++++++++++++++++++--------------------- linux-core/drm_crtc.h | 1 - linux-core/drm_fb.c | 9 +- linux-core/drm_modes.c | 2 +- linux-core/intel_fb.c | 1 + 5 files changed, 205 insertions(+), 151 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ab8b4688..e5a4b32b 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -39,8 +39,7 @@ * @ptr: object pointer, used to generate unique ID * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around IDR allocation. + * Caller must hold DRM mode_config lock. * * Create a unique identifier based on @ptr in @dev's identifier space. Used * for tracking modes, CRTCs and outputs. @@ -59,15 +58,12 @@ again: return 0; } - spin_lock(&dev->mode_config.config_lock); - ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id); if (ret == -EAGAIN) { spin_unlock(&dev->mode_config.config_lock); goto again; } - spin_unlock(&dev->mode_config.config_lock); return new_id; } @@ -116,8 +112,7 @@ struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, * @dev: DRM device * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around mode_config manipulation. + * Caller must hold mode config lock. * * Creates a new framebuffer objects and adds it to @dev's DRM mode_config. * @@ -128,27 +123,21 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) { struct drm_framebuffer *fb; - spin_lock(&dev->mode_config.config_lock); /* Limit to single framebuffer for now */ if (dev->mode_config.num_fb > 1) { spin_unlock(&dev->mode_config.config_lock); DRM_ERROR("Attempt to add multiple framebuffers failed\n"); return NULL; } - spin_unlock(&dev->mode_config.config_lock); fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); - if (!fb) { - + if (!fb) return NULL; - } fb->id = drm_idr_get(dev, fb); fb->dev = dev; - spin_lock(&dev->mode_config.config_lock); dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); - spin_unlock(&dev->mode_config.config_lock); return fb; } @@ -159,8 +148,7 @@ EXPORT_SYMBOL(drm_framebuffer_create); * @fb: framebuffer to remove * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around mode_config manipulation. + * Caller must hold mode config lock. * * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes * it, setting it to NULL. @@ -171,7 +159,6 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) struct drm_crtc *crtc; /* remove from any CRTC */ - spin_lock(&dev->mode_config.config_lock); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb == fb) crtc->fb = NULL; @@ -180,7 +167,6 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) drm_idr_put(dev, fb->id); list_del(&fb->head); dev->mode_config.num_fb--; - spin_unlock(&dev->mode_config.config_lock); kfree(fb); } @@ -191,8 +177,7 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) * @funcs: callbacks for the new CRTC * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around mode_config manipulation. + * Caller must hold mode config lock. * * Creates a new CRTC object and adds it to @dev's mode_config structure. * @@ -213,10 +198,8 @@ struct drm_crtc *drm_crtc_create(drm_device_t *dev, crtc->id = drm_idr_get(dev, crtc); - spin_lock(&dev->mode_config.config_lock); list_add_tail(&crtc->head, &dev->mode_config.crtc_list); dev->mode_config.num_crtc++; - spin_unlock(&dev->mode_config.config_lock); return crtc; } @@ -227,8 +210,7 @@ EXPORT_SYMBOL(drm_crtc_create); * @crtc: CRTC to remove * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around mode_config traversal. + * Caller must hold mode config lock. * * Cleanup @crtc. Calls @crtc's cleanup function, then removes @crtc from * its associated DRM device's mode_config. Frees it afterwards. @@ -240,11 +222,9 @@ void drm_crtc_destroy(struct drm_crtc *crtc) if (crtc->funcs->cleanup) (*crtc->funcs->cleanup)(crtc); - spin_lock(&dev->mode_config.config_lock); drm_idr_put(dev, crtc->id); list_del(&crtc->head); dev->mode_config.num_crtc--; - spin_unlock(&dev->mode_config.config_lock); kfree(crtc); } EXPORT_SYMBOL(drm_crtc_destroy); @@ -254,7 +234,7 @@ EXPORT_SYMBOL(drm_crtc_destroy); * @crtc: CRTC to check * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Walk @crtc's DRM device's mode_config and see if it's in use. * @@ -289,7 +269,7 @@ static struct drm_display_mode std_mode[] = { * @maxY: max height for modes * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Based on @dev's mode_config layout, scan all the outputs and try to detect * modes on them. Modes will first be added to the output's probed_modes @@ -379,7 +359,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) * @y: height of mode * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance * to fixup or reject the mode prior to trying to set it. @@ -497,7 +477,7 @@ EXPORT_SYMBOL(drm_crtc_set_mode); * @dev: DRM device * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * If an output or CRTC isn't part of @dev's mode_config, it can be disabled * by calling its dpms function, which should power it off. @@ -524,17 +504,14 @@ void drm_disable_unused_functions(struct drm_device *dev) * @mode: mode data * * LOCKING: - * Process context (either init or calling process). Must take @output's - * mode_lock around mode list manipulation. + * Caller must hold mode config lock. * * Add @mode to @output's mode list for later use. */ void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode) { - spin_lock(&output->modes_lock); list_add(&mode->head, &output->probed_modes); - spin_unlock(&output->modes_lock); } EXPORT_SYMBOL(drm_mode_probed_add); @@ -544,16 +521,13 @@ EXPORT_SYMBOL(drm_mode_probed_add); * @mode: mode to remove * * LOCKING: - * Process context (either init or calling process). Must take @output's - * mode_lock around mode list manipulation. + * Caller must hold mode config lock. * * Remove @mode from @output's mode list, then free it. */ void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) { - spin_lock(&output->modes_lock); list_del(&mode->head); - spin_unlock(&output->modes_lock); kfree(mode); } EXPORT_SYMBOL(drm_mode_remove); @@ -565,8 +539,7 @@ EXPORT_SYMBOL(drm_mode_remove); * @name: user visible name of the output * * LOCKING: - * Process context (either init or calling process). Must take @dev's - * mode_config lock around mode list manipulation. + * Caller must hold @dev's mode_config lock. * * Creates a new drm_output structure and adds it to @dev's mode_config * structure. @@ -593,7 +566,6 @@ struct drm_output *drm_output_create(drm_device_t *dev, output->subpixel_order = SubPixelUnknown; INIT_LIST_HEAD(&output->probed_modes); INIT_LIST_HEAD(&output->modes); - spin_lock_init(&output->modes_lock); /* randr_output? */ /* output_set_monitor(output)? */ /* check for output_ignored(output)? */ @@ -614,9 +586,7 @@ EXPORT_SYMBOL(drm_output_create); * @output: output to remove * * LOCKING: - * Process context (either init or calling process). Must take @dev's - * mode_config lock around mode list manipulation. Caller must hold - * modes lock? (FIXME) + * Caller must hold @dev's mode_config lock. * * Call @output's cleanup function, then remove the output from the DRM * mode_config after freeing @output's modes. @@ -704,7 +674,7 @@ EXPORT_SYMBOL(drm_mode_create); * @mode: mode to remove * * LOCKING: - * None. + * Caller must hold mode config lock. * * Free @mode's unique identifier, then free it. */ @@ -786,7 +756,7 @@ out_err: * @dev: DRM device * * LOCKING: - * None. + * Caller must hold mode config lock. */ static void drm_pick_crtcs (drm_device_t *dev) { @@ -876,7 +846,7 @@ clone: * @can_grow: this configuration is growable * * LOCKING: - * Must take various locks. (FIXME) + * Called at init time, must take mode config lock. * * Scan the CRTCs and outputs and try to put together an initial setup. * At the moment, this is a cloned configuration across all heads with @@ -893,7 +863,9 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) struct drm_framebuffer *fb; drm_buffer_object_t *fbo; unsigned long size, bytes_per_pixel; - int ret; + int ret = false; + + spin_lock(&dev->mode_config.config_lock); drm_crtc_probe_output_modes(dev, 2048, 2048); @@ -908,7 +880,8 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) fb = drm_framebuffer_create(dev); if (!fb) { DRM_ERROR("failed to allocate fb.\n"); - return true; + ret = true; + goto out; } output->crtc->fb = fb; des_mode = output->crtc->desired_mode; @@ -945,7 +918,9 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) } drm_disable_unused_functions(dev); - return false; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } EXPORT_SYMBOL(drm_initial_config); @@ -954,7 +929,7 @@ EXPORT_SYMBOL(drm_initial_config); * @dev: DRM device * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Free up all the outputs and CRTCs associated with this DRM device, then * free up the framebuffers and associated buffer objects. @@ -1001,7 +976,7 @@ EXPORT_SYMBOL(drm_mode_config_cleanup); * @fb: new framebuffer * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Setup a new configuration, provided by the user in @crtc_info, and enable * it. @@ -1144,7 +1119,7 @@ void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modein * @arg: arg from ioctl * * LOCKING: - * Caller? (FIXME) + * Takes mode config lock. * * Construct a set of configuration description structures and return * them to the user, including CRTC, output and framebuffer configuration. @@ -1167,7 +1142,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, struct drm_crtc *crtc; struct drm_mode_modeinfo u_mode; struct drm_display_mode *mode; - int retcode = 0; + int ret = 0; int mode_count= 0; int output_count = 0; int crtc_count = 0; @@ -1176,6 +1151,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); + spin_lock(&dev->mode_config.config_lock); + list_for_each(lh, &dev->mode_config.fb_list) fb_count++; @@ -1191,8 +1168,10 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each(lh, &dev->mode_config.usermode_list) mode_count++; - if (copy_from_user(&card_res, argp, sizeof(card_res))) - return -EFAULT; + if (copy_from_user(&card_res, argp, sizeof(card_res))) { + ret = -EFAULT; + goto out_unlock; + } if (card_res.count_modes == 0) { DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width, dev->mode_config.max_height); @@ -1212,7 +1191,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, copied = 0; list_for_each_entry(fb, &dev->mode_config.fb_list, head) { if (put_user(fb->id, &card_res.fb_id[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1225,7 +1204,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ DRM_DEBUG("CRTC ID is %d\n", crtc->id); if (put_user(crtc->id, &card_res.crtc_id[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1240,7 +1219,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, head) { DRM_DEBUG("OUTPUT ID is %d\n", output->id); if (put_user(output->id, &card_res.output_id[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1255,7 +1234,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each_entry(mode, &output->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1264,7 +1243,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each_entry(mode, &dev->mode_config.usermode_list, head) { drm_crtc_convert_to_umode(&u_mode, mode); if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1277,9 +1256,11 @@ done: card_res.count_modes); if (copy_to_user(argp, &card_res, sizeof(card_res))) - return -EFAULT; + ret = -EFAULT; - return retcode; +out_unlock: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1309,14 +1290,18 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, struct drm_crtc *crtc; struct drm_output *output; int ocount; - int retcode = 0; + int ret = 0; if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp.crtc_id); - if (!crtc || (crtc->id != crtc_resp.crtc_id)) - return -EINVAL; + if (!crtc || (crtc->id != crtc_resp.crtc_id)) { + ret = -EINVAL; + goto out; + } + crtc_resp.x = crtc->x; crtc_resp.y = crtc->y; crtc_resp.fb_id = 1; @@ -1335,9 +1320,11 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, } if (copy_to_user(argp, &crtc_resp, sizeof(crtc_resp))) - return -EFAULT; + ret = -EFAULT; - return retcode; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1367,7 +1354,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, struct drm_output *output; struct drm_display_mode *mode; int mode_count = 0; - int retcode = 0; + int ret = 0; int copied = 0; int i; @@ -1375,9 +1362,13 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, return -EFAULT; DRM_DEBUG("output id %d:\n", out_resp.output); + + spin_lock(&dev->mode_config.config_lock); output= idr_find(&dev->mode_config.crtc_idr, out_resp.output); - if (!output || (output->id != out_resp.output)) - return -EINVAL; + if (!output || (output->id != out_resp.output)) { + ret = -EINVAL; + goto out_unlock; + } list_for_each_entry(mode, &output->modes, head) mode_count++; @@ -1402,14 +1393,14 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, copied = 0; list_for_each_entry(mode, &output->modes, head) { if (put_user(mode->mode_id, &out_resp.modes[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { if (output->user_mode_ids[i] != 0) if (put_user(output->user_mode_ids[i], &out_resp.modes[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1419,9 +1410,11 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, done: if (copy_to_user(argp, &out_resp, sizeof(out_resp))) - return -EFAULT; + ret = -EFAULT; - return retcode; +out_unlock: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1452,26 +1445,28 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, struct drm_output **output_set = NULL, *output; struct drm_display_mode *mode; struct drm_framebuffer *fb = NULL; - int retcode = 0; + int ret = 0; int i; if (copy_from_user(&crtc_req, argp, sizeof(crtc_req))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id); if (!crtc || (crtc->id != crtc_req.crtc_id)) { DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req.crtc_id); - return -EINVAL; + ret = -EINVAL; + goto out; } if (crtc_req.mode) { - /* if we have a mode we need a framebuffer */ if (crtc_req.fb_id) { fb = idr_find(&dev->mode_config.crtc_idr, crtc_req.fb_id); if (!fb || (fb->id != crtc_req.fb_id)) { DRM_DEBUG("Unknown FB ID%d\n", crtc_req.fb_id); - return -EINVAL; + ret = -EINVAL; + goto out; } } mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode); @@ -1489,43 +1484,55 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, } DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req.mode, mode); - return -EINVAL; + ret = -EINVAL; + goto out; } } else mode = NULL; if (crtc_req.count_outputs == 0 && mode) { DRM_DEBUG("Count outputs is 0 but mode set\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } if (crtc_req.count_outputs > 0 && !mode && !fb) { DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req.count_outputs); - return -EINVAL; + ret = -EINVAL; + goto out; } if (crtc_req.count_outputs > 0) { u32 out_id; - output_set = kmalloc(crtc_req.count_outputs * sizeof(struct drm_output *), GFP_KERNEL); - if (!output_set) - return -ENOMEM; + output_set = kmalloc(crtc_req.count_outputs * + sizeof(struct drm_output *), GFP_KERNEL); + if (!output_set) { + ret = -ENOMEM; + goto out; + } for (i = 0; i < crtc_req.count_outputs; i++) { - if (get_user(out_id, &crtc_req.set_outputs[i])) - return -EFAULT; + if (get_user(out_id, &crtc_req.set_outputs[i])) { + ret = -EFAULT; + goto out; + } output = idr_find(&dev->mode_config.crtc_idr, out_id); if (!output || (out_id != output->id)) { DRM_DEBUG("Output id %d unknown\n", out_id); - return -EINVAL; + ret = -EINVAL; + goto out; } output_set[i] = output; } } - retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb); - return retcode; + ret = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb); + +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1536,7 +1543,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, * @arg: arg from ioctl * * LOCKING: - * Caller? (FIXME) + * Takes mode config lock. * * Add a new FB to the specified CRTC, given a user request. * @@ -1555,7 +1562,8 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; struct drm_buffer_object *bo; - int ret; + struct drm_crtc *crtc; + int ret = 0; if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -1569,17 +1577,22 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, return -EINVAL; } + spin_lock(&dev->mode_config.config_lock); /* TODO check limits are okay */ ret = drm_get_buffer_object(dev, &bo, r.handle); - if (ret || !bo) - return -EINVAL; + if (ret || !bo) { + ret = -EINVAL; + goto out; + } /* TODO check buffer is sufficently large */ /* TODO setup destructor callback */ fb = drm_framebuffer_create(dev); - if(!fb) - return -EINVAL;; + if (!fb) { + ret = -EINVAL; + goto out; + } fb->width = r.width; fb->height = r.height; @@ -1593,20 +1606,20 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, list_add(&fb->filp_head, &priv->fbs); - if (copy_to_user(argp, &r, sizeof(r))) - return -EFAULT; + if (copy_to_user(argp, &r, sizeof(r))) { + ret = -EFAULT; + goto out; + } - /* bind the fb to the crtc for now */ - { - struct drm_crtc *crtc; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - crtc->fb = fb; - - dev->driver->fb_probe(dev, crtc); - } + /* FIXME: bind the fb to the right crtc */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + crtc->fb = fb; + dev->driver->fb_probe(dev, crtc); } - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1617,7 +1630,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, * @arg: arg from ioctl * * LOCKING: - * Caller? (FIXME) + * Takes mode config lock. * * Remove the FB specified by the user. * @@ -1633,12 +1646,15 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, drm_device_t *dev = priv->head->dev; struct drm_framebuffer *fb = 0; uint32_t id = arg; + int ret = 0; + spin_lock(&dev->mode_config.config_lock); fb = idr_find(&dev->mode_config.crtc_idr, id); /* TODO check that we realy get a framebuffer back. */ if (!fb || (id != fb->id)) { DRM_ERROR("mode invalid framebuffer id\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); @@ -1650,7 +1666,9 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, drm_framebuffer_destroy(fb); - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1678,14 +1696,17 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, struct drm_mode_fb_cmd __user *argp = (void __user *)arg; struct drm_mode_fb_cmd r; struct drm_framebuffer *fb; + int ret = 0; if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); fb = idr_find(&dev->mode_config.crtc_idr, r.buffer_id); if (!fb || (r.buffer_id != fb->id)) { DRM_ERROR("invalid framebuffer id\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } r.height = fb->height; @@ -1696,9 +1717,11 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, r.pitch = fb->pitch; if (copy_to_user(argp, &r, sizeof(r))) - return -EFAULT; + ret = -EFAULT; - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1706,7 +1729,7 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, * @filp: file * from the ioctl * * LOCKING: - * Caller? (FIXME) + * Takes mode config lock. * * Destroy all the FBs associated with @filp. * @@ -1721,11 +1744,13 @@ void drm_fb_release(struct file *filp) drm_device_t *dev = priv->head->dev; struct drm_framebuffer *fb, *tfb; + spin_lock(&dev->mode_config.config_lock); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { list_del(&fb->filp_head); dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); drm_framebuffer_destroy(fb); } + spin_unlock(&dev->mode_config.config_lock); } /** @@ -1751,28 +1776,32 @@ int drm_mode_addmode(struct inode *inode, struct file *filp, struct drm_mode_modeinfo __user *argp = (void __user *)arg; struct drm_mode_modeinfo new_mode; struct drm_display_mode *user_mode; + int ret = 0; if (copy_from_user(&new_mode, argp, sizeof(new_mode))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); user_mode = drm_mode_create(dev); - if (!user_mode) - return -ENOMEM; + if (!user_mode) { + ret = -ENOMEM; + goto out; + } drm_crtc_convert_umode(user_mode, &new_mode); user_mode->type |= DRM_MODE_TYPE_USERDEF; user_mode->output_count = 0; - spin_lock(&dev->mode_config.config_lock); list_add(&user_mode->head, &dev->mode_config.usermode_list); - spin_unlock(&dev->mode_config.config_lock); new_mode.id = user_mode->mode_id; if (copy_to_user(argp, &new_mode, sizeof(new_mode))) - return -EFAULT; + ret = -EFAULT; - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1796,29 +1825,37 @@ int drm_mode_rmmode(struct inode *inode, struct file *filp, drm_device_t *dev = priv->head->dev; uint32_t id = arg; struct drm_display_mode *mode, *t; - int retcode = -EINVAL; + int ret = -EINVAL; + spin_lock(&dev->mode_config.config_lock); mode = idr_find(&dev->mode_config.crtc_idr, id); - if (!mode || (id != mode->mode_id)) - return -EINVAL; + if (!mode || (id != mode->mode_id)) { + ret = -EINVAL; + goto out; + } - if (!(mode->type & DRM_MODE_TYPE_USERDEF)) - return -EINVAL; + if (!(mode->type & DRM_MODE_TYPE_USERDEF)) { + ret = -EINVAL; + goto out; + } - if (mode->output_count) - return -EINVAL; + if (mode->output_count) { + ret = -EINVAL; + goto out; + } - spin_lock(&dev->mode_config.config_lock); list_for_each_entry(t, &dev->mode_config.usermode_list, head) { if (t == mode) { list_del(&mode->head); drm_mode_destroy(dev, mode); - retcode = 0; + ret = 0; break; } } + +out: spin_unlock(&dev->mode_config.config_lock); - return retcode; + return ret; } /** @@ -1843,18 +1880,24 @@ int drm_mode_attachmode(struct inode *inode, struct file *filp, struct drm_mode_mode_cmd mode_cmd; struct drm_output *output; struct drm_display_mode *mode; - int i; + int i, ret = 0; if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); - if (!mode || (mode->mode_id != mode_cmd.mode_id)) - return -EINVAL; + if (!mode || (mode->mode_id != mode_cmd.mode_id)) { + ret = -EINVAL; + goto out; + } output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); - if (!output || (output->id != mode_cmd.output_id)) - return -EINVAL; + if (!output || (output->id != mode_cmd.output_id)) { + ret = -EINVAL; + goto out; + } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { if (output->user_mode_ids[i] == 0) { @@ -1865,9 +1908,11 @@ int drm_mode_attachmode(struct inode *inode, struct file *filp, } if (i == DRM_OUTPUT_MAX_UMODES) - return -ENOSPC; + ret = -ENOSPC; - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } @@ -1892,18 +1937,24 @@ int drm_mode_detachmode(struct inode *inode, struct file *filp, struct drm_mode_mode_cmd mode_cmd; struct drm_output *output; struct drm_display_mode *mode; - int i, found = 0; + int i, found = 0, ret = 0; if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); - if (!mode || (mode->mode_id != mode_cmd.mode_id)) - return -EINVAL; + if (!mode || (mode->mode_id != mode_cmd.mode_id)) { + ret = -EINVAL; + goto out; + } output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); - if (!output || (output->id != mode_cmd.output_id)) - return -EINVAL; + if (!output || (output->id != mode_cmd.output_id)) { + ret = -EINVAL; + goto out; + } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { @@ -1915,7 +1966,9 @@ int drm_mode_detachmode(struct inode *inode, struct file *filp, } if (!found) - return -EINVAL; - - return 0; + ret = -EINVAL; + +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index fa143e6e..7ca8311b 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -417,7 +417,6 @@ struct drm_output { unsigned long possible_clones; bool interlace_allowed; bool doublescan_allowed; - spinlock_t modes_lock; /* protects modes and probed_modes lists */ struct list_head modes; /* list of modes on this output */ /* diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 5f2b1cea..7a105d59 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -299,9 +299,8 @@ int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) int ret; info = framebuffer_alloc(sizeof(struct drmfb_par), device); - if (!info){ - return -EINVAL; - } + if (!info) + return -ENOMEM; fb->fbdev = info; @@ -408,8 +407,10 @@ int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) break; } - if (register_framebuffer(info) < 0) + if (register_framebuffer(info) < 0) { + unregister_framebuffer(info); return -EINVAL; + } printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 97f7607d..41b5fade 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -141,7 +141,7 @@ EXPORT_SYMBOL(drm_mode_height); * * Return @mode's vrefresh rate or calculate it if necessary. * - * FIXME: why is this needed? + * FIXME: why is this needed? shouldn't vrefresh be set already? * * RETURNS: * Vertical refresh rate of @mode x 1000. For precision reasons. diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 7126c16c..2ce66460 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -203,6 +203,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, } /* this will let fbcon do the mode init */ +/* FIXME: take mode config lock? */ static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; -- cgit v1.2.3 From e918d2b7814e2cf5345dba63031c402010b1d3e4 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 22 May 2007 13:38:58 -0700 Subject: Call preallocated space VRAM instead of PRIV0 to be more consistent with other drivers. --- linux-core/i915_buffer.c | 5 ++++- linux-core/i915_drv.c | 4 ++-- linux-core/intel_fb.c | 2 +- shared-core/i915_init.c | 8 ++++---- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 8589f467..6e93ae21 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -86,7 +86,7 @@ int i915_init_mem_type(drm_device_t * dev, uint32_t type, _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; man->drm_bus_maptype = _DRM_AGP; break; - case DRM_BO_MEM_PRIV0: + case DRM_BO_MEM_VRAM: if (!(drm_core_has_AGP(dev) && dev->agp)) { DRM_ERROR("AGP is not enabled for memory type %u\n", (unsigned)type); @@ -99,6 +99,9 @@ int i915_init_mem_type(drm_device_t * dev, uint32_t type, _DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_NEEDS_IOREMAP; man->drm_bus_maptype = _DRM_AGP; break; + case DRM_BO_MEM_PRIV0: /* for OS preallocated space */ + DRM_ERROR("PRIV0 not used yet.\n"); + break; default: DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); return -EINVAL; diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index ecf42771..4d4029aa 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -53,8 +53,8 @@ static drm_fence_driver_t i915_fence_driver = { #endif #ifdef I915_HAVE_BUFFER -static uint32_t i915_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; -static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_LOCAL}; +static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; +static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; static drm_bo_driver_t i915_bo_driver = { .mem_type_prio = i915_mem_prios, diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 449ef543..3bfbcda3 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -473,7 +473,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_PRIV0 | /* FIXME! */ + DRM_BO_FLAG_MEM_VRAM | /* FIXME! */ DRM_BO_FLAG_NO_MOVE, 0, 0, 0, &fbo); diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 61576aae..7516b2ce 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -175,8 +175,8 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) drm_bo_driver_init(dev); i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); - DRM_DEBUG("setting up %ld bytes of PRIV0 space\n", prealloc_size); - drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, 0, prealloc_size >> PAGE_SHIFT); + DRM_DEBUG("setting up %ld bytes of VRAM space\n", prealloc_size); + drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT); I915_WRITE(LP_RING + RING_LEN, 0); I915_WRITE(LP_RING + RING_HEAD, 0); @@ -185,7 +185,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags) size = PRIMARY_RINGBUFFER_SIZE; ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_PRIV0 | + DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_NO_EVICT, DRM_BO_HINT_DONT_FENCE, 0x1, 0, &dev_priv->ring_buffer); @@ -277,7 +277,7 @@ int i915_driver_unload(drm_device_t *dev) drm_bo_usage_deref_locked(dev_priv->ring_buffer); mutex_unlock(&dev->struct_mutex); - if (drm_bo_clean_mm(dev, DRM_BO_MEM_PRIV0)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { DRM_ERROR("Memory manager type 3 not clean. " "Delaying takedown\n"); } -- cgit v1.2.3 From 462d5a0dfc80dfa02da3d24d30ad90ad0387f0a2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 22 May 2007 17:49:04 -0700 Subject: Suspend/resume support (incomplete). --- linux-core/i915_drv.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_drv.h | 86 ++++++++++++++++++ shared-core/i915_irq.c | 13 +++ 3 files changed, 330 insertions(+) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 4d4029aa..ffdbab06 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -70,6 +70,235 @@ static drm_bo_driver_t i915_bo_driver = { }; #endif +static int i915_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_output *output; + int i; + + pci_save_state(pdev); + + /* Save video mode information for native mode-setting. */ + dev_priv->saveDSPACNTR = I915_READ(DSPACNTR); + dev_priv->savePIPEACONF = I915_READ(PIPEACONF); + dev_priv->savePIPEASRC = I915_READ(PIPEASRC); + dev_priv->saveFPA0 = I915_READ(FPA0); + dev_priv->saveFPA1 = I915_READ(FPA1); + dev_priv->saveDPLL_A = I915_READ(DPLL_A); + if (IS_I965G(dev)) + dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); + dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); + dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); + dev_priv->saveHSYNC_A = I915_READ(HSYNC_A); + dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A); + dev_priv->saveVBLANK_A = I915_READ(VBLANK_A); + dev_priv->saveVSYNC_A = I915_READ(VSYNC_A); + dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE); + dev_priv->saveDSPASIZE = I915_READ(DSPASIZE); + dev_priv->saveDSPAPOS = I915_READ(DSPAPOS); + dev_priv->saveDSPABASE = I915_READ(DSPABASE); + + for(i= 0; i < 256; i++) + dev_priv->savePaletteA[i] = I915_READ(PALETTE_A + (i << 2)); + + if(dev->mode_config.num_crtc == 2) { + dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); + dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); + dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR); + dev_priv->saveFPB0 = I915_READ(FPB0); + dev_priv->saveFPB1 = I915_READ(FPB1); + dev_priv->saveDPLL_B = I915_READ(DPLL_B); + if (IS_I965G(dev)) + dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); + dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); + dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); + dev_priv->saveHSYNC_B = I915_READ(HSYNC_B); + dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B); + dev_priv->saveVBLANK_B = I915_READ(VBLANK_B); + dev_priv->saveVSYNC_B = I915_READ(VSYNC_B); + dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE); + dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); + dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); + dev_priv->saveDSPBBASE = I915_READ(DSPBBASE); + for(i= 0; i < 256; i++) + dev_priv->savePaletteB[i] = + I915_READ(PALETTE_B + (i << 2)); + } + + if (IS_I965G(dev)) { + dev_priv->saveDSPASURF = I915_READ(DSPASURF); + dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); + } + + dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); + dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); + dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); + dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); + + for(i = 0; i < 7; i++) { + dev_priv->saveSWF[i] = I915_READ(SWF0 + (i << 2)); + dev_priv->saveSWF[i+7] = I915_READ(SWF00 + (i << 2)); + } + dev_priv->saveSWF[14] = I915_READ(SWF30); + dev_priv->saveSWF[15] = I915_READ(SWF31); + dev_priv->saveSWF[16] = I915_READ(SWF32); + + if (IS_MOBILE(dev) && !IS_I830(dev)) + dev_priv->saveLVDS = I915_READ(LVDS); + dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); + + list_for_each_entry(output, &dev->mode_config.output_list, head) + if (output->funcs->save) + (*output->funcs->save) (output); + +#if 0 /* FIXME: save VGA bits */ + vgaHWUnlock(hwp); + vgaHWSave(pScrn, vgaReg, VGA_SR_FONTS); +#endif + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int i915_resume(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_output *output; + struct drm_crtc *crtc; + int i; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + pci_enable_device(pdev); + + /* Disable outputs */ + list_for_each_entry(output, &dev->mode_config.output_list, head) + output->funcs->dpms(output, DPMSModeOff); + + i915_driver_wait_next_vblank(dev, 0); + + /* Disable pipes */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + crtc->funcs->dpms(crtc, DPMSModeOff); + + /* FIXME: wait for vblank on each pipe? */ + i915_driver_wait_next_vblank(dev, 0); + + if (IS_MOBILE(dev) && !IS_I830(dev)) + I915_WRITE(LVDS, dev_priv->saveLVDS); + + if (!IS_I830(dev) && !IS_845G(dev)) + I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); + + if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A & ~DPLL_VCO_ENABLE); + udelay(150); + } + I915_WRITE(FPA0, dev_priv->saveFPA0); + I915_WRITE(FPA1, dev_priv->saveFPA1); + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); + udelay(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); + else + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); + udelay(150); + + I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); + I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A); + I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A); + I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); + I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); + I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); + + I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); + I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); + I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); + I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); + I915_WRITE(DSPABASE, dev_priv->saveDSPABASE); + if (IS_I965G(dev)) + I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); + I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + i915_driver_wait_next_vblank(dev, 0); + I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); + I915_WRITE(DSPABASE, I915_READ(DSPABASE)); + i915_driver_wait_next_vblank(dev, 0); + + if(dev->mode_config.num_crtc == 2) { + if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & ~DPLL_VCO_ENABLE); + udelay(150); + } + I915_WRITE(FPB0, dev_priv->saveFPB0); + I915_WRITE(FPB1, dev_priv->saveFPB1); + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); + udelay(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); + else + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); + udelay(150); + + I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); + I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B); + I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B); + I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); + I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); + I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); + I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); + I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); + I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); + I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); + I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE); + if (IS_I965G(dev)) + I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); + I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + i915_driver_wait_next_vblank(dev, 0); + I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); + I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); + i915_driver_wait_next_vblank(dev, 0); + } + + /* Restore outputs */ + list_for_each_entry(output, &dev->mode_config.output_list, head) + if (output->funcs->restore) + output->funcs->restore(output); + + I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); + + I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0); + I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1); + I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); + + for(i = 0; i < 256; i++) + I915_WRITE(PALETTE_A + (i << 2), dev_priv->savePaletteA[i]); + + if(dev->mode_config.num_crtc == 2) + for(i= 0; i < 256; i++) + I915_WRITE(PALETTE_B + (i << 2), dev_priv->savePaletteB[i]); + + for(i = 0; i < 7; i++) { + I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF[i]); + I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF[i+7]); + } + + I915_WRITE(SWF30, dev_priv->saveSWF[14]); + I915_WRITE(SWF31, dev_priv->saveSWF[15]); + I915_WRITE(SWF32, dev_priv->saveSWF[16]); + +#if 0 /* FIXME: restore VGA bits */ + vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS); + vgaHWLock(hwp); +#endif + + drm_initial_config(dev, 0); + + return 0; +} + static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { /* don't use mtrr's here, the Xserver or user space app should @@ -113,6 +342,8 @@ static struct drm_driver driver = { .id_table = pciidlist, .probe = probe, .remove = __devexit_p(drm_cleanup_pci), + .suspend = i915_suspend, + .resume = i915_resume, }, #ifdef I915_HAVE_FENCE .fence_driver = &i915_fence_driver, diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index c41fbbc5..b0aa5df1 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -227,6 +227,7 @@ extern int i915_dma_cleanup(drm_device_t * dev); extern int i915_irq_emit(DRM_IOCTL_ARGS); extern int i915_irq_wait(DRM_IOCTL_ARGS); +extern void i915_driver_wait_next_vblank(drm_device_t *dev, int pipe); extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); @@ -395,6 +396,39 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); # define GPIO_DATA_VAL_IN (1 << 12) # define GPIO_DATA_PULLUP_DISABLE (1 << 13) +/* p317, 319 + */ +#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */ +#define VCLK2_VCO_N 0x600a +#define VCLK2_VCO_DIV_SEL 0x6012 + +#define VCLK_DIVISOR_VGA0 0x6000 +#define VCLK_DIVISOR_VGA1 0x6004 +#define VCLK_POST_DIV 0x6010 +/** Selects a post divisor of 4 instead of 2. */ +# define VGA1_PD_P2_DIV_4 (1 << 15) +/** Overrides the p2 post divisor field */ +# define VGA1_PD_P1_DIV_2 (1 << 13) +# define VGA1_PD_P1_SHIFT 8 +/** P1 value is 2 greater than this field */ +# define VGA1_PD_P1_MASK (0x1f << 8) +/** Selects a post divisor of 4 instead of 2. */ +# define VGA0_PD_P2_DIV_4 (1 << 7) +/** Overrides the p2 post divisor field */ +# define VGA0_PD_P1_DIV_2 (1 << 5) +# define VGA0_PD_P1_SHIFT 0 +/** P1 value is 2 greater than this field */ +# define VGA0_PD_P1_MASK (0x1f << 0) + +#define POST_DIV_SELECT 0x70 +#define POST_DIV_1 0x00 +#define POST_DIV_2 0x10 +#define POST_DIV_4 0x20 +#define POST_DIV_8 0x30 +#define POST_DIV_16 0x40 +#define POST_DIV_32 0x50 +#define VCO_LOOP_DIV_BY_4M 0x00 +#define VCO_LOOP_DIV_BY_16M 0x04 #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 @@ -906,6 +940,58 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) +/* + * Some BIOS scratch area registers. The 845 (and 830?) store the amount + * of video memory available to the BIOS in SWF1. + */ + +#define SWF0 0x71410 +#define SWF1 0x71414 +#define SWF2 0x71418 +#define SWF3 0x7141c +#define SWF4 0x71420 +#define SWF5 0x71424 +#define SWF6 0x71428 + +/* + * 855 scratch registers. + */ +#define SWF00 0x70410 +#define SWF01 0x70414 +#define SWF02 0x70418 +#define SWF03 0x7041c +#define SWF04 0x70420 +#define SWF05 0x70424 +#define SWF06 0x70428 + +#define SWF10 SWF0 +#define SWF11 SWF1 +#define SWF12 SWF2 +#define SWF13 SWF3 +#define SWF14 SWF4 +#define SWF15 SWF5 +#define SWF16 SWF6 + +#define SWF30 0x72414 +#define SWF31 0x72418 +#define SWF32 0x7241c + +/* + * Overlay registers. These are overlay registers accessed via MMIO. + * Those loaded via the overlay register page are defined in i830_video.c. + */ +#define OVADD 0x30000 + +#define DOVSTA 0x30008 +#define OC_BUF (0x3<<20) + +#define OGAMC5 0x30010 +#define OGAMC4 0x30014 +#define OGAMC3 0x30018 +#define OGAMC2 0x3001c +#define OGAMC1 0x30020 +#define OGAMC0 0x30024 + /* * Palette registers */ diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4ceed3e3..2d4df76e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -438,6 +438,19 @@ static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence, return ret; } +void i915_driver_wait_next_vblank(drm_device_t *dev, int pipe) +{ + unsigned int seq; + + seq = pipe ? atomic_read(&dev->vbl_received2) + 1 : + atomic_read(&dev->vbl_received) + 1; + + if (!pipe) + i915_driver_vblank_do_wait(dev, &seq, &dev->vbl_received); + else + i915_driver_vblank_do_wait(dev, &seq, &dev->vbl_received2); +} + int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) { return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); -- cgit v1.2.3 From fa92e1f2ec396d2e772734f726a0958801b9fc99 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 24 May 2007 18:41:44 -0700 Subject: Suspend/resume shouldn't call drm_initial_config (seems to work ok for me now), also we should fail if we can't enable the device at resume time. --- linux-core/i915_drv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index ffdbab06..d58ca589 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -172,7 +172,8 @@ static int i915_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_device(pdev); + if (pci_enable_device(pdev)) + return -1; /* Disable outputs */ list_for_each_entry(output, &dev->mode_config.output_list, head) @@ -294,8 +295,6 @@ static int i915_resume(struct pci_dev *pdev) vgaHWLock(hwp); #endif - drm_initial_config(dev, 0); - return 0; } -- cgit v1.2.3 From 704ca0638977f58742a8bff6aba9905fe862cfb3 Mon Sep 17 00:00:00 2001 From: David Airlie Date: Fri, 1 Jun 2007 18:12:45 +1000 Subject: WIP more code for radeon --- linux-core/ati_pcigart.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 108e1875..ad47ed25 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -234,6 +234,19 @@ static int ati_pcigart_needs_unbind_cache_adjust(drm_ttm_backend_t *backend) return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); } +void ati_pcigart_alloc_page_array(size_t size, struct ati_pcigart_memory *mem) +{ + mem->memory = NULL; + mem->flags = 0; + + if (size <= 2*PAGE_SIZE) + mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY); + if (mem->memory == NULL) { + mem->memory = vmalloc(size); + mem->flags |= ATI_PCIGART_FLAG_VMALLOC; + } +} + static int ati_pcigart_populate(drm_ttm_backend_t *backend, unsigned long num_pages, struct page **pages) @@ -241,6 +254,7 @@ static int ati_pcigart_populate(drm_ttm_backend_t *backend, ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; struct page **cur_page, **last_page = pages + num_pages; struct ati_pcigart_memory *mem; + unsigned long alloc_size = num_pages * sizeof(struct page *); DRM_DEBUG("%d\n", num_pages); if (drm_alloc_memctl(num_pages * sizeof(void *))) @@ -252,7 +266,11 @@ static int ati_pcigart_populate(drm_ttm_backend_t *backend, return -1; } - mem->page_count = num_pages; + ati_pcigart_alloc_page_array(alloc_size, mem); + mem->page_count = 0; + for (cur_page = pages; cur_page < last_page; ++cur_page) { + mem->memory[mem->page_count++] = page_to_phys(*cur_page); + } atipci_priv->mem = mem; return 0; } @@ -262,7 +280,19 @@ static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, int cached) { ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + struct ati_pcigart_memory *mem = atipci_priv->mem; + off_t j; + + j = offset; + while (j < (pg_start + mem->page_count)) { + j++; + } + + for (i = 0, j = offset; i < mem->page_count; i++, j++) { + /* write value */ + } + /* need to traverse table and add entries */ DRM_DEBUG("\n"); return -1; } -- cgit v1.2.3 From 77b9d9d16b1d1f1715722182d5893aa202f73074 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Jun 2007 10:35:41 +1000 Subject: cleanup pcigart ttm for new backend layout --- linux-core/ati_pcigart.c | 94 ++++++++++++++++++++++------------------------ linux-core/drmP.h | 6 ++- linux-core/radeon_buffer.c | 4 +- 3 files changed, 50 insertions(+), 54 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 66742bbc..08dbfe6c 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -261,7 +261,8 @@ static int ati_pcigart_populate(drm_ttm_backend_t *backend, unsigned long num_pages, struct page **pages) { - ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + ati_pcigart_ttm_backend_t *atipci_be = + container_of(backend, ati_pcigart_ttm_backend_t, backend); struct page **cur_page, **last_page = pages + num_pages; struct ati_pcigart_memory *mem; unsigned long alloc_size = num_pages * sizeof(struct page *); @@ -281,7 +282,7 @@ static int ati_pcigart_populate(drm_ttm_backend_t *backend, for (cur_page = pages; cur_page < last_page; ++cur_page) { mem->memory[mem->page_count++] = page_to_phys(*cur_page); } - atipci_priv->mem = mem; + atipci_be->mem = mem; return 0; } @@ -289,18 +290,20 @@ static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, unsigned long offset, int cached) { - ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; - struct ati_pcigart_memory *mem = atipci_priv->mem; + ati_pcigart_ttm_backend_t *atipci_be = + container_of(backend, ati_pcigart_ttm_backend_t, backend); + + struct ati_pcigart_memory *mem = atipci_be->mem; off_t j; j = offset; - while (j < (pg_start + mem->page_count)) { + while (j < (offset + mem->page_count)) { j++; } - for (i = 0, j = offset; i < mem->page_count; i++, j++) { +// for (i = 0, j = offset; i < mem->page_count; i++, j++) { /* write value */ - } +// } /* need to traverse table and add entries */ DRM_DEBUG("\n"); @@ -309,7 +312,8 @@ static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, static int ati_pcigart_unbind_ttm(drm_ttm_backend_t *backend) { - ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; + ati_pcigart_ttm_backend_t *atipci_be = + container_of(backend, ati_pcigart_ttm_backend_t, backend); DRM_DEBUG("\n"); return -1; @@ -317,69 +321,59 @@ static int ati_pcigart_unbind_ttm(drm_ttm_backend_t *backend) static void ati_pcigart_clear_ttm(drm_ttm_backend_t *backend) { - ati_pcigart_ttm_priv *atipci_priv = (ati_pcigart_ttm_priv *)backend->private; - struct ati_pcigart_memory *mem = atipci_priv->mem; + ati_pcigart_ttm_backend_t *atipci_be = + container_of(backend, ati_pcigart_ttm_backend_t, backend); + struct ati_pcigart_memory *mem = atipci_be->mem; DRM_DEBUG("\n"); if (mem) { unsigned long num_pages = mem->page_count; - backend->unbind(backend); + backend->func->unbind(backend); /* free test */ - drm_free(mem, sizeof(struct ati_pcigart_memory), DRM_MEM_MAPPINGS); - drm_free_memctl(num_pages * sizeof(void *)); +// drm_free(mem, sizeof(struct ati_pcigart_memory), DRM_MEM_MAPPINGS); +// drm_free_memctl(num_pages * sizeof(void *)); } - atipci_priv->mem = NULL; + atipci_be->mem = NULL; } static void ati_pcigart_destroy_ttm(drm_ttm_backend_t *backend) { - ati_pcigart_ttm_priv *atipci_priv; - + ati_pcigart_ttm_backend_t *atipci_be; if (backend) { DRM_DEBUG("\n"); - atipci_priv = (ati_pcigart_ttm_priv *)backend->private; - if (atipci_priv) { - if (atipci_priv->mem) { - backend->clear(backend); + atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); + if (atipci_be) { + if (atipci_be->mem) { + backend->func->clear(backend); } - drm_ctl_free(atipci_priv, sizeof(*atipci_priv), DRM_MEM_MAPPINGS); - backend->private = NULL; - } - if (backend->flags & DRM_BE_FLAG_NEEDS_FREE) { - drm_ctl_free(backend, sizeof(*backend), DRM_MEM_MAPPINGS); + drm_ctl_free(atipci_be, sizeof(*atipci_be), DRM_MEM_TTM); } } } - -drm_ttm_backend_t *ati_pcigart_init_ttm(struct drm_device *dev, - drm_ttm_backend_t *backend) +static drm_ttm_backend_func_t ati_pcigart_ttm_backend = { - drm_ttm_backend_t *atipci_be; - ati_pcigart_ttm_priv *atipci_priv; - - atipci_be = (backend != NULL) ? backend : - drm_ctl_calloc(1, sizeof (*atipci_be), DRM_MEM_MAPPINGS); + .needs_ub_cache_adjust = ati_pcigart_needs_unbind_cache_adjust, + .populate = ati_pcigart_populate, + .clear = ati_pcigart_clear_ttm, + .bind = ati_pcigart_bind_ttm, + .unbind = ati_pcigart_unbind_ttm, + .destroy = ati_pcigart_destroy_ttm, +}; + +drm_ttm_backend_t *ati_pcigart_init_ttm(struct drm_device *dev, struct ati_pcigart_info *info) +{ + ati_pcigart_ttm_backend_t *atipci_be; + atipci_be = drm_ctl_calloc(1, sizeof (*atipci_be), DRM_MEM_TTM); if (!atipci_be) return NULL; - - atipci_priv = drm_ctl_calloc(1, sizeof(*atipci_priv), DRM_MEM_MAPPINGS); - if (!atipci_priv) { - drm_ctl_free(atipci_be, sizeof(*atipci_be), DRM_MEM_MAPPINGS); - return NULL; - } - - atipci_priv->populated = FALSE; - atipci_be->needs_ub_cache_adjust = ati_pcigart_needs_unbind_cache_adjust; - atipci_be->populate = ati_pcigart_populate; - atipci_be->clear = ati_pcigart_clear_ttm; - atipci_be->bind = ati_pcigart_bind_ttm; - atipci_be->unbind = ati_pcigart_unbind_ttm; - atipci_be->destroy = ati_pcigart_destroy_ttm; - DRM_FLAG_MASKED(atipci_be->flags, (backend == NULL) ? DRM_BE_FLAG_NEEDS_FREE : 0, DRM_BE_FLAG_NEEDS_FREE); - atipci_be->drm_map_type = _DRM_SCATTER_GATHER; - return atipci_be; + atipci_be->populated = 0; + atipci_be->backend.func = &ati_pcigart_ttm_backend; + atipci_be->backend.mem_type = DRM_BO_MEM_TT; + atipci_be->gart_info = info; + + return &atipci_be->backend; } EXPORT_SYMBOL(ati_pcigart_init_ttm); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index ec432b2a..ef9e133a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -850,10 +850,12 @@ struct ati_pcigart_memory { int flags; }; -typedef struct ati_pcigart_ttm_priv { +typedef struct ati_pcigart_ttm_backend { + drm_ttm_backend_t backend; int populated; + struct ati_pcigart_info *gart_info; struct ati_pcigart_memory *mem; -} ati_pcigart_ttm_priv; +} ati_pcigart_ttm_backend_t; static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index dd387604..a90dae83 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -39,9 +39,9 @@ drm_ttm_backend_t *radeon_create_ttm_backend_entry(drm_device_t * dev) drm_radeon_private_t *dev_priv = dev->dev_private; if(dev_priv->flags & RADEON_IS_AGP) - return drm_agp_init_ttm(dev, NULL); + return drm_agp_init_ttm(dev); else - return ati_pcigart_init_ttm(dev, NULL); + return ati_pcigart_init_ttm(dev, &dev_priv->gart_info); } int radeon_fence_types(drm_buffer_object_t *bo, uint32_t * class, uint32_t * type) -- cgit v1.2.3 From 234a9062009e48bf7b6c7239564ab95b3bcb06aa Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Jun 2007 10:47:42 +1000 Subject: WIP cleanup --- linux-core/ati_pcigart.c | 81 ++++++++++++++++-------------------------------- linux-core/drmP.h | 11 ++----- 2 files changed, 30 insertions(+), 62 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 08dbfe6c..44229a0d 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -35,6 +35,24 @@ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ +static __inline__ void insert_page_into_table(struct ati_pcigart_info *info, u32 page_base, u32 *pci_gart) +{ + switch(info->gart_reg_if) { + case DRM_ATI_GART_IGP: + *pci_gart = cpu_to_le32((page_base) | 0xc); + break; + case DRM_ATI_GART_PCIE: + *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); + break; + default: + case DRM_ATI_GART_PCI: + *pci_gart = cpu_to_le32(page_base); + break; + } +} + + + static void *drm_ati_alloc_pcigart_table(int order) { unsigned long address; @@ -207,18 +225,7 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) page_base = (u32) entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { - switch(gart_info->gart_reg_if) { - case DRM_ATI_GART_IGP: - *pci_gart = cpu_to_le32((page_base) | 0xc); - break; - case DRM_ATI_GART_PCIE: - *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); - break; - default: - case DRM_ATI_GART_PCI: - *pci_gart = cpu_to_le32(page_base); - break; - } + insert_page_into_table(gart_info, page_base, pci_gart); pci_gart++; page_base += ATI_PCIGART_PAGE_SIZE; } @@ -244,45 +251,16 @@ static int ati_pcigart_needs_unbind_cache_adjust(drm_ttm_backend_t *backend) return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); } -void ati_pcigart_alloc_page_array(size_t size, struct ati_pcigart_memory *mem) -{ - mem->memory = NULL; - mem->flags = 0; - - if (size <= 2*PAGE_SIZE) - mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY); - if (mem->memory == NULL) { - mem->memory = vmalloc(size); - mem->flags |= ATI_PCIGART_FLAG_VMALLOC; - } -} - static int ati_pcigart_populate(drm_ttm_backend_t *backend, unsigned long num_pages, struct page **pages) { ati_pcigart_ttm_backend_t *atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); - struct page **cur_page, **last_page = pages + num_pages; - struct ati_pcigart_memory *mem; - unsigned long alloc_size = num_pages * sizeof(struct page *); DRM_DEBUG("%d\n", num_pages); - if (drm_alloc_memctl(num_pages * sizeof(void *))) - return -1; - - mem = drm_alloc(sizeof(struct ati_pcigart_memory), DRM_MEM_MAPPINGS); - if (!mem) { - drm_free_memctl(num_pages * sizeof(void *)); - return -1; - } - - ati_pcigart_alloc_page_array(alloc_size, mem); - mem->page_count = 0; - for (cur_page = pages; cur_page < last_page; ++cur_page) { - mem->memory[mem->page_count++] = page_to_phys(*cur_page); - } - atipci_be->mem = mem; + atipci_be->pages = pages; + atipci_be->num_pages = num_pages; return 0; } @@ -292,12 +270,10 @@ static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, { ati_pcigart_ttm_backend_t *atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); - - struct ati_pcigart_memory *mem = atipci_be->mem; off_t j; j = offset; - while (j < (offset + mem->page_count)) { + while (j < (offset + atipci_be->num_pages)) { j++; } @@ -323,17 +299,14 @@ static void ati_pcigart_clear_ttm(drm_ttm_backend_t *backend) { ati_pcigart_ttm_backend_t *atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); - struct ati_pcigart_memory *mem = atipci_be->mem; DRM_DEBUG("\n"); - if (mem) { - unsigned long num_pages = mem->page_count; + if (atipci_be->pages) { backend->func->unbind(backend); - /* free test */ -// drm_free(mem, sizeof(struct ati_pcigart_memory), DRM_MEM_MAPPINGS); -// drm_free_memctl(num_pages * sizeof(void *)); + atipci_be->pages = NULL; + } - atipci_be->mem = NULL; + atipci_be->num_pages = 0; } static void ati_pcigart_destroy_ttm(drm_ttm_backend_t *backend) @@ -343,7 +316,7 @@ static void ati_pcigart_destroy_ttm(drm_ttm_backend_t *backend) DRM_DEBUG("\n"); atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); if (atipci_be) { - if (atipci_be->mem) { + if (atipci_be->pages) { backend->func->clear(backend); } drm_ctl_free(atipci_be, sizeof(*atipci_be), DRM_MEM_TTM); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index ef9e133a..16e3f5b0 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -843,18 +843,13 @@ typedef struct drm_agp_ttm_backend { } drm_agp_ttm_backend_t; #endif -#define ATI_PCIGART_FLAG_VMALLOC 1 -struct ati_pcigart_memory { - size_t page_count; - unsigned long *memory; - int flags; -}; - typedef struct ati_pcigart_ttm_backend { drm_ttm_backend_t backend; int populated; struct ati_pcigart_info *gart_info; - struct ati_pcigart_memory *mem; + struct page **pages; + int num_pages; + int bound; } ati_pcigart_ttm_backend_t; static __inline__ int drm_core_check_feature(struct drm_device *dev, -- cgit v1.2.3 From 4294dcc050c5d2685f633e8a52deb925d806be85 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Jun 2007 12:26:06 +1000 Subject: complete PCIE backend for ttm ttm test runs with it at least, needs to do more testing on it --- linux-core/ati_pcigart.c | 68 +++++++++++++++++++++++++++++++++++++++++----- linux-core/drmP.h | 3 ++ linux-core/radeon_buffer.c | 3 +- shared-core/radeon_cp.c | 20 ++++++++++++++ shared-core/radeon_drv.h | 1 + 5 files changed, 86 insertions(+), 9 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 44229a0d..91136060 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -51,6 +51,27 @@ static __inline__ void insert_page_into_table(struct ati_pcigart_info *info, u32 } } +static __inline__ u32 get_page_base_from_table(struct ati_pcigart_info *info, u32 *pci_gart) +{ + u32 retval; + switch(info->gart_reg_if) { + case DRM_ATI_GART_IGP: + retval = *pci_gart; + retval &= ~0xc; + break; + case DRM_ATI_GART_PCIE: + retval = *pci_gart; + retval &= ~0xc; + retval <<= 8; + break; + default: + case DRM_ATI_GART_PCI: + retval = *pci_gart; + break; + } + return retval; +} + static void *drm_ati_alloc_pcigart_table(int order) @@ -258,9 +279,10 @@ static int ati_pcigart_populate(drm_ttm_backend_t *backend, ati_pcigart_ttm_backend_t *atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); - DRM_DEBUG("%d\n", num_pages); + DRM_ERROR("%ld\n", num_pages); atipci_be->pages = pages; atipci_be->num_pages = num_pages; + atipci_be->populated = 1; return 0; } @@ -271,28 +293,58 @@ static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, ati_pcigart_ttm_backend_t *atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); off_t j; + int i; + struct ati_pcigart_info *info = atipci_be->gart_info; + u32 *pci_gart; + u32 page_base; + pci_gart = info->addr; + DRM_ERROR("Offset is %08lX\n", offset); j = offset; while (j < (offset + atipci_be->num_pages)) { + if (get_page_base_from_table(info, pci_gart+j)) + return -EBUSY; j++; } -// for (i = 0, j = offset; i < mem->page_count; i++, j++) { + for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { + struct page *cur_page = atipci_be->pages[i]; /* write value */ -// } + page_base = page_to_phys(cur_page); + insert_page_into_table(info, page_base, pci_gart + j); + } + + atipci_be->gart_flush_fn(atipci_be->dev); + atipci_be->bound = 1; + atipci_be->offset = offset; /* need to traverse table and add entries */ DRM_DEBUG("\n"); - return -1; + return 0; } static int ati_pcigart_unbind_ttm(drm_ttm_backend_t *backend) { ati_pcigart_ttm_backend_t *atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); - + struct ati_pcigart_info *info = atipci_be->gart_info; + unsigned long offset = atipci_be->offset; + int i; + off_t j; + u32 *pci_gart = info->addr; + DRM_DEBUG("\n"); - return -1; + + if (atipci_be->bound != 1) + return -EINVAL; + + for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { + *(pci_gart + j) = 0; + } + atipci_be->gart_flush_fn(atipci_be->dev); + atipci_be->bound = 0; + atipci_be->offset = 0; + return 0; } static void ati_pcigart_clear_ttm(drm_ttm_backend_t *backend) @@ -334,7 +386,7 @@ static drm_ttm_backend_func_t ati_pcigart_ttm_backend = .destroy = ati_pcigart_destroy_ttm, }; -drm_ttm_backend_t *ati_pcigart_init_ttm(struct drm_device *dev, struct ati_pcigart_info *info) +drm_ttm_backend_t *ati_pcigart_init_ttm(struct drm_device *dev, struct ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev)) { ati_pcigart_ttm_backend_t *atipci_be; @@ -346,6 +398,8 @@ drm_ttm_backend_t *ati_pcigart_init_ttm(struct drm_device *dev, struct ati_pciga atipci_be->backend.func = &ati_pcigart_ttm_backend; atipci_be->backend.mem_type = DRM_BO_MEM_TT; atipci_be->gart_info = info; + atipci_be->gart_flush_fn = gart_flush_fn; + atipci_be->dev = dev; return &atipci_be->backend; } diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 16e3f5b0..5eb7c037 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -846,10 +846,13 @@ typedef struct drm_agp_ttm_backend { typedef struct ati_pcigart_ttm_backend { drm_ttm_backend_t backend; int populated; + void (*gart_flush_fn)(struct drm_device *dev); struct ati_pcigart_info *gart_info; + unsigned long offset; struct page **pages; int num_pages; int bound; + drm_device_t *dev; } ati_pcigart_ttm_backend_t; static __inline__ int drm_core_check_feature(struct drm_device *dev, diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index a90dae83..6f7a7603 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -33,7 +33,6 @@ #include "radeon_drm.h" #include "radeon_drv.h" - drm_ttm_backend_t *radeon_create_ttm_backend_entry(drm_device_t * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -41,7 +40,7 @@ drm_ttm_backend_t *radeon_create_ttm_backend_entry(drm_device_t * dev) if(dev_priv->flags & RADEON_IS_AGP) return drm_agp_init_ttm(dev); else - return ati_pcigart_init_ttm(dev, &dev_priv->gart_info); + return ati_pcigart_init_ttm(dev, &dev_priv->gart_info, radeon_gart_flush); } int radeon_fence_types(drm_buffer_object_t *bo, uint32_t * class, uint32_t * type) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 56d17b9a..9dc871ca 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1384,6 +1384,26 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) } } + +void radeon_gart_flush(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (dev_priv->flags & RADEON_IS_IGPGART) { + RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); + RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1); + RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); + RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0); + } else if (dev_priv->flags & RADEON_IS_PCIE) { + + + } else { + + + } + +} + static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index c16a43eb..5a33231a 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -344,6 +344,7 @@ extern int radeon_cp_resume(DRM_IOCTL_ARGS); extern int radeon_engine_reset(DRM_IOCTL_ARGS); extern int radeon_fullscreen(DRM_IOCTL_ARGS); extern int radeon_cp_buffers(DRM_IOCTL_ARGS); +extern void radeon_gart_flush(struct drm_device *dev); extern void radeon_freelist_reset(drm_device_t * dev); extern drm_buf_t *radeon_freelist_get(drm_device_t * dev); -- cgit v1.2.3 From f6e8023e03278731db38dcc0c429025f36817c65 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Jun 2007 12:26:18 +1000 Subject: take the lock earlier in ttmtest --- tests/ttmtest/src/ttmtest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ttmtest/src/ttmtest.c b/tests/ttmtest/src/ttmtest.c index 606fb0cb..052947b1 100644 --- a/tests/ttmtest/src/ttmtest.c +++ b/tests/ttmtest/src/ttmtest.c @@ -176,7 +176,7 @@ benchmarkBuffer(TinyDRIContext * ctx, unsigned long size, /* * Test system memory objects. */ - + BM_CKFATAL(drmGetLock(ctx->drmFD, ctx->hwContext, 0)); oldTime = fastrdtsc(); BM_CKFATAL(drmBOCreate(ctx->drmFD, 0, size, 0, NULL, drm_bo_type_dc, @@ -216,7 +216,7 @@ benchmarkBuffer(TinyDRIContext * ctx, unsigned long size, * Test TT bound buffer objects. */ - BM_CKFATAL(drmGetLock(ctx->drmFD, ctx->hwContext, 0)); + // BM_CKFATAL(drmGetLock(ctx->drmFD, ctx->hwContext, 0)); oldTime = fastrdtsc(); BM_CKFATAL(drmBOValidate(ctx->drmFD, &buf, DRM_BO_FLAG_MEM_TT, DRM_BO_MASK_MEM, DRM_BO_HINT_DONT_FENCE)); -- cgit v1.2.3 From c9dbe0f2c2248ef8c3ba5718f77922d1c7429e6f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Jun 2007 12:38:43 +1000 Subject: invalidate gart tlb on PCIE after table change --- shared-core/radeon_cp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 9dc871ca..2c0549e5 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1395,8 +1395,11 @@ void radeon_gart_flush(struct drm_device *dev) RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0); } else if (dev_priv->flags & RADEON_IS_PCIE) { - - + u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); + tmp |= RADEON_PCIE_TX_GART_INVALIDATE_TLB; + RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + tmp &= ~RADEON_PCIE_TX_GART_INVALIDATE_TLB; + RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); } else { -- cgit v1.2.3 From 96705ce6644389722f1605571e0a0dfde5568b8f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Jun 2007 18:23:05 +1000 Subject: add wbinvd calls --- linux-core/ati_pcigart.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 91136060..ebf19a2b 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -314,6 +314,12 @@ static int ati_pcigart_bind_ttm(drm_ttm_backend_t *backend, insert_page_into_table(info, page_base, pci_gart + j); } +#if defined(__i386__) || defined(__x86_64__) + wbinvd(); +#else + mb(); +#endif + atipci_be->gart_flush_fn(atipci_be->dev); atipci_be->bound = 1; -- cgit v1.2.3 From 03ce98aa2814dfd473c70487861aece79007a571 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Jun 2007 18:23:24 +1000 Subject: set start to gart_vm_start at least --- linux-core/radeon_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 6f7a7603..159e87ea 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -101,7 +101,7 @@ int radeon_init_mem_type(drm_device_t * dev, uint32_t type, _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; man->drm_bus_maptype = _DRM_AGP; } else { - man->io_offset = 0; + man->io_offset = dev_priv->gart_vm_start; man->io_size = dev_priv->gart_size; man->io_addr = NULL; man->flags = _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_MEMTYPE_MAPPABLE; @@ -120,6 +120,7 @@ int radeon_move(drm_buffer_object_t * bo, { drm_bo_mem_reg_t *old_mem = &bo->mem; + DRM_DEBUG("\n"); if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); } -- cgit v1.2.3 From abf35cbdcf5743c73929ddbe67ed4cae69b32aeb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 7 Jun 2007 15:36:04 +1000 Subject: radeon: PCIGART memory is Can't map aperture as well there is one on the CPU.... with this my indirect buffers at least start to live.. (cherry picked from commit 699cd9fc6c3794856f7e602088c77d0dfc11a122) --- linux-core/radeon_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 159e87ea..67e6c585 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -104,7 +104,7 @@ int radeon_init_mem_type(drm_device_t * dev, uint32_t type, man->io_offset = dev_priv->gart_vm_start; man->io_size = dev_priv->gart_size; man->io_addr = NULL; - man->flags = _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_MEMTYPE_MAPPABLE; + man->flags = _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_MEMTYPE_CMA; man->drm_bus_maptype = _DRM_SCATTER_GATHER; } break; -- cgit v1.2.3 From e79e2a58161d44754fd55507e155b7e12a09c4d2 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 28 Jun 2007 21:25:13 +0100 Subject: Fix type/flags usage problem to check for preferred modes. Add more debugging to help diagnose problems. --- linux-core/drm_crtc.c | 15 ++++++++------- linux-core/drm_modes.c | 8 +++++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 245fe5be..04d3b723 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -436,8 +436,11 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, */ crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == crtc) + if (output->crtc == crtc) { + dev_warn(&output->dev->pdev->dev, "%s: set mode %s\n", + output->name, mode->name); output->funcs->mode_set(output, mode, adjusted_mode); + } } /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ @@ -787,16 +790,14 @@ static void drm_pick_crtcs (drm_device_t *dev) des_mode = NULL; list_for_each_entry(des_mode, &output->modes, head) { - if (des_mode->flags & DRM_MODE_TYPE_PREFERRED) + if (des_mode->type & DRM_MODE_TYPE_PREFERRED) break; } - /* No preferred mode, let's select another which should pick - * the default 640x480 if nothing else is here. - */ - if (!des_mode || !(des_mode->flags & DRM_MODE_TYPE_PREFERRED)) { + /* No preferred mode, let's just select the first available */ + if (!des_mode || !(des_mode->type & DRM_MODE_TYPE_PREFERRED)) { list_for_each_entry(des_mode, &output->modes, head) { - if (des_mode->flags & DRM_MODE_TYPE_DEFAULT) + if (des_mode) break; } } diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 41b5fade..fd00841e 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -46,12 +46,12 @@ void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode) { - DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d\n", + DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x\n", mode->mode_id, mode->name, mode->vrefresh, mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal); + mode->vsync_end, mode->vtotal, mode->type); } EXPORT_SYMBOL(drm_mode_debug_printmodeline); @@ -387,8 +387,10 @@ void drm_mode_prune_invalid(struct drm_device *dev, list_for_each_entry_safe(mode, t, mode_list, head) { if (mode->status != MODE_OK) { list_del(&mode->head); - if (verbose) + if (verbose) { + drm_mode_debug_printmodeline(dev, mode); DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status); + } kfree(mode); } } -- cgit v1.2.3 From 14c49df06bb0b1adc0fa2a9bd575c454d39c7cf0 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 29 Jun 2007 20:14:09 +0100 Subject: merge fixes --- linux-core/drm_crtc.c | 2 +- shared-core/i915_dma.c | 2 +- shared-core/i915_drv.h | 2 -- shared-core/i915_init.c | 3 +-- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 04d3b723..65ccc870 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -912,7 +912,7 @@ void drm_mode_config_cleanup(drm_device_t *dev) /* If this FB was the kernel one, free it */ if (fb->bo->type == drm_bo_type_kernel) { mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(fb->bo); + drm_bo_usage_deref_locked(&fb->bo); mutex_unlock(&dev->struct_mutex); } drm_framebuffer_destroy(fb); diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index c95f1857..59bf15ef 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -78,7 +78,7 @@ void i915_kernel_lost_context(drm_device_t * dev) dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; } -static int i915_dma_cleanup(drm_device_t * dev) +int i915_dma_cleanup(drm_device_t * dev) { /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 35451feb..35e5be1c 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -213,7 +213,6 @@ extern int i915_max_ioctl; extern void i915_kernel_lost_context(drm_device_t * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); extern int i915_driver_unload(drm_device_t *dev); -extern int i915_driver_firstopen(struct drm_device *dev); extern void i915_driver_lastclose(drm_device_t * dev); extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp); extern int i915_driver_device_is_agp(drm_device_t * dev); @@ -222,7 +221,6 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, extern void i915_emit_breadcrumb(drm_device_t *dev); extern void i915_dispatch_flip(drm_device_t * dev, int pipes, int sync); extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush); -extern int i915_driver_firstopen(struct drm_device *dev); extern int i915_dma_cleanup(drm_device_t * dev); /* i915_irq.c */ diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 83219e49..e4a2cdef 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -275,7 +275,7 @@ int i915_driver_unload(drm_device_t *dev) DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage)); mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(dev_priv->ring_buffer); + drm_bo_usage_deref_locked(&dev_priv->ring_buffer); mutex_unlock(&dev->struct_mutex); if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { @@ -302,7 +302,6 @@ void i915_driver_lastclose(drm_device_t * dev) i915_mem_takedown(&(dev_priv->agp_heap)); i915_dma_cleanup(dev); - } void i915_driver_preclose(drm_device_t * dev, DRMFILE filp) -- cgit v1.2.3 From adff58223f4568d084cf62d03d4ecfc3a6cec000 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 29 Jun 2007 20:58:16 +0100 Subject: Bring back code from merge that was accidentally removed. --- shared-core/i915_dma.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 59bf15ef..008adc0a 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -80,13 +80,41 @@ void i915_kernel_lost_context(drm_device_t * dev) int i915_dma_cleanup(drm_device_t * dev) { + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. */ + I915_WRITE(LP_RING + RING_LEN, 0); + if (dev->irq) drm_irq_uninstall(dev); + if (dev->dev_private) { + drm_i915_private_t *dev_priv = + (drm_i915_private_t *) dev->dev_private; + + if (dev_priv->ring.virtual_start) { + drm_core_ioremapfree(&dev_priv->ring.map, dev); + } + + if (dev_priv->status_page_dmah) { + drm_pci_free(dev, dev_priv->status_page_dmah); + /* Need to rewrite hardware status page */ + I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); + } + if (dev_priv->status_gfx_addr) { + dev_priv->status_gfx_addr = 0; + drm_core_ioremapfree(&dev_priv->hws_map, dev); + I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); + } + drm_free(dev->dev_private, sizeof(drm_i915_private_t), + DRM_MEM_DRIVER); + + dev->dev_private = NULL; + } + return 0; } -- cgit v1.2.3 From 70fd9351ed6c666def710fd61b542a7c975d9ac9 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 29 Jun 2007 21:04:17 +0100 Subject: Move out the code from i915_dma_cleanup to unload to match existing code. This needs verifying. --- shared-core/i915_dma.c | 24 ------------------------ shared-core/i915_init.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 008adc0a..7dd68954 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -91,30 +91,6 @@ int i915_dma_cleanup(drm_device_t * dev) if (dev->irq) drm_irq_uninstall(dev); - if (dev->dev_private) { - drm_i915_private_t *dev_priv = - (drm_i915_private_t *) dev->dev_private; - - if (dev_priv->ring.virtual_start) { - drm_core_ioremapfree(&dev_priv->ring.map, dev); - } - - if (dev_priv->status_page_dmah) { - drm_pci_free(dev, dev_priv->status_page_dmah); - /* Need to rewrite hardware status page */ - I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); - } - if (dev_priv->status_gfx_addr) { - dev_priv->status_gfx_addr = 0; - drm_core_ioremapfree(&dev_priv->hws_map, dev); - I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); - } - drm_free(dev->dev_private, sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); - - dev->dev_private = NULL; - } - return 0; } diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index e4a2cdef..fd102b35 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -257,6 +257,10 @@ int i915_driver_unload(drm_device_t *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + if (dev_priv->ring.virtual_start) { + drm_core_ioremapfree(&dev_priv->ring.map, dev); + } + if (dev_priv->status_page_dmah) { drm_pci_free(dev, dev_priv->status_page_dmah); dev_priv->status_page_dmah = NULL; @@ -266,6 +270,12 @@ int i915_driver_unload(drm_device_t *dev) I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); } + if (dev_priv->status_gfx_addr) { + dev_priv->status_gfx_addr = 0; + drm_core_ioremapfree(&dev_priv->hws_map, dev); + I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); + } + I915_WRITE(LP_RING + RING_LEN, 0); intel_modeset_cleanup(dev); -- cgit v1.2.3 From 5c6a23704afa9445a58585ea2b8686b054f4074a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Jul 2007 14:25:29 +1000 Subject: Merge branch 'radeon-ttm' of git://people.freedesktop.org/~airlied/drm into radeon-ttm Conflicts: linux-core/ati_pcigart.c linux-core/drmP.h linux-core/radeon_buffer.c --- linux-core/drmP.h | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5eb7c037..4b54c244 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1161,6 +1161,7 @@ extern int drm_sg_free(struct inode *inode, struct file *filp, /* ATI PCIGART support (ati_pcigart.h) */ extern int drm_ati_pcigart_init(drm_device_t * dev, drm_ati_pcigart_info *gart_info); extern int drm_ati_pcigart_cleanup(drm_device_t * dev, drm_ati_pcigart_info *gart_info); +extern drm_ttm_backend_t *ati_pcigart_init_ttm(struct drm_device *dev, struct ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev)); extern drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, dma_addr_t maxaddr); -- cgit v1.2.3 From ead9cd64bd767a30235860e9cfca25d937784bee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 12 Jul 2007 14:26:03 +1000 Subject: radeon: add VRAM support for radeon ttm This needs a lot of testing --- linux-core/radeon_buffer.c | 134 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 67e6c585..611d0d6a 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * Copyright 2007 Dave Airlie * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -26,7 +26,7 @@ * **************************************************************************/ /* - * Authors: Thomas Hellström + * Authors: Dave Airlie */ #include "drmP.h" @@ -87,6 +87,14 @@ int radeon_init_mem_type(drm_device_t * dev, uint32_t type, _DRM_FLAG_MEMTYPE_CACHED; man->drm_bus_maptype = 0; break; + case DRM_BO_MEM_VRAM: + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_NEEDS_IOREMAP; + man->io_addr = NULL; + man->drm_bus_maptype = _DRM_FRAME_BUFFER; + man->io_offset = drm_get_resource_start(dev, 0); + man->io_size = drm_get_resource_len(dev, 0); + break; case DRM_BO_MEM_TT: if (dev_priv->flags & RADEON_IS_AGP) { if (!(drm_core_has_AGP(dev) && dev->agp)) { @@ -115,6 +123,122 @@ int radeon_init_mem_type(drm_device_t * dev, uint32_t type, return 0; } +static void radeon_emit_copy_blit(drm_device_t * dev, + uint32_t src_offset, + uint32_t dst_offset, + uint32_t pages, int direction) +{ + uint32_t cur_pages; + uint32_t stride = PAGE_SIZE; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t format, height; + RING_LOCALS; + + if (!dev_priv) + return; + + /* 32-bit copy format */ + format = RADEON_COLOR_FORMAT_ARGB8888; + + /* radeon limited to 16k stride */ + stride &= 0x3fff; + while(pages > 0) { + cur_pages = pages; + if (cur_pages > 2048) + cur_pages = 2048; + pages -= cur_pages; + + /* needs verification */ + BEGIN_RING(7); + OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); + OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | + RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_NONE | + (format << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_MEMORY | + RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); + if (direction) { + OUT_RING((stride << 22) | (src_offset >> 10)); + OUT_RING((stride << 22) | (dst_offset >> 10)); + } else { + OUT_RING((stride << 22) | (dst_offset >> 10)); + OUT_RING((stride << 22) | (src_offset >> 10)); + } + OUT_RING(0); + OUT_RING(pages); /* x - y */ + OUT_RING((stride << 16) | cur_pages); + ADVANCE_RING(); + } + + BEGIN_RING(2); + RADEON_WAIT_UNTIL_2D_IDLE(); + ADVANCE_RING(); + + return; +} + +static int radeon_move_blit(drm_buffer_object_t * bo, + int evict, int no_wait, drm_bo_mem_reg_t *new_mem) +{ + drm_bo_mem_reg_t *old_mem = &bo->mem; + int dir = 0; + + if ((old_mem->mem_type == new_mem->mem_type) && + (new_mem->mm_node->start < + old_mem->mm_node->start + old_mem->mm_node->size)) { + dir = 1; + } + + radeon_emit_copy_blit(bo->dev, + old_mem->mm_node->start << PAGE_SHIFT, + new_mem->mm_node->start << PAGE_SHIFT, + new_mem->num_pages, dir); + + + return drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, + DRM_FENCE_TYPE_EXE | + DRM_RADEON_FENCE_TYPE_RW, + DRM_RADEON_FENCE_FLAG_FLUSHED, new_mem); +} + +static int radeon_move_flip(drm_buffer_object_t * bo, + int evict, int no_wait, drm_bo_mem_reg_t * new_mem) +{ + drm_device_t *dev = bo->dev; + drm_bo_mem_reg_t tmp_mem; + int ret; + + tmp_mem = *new_mem; + tmp_mem.mm_node = NULL; + tmp_mem.mask = DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING; + + ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); + if (ret) + return ret; + + ret = drm_bind_ttm(bo->ttm, 1, tmp_mem.mm_node->start); + if (ret) + goto out_cleanup; + + ret = radeon_move_blit(bo, 1, no_wait, &tmp_mem); + if (ret) + goto out_cleanup; + + ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); +out_cleanup: + if (tmp_mem.mm_node) { + mutex_lock(&dev->struct_mutex); + if (tmp_mem.mm_node != bo->pinned_node) + drm_mm_put_block(tmp_mem.mm_node); + tmp_mem.mm_node = NULL; + mutex_unlock(&dev->struct_mutex); + } + return ret; +} + int radeon_move(drm_buffer_object_t * bo, int evict, int no_wait, drm_bo_mem_reg_t * new_mem) { @@ -123,6 +247,12 @@ int radeon_move(drm_buffer_object_t * bo, DRM_DEBUG("\n"); if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + if (radeon_move_flip(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } else { + if (radeon_move_blit(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); } return 0; } -- cgit v1.2.3 From 0be629a914129446b353881f7d92aae707137047 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 16 Jul 2007 14:45:47 +1000 Subject: drm/radeon/ttm: more VRAM fixes --- linux-core/radeon_buffer.c | 8 ++++++-- linux-core/radeon_drv.c | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 611d0d6a..5b10c24a 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -71,6 +71,11 @@ uint32_t radeon_evict_mask(drm_buffer_object_t *bo) case DRM_BO_MEM_LOCAL: case DRM_BO_MEM_TT: return DRM_BO_FLAG_MEM_LOCAL; + case DRM_BO_MEM_VRAM: + if (bo->mem.num_pages > 128) + return DRM_BO_MEM_TT; + else + return DRM_BO_MEM_LOCAL; default: return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; } @@ -88,8 +93,7 @@ int radeon_init_mem_type(drm_device_t * dev, uint32_t type, man->drm_bus_maptype = 0; break; case DRM_BO_MEM_VRAM: - man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_NEEDS_IOREMAP; + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_NEEDS_IOREMAP; man->io_addr = NULL; man->drm_bus_maptype = _DRM_FRAME_BUFFER; man->io_offset = drm_get_resource_start(dev, 0); diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index d0995b5b..079971d5 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -71,8 +71,8 @@ static drm_fence_driver_t radeon_fence_driver = { #endif #ifdef RADEON_HAVE_BUFFER -static uint32_t radeon_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; -static uint32_t radeon_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_LOCAL}; +static uint32_t radeon_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; +static uint32_t radeon_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; static drm_bo_driver_t radeon_bo_driver = { .mem_type_prio = radeon_mem_prios, -- cgit v1.2.3 From 43c9abdedc88807a40034513de842d6eeb8c3ed2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 19 Jul 2007 16:58:23 +0200 Subject: Fix unlocking of spinlock when we should not --- linux-core/drm_crtc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 65ccc870..0ede1571 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -59,10 +59,8 @@ again: } ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id); - if (ret == -EAGAIN) { - spin_unlock(&dev->mode_config.config_lock); - goto again; - } + if (ret == -EAGAIN) + goto again; return new_id; } -- cgit v1.2.3 From 9ccb8440f393a395941b211ee87d9addcfa6d69a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 20 Jul 2007 11:36:57 +0200 Subject: Changed mode config spinlock to mutex --- linux-core/drm_crtc.c | 64 +++++++++++++++++++++++++-------------------------- linux-core/drm_crtc.h | 2 +- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 0ede1571..df00a7d2 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -123,7 +123,7 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) /* Limit to single framebuffer for now */ if (dev->mode_config.num_fb > 1) { - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); DRM_ERROR("Attempt to add multiple framebuffers failed\n"); return NULL; } @@ -572,11 +572,11 @@ struct drm_output *drm_output_create(drm_device_t *dev, /* output_set_monitor(output)? */ /* check for output_ignored(output)? */ - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); list_add_tail(&output->head, &dev->mode_config.output_list); dev->mode_config.num_output++; - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return output; @@ -607,10 +607,10 @@ void drm_output_destroy(struct drm_output *output) list_for_each_entry_safe(mode, t, &output->modes, head) drm_mode_remove(output, mode); - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); drm_idr_put(dev, output->id); list_del(&output->head); - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); kfree(output); } EXPORT_SYMBOL(drm_output_destroy); @@ -700,7 +700,7 @@ EXPORT_SYMBOL(drm_mode_destroy); */ void drm_mode_config_init(drm_device_t *dev) { - spin_lock_init(&dev->mode_config.config_lock); + mutex_init(&dev->mode_config.mutex); INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); @@ -858,7 +858,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) struct drm_output *output; int ret = false; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); drm_crtc_probe_output_modes(dev, 2048, 2048); @@ -874,7 +874,7 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) } drm_disable_unused_functions(dev); - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } EXPORT_SYMBOL(drm_initial_config); @@ -1107,7 +1107,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); list_for_each(lh, &dev->mode_config.fb_list) fb_count++; @@ -1215,7 +1215,7 @@ done: ret = -EFAULT; out_unlock: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1251,7 +1251,7 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp))) return -EFAULT; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp.crtc_id); if (!crtc || (crtc->id != crtc_resp.crtc_id)) { ret = -EINVAL; @@ -1279,7 +1279,7 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, ret = -EFAULT; out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1319,7 +1319,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, DRM_DEBUG("output id %d:\n", out_resp.output); - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); output= idr_find(&dev->mode_config.crtc_idr, out_resp.output); if (!output || (output->id != out_resp.output)) { ret = -EINVAL; @@ -1369,7 +1369,7 @@ done: ret = -EFAULT; out_unlock: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1407,7 +1407,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, if (copy_from_user(&crtc_req, argp, sizeof(crtc_req))) return -EFAULT; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id); if (!crtc || (crtc->id != crtc_req.crtc_id)) { DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req.crtc_id); @@ -1487,7 +1487,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, ret = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb); out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1533,7 +1533,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, return -EINVAL; } - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); /* TODO check limits are okay */ ret = drm_get_buffer_object(dev, &bo, r.handle); if (ret || !bo) { @@ -1574,7 +1574,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, } out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1604,7 +1604,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, uint32_t id = arg; int ret = 0; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); fb = idr_find(&dev->mode_config.crtc_idr, id); /* TODO check that we realy get a framebuffer back. */ if (!fb || (id != fb->id)) { @@ -1623,7 +1623,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, drm_framebuffer_destroy(fb); out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1657,7 +1657,7 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); fb = idr_find(&dev->mode_config.crtc_idr, r.buffer_id); if (!fb || (r.buffer_id != fb->id)) { DRM_ERROR("invalid framebuffer id\n"); @@ -1676,7 +1676,7 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, ret = -EFAULT; out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1700,13 +1700,13 @@ void drm_fb_release(struct file *filp) drm_device_t *dev = priv->head->dev; struct drm_framebuffer *fb, *tfb; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { list_del(&fb->filp_head); dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); drm_framebuffer_destroy(fb); } - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); } /** @@ -1737,7 +1737,7 @@ int drm_mode_addmode(struct inode *inode, struct file *filp, if (copy_from_user(&new_mode, argp, sizeof(new_mode))) return -EFAULT; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); user_mode = drm_mode_create(dev); if (!user_mode) { ret = -ENOMEM; @@ -1756,7 +1756,7 @@ int drm_mode_addmode(struct inode *inode, struct file *filp, ret = -EFAULT; out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1783,7 +1783,7 @@ int drm_mode_rmmode(struct inode *inode, struct file *filp, struct drm_display_mode *mode, *t; int ret = -EINVAL; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); mode = idr_find(&dev->mode_config.crtc_idr, id); if (!mode || (id != mode->mode_id)) { ret = -EINVAL; @@ -1810,7 +1810,7 @@ int drm_mode_rmmode(struct inode *inode, struct file *filp, } out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1841,7 +1841,7 @@ int drm_mode_attachmode(struct inode *inode, struct file *filp, if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) return -EFAULT; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); if (!mode || (mode->mode_id != mode_cmd.mode_id)) { @@ -1867,7 +1867,7 @@ int drm_mode_attachmode(struct inode *inode, struct file *filp, ret = -ENOSPC; out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1898,7 +1898,7 @@ int drm_mode_detachmode(struct inode *inode, struct file *filp, if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) return -EFAULT; - spin_lock(&dev->mode_config.config_lock); + mutex_lock(&dev->mode_config.mutex); mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); if (!mode || (mode->mode_id != mode_cmd.mode_id)) { @@ -1925,6 +1925,6 @@ int drm_mode_detachmode(struct inode *inode, struct file *filp, ret = -EINVAL; out: - spin_unlock(&dev->mode_config.config_lock); + mutex_unlock(&dev->mode_config.mutex); return ret; } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index e8a527b0..75db5b05 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -459,7 +459,7 @@ struct drm_mode_config_funcs { * */ struct drm_mode_config { - spinlock_t config_lock; /* protects configuration and IDR */ + struct mutex mutex; /* protects configuration and IDR */ struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output, modes - just makes life easier */ /* this is limited to one for now */ int num_fb; -- cgit v1.2.3 From 2a2d02bbc500140a861380df52ce66abcac39312 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 24 Sep 2007 14:53:10 +0200 Subject: Added small modesetting test --- tests/mode/Makefile | 11 ++ tests/mode/modetest.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/mode/test | 1 + 3 files changed, 349 insertions(+) create mode 100644 tests/mode/Makefile create mode 100644 tests/mode/modetest.c create mode 100755 tests/mode/test diff --git a/tests/mode/Makefile b/tests/mode/Makefile new file mode 100644 index 00000000..205c2ba1 --- /dev/null +++ b/tests/mode/Makefile @@ -0,0 +1,11 @@ + +all: modetest + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +modetest: modetest.c + @gcc -o modetest -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c + +clean: + @rm -f modetest diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c new file mode 100644 index 00000000..bf1a5169 --- /dev/null +++ b/tests/mode/modetest.c @@ -0,0 +1,337 @@ + +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +const char* getConnectionText(drmModeConnection conn) +{ + switch (conn) { + case DRM_MODE_CONNECTED: + return "connected"; + case DRM_MODE_DISCONNECTED: + return "disconnected"; + default: + return "unknown"; + } + +} + +struct drm_mode_modeinfo* findMode(drmModeResPtr res, uint32_t id) +{ + int i; + for (i = 0; i < res->count_modes; i++) { + if (res->modes[i].id == id) + return &res->modes[i]; + } + + return 0; +} + +int printMode(struct drm_mode_modeinfo *mode) +{ +#if 0 + printf("Mode: %s\n", mode->name); + printf("\tclock : %i\n", mode->clock); + printf("\thdisplay : %i\n", mode->hdisplay); + printf("\thsync_start : %i\n", mode->hsync_start); + printf("\thsync_end : %i\n", mode->hsync_end); + printf("\thtotal : %i\n", mode->htotal); + printf("\thskew : %i\n", mode->hskew); + printf("\tvdisplay : %i\n", mode->vdisplay); + printf("\tvsync_start : %i\n", mode->vsync_start); + printf("\tvsync_end : %i\n", mode->vsync_end); + printf("\tvtotal : %i\n", mode->vtotal); + printf("\tvscan : %i\n", mode->vscan); + printf("\tvrefresh : %i\n", mode->vrefresh); + printf("\tflags : %i\n", mode->flags); +#else + printf("Mode: %i \"%s\" %ix%i %.0f\n", mode->id, mode->name, + mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); +#endif + return 0; +} + +int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) +{ + int i = 0; + struct drm_mode_modeinfo *mode = NULL; + + printf("Output: %s\n", output->name); + printf("\tid : %i\n", id); + printf("\tcrtc id : %i\n", output->crtc); + printf("\tconn : %s\n", getConnectionText(output->connection)); + printf("\tsize : %ix%i (mm)\n", output->mmWidth, output->mmHeight); + printf("\tcount_crtcs : %i\n", output->count_crtcs); + printf("\tcrtcs : %i\n", output->crtcs); + printf("\tcount_clones : %i\n", output->count_clones); + printf("\tclones : %i\n", output->clones); + printf("\tcount_modes : %i\n", output->count_modes); + + for (i = 0; i < output->count_modes; i++) { + mode = findMode(res, output->modes[i]); + + if (mode) + printf("\t\tmode: %i \"%s\" %ix%i %.0f\n", mode->id, mode->name, + mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); + else + printf("\t\tmode: Invalid mode %i\n", output->modes[i]); + } + + return 0; +} + +int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) +{ + printf("Crtc\n"); + printf("\tid : %i\n", id); + printf("\tx : %i\n", crtc->x); + printf("\ty : %i\n", crtc->y); + printf("\twidth : %i\n", crtc->width); + printf("\theight : %i\n", crtc->height); + printf("\tmode : %i\n", crtc->mode); + printf("\tnum outputs : %i\n", crtc->count_outputs); + printf("\toutputs : %i\n", crtc->outputs); + printf("\tnum possible : %i\n", crtc->count_possibles); + printf("\tpossibles : %i\n", crtc->possibles); + + return 0; +} + +int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb) +{ + printf("Framebuffer\n"); + printf("\thandle : %i\n", fb->handle); + printf("\twidth : %i\n", fb->width); + printf("\theight : %i\n", fb->height); + printf("\tpitch : %i\n", fb->pitch);; + printf("\tbpp : %i\n", fb->bpp); + printf("\tdepth : %i\n", fb->depth); + printf("\tbuffer_id : %i\n", fb->buffer_id); + + return 0; +} + +int printRes(int fd, drmModeResPtr res) +{ + int i; + drmModeOutputPtr output; + drmModeCrtcPtr crtc; + drmModeFBPtr fb; + + for (i = 0; i < res->count_modes; i++) { + printMode(&res->modes[i]); + } + + for (i = 0; i < res->count_outputs; i++) { + output = drmModeGetOutput(fd, res->outputs[i]); + + if (!output) + printf("Could not get output %i\n", i); + else { + printOutput(fd, res, output, res->outputs[i]); + drmModeFreeOutput(output); + } + } + + for (i = 0; i < res->count_crtcs; i++) { + crtc = drmModeGetCrtc(fd, res->crtcs[i]); + + if (!crtc) + printf("Could not get crtc %i\n", i); + else { + printCrtc(fd, res, crtc, res->crtcs[i]); + drmModeFreeCrtc(crtc); + } + } + + for (i = 0; i < res->count_fbs; i++) { + fb = drmModeGetFB(fd, res->fbs[i]); + + if (!fb) + printf("Could not get fb %i\n", res->fbs[i]); + else { + printFrameBuffer(fd, res, fb); + drmModeFreeFB(fb); + } + } + + return 0; +} + +static struct drm_mode_modeinfo mode = { + .name = "Test mode", + .clock = 25200, + .hdisplay = 640, + .hsync_start = 656, + .hsync_end = 752, + .htotal = 800, + .hskew = 0, + .vdisplay = 480, + .vsync_start = 490, + .vsync_end = 492, + .vtotal = 525, + .vscan = 0, + .vrefresh = 60000, /* vertical refresh * 1000 */ + .flags = 10, +}; + +int testMode(int fd, drmModeResPtr res) +{ + uint32_t output = res->outputs[0]; + uint32_t newMode = 0; + int ret = 0; + int error = 0; + + printf("Test: adding mode to output %i\n", output); + + /* printMode(&mode); */ + + printf("\tAdding mode\n"); + newMode = drmModeAddMode(fd, &mode); + if (!newMode) + goto err; + + printf("\tAttaching mode %i to output %i\n", newMode, output); + + ret = drmModeAttachMode(fd, output, newMode); + + if (ret) + goto err_mode; + + printf("\tDetaching mode %i from output %i\n", newMode, output); + ret = drmModeDetachMode(fd, output, newMode); + + if (ret) + goto err_mode; + + printf("\tRemoveing new mode %i\n", newMode); + ret = drmModeRmMode(fd, newMode); + if (ret) + goto err; + + return 0; + +err_mode: + error = drmModeRmMode(fd, newMode); + +err: + printf("\tFailed\n"); + + if (error) + printf("\tFailed to delete mode %i\n", newMode); + + return 1; +} + +/* +int testFrameBufferGet(int fd, uint32_t fb) +{ + drmModeFBPtr frame; + + printf("Test: get framebuffer %i\n", fb); + + frame = drmModeGetFB(fd, fb); + + if (!frame) { + printf("\tFailed\n"); + } else { + printFrameBuffer(fd, frame); + drmModeFreeFB(frame); + } + + return 0; +} +*/ + +int testFrameBufferAdd(int fd, drmModeResPtr res) +{ + uint32_t fb = 0; + int ret = 0; + drmModeFBPtr frame = 0; + drmBO bo; + + printf("Test: adding framebuffer\n"); + + printf("\tCreating BO\n"); + + /* TODO */ + ret = 1; + if (ret) + goto err; + + printf("\tAdding FB\n"); + ret = drmModeAddFB(fd, 640, 480, 32, 8, 0, &bo, &fb); + if (ret) + goto err_bo; + + frame = drmModeGetFB(fd, fb); + + if (!frame) { + printf("Couldn't retrive created framebuffer\n"); + } else { + printFrameBuffer(fd, res, frame); + drmModeFreeFB(frame); + } + + printf("\tRemoveing FB\n"); + + ret = drmModeRmFB(fd, fb); + + if (ret) { + printf("\tFailed this shouldn't happen!\n"); + goto err_bo; + } + + printf("\tRemoveing BO\n"); + + ret = drmBODestroy(fb, &bo); + + return 0; + +err_bo: + drmBODestroy(fd, &bo); + +err: + printf("\tFailed\n"); + + return 1; +} + + +int main(int argc, char **argv) +{ + int fd; + const char *driver = "i915"; /* hardcoded for now */ + drmModeResPtr res; + + printf("Starting test\n"); + + fd = drmOpen(driver, NULL); + + if (fd < 0) { + printf("Failed to open the card fb\n"); + return 1; + } + + res = drmModeGetResources(fd); + if (res == 0) { + printf("Failed to get resources from card\n"); + drmClose(fd); + return 1; + } + + printRes(fd, res); + + testMode(fd, res); + + testFrameBufferAdd(fd, res); + + drmModeFreeResources(res); + printf("Ok\n"); + + return 0; +} diff --git a/tests/mode/test b/tests/mode/test new file mode 100755 index 00000000..fa155f4e --- /dev/null +++ b/tests/mode/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./modetest -- cgit v1.2.3 From 0be6e919aa3e7af884980e2004755848a2aa7519 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 24 Sep 2007 15:40:55 -0700 Subject: Add 965GM macro bits Update IS_MOBILE macro to include new IS_I965GM test. --- shared-core/i915_drv.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index d6b64b61..2d2d3a20 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -1160,6 +1160,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); (dev)->pci_device == 0x2A02 || \ (dev)->pci_device == 0x2A12) +#define IS_I965GM(dev) (((dev)->pci_device == 0x2A02)) #define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \ IS_I945GM(dev) || IS_I965G(dev)) @@ -1169,7 +1170,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); (dev)->pci_device == 0x29D2) #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ - IS_I945GM(dev)) + IS_I945GM(dev) || IS_I965GM(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) -- cgit v1.2.3 From cbcbe80c09bd95485ce8a9b0d86242fedcd7c182 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 24 Sep 2007 15:43:00 -0700 Subject: Cleanup SDVO debug output SDVO debug messages were incorrectly including severity prefixes in each print rather than each unique line. Fix it up. --- linux-core/intel_sdvo.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 11f3a0a6..19df1d4d 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -215,18 +215,18 @@ static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd, if (1) { DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); for (i = 0; i < args_len; i++) - DRM_DEBUG("%02X ", ((u8 *)args)[i]); + printk("%02X ", ((u8 *)args)[i]); for (; i < 8; i++) - DRM_DEBUG(" "); + printk(" "); for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - DRM_DEBUG("(%s)", sdvo_cmd_names[i].name); + printk("(%s)", sdvo_cmd_names[i].name); break; } } if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) - DRM_DEBUG("(%02X)",cmd); - DRM_DEBUG("\n"); + printk("(%02X)",cmd); + printk("\n"); } for (i = 0; i < args_len; i++) { @@ -268,14 +268,14 @@ static u8 intel_sdvo_read_response(struct drm_output *output, void *response, if (1) { DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv)); for (i = 0; i < response_len; i++) - DRM_DEBUG("%02X ", ((u8 *)response)[i]); + printk("%02X ", ((u8 *)response)[i]); for (; i < 8; i++) - DRM_DEBUG(" "); + printk(" "); if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - DRM_DEBUG("(%s)", cmd_status_names[status]); + printk("(%s)", cmd_status_names[status]); else - DRM_DEBUG("(??? %d)", status); - DRM_DEBUG("\n"); + printk("(??? %d)", status); + printk("\n"); } if (status != SDVO_CMD_STATUS_PENDING) -- cgit v1.2.3 From 5433bbbfde10bed7fbafcd90c64c364546ca724f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 25 Sep 2007 16:15:48 -0700 Subject: Remove buffer object user list check in drm_bo_destroy_unlocked In the case of driver allocated buffers, there won't necessarily be a user list associated with the buffer, so don't bug out on an empty list. --- linux-core/drm_bo.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 89062f11..ea93ed16 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -417,7 +417,6 @@ static void drm_bo_destroy_locked(struct drm_buffer_object * bo) atomic_dec(&bm->count); - BUG_ON(!list_empty(&bo->base.list)); drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); return; -- cgit v1.2.3 From 053ff86566bcf050c7fd5b5dc7158bb35d39c38b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 25 Sep 2007 16:16:33 -0700 Subject: Move map hash destruction to after driver unload hook is called The driver unload routine will want to remove register and SAREA maps, so don't destroy the map hash before we get there. --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 9004d535..5d2745e2 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -391,7 +391,6 @@ static void drm_cleanup(struct drm_device * dev) drm_lastclose(dev); drm_fence_manager_takedown(dev); - drm_ht_remove(&dev->map_hash); drm_mm_takedown(&dev->offset_manager); drm_ht_remove(&dev->object_hash); @@ -412,6 +411,7 @@ static void drm_cleanup(struct drm_device * dev) if (dev->driver->unload) dev->driver->unload(dev); + drm_ht_remove(&dev->map_hash); if (drm_core_has_AGP(dev) && dev->agp) { drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); dev->agp = NULL; -- cgit v1.2.3 From 972ec4fa25059c84ed103c28efcb17f9f97a6d74 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 25 Sep 2007 16:18:01 -0700 Subject: Hack out i915_mem_takedown We may want to make the old i915 memory manager obsolete eventually, and in the meantime the takedown causes problems on unload so remove it for now. --- shared-core/i915_init.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 065afcdf..918bbcb8 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -291,12 +291,12 @@ int i915_driver_unload(struct drm_device *dev) DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage)); mutex_lock(&dev->struct_mutex); drm_bo_usage_deref_locked(&dev_priv->ring_buffer); - mutex_unlock(&dev->struct_mutex); if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { DRM_ERROR("Memory manager type 3 not clean. " "Delaying takedown\n"); } + mutex_unlock(&dev->struct_mutex); drm_bo_driver_finish(dev); @@ -315,15 +315,14 @@ void i915_driver_lastclose(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; i915_do_cleanup_pageflip(dev); - - i915_mem_takedown(&(dev_priv->agp_heap)); - + //i915_mem_takedown(&(dev_priv->agp_heap)); i915_dma_cleanup(dev); } void i915_driver_preclose(struct drm_device *dev, struct drm_file *filp) { struct drm_i915_private *dev_priv = dev->dev_private; - i915_mem_release(dev, filp, dev_priv->agp_heap); + + //i915_mem_release(dev, filp, dev_priv->agp_heap); } -- cgit v1.2.3 From b2c4c7ae5e14598dbb8c1de32918ec9cc8dde7c9 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 26 Sep 2007 15:38:54 +0100 Subject: don't copy back if an error was returned. --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5d2745e2..e991f117 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -660,7 +660,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retcode = func(dev, kdata, file_priv); } - if (cmd & IOC_OUT) { + if ((retcode == 0) && cmd & IOC_OUT) { if (copy_to_user((void __user *)arg, kdata, _IOC_SIZE(cmd)) != 0) retcode = -EACCES; -- cgit v1.2.3 From dfcf9272ce4427d959098b0f9e1748832a47a786 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 26 Sep 2007 15:40:40 +0100 Subject: no need to copy to/from user as the unlocked ioctl does that for us. other small cleanups. --- linux-core/drm_crtc.c | 365 +++++++++++++++++++++++--------------------------- 1 file changed, 164 insertions(+), 201 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ed5f1dfa..fcddc7d9 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -433,24 +433,31 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, * on the DPLL. */ crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); + list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == crtc) { - dev_warn(&output->dev->pdev->dev, "%s: set mode %s\n", - output->name, mode->name); - output->funcs->mode_set(output, mode, adjusted_mode); - } + + if (output->crtc != crtc) + continue; + + DRM_INFO("%s: set mode %s\n", output->name, mode->name); + + output->funcs->mode_set(output, mode, adjusted_mode); } /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ crtc->funcs->commit(crtc); + list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == crtc) { - output->funcs->commit(output); + + if (output->crtc != crtc) + continue; + + output->funcs->commit(output); + #if 0 // TODO def RANDR_12_INTERFACE - if (output->randr_output) - RRPostPendingProperties (output->randr_output); + if (output->randr_output) + RRPostPendingProperties (output->randr_output); #endif - } } /* XXX free adjustedmode */ @@ -762,7 +769,7 @@ out_err: */ static void drm_pick_crtcs (struct drm_device *dev) { - int c, o; + int c, o, assigned; struct drm_output *output, *output_equal; struct drm_crtc *crtc; struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; @@ -802,11 +809,26 @@ static void drm_pick_crtcs (struct drm_device *dev) c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + assigned = 0; + c++; if ((output->possible_crtcs & (1 << c)) == 0) continue; -#if 0 /* should we try and clone ?? - code not tested - FIXME */ + list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { + if (output->id == output_equal->id) + continue; + + /* Find out if crtc has been assigned before */ + if (output_equal->crtc == crtc) + assigned = 1; + } + +#if 1 /* continue for now */ + if (assigned) + continue; +#endif + o = -1; list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { o++; @@ -816,7 +838,9 @@ static void drm_pick_crtcs (struct drm_device *dev) list_for_each_entry(modes, &output->modes, head) { list_for_each_entry(modes_equal, &output_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { - if ((output->possible_clones & (1 << o))) { + if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) { + printk("Cloning %s (0x%lx) to %s (0x%lx)\n",output->name,output->possible_clones,output_equal->name,output_equal->possible_clones); + assigned = 0; goto clone; } } @@ -825,7 +849,10 @@ static void drm_pick_crtcs (struct drm_device *dev) } clone: -#endif + /* crtc has been assigned skip it */ + if (assigned) + continue; + /* Found a CRTC to attach to, do it ! */ output->crtc = crtc; output->crtc->desired_mode = des_mode; @@ -856,6 +883,7 @@ clone: bool drm_initial_config(struct drm_device *dev, bool can_grow) { struct drm_output *output; + struct drm_crtc *crtc; int ret = false; mutex_lock(&dev->mode_config.mutex); @@ -864,14 +892,31 @@ bool drm_initial_config(struct drm_device *dev, bool can_grow) drm_pick_crtcs(dev); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + + /* can't setup the crtc if there's no assigned mode */ + if (!crtc->desired_mode) + continue; + + /* Now setup the fbdev for attached crtcs */ + dev->driver->fb_probe(dev, crtc); + } + + /* This is a little screwy, as we've already walked the outputs + * above, but it's a little bit of magic too. There's the potential + * for things not to get setup above if an existing device gets + * re-assigned thus confusing the hardware. By walking the outputs + * this fixes up their crtc's. + */ list_for_each_entry(output, &dev->mode_config.output_list, head) { - /* can't setup the output if there's no assigned crtc or mode */ + /* can't setup the output if there's no assigned mode */ if (!output->crtc || !output->crtc->desired_mode) continue; - dev->driver->fb_probe(dev, output->crtc); + drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); } + drm_disable_unused_functions(dev); mutex_unlock(&dev->mode_config.mutex); @@ -1088,8 +1133,7 @@ void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modein int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_card_res __user *argp = (void __user *)data; - struct drm_mode_card_res card_res; + struct drm_mode_card_res *card_res = data; struct list_head *lh; struct drm_framebuffer *fb; struct drm_output *output; @@ -1122,12 +1166,7 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each(lh, &dev->mode_config.usermode_list) mode_count++; - if (copy_from_user(&card_res, argp, sizeof(card_res))) { - ret = -EFAULT; - goto out_unlock; - } - - if (card_res.count_modes == 0) { + if (card_res->count_modes == 0) { DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width, dev->mode_config.max_height); drm_crtc_probe_output_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); mode_count = 0; @@ -1141,78 +1180,58 @@ int drm_mode_getresources(struct drm_device *dev, /* handle this in 4 parts */ /* FBs */ - if (card_res.count_fbs >= fb_count) { + if (card_res->count_fbs >= fb_count) { copied = 0; list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - if (put_user(fb->id, &card_res.fb_id[copied++])) { - ret = -EFAULT; - goto done; - } + card_res->fb_id[copied++] = fb->id; } } - card_res.count_fbs = fb_count; + card_res->count_fbs = fb_count; /* CRTCs */ - if (card_res.count_crtcs >= crtc_count) { + if (card_res->count_crtcs >= crtc_count) { copied = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ DRM_DEBUG("CRTC ID is %d\n", crtc->id); - if (put_user(crtc->id, &card_res.crtc_id[copied++])) { - ret = -EFAULT; - goto done; - } + card_res->crtc_id[copied++] = crtc->id; } } - card_res.count_crtcs = crtc_count; + card_res->count_crtcs = crtc_count; /* Outputs */ - if (card_res.count_outputs >= output_count) { + if (card_res->count_outputs >= output_count) { copied = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { DRM_DEBUG("OUTPUT ID is %d\n", output->id); - if (put_user(output->id, &card_res.output_id[copied++])) { - ret = -EFAULT; - goto done; - } + card_res->output_id[copied++] = output->id; } } - card_res.count_outputs = output_count; + card_res->count_outputs = output_count; /* Modes */ - if (card_res.count_modes >= mode_count) { + if (card_res->count_modes >= mode_count) { copied = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { list_for_each_entry(mode, &output->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { - ret = -EFAULT; - goto done; - } + card_res->modes[copied++] = u_mode; } } /* add in user modes */ list_for_each_entry(mode, &dev->mode_config.usermode_list, head) { drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { - ret = -EFAULT; - goto done; - } + card_res->modes[copied++] = u_mode; } } - card_res.count_modes = mode_count; + card_res->count_modes = mode_count; -done: - DRM_DEBUG("Counted %d %d %d\n", card_res.count_crtcs, - card_res.count_outputs, - card_res.count_modes); + DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs, + card_res->count_outputs, + card_res->count_modes); - if (copy_to_user(argp, &card_res, sizeof(card_res))) - ret = -EFAULT; - -out_unlock: mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1237,43 +1256,36 @@ out_unlock: int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_crtc __user *argp = (void __user *)data; - struct drm_mode_crtc crtc_resp; + struct drm_mode_crtc *crtc_resp = data; struct drm_crtc *crtc; struct drm_output *output; int ocount; int ret = 0; - if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp))) - return -EFAULT; - mutex_lock(&dev->mode_config.mutex); - crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp.crtc_id); - if (!crtc || (crtc->id != crtc_resp.crtc_id)) { + crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp->crtc_id); + if (!crtc || (crtc->id != crtc_resp->crtc_id)) { ret = -EINVAL; goto out; } - crtc_resp.x = crtc->x; - crtc_resp.y = crtc->y; - crtc_resp.fb_id = 1; + crtc_resp->x = crtc->x; + crtc_resp->y = crtc->y; + crtc_resp->fb_id = 1; - crtc_resp.outputs = 0; + crtc_resp->outputs = 0; if (crtc->enabled) { - crtc_resp.mode = crtc->mode.mode_id; + crtc_resp->mode = crtc->mode.mode_id; ocount = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { if (output->crtc == crtc) - crtc_resp.outputs |= 1 << (ocount++); + crtc_resp->outputs |= 1 << (ocount++); } } else { - crtc_resp.mode = 0; + crtc_resp->mode = 0; } - if (copy_to_user(argp, &crtc_resp, sizeof(crtc_resp))) - ret = -EFAULT; - out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1299,8 +1311,7 @@ out: int drm_mode_getoutput(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_get_output __user *argp = (void __user *)data; - struct drm_mode_get_output out_resp; + struct drm_mode_get_output *out_resp = data; struct drm_output *output; struct drm_display_mode *mode; int mode_count = 0; @@ -1308,16 +1319,13 @@ int drm_mode_getoutput(struct drm_device *dev, int copied = 0; int i; - if (copy_from_user(&out_resp, argp, sizeof(out_resp))) - return -EFAULT; - - DRM_DEBUG("output id %d:\n", out_resp.output); + DRM_DEBUG("output id %d:\n", out_resp->output); mutex_lock(&dev->mode_config.mutex); - output= idr_find(&dev->mode_config.crtc_idr, out_resp.output); - if (!output || (output->id != out_resp.output)) { + output= idr_find(&dev->mode_config.crtc_idr, out_resp->output); + if (!output || (output->id != out_resp->output)) { ret = -EINVAL; - goto out_unlock; + goto done; } list_for_each_entry(mode, &output->modes, head) @@ -1327,42 +1335,32 @@ int drm_mode_getoutput(struct drm_device *dev, if (output->user_mode_ids[i] != 0) mode_count++; - strncpy(out_resp.name, output->name, DRM_OUTPUT_NAME_LEN); - out_resp.name[DRM_OUTPUT_NAME_LEN-1] = 0; + strncpy(out_resp->name, output->name, DRM_OUTPUT_NAME_LEN); + out_resp->name[DRM_OUTPUT_NAME_LEN-1] = 0; - out_resp.mm_width = output->mm_width; - out_resp.mm_height = output->mm_height; - out_resp.subpixel = output->subpixel_order; - out_resp.connection = output->status; + out_resp->mm_width = output->mm_width; + out_resp->mm_height = output->mm_height; + out_resp->subpixel = output->subpixel_order; + out_resp->connection = output->status; if (output->crtc) - out_resp.crtc = output->crtc->id; + out_resp->crtc = output->crtc->id; else - out_resp.crtc = 0; + out_resp->crtc = 0; - if ((out_resp.count_modes >= mode_count) && mode_count) { + if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; list_for_each_entry(mode, &output->modes, head) { - if (put_user(mode->mode_id, &out_resp.modes[copied++])) { - ret = -EFAULT; - goto done; - } + out_resp->modes[copied++] = mode->mode_id; } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { if (output->user_mode_ids[i] != 0) - if (put_user(output->user_mode_ids[i], &out_resp.modes[copied++])) { - ret = -EFAULT; - goto done; - } + out_resp->modes[copied++] = output->user_mode_ids[i]; } } - out_resp.count_modes = mode_count; + out_resp->count_modes = mode_count; done: - if (copy_to_user(argp, &out_resp, sizeof(out_resp))) - ret = -EFAULT; - -out_unlock: mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1387,8 +1385,7 @@ out_unlock: int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_crtc __user *argp = (void __user *)data; - struct drm_mode_crtc crtc_req; + struct drm_mode_crtc *crtc_req = data; struct drm_crtc *crtc; struct drm_output **output_set = NULL, *output; struct drm_display_mode *mode; @@ -1396,29 +1393,26 @@ int drm_mode_setcrtc(struct drm_device *dev, int ret = 0; int i; - if (copy_from_user(&crtc_req, argp, sizeof(crtc_req))) - return -EFAULT; - mutex_lock(&dev->mode_config.mutex); - crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id); - if (!crtc || (crtc->id != crtc_req.crtc_id)) { - DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req.crtc_id); + crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req->crtc_id); + if (!crtc || (crtc->id != crtc_req->crtc_id)) { + DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req->crtc_id); ret = -EINVAL; goto out; } - if (crtc_req.mode) { + if (crtc_req->mode) { /* if we have a mode we need a framebuffer */ - if (crtc_req.fb_id) { - fb = idr_find(&dev->mode_config.crtc_idr, crtc_req.fb_id); - if (!fb || (fb->id != crtc_req.fb_id)) { - DRM_DEBUG("Unknown FB ID%d\n", crtc_req.fb_id); + if (crtc_req->fb_id) { + fb = idr_find(&dev->mode_config.crtc_idr, crtc_req->fb_id); + if (!fb || (fb->id != crtc_req->fb_id)) { + DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id); ret = -EINVAL; goto out; } } - mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode); - if (!mode || (mode->mode_id != crtc_req.mode)) { + mode = idr_find(&dev->mode_config.crtc_idr, crtc_req->mode); + if (!mode || (mode->mode_id != crtc_req->mode)) { struct drm_output *output; list_for_each_entry(output, @@ -1431,36 +1425,36 @@ int drm_mode_setcrtc(struct drm_device *dev, } } - DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req.mode, mode); + DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req->mode, mode); ret = -EINVAL; goto out; } } else mode = NULL; - if (crtc_req.count_outputs == 0 && mode) { + if (crtc_req->count_outputs == 0 && mode) { DRM_DEBUG("Count outputs is 0 but mode set\n"); ret = -EINVAL; goto out; } - if (crtc_req.count_outputs > 0 && !mode && !fb) { - DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req.count_outputs); + if (crtc_req->count_outputs > 0 && !mode && !fb) { + DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req->count_outputs); ret = -EINVAL; goto out; } - if (crtc_req.count_outputs > 0) { + if (crtc_req->count_outputs > 0) { u32 out_id; - output_set = kmalloc(crtc_req.count_outputs * + output_set = kmalloc(crtc_req->count_outputs * sizeof(struct drm_output *), GFP_KERNEL); if (!output_set) { ret = -ENOMEM; goto out; } - for (i = 0; i < crtc_req.count_outputs; i++) { - if (get_user(out_id, &crtc_req.set_outputs[i])) { + for (i = 0; i < crtc_req->count_outputs; i++) { + if (get_user(out_id, &crtc_req->set_outputs[i])) { ret = -EFAULT; goto out; } @@ -1476,7 +1470,7 @@ int drm_mode_setcrtc(struct drm_device *dev, } } - ret = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb); + ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb); out: mutex_unlock(&dev->mode_config.mutex); @@ -1503,29 +1497,25 @@ out: int drm_mode_addfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_fb_cmd __user *argp = (void __user *)data; - struct drm_mode_fb_cmd r; + struct drm_mode_fb_cmd *r = data; struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; struct drm_buffer_object *bo; struct drm_crtc *crtc; int ret = 0; - if (copy_from_user(&r, argp, sizeof(r))) - return -EFAULT; - - if ((config->min_width > r.width) || (r.width > config->max_width)) { + if ((config->min_width > r->width) || (r->width > config->max_width)) { DRM_ERROR("mode new framebuffer width not within limits\n"); return -EINVAL; } - if ((config->min_height > r.height) || (r.height > config->max_height)) { + if ((config->min_height > r->height) || (r->height > config->max_height)) { DRM_ERROR("mode new framebuffer height not within limits\n"); return -EINVAL; } mutex_lock(&dev->mode_config.mutex); /* TODO check limits are okay */ - ret = drm_get_buffer_object(dev, &bo, r.handle); + ret = drm_get_buffer_object(dev, &bo, r->handle); if (ret || !bo) { ret = -EINVAL; goto out; @@ -1540,23 +1530,18 @@ int drm_mode_addfb(struct drm_device *dev, goto out; } - fb->width = r.width; - fb->height = r.height; - fb->pitch = r.pitch; - fb->bits_per_pixel = r.bpp; - fb->depth = r.depth; + fb->width = r->width; + fb->height = r->height; + fb->pitch = r->pitch; + fb->bits_per_pixel = r->bpp; + fb->depth = r->depth; fb->offset = bo->offset; fb->bo = bo; - r.buffer_id = fb->id; + r->buffer_id = fb->id; list_add(&fb->filp_head, &file_priv->fbs); - if (copy_to_user(argp, &r, sizeof(r))) { - ret = -EFAULT; - goto out; - } - /* FIXME: bind the fb to the right crtc */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { crtc->fb = fb; @@ -1589,13 +1574,12 @@ int drm_mode_rmfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_framebuffer *fb = 0; - uint32_t id = data; + uint32_t *id = data; int ret = 0; - mutex_lock(&dev->mode_config.mutex); - fb = idr_find(&dev->mode_config.crtc_idr, id); + fb = idr_find(&dev->mode_config.crtc_idr, *id); /* TODO check that we realy get a framebuffer back. */ - if (!fb || (id != fb->id)) { + if (!fb || (*id != fb->id)) { DRM_ERROR("mode invalid framebuffer id\n"); ret = -EINVAL; goto out; @@ -1635,31 +1619,24 @@ out: int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_fb_cmd __user *argp = (void __user *)data; - struct drm_mode_fb_cmd r; + struct drm_mode_fb_cmd *r = data; struct drm_framebuffer *fb; int ret = 0; - if (copy_from_user(&r, argp, sizeof(r))) - return -EFAULT; - mutex_lock(&dev->mode_config.mutex); - fb = idr_find(&dev->mode_config.crtc_idr, r.buffer_id); - if (!fb || (r.buffer_id != fb->id)) { + fb = idr_find(&dev->mode_config.crtc_idr, r->buffer_id); + if (!fb || (r->buffer_id != fb->id)) { DRM_ERROR("invalid framebuffer id\n"); ret = -EINVAL; goto out; } - r.height = fb->height; - r.width = fb->width; - r.depth = fb->depth; - r.bpp = fb->bits_per_pixel; - r.handle = fb->bo->base.hash.key; - r.pitch = fb->pitch; - - if (copy_to_user(argp, &r, sizeof(r))) - ret = -EFAULT; + r->height = fb->height; + r->width = fb->width; + r->depth = fb->depth; + r->bpp = fb->bits_per_pixel; + r->handle = fb->bo->base.hash.key; + r->pitch = fb->pitch; out: mutex_unlock(&dev->mode_config.mutex); @@ -1713,14 +1690,10 @@ void drm_fb_release(struct file *filp) int drm_mode_addmode(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_modeinfo __user *argp = (void __user *)data; - struct drm_mode_modeinfo new_mode; + struct drm_mode_modeinfo *new_mode = data; struct drm_display_mode *user_mode; int ret = 0; - if (copy_from_user(&new_mode, argp, sizeof(new_mode))) - return -EFAULT; - mutex_lock(&dev->mode_config.mutex); user_mode = drm_mode_create(dev); if (!user_mode) { @@ -1728,16 +1701,14 @@ int drm_mode_addmode(struct drm_device *dev, goto out; } - drm_crtc_convert_umode(user_mode, &new_mode); + drm_crtc_convert_umode(user_mode, new_mode); user_mode->type |= DRM_MODE_TYPE_USERDEF; user_mode->output_count = 0; list_add(&user_mode->head, &dev->mode_config.usermode_list); - new_mode.id = user_mode->mode_id; - if (copy_to_user(argp, &new_mode, sizeof(new_mode))) - ret = -EFAULT; + new_mode->id = user_mode->mode_id; out: mutex_unlock(&dev->mode_config.mutex); @@ -1761,13 +1732,13 @@ out: int drm_mode_rmmode(struct drm_device *dev, void *data, struct drm_file *file_priv) { - uint32_t id = (uint32_t)data; + uint32_t *id = data; struct drm_display_mode *mode, *t; int ret = -EINVAL; mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, id); - if (!mode || (id != mode->mode_id)) { + mode = idr_find(&dev->mode_config.crtc_idr, *id); + if (!mode || (*id != mode->mode_id)) { ret = -EINVAL; goto out; } @@ -1812,25 +1783,21 @@ out: int drm_mode_attachmode(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_mode_cmd __user *argp = (void __user *)data; - struct drm_mode_mode_cmd mode_cmd; + struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; struct drm_display_mode *mode; int i, ret = 0; - if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) - return -EFAULT; - mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); - if (!mode || (mode->mode_id != mode_cmd.mode_id)) { + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd->mode_id); + if (!mode || (mode->mode_id != mode_cmd->mode_id)) { ret = -EINVAL; goto out; } - output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); - if (!output || (output->id != mode_cmd.output_id)) { + output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); + if (!output || (output->id != mode_cmd->output_id)) { ret = -EINVAL; goto out; } @@ -1867,25 +1834,21 @@ out: int drm_mode_detachmode(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_mode_cmd __user *argp = (void __user *)data; - struct drm_mode_mode_cmd mode_cmd; + struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; struct drm_display_mode *mode; int i, found = 0, ret = 0; - if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) - return -EFAULT; - mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); - if (!mode || (mode->mode_id != mode_cmd.mode_id)) { + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd->mode_id); + if (!mode || (mode->mode_id != mode_cmd->mode_id)) { ret = -EINVAL; goto out; } - output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); - if (!output || (output->id != mode_cmd.output_id)) { + output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); + if (!output || (output->id != mode_cmd->output_id)) { ret = -EINVAL; goto out; } -- cgit v1.2.3 From 61dfd19de81716aea0eaba90518fcb110b46b8f0 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 26 Sep 2007 16:18:19 +0100 Subject: Add brackets --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index e991f117..a313c26c 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -660,7 +660,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retcode = func(dev, kdata, file_priv); } - if ((retcode == 0) && cmd & IOC_OUT) { + if ((retcode == 0) && (cmd & IOC_OUT)) { if (copy_to_user((void __user *)arg, kdata, _IOC_SIZE(cmd)) != 0) retcode = -EACCES; -- cgit v1.2.3 From 2ed12b6b7eee8a1b5b0adf0cd8f3cb8c1bc3ccaf Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 27 Sep 2007 14:21:03 +0100 Subject: Add some more checks to modelist walking for matching incoming modes to current modelist. --- linux-core/intel_fb.c | 39 ++++++++++++++++++++++++++++++++++----- linux-core/intel_i2c.c | 3 +++ linux-core/intel_sdvo.c | 11 +++++++---- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 048295ab..04fd0fdd 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -49,6 +49,17 @@ struct intelfb_par { struct drm_crtc *crtc; }; +static int +var_to_refresh(const struct fb_var_screeninfo *var) +{ + int xtot = var->xres + var->left_margin + var->right_margin + + var->hsync_len; + int ytot = var->yres + var->upper_margin + var->lower_margin + + var->vsync_len; + + return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; +} + static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) @@ -98,7 +109,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct drm_framebuffer *fb = par->crtc->fb; struct drm_display_mode *drm_mode; struct drm_output *output; - int depth; + int depth, found = 0; if (!var->pixclock) return -EINVAL; @@ -191,11 +202,14 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, list_for_each_entry(drm_mode, &output->modes, head) { if (drm_mode->hdisplay == var->xres && drm_mode->vdisplay == var->yres && - drm_mode->clock != 0) + (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && + (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { + found = 1; break; + } } - if (!drm_mode) + if (!found) return -EINVAL; #endif @@ -210,7 +224,9 @@ static int intelfb_set_par(struct fb_info *info) struct drm_framebuffer *fb = par->crtc->fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode; + struct drm_output *output; struct fb_var_screeninfo *var = &info->var; + int found = 0; switch (var->bits_per_pixel) { case 16: @@ -246,9 +262,18 @@ static int intelfb_set_par(struct fb_info *info) list_for_each_entry(drm_mode, &output->modes, head) { if (drm_mode->hdisplay == var->xres && drm_mode->vdisplay == var->yres && - drm_mode->clock != 0) + (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && + (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { + found = 1; break; + } } + + if (!found) { + DRM_ERROR("Couldn't find a mode for requested %dx%d-%d\n", + var->xres,var->yres,var_to_refresh(var)); + return -EINVAL; + } #else drm_mode = drm_mode_create(dev); drm_mode->hdisplay = var->xres; @@ -265,13 +290,15 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); #endif + drm_mode_debug_printmodeline(dev, drm_mode); + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; /* Have to destroy our created mode if we're not searching the mode * list for it. */ -#if 1 +#if 1 drm_mode_destroy(dev, drm_mode); #endif @@ -472,6 +499,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM, 0, 0, 0, &fbo); @@ -629,6 +657,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) unregister_framebuffer(info); framebuffer_release(info); drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + drm_framebuffer_destroy(fb); } return 0; } diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c index b512e592..efcbf656 100644 --- a/linux-core/intel_i2c.c +++ b/linux-core/intel_i2c.c @@ -140,6 +140,9 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, chan->reg = reg; snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); chan->adapter.owner = THIS_MODULE; +#ifndef I2C_HW_B_INTELFB +#define I2C_HW_B_INTELFB I2C_HW_B_I810 +#endif chan->adapter.id = I2C_HW_B_INTELFB; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &dev->pdev->dev; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 19df1d4d..51fe43cb 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -730,9 +730,12 @@ static void intel_sdvo_dpms(struct drm_output *output, int mode) &input2); - /* Warn if the device reported failure to sync. */ + /* Warn if the device reported failure to sync. + * A lot of SDVO devices fail to notify of sync, but it's + * a given it the status is a success, we succeeded. + */ if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { - DRM_ERROR("First %s output reported failure to sync\n", + DRM_DEBUG("First %s output reported failure to sync\n", SDVO_NAME(sdvo_priv)); } @@ -839,10 +842,10 @@ static int intel_sdvo_mode_valid(struct drm_output *output, return MODE_NO_DBLESCAN; if (sdvo_priv->pixel_clock_min > mode->clock) - return MODE_CLOCK_HIGH; + return MODE_CLOCK_LOW; if (sdvo_priv->pixel_clock_max < mode->clock) - return MODE_CLOCK_LOW; + return MODE_CLOCK_HIGH; return MODE_OK; } -- cgit v1.2.3 From bf9bd5671c184e1caeeb25ead588cbb2ab77c360 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 27 Sep 2007 14:21:29 +0100 Subject: Create memory pool for TT memory --- shared-core/i915_init.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 918bbcb8..8e419b8a 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -175,8 +175,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) drm_bo_driver_init(dev); i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); - DRM_DEBUG("setting up %ld bytes of VRAM space\n", prealloc_size); + printk("setting up %ld bytes of VRAM space\n", prealloc_size); + printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT); + drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT); I915_WRITE(LP_RING + RING_LEN, 0); I915_WRITE(LP_RING + RING_HEAD, 0); @@ -292,6 +294,10 @@ int i915_driver_unload(struct drm_device *dev) mutex_lock(&dev->struct_mutex); drm_bo_usage_deref_locked(&dev_priv->ring_buffer); + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) { + DRM_ERROR("Memory manager type 3 not clean. " + "Delaying takedown\n"); + } if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { DRM_ERROR("Memory manager type 3 not clean. " "Delaying takedown\n"); -- cgit v1.2.3 From d69721a14a8954420b4e0022ecf10bb040c6b807 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 28 Sep 2007 09:21:09 +0100 Subject: Set the fb_base, so userspace applications can actually work now instead of locking up. --- linux-core/intel_display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 3ff9f822..a81cfe69 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1207,6 +1207,12 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.max_width = 4096; dev->mode_config.max_height = 4096; + /* set memory base */ + if (IS_I9XX(dev)) + dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); + else + dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); + if (IS_MOBILE(dev) || IS_I9XX(dev)) num_pipe = 2; else -- cgit v1.2.3 From 89d44a1023543a95b429bf72662b5e2308b0a550 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 7 Oct 2007 08:16:38 +1000 Subject: radeon: make vram fixed type --- linux-core/radeon_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 5b10c24a..3afc17ee 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -93,7 +93,7 @@ int radeon_init_mem_type(drm_device_t * dev, uint32_t type, man->drm_bus_maptype = 0; break; case DRM_BO_MEM_VRAM: - man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_NEEDS_IOREMAP; + man->flags = _DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_NEEDS_IOREMAP; man->io_addr = NULL; man->drm_bus_maptype = _DRM_FRAME_BUFFER; man->io_offset = drm_get_resource_start(dev, 0); -- cgit v1.2.3 From cc9be8ac323e47616e48adebc5cc85c654524b45 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 15 Oct 2007 11:51:19 +0100 Subject: Fix some buffer teardown problems. --- linux-core/drm_crtc.c | 25 ++++++++++++------------- linux-core/intel_fb.c | 1 + 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fcddc7d9..bdea20c9 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -951,14 +951,10 @@ void drm_mode_config_cleanup(struct drm_device *dev) } list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { - dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); - /* If this FB was the kernel one, free it */ - if (fb->bo->type == drm_bo_type_kernel) { - mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(&fb->bo); - mutex_unlock(&dev->struct_mutex); - } - drm_framebuffer_destroy(fb); + if (fb->bo->type != drm_bo_type_kernel) + drm_framebuffer_destroy(fb); + else + dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); } list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { @@ -1585,14 +1581,15 @@ int drm_mode_rmfb(struct drm_device *dev, goto out; } - dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); - /* TODO check if we own the buffer */ /* TODO release all crtc connected to the framebuffer */ /* bind the fb to the crtc for now */ /* TODO unhock the destructor from the buffer object */ - drm_framebuffer_destroy(fb); + if (fb->bo->type != drm_bo_type_kernel) + drm_framebuffer_destroy(fb); + else + dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); out: mutex_unlock(&dev->mode_config.mutex); @@ -1666,8 +1663,10 @@ void drm_fb_release(struct file *filp) mutex_lock(&dev->mode_config.mutex); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { list_del(&fb->filp_head); - dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); - drm_framebuffer_destroy(fb); + if (fb->bo->type != drm_bo_type_kernel) + drm_framebuffer_destroy(fb); + else + dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); } mutex_unlock(&dev->mode_config.mutex); } diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 04fd0fdd..ecfab3ed 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -657,6 +657,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) unregister_framebuffer(info); framebuffer_release(info); drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + drm_bo_usage_deref_locked(&fb->bo); drm_framebuffer_destroy(fb); } return 0; -- cgit v1.2.3 From 2b07b0a45d32a9ffb7f6b9bb1b8f6f8e615524cb Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 15 Oct 2007 11:54:18 +0100 Subject: should be unlocked --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index ecfab3ed..c9cb293a 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -657,7 +657,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) unregister_framebuffer(info); framebuffer_release(info); drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); - drm_bo_usage_deref_locked(&fb->bo); + drm_bo_usage_deref_unlocked(&fb->bo); drm_framebuffer_destroy(fb); } return 0; -- cgit v1.2.3 From be2d68914d0992a37b9fb4d93338aeaf2240c4f5 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 17 Oct 2007 09:35:44 +0100 Subject: Fix a crash on X startup --- shared-core/i915_dma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 23994821..54621d9e 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -86,8 +86,6 @@ int i915_dma_cleanup(struct drm_device * dev) * may not have been called from userspace and after dev_private * is freed, it's too late. */ - I915_WRITE(LP_RING + RING_LEN, 0); - if (dev->irq) drm_irq_uninstall(dev); @@ -1042,7 +1040,7 @@ int i915_do_cleanup_pageflip(struct drm_device * dev) DRM_DEBUG("%s\n", __FUNCTION__); - for (i = 0, planes = 0; i < 2; i++) + for (i = 0, planes = 0; i < 2; i++) { if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { dev_priv->sarea_priv->pf_current_page = (dev_priv->sarea_priv->pf_current_page & @@ -1050,6 +1048,7 @@ int i915_do_cleanup_pageflip(struct drm_device * dev) planes |= 1 << i; } + } if (planes) i915_dispatch_flip(dev, planes, 0); -- cgit v1.2.3 From 198170ab97bbf2ca6362bb7100e9ed86d90aa51f Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 23 Oct 2007 15:33:20 +0100 Subject: Need fb attached --- linux-core/drm_crtc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bdea20c9..5bc02206 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -914,7 +914,9 @@ bool drm_initial_config(struct drm_device *dev, bool can_grow) if (!output->crtc || !output->crtc->desired_mode) continue; - drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); + /* and needs an attached fb */ + if (output->crtc->fb) + drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); } drm_disable_unused_functions(dev); -- cgit v1.2.3 From 26c32a3d797efb7474e5ae88c46afcb0e6015294 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 26 Oct 2007 10:25:57 +0200 Subject: Buffer flags and masks are 64-bit. don't mask off the high dword. --- linux-core/drm_bo.c | 12 ++++++------ linux-core/drm_bo_move.c | 12 ++++++------ linux-core/drm_objects.h | 3 ++- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index b6a972ed..04900fec 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -54,9 +54,9 @@ static int drm_bo_setup_vm_locked(struct drm_buffer_object * bo); static void drm_bo_takedown_vm_locked(struct drm_buffer_object * bo); static void drm_bo_unmap_virtual(struct drm_buffer_object * bo); -static inline uint32_t drm_bo_type_flags(unsigned type) +static inline uint64_t drm_bo_type_flags(unsigned type) { - return (1 << (24 + type)); + return (1ULL << (24 + type)); } /* @@ -784,10 +784,10 @@ static int drm_bo_mem_force_space(struct drm_device * dev, static int drm_bo_mt_compatible(struct drm_mem_type_manager * man, uint32_t mem_type, - uint32_t mask, uint32_t * res_mask) + uint64_t mask, uint32_t * res_mask) { - uint32_t cur_flags = drm_bo_type_flags(mem_type); - uint32_t flag_diff; + uint64_t cur_flags = drm_bo_type_flags(mem_type); + uint64_t flag_diff; if (man->flags & _DRM_FLAG_MEMTYPE_CACHED) cur_flags |= DRM_BO_FLAG_CACHED; @@ -1270,7 +1270,7 @@ static void drm_buffer_user_object_unmap(struct drm_file *file_priv, * Note that new_mem_flags are NOT transferred to the bo->mem.mask. */ -int drm_bo_move_buffer(struct drm_buffer_object * bo, uint32_t new_mem_flags, +int drm_bo_move_buffer(struct drm_buffer_object * bo, uint64_t new_mem_flags, int no_wait, int move_unfenced) { struct drm_device *dev = bo->dev; diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index d6c58970..06b2e5aa 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -53,8 +53,8 @@ int drm_bo_move_ttm(struct drm_buffer_object * bo, { struct drm_ttm *ttm = bo->ttm; struct drm_bo_mem_reg *old_mem = &bo->mem; - uint32_t save_flags = old_mem->flags; - uint32_t save_mask = old_mem->mask; + uint64_t save_flags = old_mem->flags; + uint64_t save_mask = old_mem->mask; int ret; if (old_mem->mem_type == DRM_BO_MEM_TT) { @@ -211,8 +211,8 @@ int drm_bo_move_memcpy(struct drm_buffer_object * bo, void *old_iomap; void *new_iomap; int ret; - uint32_t save_flags = old_mem->flags; - uint32_t save_mask = old_mem->mask; + uint64_t save_flags = old_mem->flags; + uint64_t save_mask = old_mem->mask; unsigned long i; unsigned long page; unsigned long add = 0; @@ -334,8 +334,8 @@ int drm_bo_move_accel_cleanup(struct drm_buffer_object * bo, struct drm_mem_type_manager *man = &dev->bm.man[new_mem->mem_type]; struct drm_bo_mem_reg *old_mem = &bo->mem; int ret; - uint32_t save_flags = old_mem->flags; - uint32_t save_mask = old_mem->mask; + uint64_t save_flags = old_mem->flags; + uint64_t save_mask = old_mem->mask; struct drm_buffer_object *old_obj; if (bo->fence) diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 8ae55bf0..ed9a87ae 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -511,7 +511,8 @@ extern int drm_bo_wait(struct drm_buffer_object * bo, int lazy, int ignore_signa int no_wait); extern int drm_bo_mem_space(struct drm_buffer_object * bo, struct drm_bo_mem_reg * mem, int no_wait); -extern int drm_bo_move_buffer(struct drm_buffer_object * bo, uint32_t new_mem_flags, +extern int drm_bo_move_buffer(struct drm_buffer_object * bo, + uint64_t new_mem_flags, int no_wait, int move_unfenced); extern int drm_bo_clean_mm(struct drm_device * dev, unsigned mem_type); extern int drm_bo_init_mm(struct drm_device * dev, unsigned type, -- cgit v1.2.3 From 5e86f67a34c50ec49e1d7b3b834d1695ebf5d4c8 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 5 Nov 2007 10:00:11 +0000 Subject: pass pointer for drmModeRmFB --- libdrm/xf86drmMode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index a7241ffd..cfe133fe 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -212,7 +212,7 @@ int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, int drmModeRmFB(int fd, uint32_t bufferId) { - return ioctl(fd, DRM_IOCTL_MODE_RMFB, bufferId); + return ioctl(fd, DRM_IOCTL_MODE_RMFB, &bufferId); } drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) -- cgit v1.2.3 From 0bee83a8c8bca817459a0ee9caa6e13f3f1aa281 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 5 Nov 2007 10:00:43 +0000 Subject: Pass pointer to drmModeRmMode. --- libdrm/xf86drmMode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index cfe133fe..e7ac58ba 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -368,7 +368,7 @@ uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *mode_info) int drmModeRmMode(int fd, uint32_t mode_id) { - return ioctl(fd, DRM_IOCTL_MODE_RMMODE, mode_id); + return ioctl(fd, DRM_IOCTL_MODE_RMMODE, &mode_id); } int drmModeAttachMode(int fd, uint32_t output_id, uint32_t mode_id) -- cgit v1.2.3 From d0956339e322238d2af5d63a2e65405ca3b8c4f8 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 5 Nov 2007 10:02:46 +0000 Subject: Use _size --- linux-core/drm_compat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 0895e5e5..f861abfd 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -159,7 +159,7 @@ static __inline__ void *kcalloc(size_t nmemb, size_t size, int flags) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) #define vmalloc_user(_size) ({void * tmp = vmalloc(_size); \ - if (tmp) memset(tmp, 0, size); \ + if (tmp) memset(tmp, 0, _size); \ (tmp);}) #endif -- cgit v1.2.3 From 71385d6f75bb3b551e2f8d9f74a4438f0f3da9df Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 5 Nov 2007 10:03:26 +0000 Subject: add missing lock --- linux-core/drm_crtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 5bc02206..cad7cd83 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1575,6 +1575,7 @@ int drm_mode_rmfb(struct drm_device *dev, uint32_t *id = data; int ret = 0; + mutex_lock(&dev->mode_config.mutex); fb = idr_find(&dev->mode_config.crtc_idr, *id); /* TODO check that we realy get a framebuffer back. */ if (!fb || (*id != fb->id)) { -- cgit v1.2.3 From 306bb12603ad724f50fb6ce212a090ea7ea78013 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 5 Nov 2007 10:05:01 +0000 Subject: remove duplicate and obsolete ioctl statements --- linux-core/drm_drv.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 1c9895eb..e46e8d95 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -116,9 +116,6 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), - // DRM_IOCTL_DEF(DRM_IOCTL_BUFOBJ, drm_bo_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, - DRM_AUTH ), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY), @@ -131,10 +128,6 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMMODE, drm_mode_rmmode, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode, DRM_MASTER|DRM_ROOT_ONLY), - // DRM_IOCTL_DEF(DRM_IOCTL_BUFOBJ, drm_bo_ioctl, DRM_AUTH), - - DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -- cgit v1.2.3 From 1b91113957e731d264d1e5d49326597f3b78e96f Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 5 Nov 2007 10:06:37 +0000 Subject: remove unused define --- linux-core/drm_objects.h | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 01876d93..bbce2ea5 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -157,7 +157,6 @@ struct drm_fence_object { }; #define _DRM_FENCE_CLASSES 8 -#define _DRM_FENCE_TYPE_EXE 0x00 struct drm_fence_class_manager { struct list_head ring; -- cgit v1.2.3 From d983ed90cb9de559271817e04bddc8b40fc16a0d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 9 Nov 2007 11:30:50 +1000 Subject: i915: cleanup pageflip derefs sarea even if no sarea exists --- shared-core/i915_dma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 47befeb5..117f1265 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1070,10 +1070,12 @@ out_free: int i915_do_cleanup_pageflip(struct drm_device * dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; + int i, planes, num_pages; DRM_DEBUG("%s\n", __FUNCTION__); - + if (!dev_priv->sarea_priv) + return 0; + num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; for (i = 0, planes = 0; i < 2; i++) { if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { dev_priv->sarea_priv->pf_current_page = -- cgit v1.2.3 From ffb89d4c3b6650551aaab06076896540a78faddf Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 9 Nov 2007 15:47:24 +0100 Subject: drm: split edid handling in get_edid & add_edid_mode This way driver can get_edid in output status detection (using all workaround which are in get_edid) and then provide this edid data in get_mode callback of output. --- linux-core/drm_crtc.h | 5 +++-- linux-core/drm_edid.c | 40 +++++++++++++++++++++++++--------------- linux-core/intel_modes.c | 9 ++++++++- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d97cd196..9dd00b3d 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -487,8 +487,9 @@ extern void drm_output_destroy(struct drm_output *output); extern bool drm_output_rename(struct drm_output *output, const char *name); extern void drm_fb_release(struct file *filp); -extern int drm_add_edid_modes(struct drm_output *output, - struct i2c_adapter *adapter); +extern struct edid *drm_get_edid(struct drm_output *output, + struct i2c_adapter *adapter); +extern int drm_add_edid_modes(struct drm_output *output, struct edid *edid); extern void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode); extern void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode); extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index d7d3939a..b8eee1a4 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -427,41 +427,51 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) } /** - * drm_add_edid_modes - add modes from EDID data, if available + * drm_get_edid - get EDID data, if available * @output: output we're probing * @adapter: i2c adapter to use for DDC * - * Poke the given output's i2c channel to grab EDID data if possible. If we - * get any, add the specified modes to the output's mode list. - * - * Return number of modes added or 0 if we couldn't find any. + * Poke the given output's i2c channel to grab EDID data if possible. + * + * Return edid data or NULL if we couldn't find any. */ -int drm_add_edid_modes(struct drm_output *output, struct i2c_adapter *adapter) +struct edid *drm_get_edid(struct drm_output *output, + struct i2c_adapter *adapter) { struct edid *edid; - int num_modes = 0; edid = (struct edid *)drm_ddc_read(adapter); if (!edid) { dev_warn(&output->dev->pdev->dev, "%s: no EDID data\n", output->name); - goto out_err; + return NULL; } - if (!edid_valid(edid)) { dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", output->name); - goto out_err; + kfree(edid); + return NULL; } + return edid; +} +EXPORT_SYMBOL(drm_get_edid); + +/** + * drm_add_edid_modes - add modes from EDID data, if available + * @output: output we're probing + * @edid: edid data + * + * Add the specified modes to the output's mode list. + * + * Return number of modes added or 0 if we couldn't find any. + */ +int drm_add_edid_modes(struct drm_output *output, struct edid *edid) +{ + int num_modes = 0; num_modes += add_established_modes(output, edid); num_modes += add_standard_modes(output, edid); num_modes += add_detailed_info(output, edid); - return num_modes; - -out_err: - kfree(edid); - return 0; } EXPORT_SYMBOL(drm_add_edid_modes); diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c index 601770e1..346cf1ac 100644 --- a/linux-core/intel_modes.c +++ b/linux-core/intel_modes.c @@ -50,6 +50,13 @@ bool intel_ddc_probe(struct drm_output *output) int intel_ddc_get_modes(struct drm_output *output) { struct intel_output *intel_output = output->driver_private; + struct edid *edid; + int ret = 0; - return drm_add_edid_modes(output, &intel_output->ddc_bus->adapter); + edid = drm_get_edid(output, &intel_output->ddc_bus->adapter); + if (edid) { + ret = drm_add_edid_modes(output, edid); + kfree(edid); + } + return ret; } -- cgit v1.2.3 From e1bc147ac9aa8ac2ac271b0a21f4138b17875ce5 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 9 Nov 2007 17:28:56 +0100 Subject: drm: check edid data, so we deal well with broken driver. --- linux-core/drm_edid.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index b8eee1a4..7068cef3 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -469,6 +469,14 @@ int drm_add_edid_modes(struct drm_output *output, struct edid *edid) { int num_modes = 0; + if (edid == NULL) { + return 0; + } + if (!edid_valid(edid)) { + dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", + output->name); + return 0; + } num_modes += add_established_modes(output, edid); num_modes += add_standard_modes(output, edid); num_modes += add_detailed_info(output, edid); -- cgit v1.2.3 From d275bb8fb87d8dc23e9a62c5f82627e36c8dc589 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 15 Nov 2007 16:51:15 +1100 Subject: tests: update for new drm interface --- tests/mode/modetest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index bf1a5169..8f151758 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -288,12 +288,12 @@ int testFrameBufferAdd(int fd, drmModeResPtr res) printf("\tRemoveing BO\n"); - ret = drmBODestroy(fb, &bo); + ret = drmBOUnreference(fb, &bo); return 0; err_bo: - drmBODestroy(fd, &bo); + drmBOUnreference(fd, &bo); err: printf("\tFailed\n"); -- cgit v1.2.3 From 12cbe1365b38ae04ad4979123eb5b4e9538ee533 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 15 Nov 2007 16:51:35 +1100 Subject: intel: fixup || vs | --- linux-core/intel_crt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index d2e1f95c..29c2e611 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -177,7 +177,7 @@ static enum drm_output_status intel_crt_detect(struct drm_output *output) { struct drm_device *dev = output->dev; - if (IS_I945G(dev)| IS_I945GM(dev) || IS_I965G(dev)) { + if (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) { if (intel_crt_detect_hotplug(output)) return output_status_connected; else -- cgit v1.2.3 From 7136f55faaf3afefe522ec978a4cbc906dace861 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 15 Nov 2007 16:51:48 +1100 Subject: drm: don't remove mappings added by the driver --- linux-core/drm_drv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 8313b3ea..99eba979 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -250,8 +250,10 @@ int drm_lastclose(struct drm_device * dev) } list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { - drm_rmmap_locked(dev, r_list->map); - r_list = NULL; + if (!(r_list->map->flags & _DRM_DRIVER)) { + drm_rmmap_locked(dev, r_list->map); + r_list = NULL; + } } if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) { -- cgit v1.2.3 From 2520d3fd99636e493060d51b1c3287a5faac22bf Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 15 Nov 2007 16:52:04 +1100 Subject: modes: pass type to userspace for preferred showing --- linux-core/drm_crtc.c | 4 ++++ linux-core/drm_crtc.h | 8 -------- shared-core/drm.h | 10 +++++++++- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index cad7cd83..5b00c115 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1076,6 +1076,7 @@ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display out->vscan = in->vscan; out->vrefresh = in->vrefresh; out->flags = in->flags; + out->type = in->type; strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } @@ -1106,6 +1107,7 @@ void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modein out->vscan = in->vscan; out->vrefresh = in->vrefresh; out->flags = in->flags; + out->type = in->type; strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } @@ -1345,6 +1347,8 @@ int drm_mode_getoutput(struct drm_device *dev, else out_resp->crtc = 0; + out_resp->crtcs = output->possible_crtcs; + out_resp->clones = output->possible_clones; if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; list_for_each_entry(mode, &output->modes, head) { diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 9dd00b3d..0ddefc86 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -64,14 +64,6 @@ enum drm_mode_status { MODE_ERROR = -1 /* error condition */ }; -#define DRM_MODE_TYPE_BUILTIN (1<<0) -#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) -#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) -#define DRM_MODE_TYPE_PREFERRED (1<<3) -#define DRM_MODE_TYPE_DEFAULT (1<<4) -#define DRM_MODE_TYPE_USERDEF (1<<5) -#define DRM_MODE_TYPE_DRIVER (1<<6) - #define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \ DRM_MODE_TYPE_CRTC_C) diff --git a/shared-core/drm.h b/shared-core/drm.h index e10ceb14..59cbfaf2 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -898,6 +898,14 @@ struct drm_mm_init_arg { #define DRM_OUTPUT_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 +#define DRM_MODE_TYPE_BUILTIN (1<<0) +#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED (1<<3) +#define DRM_MODE_TYPE_DEFAULT (1<<4) +#define DRM_MODE_TYPE_USERDEF (1<<5) +#define DRM_MODE_TYPE_DRIVER (1<<6) + struct drm_mode_modeinfo { unsigned int id; @@ -909,7 +917,7 @@ struct drm_mode_modeinfo { unsigned int vrefresh; /* vertical refresh * 1000 */ unsigned int flags; - + unsigned int type; char name[DRM_DISPLAY_MODE_LEN]; }; -- cgit v1.2.3 From 1e8984a3674c89c3b5ef9b6d3747fb75e10774b3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 15 Nov 2007 18:31:23 +1100 Subject: drm: send correct fb id to userspace --- linux-core/drm_crtc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 5b00c115..e40ab6da 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1271,7 +1271,11 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->x = crtc->x; crtc_resp->y = crtc->y; - crtc_resp->fb_id = 1; + + if (crtc->fb) + crtc_resp->fb_id = crtc->fb->id; + else + crtc_resp->fb_id = 0; crtc_resp->outputs = 0; if (crtc->enabled) { -- cgit v1.2.3 From f32688d3d011d631c18d584603d684edd9b9b512 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 15 Nov 2007 18:31:50 +1100 Subject: libdrm: add crtc/output ids to userspace interface --- libdrm/xf86drmMode.c | 4 +++- libdrm/xf86drmMode.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index e7ac58ba..c3abb2df 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -265,7 +265,8 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) if (!(r = drmMalloc(sizeof(*r)))) return 0; - + + r->crtc_id = crtc.crtc_id; r->x = crtc.x; r->y = crtc.y; r->mode = crtc.mode; @@ -337,6 +338,7 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) if(!(r = drmMalloc(sizeof(*r)))) return 0; + r->output_id = out.output; r->connection = out.connection; r->mmWidth = out.mm_width; r->mmHeight = out.mm_height; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index b25a6610..be9d84af 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -71,7 +71,7 @@ typedef struct _drmModeRes { typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr; typedef struct _drmModeCrtc { - + unsigned int crtc_id; unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/ uint32_t x, y; /**< Position on the frameuffer */ @@ -104,6 +104,7 @@ typedef enum { } drmModeSubPixel; typedef struct _drmModeOutput { + unsigned int output_id; unsigned int crtc; /**< Crtc currently connected to */ unsigned char name[DRM_OUTPUT_NAME_LEN]; -- cgit v1.2.3 From ca499f4d14ae29159f13957f2adc0536c71bf6d4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 15 Nov 2007 19:22:01 +1100 Subject: libdrm: return crtc id to userspace --- libdrm/xf86drmMode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index c3abb2df..e400f219 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -339,6 +339,7 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) return 0; r->output_id = out.output; + r->crtc = out.crtc; r->connection = out.connection; r->mmWidth = out.mm_width; r->mmHeight = out.mm_height; -- cgit v1.2.3 From 7ec4ebe95e7eec6625d68ae6300255901b69d5c7 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 15 Nov 2007 17:14:03 -0800 Subject: Use user copy routines for writing modes & ids back to userspace Since the drm_mode_card_res structure contains user pointers, we have to use put_user and copy_to_user to write stuff out. The DRM ioctl wrapper will only take care of copying the base drm_mode_card_res struct, not the included arrays. --- linux-core/drm_crtc.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e40ab6da..db062c1d 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1146,7 +1146,7 @@ int drm_mode_getresources(struct drm_device *dev, int crtc_count = 0; int fb_count = 0; int copied = 0; - + memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); mutex_lock(&dev->mode_config.mutex); @@ -1183,7 +1183,9 @@ int drm_mode_getresources(struct drm_device *dev, if (card_res->count_fbs >= fb_count) { copied = 0; list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - card_res->fb_id[copied++] = fb->id; + if (put_user(fb->id, card_res->fb_id + copied)) + return -EFAULT; + copied++; } } card_res->count_fbs = fb_count; @@ -1193,7 +1195,9 @@ int drm_mode_getresources(struct drm_device *dev, copied = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ DRM_DEBUG("CRTC ID is %d\n", crtc->id); - card_res->crtc_id[copied++] = crtc->id; + if (put_user(crtc->id, card_res->crtc_id + copied)) + return -EFAULT; + copied++; } } card_res->count_crtcs = crtc_count; @@ -1205,7 +1209,10 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each_entry(output, &dev->mode_config.output_list, head) { DRM_DEBUG("OUTPUT ID is %d\n", output->id); - card_res->output_id[copied++] = output->id; + if (put_user(output->id, + card_res->output_id + copied)) + return -EFAULT; + copied++; } } card_res->count_outputs = output_count; @@ -1217,13 +1224,19 @@ int drm_mode_getresources(struct drm_device *dev, head) { list_for_each_entry(mode, &output->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); - card_res->modes[copied++] = u_mode; + if (copy_to_user(&card_res->modes + copied, + &u_mode, sizeof(u_mode))) + return -EFAULT; + copied++; } } /* add in user modes */ list_for_each_entry(mode, &dev->mode_config.usermode_list, head) { drm_crtc_convert_to_umode(&u_mode, mode); - card_res->modes[copied++] = u_mode; + if (copy_to_user(&card_res->modes + copied, &u_mode, + sizeof(u_mode))) + return -EFAULT; + copied++; } } card_res->count_modes = mode_count; -- cgit v1.2.3 From 96e136c4794f9f57e18c1f984a27bbad4b5e1500 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 16 Nov 2007 13:57:42 -0800 Subject: Fix typo in copy_to_user calls We want to copy to card_res->modes + copied, not &card_res->modes + copied. --- linux-core/drm_crtc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index db062c1d..df934841 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1209,8 +1209,7 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each_entry(output, &dev->mode_config.output_list, head) { DRM_DEBUG("OUTPUT ID is %d\n", output->id); - if (put_user(output->id, - card_res->output_id + copied)) + if (put_user(output->id, card_res->output_id + copied)) return -EFAULT; copied++; } @@ -1224,7 +1223,7 @@ int drm_mode_getresources(struct drm_device *dev, head) { list_for_each_entry(mode, &output->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(&card_res->modes + copied, + if (copy_to_user(card_res->modes + copied, &u_mode, sizeof(u_mode))) return -EFAULT; copied++; @@ -1233,9 +1232,9 @@ int drm_mode_getresources(struct drm_device *dev, /* add in user modes */ list_for_each_entry(mode, &dev->mode_config.usermode_list, head) { drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(&card_res->modes + copied, &u_mode, + if (copy_to_user(card_res->modes + copied, &u_mode, sizeof(u_mode))) - return -EFAULT; + return -EFAULT; copied++; } } -- cgit v1.2.3 From e0ab2034c3d87b9a1bbd86bfccd806793ce7c5b4 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 16 Nov 2007 13:58:43 -0800 Subject: Fix connection status ABI Userspace expects a 1 based enum for connection status so fix up the kernel definition. --- linux-core/drm_crtc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 0ddefc86..0645dd6a 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -148,9 +148,9 @@ struct drm_display_mode { #define DPMSModeOff 3 enum drm_output_status { - output_status_connected, - output_status_disconnected, - output_status_unknown, + output_status_connected = 1, + output_status_disconnected = 2, + output_status_unknown = 3, }; enum subpixel_order { -- cgit v1.2.3 From f29b2a583d6f9d2cd02d58e915a0ca1cdee0919e Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 19 Nov 2007 14:37:21 +0100 Subject: drm: fix dead lock in drm_buffer_object_transfer --- linux-core/drm_bo_move.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 26df46d9..97946b3c 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -304,7 +304,7 @@ int drm_buffer_object_transfer(struct drm_buffer_object *bo, INIT_LIST_HEAD(&fbo->p_mm_list); #endif - drm_fence_reference_unlocked(&fbo->fence, bo->fence); + fbo->fence = drm_fence_reference_locked(bo->fence); fbo->pinned_node = NULL; fbo->mem.mm_node->private = (void *)fbo; atomic_set(&fbo->usage, 1); -- cgit v1.2.3 From 8fd8bf599b42b6caa062afabdfce7385d59a7695 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 18 Nov 2007 19:16:40 +0100 Subject: drm: don't reset to 0 irq_enabled when client open file descriptor --- linux-core/drm_fops.c | 1 - linux-core/drm_stub.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index ffee1027..a5277b7b 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -85,7 +85,6 @@ static int drm_setup(struct drm_device * dev) dev->queue_reserved = 0; dev->queue_slots = 0; dev->queuelist = NULL; - dev->irq_enabled = 0; dev->context_flag = 0; dev->interrupt_flag = 0; dev->dma_flag = 0; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 4aaf0a9c..eb4ba8e9 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -84,6 +84,7 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, dev->hose = pdev->sysdata; #endif dev->irq = pdev->irq; + dev->irq_enabled = 0; if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) return -ENOMEM; -- cgit v1.2.3 From 53b4e0cb789151164a0a43b55058319667847aaf Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 26 Nov 2007 14:05:49 +1100 Subject: drm: make fb modes use usermode add/remove interface this stops usermode from getting a mode in the crtc it can't make sense off. --- linux-core/drm_crtc.c | 62 +++++++++++++++++++++++++++++++-------------------- linux-core/drm_crtc.h | 11 +++++---- linux-core/drm_drv.c | 4 ++-- linux-core/intel_fb.c | 15 ++++++------- 4 files changed, 54 insertions(+), 38 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index df934841..87302555 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -439,7 +439,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, if (output->crtc != crtc) continue; - DRM_INFO("%s: set mode %s\n", output->name, mode->name); + DRM_INFO("%s: set mode %s %x\n", output->name, mode->name, mode->mode_id); output->funcs->mode_set(output, mode, adjusted_mode); } @@ -858,7 +858,7 @@ clone: output->crtc->desired_mode = des_mode; output->initial_x = 0; output->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is %s\n",c,des_mode->name); + DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); break; } } @@ -1694,8 +1694,36 @@ void drm_fb_release(struct file *filp) mutex_unlock(&dev->mode_config.mutex); } +/* + * + */ +void drm_mode_addmode(struct drm_device *dev, struct drm_display_mode *user_mode) +{ + user_mode->type |= DRM_MODE_TYPE_USERDEF; + + user_mode->output_count = 0; + list_add(&user_mode->head, &dev->mode_config.usermode_list); +} +EXPORT_SYMBOL(drm_mode_addmode); + +int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode) +{ + struct drm_display_mode *t; + int ret = -EINVAL; + list_for_each_entry(t, &dev->mode_config.usermode_list, head) { + if (t == mode) { + list_del(&mode->head); + drm_mode_destroy(dev, mode); + ret = 0; + break; + } + } + return ret; +} +EXPORT_SYMBOL(drm_mode_rmmode); + /** - * drm_fb_newmode - adds a user defined mode + * drm_fb_addmode - adds a user defined mode * @inode: inode from the ioctl * @filp: file * from the ioctl * @cmd: cmd from ioctl @@ -1709,8 +1737,8 @@ void drm_fb_release(struct file *filp) * writes new mode id into arg. * Zero on success, errno on failure. */ -int drm_mode_addmode(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_mode_addmode_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) { struct drm_mode_modeinfo *new_mode = data; struct drm_display_mode *user_mode; @@ -1724,12 +1752,8 @@ int drm_mode_addmode(struct drm_device *dev, } drm_crtc_convert_umode(user_mode, new_mode); - user_mode->type |= DRM_MODE_TYPE_USERDEF; - - user_mode->output_count = 0; - - list_add(&user_mode->head, &dev->mode_config.usermode_list); + drm_mode_addmode(dev, user_mode); new_mode->id = user_mode->mode_id; out: @@ -1751,38 +1775,28 @@ out: * RETURNS: * Zero on success, errno on failure. */ -int drm_mode_rmmode(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_mode_rmmode_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) { uint32_t *id = data; - struct drm_display_mode *mode, *t; + struct drm_display_mode *mode; int ret = -EINVAL; mutex_lock(&dev->mode_config.mutex); mode = idr_find(&dev->mode_config.crtc_idr, *id); if (!mode || (*id != mode->mode_id)) { - ret = -EINVAL; goto out; } if (!(mode->type & DRM_MODE_TYPE_USERDEF)) { - ret = -EINVAL; goto out; } if (mode->output_count) { - ret = -EINVAL; goto out; } - list_for_each_entry(t, &dev->mode_config.usermode_list, head) { - if (t == mode) { - list_del(&mode->head); - drm_mode_destroy(dev, mode); - ret = 0; - break; - } - } + ret = drm_mode_rmmode(dev, mode); out: mutex_unlock(&dev->mode_config.mutex); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 0645dd6a..f555b6bb 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -494,6 +494,9 @@ extern void drm_mode_set_name(struct drm_display_mode *mode); extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); extern void drm_disable_unused_functions(struct drm_device *dev); +extern void drm_mode_addmode(struct drm_device *dev, struct drm_display_mode *user_mode); +extern int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode); + extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_list_concat(struct list_head *head, @@ -536,10 +539,10 @@ extern int drm_mode_rmfb(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mode_addmode(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_rmmode(struct drm_device *dev, - void *data, struct drm_file *file_priv); +extern int drm_mode_addmode_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int drm_mode_rmmode_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); extern int drm_mode_attachmode(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_detachmode(struct drm_device *dev, diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 8cd7afb1..5156d15d 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -124,8 +124,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDMODE, drm_mode_addmode, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMMODE, drm_mode_rmmode, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDMODE, drm_mode_addmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMMODE, drm_mode_rmmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode, DRM_MASTER|DRM_ROOT_ONLY), diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 564a913e..3a4ffc7f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -47,6 +47,7 @@ struct intelfb_par { struct drm_device *dev; struct drm_crtc *crtc; + struct drm_display_mode *fb_mode; }; static int @@ -107,7 +108,6 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; struct drm_device *dev = par->dev; struct drm_framebuffer *fb = par->crtc->fb; - struct drm_display_mode *drm_mode; struct drm_output *output; int depth, found = 0; @@ -275,6 +275,7 @@ static int intelfb_set_par(struct fb_info *info) return -EINVAL; } #else + drm_mode = drm_mode_create(dev); drm_mode->hdisplay = var->xres; drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; @@ -290,18 +291,16 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); #endif + drm_mode_addmode(dev, drm_mode); + if (par->fb_mode) + drm_mode_rmmode(dev, par->fb_mode); + + par->fb_mode = drm_mode; drm_mode_debug_printmodeline(dev, drm_mode); if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; - /* Have to destroy our created mode if we're not searching the mode - * list for it. - */ -#if 1 - drm_mode_destroy(dev, drm_mode); -#endif - return 0; } -- cgit v1.2.3 From 362f4283205a01b2a60a49838721e9fff9ae1a4c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 26 Nov 2007 14:28:48 +1100 Subject: add _ioctl to the end of two more ioctls --- linux-core/drm_crtc.c | 8 ++++---- linux-core/drm_crtc.h | 8 ++++---- linux-core/drm_drv.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 87302555..d5f3a0ed 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1816,8 +1816,8 @@ out: * RETURNS: * Zero on success, errno on failure. */ -int drm_mode_attachmode(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_mode_attachmode_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) { struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; @@ -1867,8 +1867,8 @@ out: * RETURNS: * Zero on success, errno on failure. */ -int drm_mode_detachmode(struct drm_device *dev, - void *data, struct drm_file *file_priv) +int drm_mode_detachmode_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) { struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index f555b6bb..a9f6a135 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -543,10 +543,10 @@ extern int drm_mode_addmode_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_rmmode_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mode_attachmode(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_detachmode(struct drm_device *dev, - void *data, struct drm_file *file_priv); +extern int drm_mode_attachmode_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int drm_mode_detachmode_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5156d15d..e606bc6a 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -126,8 +126,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDMODE, drm_mode_addmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMMODE, drm_mode_rmmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -- cgit v1.2.3 From f9ac54b0319b273de83a004d6cfdf46a3b9d6ced Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 26 Nov 2007 15:06:42 +1100 Subject: fb: make fb interface use user mode attach/detach for adding modes --- linux-core/drm_crtc.c | 92 +++++++++++++++++++++++++++++++++++++-------------- linux-core/drm_crtc.h | 6 ++++ linux-core/intel_fb.c | 65 +++++++++++++++++------------------- 3 files changed, 104 insertions(+), 59 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index d5f3a0ed..bc292703 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1722,6 +1722,70 @@ int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_rmmode); +static int drm_mode_attachmode(struct drm_device *dev, + struct drm_output *output, + struct drm_display_mode *mode) +{ + int ret = 0; + int i; + + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { + if (output->user_mode_ids[i] == 0) { + output->user_mode_ids[i] = mode->mode_id; + mode->output_count++; + break; + } + } + + if (i == DRM_OUTPUT_MAX_UMODES) + ret = -ENOSPC; + + return ret; +} + +int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct drm_output *output; + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == crtc) + drm_mode_attachmode(dev, output, mode); + } +} +EXPORT_SYMBOL(drm_mode_attachmode_crtc); + +static int drm_mode_detachmode(struct drm_device *dev, + struct drm_output *output, + struct drm_display_mode *mode) +{ + int found = 0; + int ret = 0, i; + + for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { + if (output->user_mode_ids[i] == mode->mode_id) { + output->user_mode_ids[i] = 0; + mode->output_count--; + found = 1; + } + } + + if (!found) + ret = -EINVAL; + + return ret; +} + +int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) +{ + struct drm_output *output; + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + drm_mode_detachmode(dev, output, mode); + } +} +EXPORT_SYMBOL(drm_mode_detachmode_crtc); + /** * drm_fb_addmode - adds a user defined mode * @inode: inode from the ioctl @@ -1822,7 +1886,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; struct drm_display_mode *mode; - int i, ret = 0; + int ret = 0; mutex_lock(&dev->mode_config.mutex); @@ -1838,17 +1902,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, goto out; } - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] == 0) { - output->user_mode_ids[i] = mode->mode_id; - mode->output_count++; - break; - } - } - - if (i == DRM_OUTPUT_MAX_UMODES) - ret = -ENOSPC; - + ret = drm_mode_attachmode(dev, output, mode); out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1873,7 +1927,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; struct drm_display_mode *mode; - int i, found = 0, ret = 0; + int ret = 0; mutex_lock(&dev->mode_config.mutex); @@ -1890,17 +1944,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, } - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] == mode->mode_id) { - output->user_mode_ids[i] = 0; - mode->output_count--; - found = 1; - } - } - - if (!found) - ret = -EINVAL; - + ret = drm_mode_detachmode(dev, output, mode); out: mutex_unlock(&dev->mode_config.mutex); return ret; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index a9f6a135..fc97525d 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -497,6 +497,12 @@ extern void drm_disable_unused_functions(struct drm_device *dev); extern void drm_mode_addmode(struct drm_device *dev, struct drm_display_mode *user_mode); extern int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode); +/* for us by fb module */ +extern int drm_mode_attachmode_crtc(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_display_mode *mode); +extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode); + extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_list_concat(struct list_head *head, diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 3a4ffc7f..5f43f291 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -223,7 +223,7 @@ static int intelfb_set_par(struct fb_info *info) struct intelfb_par *par = info->par; struct drm_framebuffer *fb = par->crtc->fb; struct drm_device *dev = par->dev; - struct drm_display_mode *drm_mode; + struct drm_display_mode *drm_mode, *search_mode; struct drm_output *output; struct fb_var_screeninfo *var = &info->var; int found = 0; @@ -248,34 +248,7 @@ static int intelfb_set_par(struct fb_info *info) info->screen_size = info->fix.smem_len; /* ??? */ - /* Should we walk the output's modelist or just create our own ??? - * For now, we create and destroy a mode based on the incoming - * parameters. But there's commented out code below which scans - * the output list too. - */ -#if 0 - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc) - break; - } - - list_for_each_entry(drm_mode, &output->modes, head) { - if (drm_mode->hdisplay == var->xres && - drm_mode->vdisplay == var->yres && - (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && - (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { - found = 1; - break; - } - } - - if (!found) { - DRM_ERROR("Couldn't find a mode for requested %dx%d-%d\n", - var->xres,var->yres,var_to_refresh(var)); - return -EINVAL; - } -#else - + /* create a drm mode */ drm_mode = drm_mode_create(dev); drm_mode->hdisplay = var->xres; drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; @@ -289,14 +262,36 @@ static int intelfb_set_par(struct fb_info *info) drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); -#endif - drm_mode_addmode(dev, drm_mode); - if (par->fb_mode) - drm_mode_rmmode(dev, par->fb_mode); + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } + + drm_mode_debug_printmodeline(dev, drm_mode); + list_for_each_entry(search_mode, &output->modes, head) { + DRM_ERROR("mode %s : %s\n", drm_mode->name, search_mode->name); + drm_mode_debug_printmodeline(dev, search_mode); + if (drm_mode_equal(drm_mode, search_mode)) { + drm_mode_destroy(dev, drm_mode); + drm_mode = search_mode; + found = 1; + break; + } + } - par->fb_mode = drm_mode; - drm_mode_debug_printmodeline(dev, drm_mode); + if (!found) { + drm_mode_addmode(dev, drm_mode); + if (par->fb_mode) { + drm_mode_detachmode_crtc(dev, par->fb_mode); + drm_mode_rmmode(dev, par->fb_mode); + } + + par->fb_mode = drm_mode; + drm_mode_debug_printmodeline(dev, drm_mode); + /* attach mode */ + drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); + } if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; -- cgit v1.2.3 From b3af2b59a77a6916ea7151236d3da9bde6a537fc Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 27 Nov 2007 14:31:02 +1000 Subject: drm/modesetting: add initial gettable properites code. This allow the user to retrieve a list of properties for an output. Properties can either be 32-bit values or an enum with an associated name. Range properties are to be supported. This API is probably not all correct, I may make properties part of the general resource get when I think about it some more. So basically you can create properties and attached them to whatever outputs you want, so it should be possible to create some generics and just attach them to every output. --- libdrm/xf86drmMode.c | 77 +++++++++++++++++-- libdrm/xf86drmMode.h | 17 +++++ linux-core/drm_crtc.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 34 +++++++++ linux-core/drm_drv.c | 1 + shared-core/drm.h | 29 +++++++ tests/mode/modetest.c | 34 ++++++++- 7 files changed, 387 insertions(+), 12 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index e400f219..f697232d 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -316,7 +316,7 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) { struct drm_mode_get_output out; - drmModeOutputPtr r = 0; + drmModeOutputPtr r = NULL; out.output = output_id; out.count_crtcs = 0; @@ -325,18 +325,27 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) out.clones = 0; out.count_modes = 0; out.modes = 0; + out.count_props = 0; + out.props = NULL; + out.prop_values = NULL; if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) return 0; + if (out.count_props) { + out.props = drmMalloc(out.count_props*sizeof(uint32_t)); + out.prop_values = drmMalloc(out.count_props*sizeof(uint32_t)); + } + if (out.count_modes) out.modes = drmMalloc(out.count_modes*sizeof(uint32_t)); if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) goto err_allocs; - if(!(r = drmMalloc(sizeof(*r)))) - return 0; + if(!(r = drmMalloc(sizeof(*r)))) { + goto err_allocs; + } r->output_id = out.output; r->crtc = out.crtc; @@ -350,15 +359,19 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) /* TODO we should test if these alloc & cpy fails. */ r->crtcs = out.crtcs; r->clones = out.clones; + r->count_props = out.count_props; + r->props = drmAllocCpy(out.props, out.count_props, sizeof(uint32_t)); + r->prop_values = drmAllocCpy(out.prop_values, out.count_props, sizeof(uint32_t)); r->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(uint32_t)); strncpy(r->name, out.name, DRM_OUTPUT_NAME_LEN); r->name[DRM_OUTPUT_NAME_LEN-1] = 0; - return r; err_allocs: + drmFree(out.prop_values); + drmFree(out.props); drmFree(out.modes); - return 0; + return r; } uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *mode_info) @@ -396,3 +409,57 @@ int drmModeDetachMode(int fd, uint32_t output_id, uint32_t mode_id) } +drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) +{ + struct drm_mode_get_property prop; + drmModePropertyPtr r; + + prop.prop_id = property_id; + prop.count_enums = 0; + prop.count_values = 0; + prop.flags = 0; + prop.enums = NULL; + prop.values = NULL; + + if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) + return 0; + + if (prop.count_values) + prop.values = drmMalloc(prop.count_values * sizeof(uint32_t)); + + if (prop.count_enums) + prop.enums = drmMalloc(prop.count_enums * sizeof(struct drm_mode_property_enum)); + + if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) { + r = NULL; + goto err_allocs; + } + + if (!(r = drmMalloc(sizeof(*r)))) + return NULL; + + r->prop_id = prop.prop_id; + r->count_values = prop.count_values; + r->count_enums = prop.count_enums; + + r->values = drmAllocCpy(prop.values, prop.count_values, sizeof(uint32_t)); + r->enums = drmAllocCpy(prop.enums, prop.count_enums, sizeof(struct drm_mode_property_enum)); + strncpy(r->name, prop.name, DRM_PROP_NAME_LEN); + r->name[DRM_PROP_NAME_LEN-1] = 0; + +err_allocs: + drmFree(prop.values); + drmFree(prop.enums); + + return r; +} + +void drmModeFreeProperty(drmModePropertyPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->values); + drmFree(ptr->enums); + drmFree(ptr); +} diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index be9d84af..5e966e95 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -70,6 +70,17 @@ typedef struct _drmModeRes { typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr; +typedef struct _drmModeProperty { + unsigned int prop_id; + unsigned int flags; + unsigned char name[DRM_PROP_NAME_LEN]; + int count_values; + uint32_t *values; + int count_enums; + struct drm_mode_property_enum *enums; + +} drmModePropertyRes, *drmModePropertyPtr; + typedef struct _drmModeCrtc { unsigned int crtc_id; unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/ @@ -121,6 +132,10 @@ typedef struct _drmModeOutput { int count_modes; uint32_t *modes; /**< List of modes ids */ + int count_props; + uint32_t *props; /**< List of property ids */ + uint32_t *prop_values; /**< List of property values */ + } drmModeOutput, *drmModeOutputPtr; @@ -207,3 +222,5 @@ extern int drmModeAttachMode(int fd, uint32_t outputId, uint32_t modeId); */ extern int drmModeDetachMode(int fd, uint32_t outputId, uint32_t modeId); +extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId); +extern void drmModeFreeProperty(drmModePropertyPtr ptr); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bc292703..cd60f522 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -711,6 +711,7 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); + INIT_LIST_HEAD(&dev->mode_config.property_list); INIT_LIST_HEAD(&dev->mode_config.usermode_list); idr_init(&dev->mode_config.crtc_idr); } @@ -944,14 +945,20 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_crtc *crtc, *ct; struct drm_framebuffer *fb, *fbt; struct drm_display_mode *mode, *mt; + struct drm_property *property, *pt; + list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_output_destroy(output); } + list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, head) { + drm_property_destroy(dev, property); + } + list_for_each_entry_safe(mode, mt, &dev->mode_config.usermode_list, head) { drm_mode_destroy(dev, mode); } - + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { if (fb->bo->type != drm_bo_type_kernel) drm_framebuffer_destroy(fb); @@ -1331,6 +1338,7 @@ int drm_mode_getoutput(struct drm_device *dev, struct drm_output *output; struct drm_display_mode *mode; int mode_count = 0; + int props_count = 0; int ret = 0; int copied = 0; int i; @@ -1341,7 +1349,7 @@ int drm_mode_getoutput(struct drm_device *dev, output= idr_find(&dev->mode_config.crtc_idr, out_resp->output); if (!output || (output->id != out_resp->output)) { ret = -EINVAL; - goto done; + goto out; } list_for_each_entry(mode, &output->modes, head) @@ -1351,6 +1359,12 @@ int drm_mode_getoutput(struct drm_device *dev, if (output->user_mode_ids[i] != 0) mode_count++; + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] != 0) { + props_count++; + } + } + strncpy(out_resp->name, output->name, DRM_OUTPUT_NAME_LEN); out_resp->name[DRM_OUTPUT_NAME_LEN-1] = 0; @@ -1365,20 +1379,42 @@ int drm_mode_getoutput(struct drm_device *dev, out_resp->crtcs = output->possible_crtcs; out_resp->clones = output->possible_clones; + if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; list_for_each_entry(mode, &output->modes, head) { out_resp->modes[copied++] = mode->mode_id; } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] != 0) - out_resp->modes[copied++] = output->user_mode_ids[i]; + if (output->user_mode_ids[i] != 0) { + if (put_user(output->user_mode_ids[i], out_resp->modes + copied)) + return -EFAULT; + copied++; + } } - } out_resp->count_modes = mode_count; -done: + if ((out_resp->count_props >= props_count) && props_count) { + copied = 0; + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] != 0) { + if (put_user(output->property_ids[i], out_resp->props + copied)) { + ret = -EFAULT; + goto out; + } + + if (put_user(output->property_values[i], out_resp->prop_values + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + } + out_resp->count_props = props_count; + +out: mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1783,6 +1819,7 @@ int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mo list_for_each_entry(output, &dev->mode_config.output_list, head) { drm_mode_detachmode(dev, output, mode); } + return 0; } EXPORT_SYMBOL(drm_mode_detachmode_crtc); @@ -1949,3 +1986,161 @@ out: mutex_unlock(&dev->mode_config.mutex); return ret; } + +struct drm_property *drm_property_create(struct drm_device *dev, int flags, + const char *name, int num_values) +{ + struct drm_property *property = NULL; + + property = kzalloc(sizeof(struct drm_output), GFP_KERNEL); + if (!property) + return NULL; + + property->values = kzalloc(sizeof(uint32_t)*num_values, GFP_KERNEL); + if (!property->values) + goto fail; + + property->id = drm_idr_get(dev, property); + property->flags = flags; + property->num_values = num_values; + INIT_LIST_HEAD(&property->enum_list); + + if (name) + strncpy(property->name, name, DRM_PROP_NAME_LEN); + + list_add_tail(&property->head, &dev->mode_config.property_list); + return property; +fail: + kfree(property); + return NULL; +} +EXPORT_SYMBOL(drm_property_create); + +int drm_property_add_enum(struct drm_property *property, int index, + uint32_t value, const char *name) +{ + struct drm_property_enum *prop_enum; + + if (!(property->flags & DRM_MODE_PROP_ENUM)) + return -EINVAL; + + if (!list_empty(&property->enum_list)) { + list_for_each_entry(prop_enum, &property->enum_list, head) { + if (prop_enum->value == value) { + strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); + prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; + return 0; + } + } + } + + prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL); + if (!prop_enum) + return -ENOMEM; + + strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); + prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; + prop_enum->value = value; + + property->values[index] = value; + list_add_tail(&prop_enum->head, &property->enum_list); + return 0; +} +EXPORT_SYMBOL(drm_property_add_enum); + +void drm_property_destroy(struct drm_device *dev, struct drm_property *property) +{ + struct drm_property_enum *prop_enum, *pt; + + list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { + list_del(&prop_enum->head); + kfree(prop_enum); + } + + kfree(property->values); + drm_idr_put(dev, property->id); + list_del(&property->head); + kfree(property); +} +EXPORT_SYMBOL(drm_property_destroy); + + +int drm_output_attach_property(struct drm_output *output, + struct drm_property *property, int init_val) +{ + int i; + + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] == 0) { + output->property_ids[i] = property->id; + output->property_values[i] = init_val; + break; + } + } + + if (i == DRM_OUTPUT_MAX_PROPERTY) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(drm_output_attach_property); + +int drm_mode_getproperty_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_get_property *out_resp = data; + struct drm_property *property; + int enum_count = 0; + int value_count = 0; + int ret = 0, i; + int copied; + struct drm_property_enum *prop_enum; + + mutex_lock(&dev->mode_config.mutex); + property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); + if (!property || (property->id != out_resp->prop_id)) { + ret = -EINVAL; + goto done; + } + + + list_for_each_entry(prop_enum, &property->enum_list, head) + enum_count++; + + value_count = property->num_values; + + strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN); + out_resp->name[DRM_PROP_NAME_LEN-1] = 0; + out_resp->flags = property->flags; + + if ((out_resp->count_values >= value_count) && value_count) { + for (i = 0; i < value_count; i++) { + if (put_user(property->values[i], out_resp->values + i)) { + ret = -EFAULT; + goto done; + } + } + } + out_resp->count_values = value_count; + + if ((out_resp->count_enums >= enum_count) && enum_count) { + copied = 0; + list_for_each_entry(prop_enum, &property->enum_list, head) { + if (put_user(prop_enum->value, &out_resp->enums[copied].value)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user(&out_resp->enums[copied].name, + prop_enum->name, DRM_PROP_NAME_LEN)) { + ret = -EFAULT; + goto done; + } + copied++; + } + } + out_resp->count_enums = enum_count; + +done: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index fc97525d..011903ce 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -233,6 +233,24 @@ struct drm_framebuffer { void *virtual_base; struct list_head filp_head; }; + +struct drm_property_enum { + struct list_head head; + uint32_t value; + unsigned char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_property { + struct list_head head; + int id; /* idr assigned */ + uint32_t flags; + char name[DRM_PROP_NAME_LEN]; + uint32_t num_values; + uint32_t *values; + + struct list_head enum_list; +}; + struct drm_crtc; struct drm_output; @@ -376,6 +394,7 @@ struct drm_output_funcs { }; #define DRM_OUTPUT_MAX_UMODES 16 +#define DRM_OUTPUT_MAX_PROPERTY 16 #define DRM_OUTPUT_LEN 32 /** * drm_output - central DRM output control structure @@ -431,6 +450,8 @@ struct drm_output { u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES]; + u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; + u32 property_values[DRM_OUTPUT_MAX_PROPERTY]; }; /** @@ -464,6 +485,9 @@ struct drm_mode_config { struct list_head crtc_list; struct list_head usermode_list; + + struct list_head property_list; + int min_width, min_height; int max_width, max_height; /* DamagePtr rotationDamage? */ @@ -529,6 +553,14 @@ extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); +extern int drm_output_attach_property(struct drm_output *output, + struct drm_property *property, int init_val); +extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, + const char *name, int num_values); +extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); +extern int drm_property_add_enum(struct drm_property *property, int index, + uint32_t value, const char *name); + /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -554,5 +586,7 @@ extern int drm_mode_attachmode_ioctl(struct drm_device *dev, extern int drm_mode_detachmode_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_getproperty_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index e606bc6a..b3e00e84 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -128,6 +128,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMMODE, drm_mode_rmmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), diff --git a/shared-core/drm.h b/shared-core/drm.h index 55675d2f..9219b456 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -897,6 +897,7 @@ struct drm_mm_init_arg { #define DRM_DISPLAY_INFO_LEN 32 #define DRM_OUTPUT_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 +#define DRM_PROP_NAME_LEN 32 #define DRM_MODE_TYPE_BUILTIN (1<<0) #define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) @@ -976,6 +977,32 @@ struct drm_mode_get_output { int count_modes; unsigned int __user *modes; /**< list of modes it supports */ + int count_props; + unsigned int __user *props; + unsigned int __user *prop_values; +}; + +#define DRM_MODE_PROP_PENDING (1<<0) +#define DRM_MODE_PROP_RANGE (1<<1) +#define DRM_MODE_PROP_IMMUTABLE (1<<2) +#define DRM_MODE_PROP_ENUM (1<<3) // enumerated type with text strings + +struct drm_mode_property_enum { + uint32_t value; + unsigned char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_mode_get_property { + + unsigned int prop_id; + unsigned int flags; + unsigned char name[DRM_PROP_NAME_LEN]; + + int count_values; + uint32_t __user *values; + + int count_enums; + struct drm_mode_property_enum *enums; }; struct drm_mode_fb_cmd { @@ -1096,6 +1123,8 @@ struct drm_mode_mode_cmd { #define DRM_IOCTL_MODE_RMMODE DRM_IOWR(0xA8, unsigned int) #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) + +#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property) /*@}*/ /** diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 8f151758..50271af9 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -57,8 +57,10 @@ int printMode(struct drm_mode_modeinfo *mode) int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) { - int i = 0; + int i = 0, j; struct drm_mode_modeinfo *mode = NULL; + drmModePropertyPtr props; + unsigned char *name = NULL; printf("Output: %s\n", output->name); printf("\tid : %i\n", id); @@ -70,6 +72,36 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) printf("\tcount_clones : %i\n", output->count_clones); printf("\tclones : %i\n", output->clones); printf("\tcount_modes : %i\n", output->count_modes); + printf("\tcount_props : %i\n", output->count_props); + + for (i = 0; i < output->count_props; i++) { + props = drmModeGetProperty(fd, output->props[i]); + name = NULL; + if (props) { + printf("Property: %s\n", props->name); + printf("\tid: %i\n", props->prop_id); + printf("\tflags: %i\n", props->flags); + printf("\tvalues %d: ", props->count_values); + for (j = 0; j < props->count_values; j++) + printf("%d ", props->values[j]); + + printf("\n\tenums %d: \n", props->count_enums); + + for (j = 0; j < props->count_enums; j++) { + if (output->prop_values[i] == props->enums[j].value) + name = props->enums[j].name; + printf("\t\t%d = %s\n", props->enums[j].value, props->enums[j].name); + } + + if (props->count_enums && name) { + printf("\toutput property name %s %s\n", props->name, name); + } else { + printf("\toutput property id %s %i\n", props->name, output->prop_values[i]); + } + + drmModeFreeProperty(props); + } + } for (i = 0; i < output->count_modes; i++) { mode = findMode(res, output->modes[i]); -- cgit v1.2.3 From 617cbeed2ae71c5560f597db49637df10edd8a52 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 27 Nov 2007 12:39:09 -0800 Subject: Don't use panel fitter if we're programming a native mode Fix from the DDX driver. --- linux-core/intel_lvds.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 4f15c13a..e3e4b38a 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -255,8 +255,13 @@ static void intel_lvds_mode_set(struct drm_output *output, * screen. Should be enabled before the pipe is enabled, according to * register description and PRM. */ - pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | - VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR); + if (mode->hdisplay != adjusted_mode->hdisplay || + mode->vdisplay != adjusted_mode->vdisplay) + pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | + HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + else + pfit_control = 0; if (!IS_I965G(dev)) { if (dev_priv->panel_wants_dither) -- cgit v1.2.3 From 91cd3e3c097d581ea75ec4bcbc1ba8d23b471a2e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 28 Nov 2007 15:18:25 +1000 Subject: modesetting API change for removing mode ids and making modes per output. so really want to get a list of modes per output not the global hammer list. also we remove the mode ids and let the user pass back the full mode description need to fix up add/remove mode for user modes now --- libdrm/xf86drmMode.c | 22 ++-- libdrm/xf86drmMode.h | 14 ++- linux-core/drm_crtc.c | 270 +++++++++++++++++++++++--------------------------- shared-core/drm.h | 14 +-- tests/mode/modetest.c | 28 ++---- 5 files changed, 149 insertions(+), 199 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index f697232d..8b701381 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -101,7 +101,6 @@ void drmModeFreeResources(drmModeResPtr ptr) if (!ptr) return; - drmFree(ptr->modes); drmFree(ptr); } @@ -155,8 +154,6 @@ drmModeResPtr drmModeGetResources(int fd) res.crtc_id = drmMalloc(res.count_crtcs*sizeof(uint32_t)); if (res.count_outputs) res.output_id = drmMalloc(res.count_outputs*sizeof(uint32_t)); - if (res.count_modes) - res.modes = drmMalloc(res.count_modes*sizeof(*res.modes)); if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { r = NULL; @@ -174,18 +171,15 @@ drmModeResPtr drmModeGetResources(int fd) r->count_fbs = res.count_fbs; r->count_crtcs = res.count_crtcs; r->count_outputs = res.count_outputs; - r->count_modes = res.count_modes; /* TODO we realy should test if these allocs fails. */ r->fbs = drmAllocCpy(res.fb_id, res.count_fbs, sizeof(uint32_t)); r->crtcs = drmAllocCpy(res.crtc_id, res.count_crtcs, sizeof(uint32_t)); r->outputs = drmAllocCpy(res.output_id, res.count_outputs, sizeof(uint32_t)); - r->modes = drmAllocCpy(res.modes, res.count_modes, sizeof(struct drm_mode_modeinfo)); err_allocs: drmFree(res.fb_id); drmFree(res.crtc_id); drmFree(res.output_id); - drmFree(res.modes); return r; } @@ -287,8 +281,8 @@ err_allocs: int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, - uint32_t x, uint32_t y, uint32_t modeId, - uint32_t *outputs, int count) + uint32_t x, uint32_t y, uint32_t *outputs, int count, + struct drm_mode_modeinfo *mode) { struct drm_mode_crtc crtc; @@ -303,7 +297,11 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, crtc.fb_id = bufferId; crtc.set_outputs = outputs; crtc.count_outputs = count; - crtc.mode = modeId; + if (mode) { + memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo)); + crtc.mode_valid = 1; + } else + crtc.mode_valid = 0; return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); } @@ -338,7 +336,7 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) } if (out.count_modes) - out.modes = drmMalloc(out.count_modes*sizeof(uint32_t)); + out.modes = drmMalloc(out.count_modes*sizeof(struct drm_mode_modeinfo)); if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) goto err_allocs; @@ -362,7 +360,7 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) r->count_props = out.count_props; r->props = drmAllocCpy(out.props, out.count_props, sizeof(uint32_t)); r->prop_values = drmAllocCpy(out.prop_values, out.count_props, sizeof(uint32_t)); - r->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(uint32_t)); + r->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(struct drm_mode_modeinfo)); strncpy(r->name, out.name, DRM_OUTPUT_NAME_LEN); r->name[DRM_OUTPUT_NAME_LEN-1] = 0; @@ -374,6 +372,7 @@ err_allocs: return r; } +#if 0 uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *mode_info) { if (ioctl(fd, DRM_IOCTL_MODE_ADDMODE, mode_info)) @@ -386,6 +385,7 @@ int drmModeRmMode(int fd, uint32_t mode_id) { return ioctl(fd, DRM_IOCTL_MODE_RMMODE, &mode_id); } +#endif int drmModeAttachMode(int fd, uint32_t output_id, uint32_t mode_id) { diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 5e966e95..0777c596 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -63,9 +63,6 @@ typedef struct _drmModeRes { int count_outputs; uint32_t *outputs; - int count_modes; - struct drm_mode_modeinfo *modes; - } drmModeRes, *drmModeResPtr; typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr; @@ -87,7 +84,8 @@ typedef struct _drmModeCrtc { uint32_t x, y; /**< Position on the frameuffer */ uint32_t width, height; - uint32_t mode; /**< Current mode used */ + int mode_valid; + struct drm_mode_modeinfo mode; int count_outputs; uint32_t outputs; /**< Outputs that are connected */ @@ -130,7 +128,7 @@ typedef struct _drmModeOutput { uint32_t clones; /**< Mask of clones */ int count_modes; - uint32_t *modes; /**< List of modes ids */ + struct drm_mode_modeinfo *modes; int count_props; uint32_t *props; /**< List of property ids */ @@ -185,9 +183,9 @@ extern drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId); /** * Set the mode on a crtc crtcId with the given mode modeId. */ -extern int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, - uint32_t x, uint32_t y, uint32_t modeId, - uint32_t *outputs, int count); +int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t *outputs, int count, + struct drm_mode_modeinfo *mode); /* diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index cd60f522..44268337 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -280,73 +280,79 @@ static struct drm_display_mode std_mode[] = { * * FIXME: take into account monitor limits */ -void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) +void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int maxY) { - struct drm_output *output; + struct drm_device *dev = output->dev; struct drm_display_mode *mode, *t; int ret; //if (maxX == 0 || maxY == 0) // TODO - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - /* set all modes to the unverified state */ - list_for_each_entry_safe(mode, t, &output->modes, head) - mode->status = MODE_UNVERIFIED; + /* set all modes to the unverified state */ + list_for_each_entry_safe(mode, t, &output->modes, head) + mode->status = MODE_UNVERIFIED; - output->status = (*output->funcs->detect)(output); - - if (output->status == output_status_disconnected) { - DRM_DEBUG("%s is disconnected\n", output->name); - /* TODO set EDID to NULL */ - continue; - } - - ret = (*output->funcs->get_modes)(output); - - if (ret) { - drm_mode_output_list_update(output); - } - - if (maxX && maxY) - drm_mode_validate_size(dev, &output->modes, maxX, - maxY, 0); - list_for_each_entry_safe(mode, t, &output->modes, head) { - if (mode->status == MODE_OK) - mode->status = (*output->funcs->mode_valid)(output,mode); - } + output->status = (*output->funcs->detect)(output); + + if (output->status == output_status_disconnected) { + DRM_DEBUG("%s is disconnected\n", output->name); + /* TODO set EDID to NULL */ + return; + } + + ret = (*output->funcs->get_modes)(output); + + if (ret) { + drm_mode_output_list_update(output); + } + + if (maxX && maxY) + drm_mode_validate_size(dev, &output->modes, maxX, + maxY, 0); + list_for_each_entry_safe(mode, t, &output->modes, head) { + if (mode->status == MODE_OK) + mode->status = (*output->funcs->mode_valid)(output,mode); + } + + + drm_mode_prune_invalid(dev, &output->modes, TRUE); + + if (list_empty(&output->modes)) { + struct drm_display_mode *stdmode; + DRM_DEBUG("No valid modes on %s\n", output->name); + + /* Should we do this here ??? + * When no valid EDID modes are available we end up + * here and bailed in the past, now we add a standard + * 640x480@60Hz mode and carry on. + */ + stdmode = drm_mode_duplicate(dev, &std_mode[0]); + drm_mode_probed_add(output, stdmode); + drm_mode_list_concat(&output->probed_modes, + &output->modes); + + DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", + output->name); + } + + drm_mode_sort(&output->modes); + + DRM_DEBUG("Probed modes for %s\n", output->name); + list_for_each_entry_safe(mode, t, &output->modes, head) { + mode->vrefresh = drm_mode_vrefresh(mode); + + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + drm_mode_debug_printmodeline(dev, mode); + } +} - drm_mode_prune_invalid(dev, &output->modes, TRUE); - - if (list_empty(&output->modes)) { - struct drm_display_mode *stdmode; - - DRM_DEBUG("No valid modes on %s\n", output->name); - - /* Should we do this here ??? - * When no valid EDID modes are available we end up - * here and bailed in the past, now we add a standard - * 640x480@60Hz mode and carry on. - */ - stdmode = drm_mode_duplicate(dev, &std_mode[0]); - drm_mode_probed_add(output, stdmode); - drm_mode_list_concat(&output->probed_modes, - &output->modes); - - DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", - output->name); - } - - drm_mode_sort(&output->modes); - - DRM_DEBUG("Probed modes for %s\n", output->name); - list_for_each_entry_safe(mode, t, &output->modes, head) { - mode->vrefresh = drm_mode_vrefresh(mode); +void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) +{ + struct drm_output *output; - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - drm_mode_debug_printmodeline(dev, mode); - } + list_for_each_entry(output, &dev->mode_config.output_list, head) { + drm_crtc_probe_single_output_modes(output, maxX, maxY); } } @@ -1068,8 +1074,6 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, */ void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in) { - - out->id = in->mode_id; out->clock = in->clock; out->hdisplay = in->hdisplay; out->hsync_start = in->hsync_start; @@ -1145,17 +1149,12 @@ int drm_mode_getresources(struct drm_device *dev, struct drm_framebuffer *fb; struct drm_output *output; struct drm_crtc *crtc; - struct drm_mode_modeinfo u_mode; - struct drm_display_mode *mode; int ret = 0; - int mode_count= 0; int output_count = 0; int crtc_count = 0; int fb_count = 0; int copied = 0; - memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); - mutex_lock(&dev->mode_config.mutex); list_for_each(lh, &dev->mode_config.fb_list) @@ -1164,34 +1163,18 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; - list_for_each_entry(output, &dev->mode_config.output_list, - head) { + list_for_each(lh, &dev->mode_config.output_list) output_count++; - list_for_each(lh, &output->modes) - mode_count++; - } - list_for_each(lh, &dev->mode_config.usermode_list) - mode_count++; - - if (card_res->count_modes == 0) { - DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width, dev->mode_config.max_height); - drm_crtc_probe_output_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); - mode_count = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - list_for_each(lh, &output->modes) - mode_count++; - } - list_for_each(lh, &dev->mode_config.usermode_list) - mode_count++; - } /* handle this in 4 parts */ /* FBs */ if (card_res->count_fbs >= fb_count) { copied = 0; list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - if (put_user(fb->id, card_res->fb_id + copied)) - return -EFAULT; + if (put_user(fb->id, card_res->fb_id + copied)) { + ret = -EFAULT; + goto out; + } copied++; } } @@ -1202,8 +1185,10 @@ int drm_mode_getresources(struct drm_device *dev, copied = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ DRM_DEBUG("CRTC ID is %d\n", crtc->id); - if (put_user(crtc->id, card_res->crtc_id + copied)) - return -EFAULT; + if (put_user(crtc->id, card_res->crtc_id + copied)) { + ret = -EFAULT; + goto out; + } copied++; } } @@ -1216,41 +1201,20 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each_entry(output, &dev->mode_config.output_list, head) { DRM_DEBUG("OUTPUT ID is %d\n", output->id); - if (put_user(output->id, card_res->output_id + copied)) - return -EFAULT; + if (put_user(output->id, card_res->output_id + copied)) { + ret = -EFAULT; + goto out; + } copied++; } } card_res->count_outputs = output_count; - /* Modes */ - if (card_res->count_modes >= mode_count) { - copied = 0; - list_for_each_entry(output, &dev->mode_config.output_list, - head) { - list_for_each_entry(mode, &output->modes, head) { - drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(card_res->modes + copied, - &u_mode, sizeof(u_mode))) - return -EFAULT; - copied++; - } - } - /* add in user modes */ - list_for_each_entry(mode, &dev->mode_config.usermode_list, head) { - drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(card_res->modes + copied, &u_mode, - sizeof(u_mode))) - return -EFAULT; - copied++; - } - } - card_res->count_modes = mode_count; + DRM_DEBUG("Counted %d %d\n", card_res->count_crtcs, + card_res->count_outputs); - DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs, - card_res->count_outputs, - card_res->count_modes); - + +out: mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1299,14 +1263,16 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->outputs = 0; if (crtc->enabled) { - crtc_resp->mode = crtc->mode.mode_id; + drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); + crtc_resp->mode_valid = 1; ocount = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { if (output->crtc == crtc) crtc_resp->outputs |= 1 << (ocount++); } + } else { - crtc_resp->mode = 0; + crtc_resp->mode_valid = 0; } out: @@ -1342,6 +1308,9 @@ int drm_mode_getoutput(struct drm_device *dev, int ret = 0; int copied = 0; int i; + struct drm_mode_modeinfo u_mode; + + memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); DRM_DEBUG("output id %d:\n", out_resp->output); @@ -1365,6 +1334,10 @@ int drm_mode_getoutput(struct drm_device *dev, } } + if (out_resp->count_modes == 0) { + drm_crtc_probe_single_output_modes(output, dev->mode_config.max_width, dev->mode_config.max_height); + } + strncpy(out_resp->name, output->name, DRM_OUTPUT_NAME_LEN); out_resp->name[DRM_OUTPUT_NAME_LEN-1] = 0; @@ -1383,12 +1356,26 @@ int drm_mode_getoutput(struct drm_device *dev, if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; list_for_each_entry(mode, &output->modes, head) { - out_resp->modes[copied++] = mode->mode_id; + drm_crtc_convert_to_umode(&u_mode, mode); + if (copy_to_user(out_resp->modes + copied, + &u_mode, sizeof(u_mode))) { + ret = -EFAULT; + goto out; + } + copied++; + } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] != 0) { - if (put_user(output->user_mode_ids[i], out_resp->modes + copied)) - return -EFAULT; + if (!output->user_mode_ids[i]) + continue; + mode = idr_find(&dev->mode_config.crtc_idr, output->user_mode_ids[i]); + if (mode && (mode->mode_id == output->user_mode_ids[i])) { + drm_crtc_convert_to_umode(&u_mode, mode); + if (copy_to_user(out_resp->modes + copied, + &u_mode, sizeof(u_mode))) { + ret = -EFAULT; + goto out; + } copied++; } } @@ -1442,8 +1429,9 @@ int drm_mode_setcrtc(struct drm_device *dev, struct drm_mode_crtc *crtc_req = data; struct drm_crtc *crtc; struct drm_output **output_set = NULL, *output; - struct drm_display_mode *mode; struct drm_framebuffer *fb = NULL; + struct drm_display_mode mode; + int mode_valid = 0; int ret = 0; int i; @@ -1455,7 +1443,7 @@ int drm_mode_setcrtc(struct drm_device *dev, goto out; } - if (crtc_req->mode) { + if (crtc_req->mode_valid) { /* if we have a mode we need a framebuffer */ if (crtc_req->fb_id) { fb = idr_find(&dev->mode_config.crtc_idr, crtc_req->fb_id); @@ -1465,34 +1453,19 @@ int drm_mode_setcrtc(struct drm_device *dev, goto out; } } - mode = idr_find(&dev->mode_config.crtc_idr, crtc_req->mode); - if (!mode || (mode->mode_id != crtc_req->mode)) { - struct drm_output *output; - - list_for_each_entry(output, - &dev->mode_config.output_list, - head) { - list_for_each_entry(mode, &output->modes, - head) { - drm_mode_debug_printmodeline(dev, - mode); - } - } - DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req->mode, mode); - ret = -EINVAL; - goto out; - } + mode_valid = 1; + drm_crtc_convert_umode(&mode, &crtc_req->mode); } else - mode = NULL; + mode_valid = 0; - if (crtc_req->count_outputs == 0 && mode) { + if (crtc_req->count_outputs == 0 && mode_valid) { DRM_DEBUG("Count outputs is 0 but mode set\n"); ret = -EINVAL; goto out; } - if (crtc_req->count_outputs > 0 && !mode && !fb) { + if (crtc_req->count_outputs > 0 && !mode_valid && !fb) { DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req->count_outputs); ret = -EINVAL; goto out; @@ -1523,8 +1496,12 @@ int drm_mode_setcrtc(struct drm_device *dev, output_set[i] = output; } } - - ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb); + + if (mode_valid) { + ret = drm_crtc_set_config(crtc, crtc_req, &mode, output_set, fb); + } else { + ret = drm_crtc_set_config(crtc, crtc_req, NULL, output_set, fb); + } out: mutex_unlock(&dev->mode_config.mutex); @@ -1855,7 +1832,6 @@ int drm_mode_addmode_ioctl(struct drm_device *dev, drm_crtc_convert_umode(user_mode, new_mode); drm_mode_addmode(dev, user_mode); - new_mode->id = user_mode->mode_id; out: mutex_unlock(&dev->mode_config.mutex); diff --git a/shared-core/drm.h b/shared-core/drm.h index 9219b456..5c24e0af 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -908,9 +908,6 @@ struct drm_mm_init_arg { #define DRM_MODE_TYPE_DRIVER (1<<6) struct drm_mode_modeinfo { - - unsigned int id; - unsigned int clock; unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; @@ -932,10 +929,6 @@ struct drm_mode_card_res { int count_outputs; unsigned int __user *output_id; - - int count_modes; - struct drm_mode_modeinfo __user *modes; - }; struct drm_mode_crtc { @@ -944,8 +937,6 @@ struct drm_mode_crtc { int x, y; /**< Position on the frameuffer */ - unsigned int mode; /**< Current mode used */ - int count_outputs; unsigned int outputs; /**< Outputs that are connected */ @@ -955,7 +946,8 @@ struct drm_mode_crtc { unsigned int __user *set_outputs; /**< Outputs to be connected */ int gamma_size; - + int mode_valid; + struct drm_mode_modeinfo mode; }; struct drm_mode_get_output { @@ -975,7 +967,7 @@ struct drm_mode_get_output { unsigned int clones; /**< list of clones */ int count_modes; - unsigned int __user *modes; /**< list of modes it supports */ + struct drm_mode_modeinfo *modes; int count_props; unsigned int __user *props; diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 50271af9..2871fde4 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -20,20 +20,9 @@ const char* getConnectionText(drmModeConnection conn) } -struct drm_mode_modeinfo* findMode(drmModeResPtr res, uint32_t id) -{ - int i; - for (i = 0; i < res->count_modes; i++) { - if (res->modes[i].id == id) - return &res->modes[i]; - } - - return 0; -} - int printMode(struct drm_mode_modeinfo *mode) { -#if 0 +#if 1 printf("Mode: %s\n", mode->name); printf("\tclock : %i\n", mode->clock); printf("\thdisplay : %i\n", mode->hdisplay); @@ -49,7 +38,7 @@ int printMode(struct drm_mode_modeinfo *mode) printf("\tvrefresh : %i\n", mode->vrefresh); printf("\tflags : %i\n", mode->flags); #else - printf("Mode: %i \"%s\" %ix%i %.0f\n", mode->id, mode->name, + printf("Mode: \"%s\" %ix%i %.0f\n", mode->name, mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); #endif return 0; @@ -104,11 +93,9 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) } for (i = 0; i < output->count_modes; i++) { - mode = findMode(res, output->modes[i]); - + mode = &output->modes[i]; if (mode) - printf("\t\tmode: %i \"%s\" %ix%i %.0f\n", mode->id, mode->name, - mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); + printMode(mode); else printf("\t\tmode: Invalid mode %i\n", output->modes[i]); } @@ -154,10 +141,6 @@ int printRes(int fd, drmModeResPtr res) drmModeCrtcPtr crtc; drmModeFBPtr fb; - for (i = 0; i < res->count_modes; i++) { - printMode(&res->modes[i]); - } - for (i = 0; i < res->count_outputs; i++) { output = drmModeGetOutput(fd, res->outputs[i]); @@ -218,6 +201,7 @@ int testMode(int fd, drmModeResPtr res) int ret = 0; int error = 0; +#if 0 printf("Test: adding mode to output %i\n", output); /* printMode(&mode); */ @@ -255,7 +239,7 @@ err: if (error) printf("\tFailed to delete mode %i\n", newMode); - +#endif return 1; } -- cgit v1.2.3 From 96df9b11ad8974d7a2a0a589114cbbb04a584f18 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 13:42:32 +1000 Subject: finish of mode add/remove, just have attach/detach modes --- libdrm/xf86drmMode.c | 24 +----- libdrm/xf86drmMode.h | 15 +--- linux-core/drm_crtc.c | 202 ++++++++++---------------------------------------- linux-core/drm_crtc.h | 7 +- linux-core/drm_drv.c | 3 +- linux-core/intel_fb.c | 2 - shared-core/drm.h | 4 +- tests/mode/modetest.c | 19 +---- 8 files changed, 50 insertions(+), 226 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 8b701381..cf596730 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -372,38 +372,22 @@ err_allocs: return r; } -#if 0 -uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *mode_info) +int drmModeAttachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info) { - if (ioctl(fd, DRM_IOCTL_MODE_ADDMODE, mode_info)) - return 0; - - return mode_info->id; -} - -int drmModeRmMode(int fd, uint32_t mode_id) -{ - return ioctl(fd, DRM_IOCTL_MODE_RMMODE, &mode_id); -} -#endif - -int drmModeAttachMode(int fd, uint32_t output_id, uint32_t mode_id) -{ - struct drm_mode_mode_cmd res; + memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); res.output_id = output_id; - res.mode_id = mode_id; return ioctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res); } -int drmModeDetachMode(int fd, uint32_t output_id, uint32_t mode_id) +int drmModeDetachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info) { struct drm_mode_mode_cmd res; + memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); res.output_id = output_id; - res.mode_id = mode_id; return ioctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res); } diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 0777c596..a1d717f9 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -198,27 +198,16 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, extern drmModeOutputPtr drmModeGetOutput(int fd, uint32_t outputId); -/** - * Adds a new mode from the given mode info. - * Name must be unique. - */ -extern uint32_t drmModeAddMode(int fd, struct drm_mode_modeinfo *modeInfo); - -/** - * Removes a mode created with AddMode, must be unused. - */ -extern int drmModeRmMode(int fd, uint32_t modeId); - /** * Attaches the given mode to an output. */ -extern int drmModeAttachMode(int fd, uint32_t outputId, uint32_t modeId); +extern int drmModeAttachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo *mode_info); /** * Detaches a mode from the output * must be unused, by the given mode. */ -extern int drmModeDetachMode(int fd, uint32_t outputId, uint32_t modeId); +extern int drmModeDetachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo *mode_info); extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId); extern void drmModeFreeProperty(drmModePropertyPtr ptr); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 44268337..26aa5206 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -579,6 +579,7 @@ struct drm_output *drm_output_create(struct drm_device *dev, strncpy(output->name, name, DRM_OUTPUT_LEN); output->name[DRM_OUTPUT_LEN - 1] = 0; output->subpixel_order = SubPixelUnknown; + INIT_LIST_HEAD(&output->user_modes); INIT_LIST_HEAD(&output->probed_modes); INIT_LIST_HEAD(&output->modes); /* randr_output? */ @@ -620,6 +621,9 @@ void drm_output_destroy(struct drm_output *output) list_for_each_entry_safe(mode, t, &output->modes, head) drm_mode_remove(output, mode); + list_for_each_entry_safe(mode, t, &output->user_modes, head) + drm_mode_remove(output, mode); + mutex_lock(&dev->mode_config.mutex); drm_idr_put(dev, output->id); list_del(&output->head); @@ -718,7 +722,6 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); INIT_LIST_HEAD(&dev->mode_config.property_list); - INIT_LIST_HEAD(&dev->mode_config.usermode_list); idr_init(&dev->mode_config.crtc_idr); } EXPORT_SYMBOL(drm_mode_config_init); @@ -950,7 +953,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_output *output, *ot; struct drm_crtc *crtc, *ct; struct drm_framebuffer *fb, *fbt; - struct drm_display_mode *mode, *mt; struct drm_property *property, *pt; list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { @@ -961,10 +963,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) drm_property_destroy(dev, property); } - list_for_each_entry_safe(mode, mt, &dev->mode_config.usermode_list, head) { - drm_mode_destroy(dev, mode); - } - list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { if (fb->bo->type != drm_bo_type_kernel) drm_framebuffer_destroy(fb); @@ -1324,10 +1322,6 @@ int drm_mode_getoutput(struct drm_device *dev, list_for_each_entry(mode, &output->modes, head) mode_count++; - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) - if (output->user_mode_ids[i] != 0) - mode_count++; - for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { if (output->property_ids[i] != 0) { props_count++; @@ -1365,20 +1359,6 @@ int drm_mode_getoutput(struct drm_device *dev, copied++; } - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (!output->user_mode_ids[i]) - continue; - mode = idr_find(&dev->mode_config.crtc_idr, output->user_mode_ids[i]); - if (mode && (mode->mode_id == output->user_mode_ids[i])) { - drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(out_resp->modes + copied, - &u_mode, sizeof(u_mode))) { - ret = -EFAULT; - goto out; - } - copied++; - } - } } out_resp->count_modes = mode_count; @@ -1710,49 +1690,14 @@ void drm_fb_release(struct file *filp) /* * */ -void drm_mode_addmode(struct drm_device *dev, struct drm_display_mode *user_mode) -{ - user_mode->type |= DRM_MODE_TYPE_USERDEF; - - user_mode->output_count = 0; - list_add(&user_mode->head, &dev->mode_config.usermode_list); -} -EXPORT_SYMBOL(drm_mode_addmode); - -int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode) -{ - struct drm_display_mode *t; - int ret = -EINVAL; - list_for_each_entry(t, &dev->mode_config.usermode_list, head) { - if (t == mode) { - list_del(&mode->head); - drm_mode_destroy(dev, mode); - ret = 0; - break; - } - } - return ret; -} -EXPORT_SYMBOL(drm_mode_rmmode); static int drm_mode_attachmode(struct drm_device *dev, struct drm_output *output, struct drm_display_mode *mode) { int ret = 0; - int i; - - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] == 0) { - output->user_mode_ids[i] = mode->mode_id; - mode->output_count++; - break; - } - } - - if (i == DRM_OUTPUT_MAX_UMODES) - ret = -ENOSPC; + list_add_tail(&mode->head, &output->user_modes); return ret; } @@ -1760,11 +1705,22 @@ int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, struct drm_display_mode *mode) { struct drm_output *output; - + int ret = 0; + struct drm_display_mode *dup_mode; + int need_dup = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == crtc) - drm_mode_attachmode(dev, output, mode); + if (output->crtc == crtc) { + if (need_dup) + dup_mode = drm_mode_duplicate(dev, mode); + else + dup_mode = mode; + ret = drm_mode_attachmode(dev, output, dup_mode); + if (ret) + return ret; + need_dup = 1; + } } + return 0; } EXPORT_SYMBOL(drm_mode_attachmode_crtc); @@ -1773,13 +1729,15 @@ static int drm_mode_detachmode(struct drm_device *dev, struct drm_display_mode *mode) { int found = 0; - int ret = 0, i; + int ret = 0; + struct drm_display_mode *match_mode, *t; - for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { - if (output->user_mode_ids[i] == mode->mode_id) { - output->user_mode_ids[i] = 0; - mode->output_count--; + list_for_each_entry_safe(match_mode, t, &output->user_modes, head) { + if (drm_mode_equal(match_mode, mode)) { + list_del(&match_mode->head); + drm_mode_destroy(dev, match_mode); found = 1; + break; } } @@ -1800,86 +1758,6 @@ int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mo } EXPORT_SYMBOL(drm_mode_detachmode_crtc); -/** - * drm_fb_addmode - adds a user defined mode - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * Adds a user specified mode to the kernel. - * - * Called by the user via ioctl. - * - * RETURNS: - * writes new mode id into arg. - * Zero on success, errno on failure. - */ -int drm_mode_addmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_modeinfo *new_mode = data; - struct drm_display_mode *user_mode; - int ret = 0; - - mutex_lock(&dev->mode_config.mutex); - user_mode = drm_mode_create(dev); - if (!user_mode) { - ret = -ENOMEM; - goto out; - } - - drm_crtc_convert_umode(user_mode, new_mode); - - drm_mode_addmode(dev, user_mode); - -out: - mutex_unlock(&dev->mode_config.mutex); - return ret; -} - -/** - * drm_fb_rmmode - removes a user defined mode - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * Remove the user defined mode specified by the user. - * - * Called by the user via ioctl - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_mode_rmmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - uint32_t *id = data; - struct drm_display_mode *mode; - int ret = -EINVAL; - - mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, *id); - if (!mode || (*id != mode->mode_id)) { - goto out; - } - - if (!(mode->type & DRM_MODE_TYPE_USERDEF)) { - goto out; - } - - if (mode->output_count) { - goto out; - } - - ret = drm_mode_rmmode(dev, mode); - -out: - mutex_unlock(&dev->mode_config.mutex); - return ret; -} - /** * drm_fb_attachmode - Attach a user mode to an output * @inode: inode from the ioctl @@ -1899,21 +1777,24 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; struct drm_display_mode *mode; + struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd->mode_id); - if (!mode || (mode->mode_id != mode_cmd->mode_id)) { + output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); + if (!output || (output->id != mode_cmd->output_id)) { ret = -EINVAL; goto out; } - output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); - if (!output || (output->id != mode_cmd->output_id)) { - ret = -EINVAL; + mode = drm_mode_create(dev); + if (!mode) { + ret = -ENOMEM; goto out; } + + drm_crtc_convert_umode(mode, umode); ret = drm_mode_attachmode(dev, output, mode); out: @@ -1939,25 +1820,20 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, { struct drm_mode_mode_cmd *mode_cmd = data; struct drm_output *output; - struct drm_display_mode *mode; + struct drm_display_mode mode; + struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; mutex_lock(&dev->mode_config.mutex); - mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd->mode_id); - if (!mode || (mode->mode_id != mode_cmd->mode_id)) { - ret = -EINVAL; - goto out; - } - output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); if (!output || (output->id != mode_cmd->output_id)) { ret = -EINVAL; goto out; } - - - ret = drm_mode_detachmode(dev, output, mode); + + drm_crtc_convert_umode(&mode, umode); + ret = drm_mode_detachmode(dev, output, &mode); out: mutex_unlock(&dev->mode_config.mutex); return ret; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 011903ce..90d6104f 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -448,7 +448,7 @@ struct drm_output { const struct drm_output_funcs *funcs; void *driver_private; - u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES]; + struct list_head user_modes; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; u32 property_values[DRM_OUTPUT_MAX_PROPERTY]; @@ -484,8 +484,6 @@ struct drm_mode_config { int num_crtc; struct list_head crtc_list; - struct list_head usermode_list; - struct list_head property_list; int min_width, min_height; @@ -518,9 +516,6 @@ extern void drm_mode_set_name(struct drm_display_mode *mode); extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); extern void drm_disable_unused_functions(struct drm_device *dev); -extern void drm_mode_addmode(struct drm_device *dev, struct drm_display_mode *user_mode); -extern int drm_mode_rmmode(struct drm_device *dev, struct drm_display_mode *mode); - /* for us by fb module */ extern int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index b3e00e84..6a3e7041 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -124,8 +124,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDMODE, drm_mode_addmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMMODE, drm_mode_rmmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY), diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 5f43f291..a8c9188d 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -281,10 +281,8 @@ static int intelfb_set_par(struct fb_info *info) } if (!found) { - drm_mode_addmode(dev, drm_mode); if (par->fb_mode) { drm_mode_detachmode_crtc(dev, par->fb_mode); - drm_mode_rmmode(dev, par->fb_mode); } par->fb_mode = drm_mode; diff --git a/shared-core/drm.h b/shared-core/drm.h index 5c24e0af..f4f75cf5 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1008,7 +1008,7 @@ struct drm_mode_fb_cmd { struct drm_mode_mode_cmd { unsigned int output_id; - unsigned int mode_id; + struct drm_mode_modeinfo mode; }; /** @@ -1111,8 +1111,6 @@ struct drm_mode_mode_cmd { #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) -#define DRM_IOCTL_MODE_ADDMODE DRM_IOWR(0xA7, struct drm_mode_modeinfo) -#define DRM_IOCTL_MODE_RMMODE DRM_IOWR(0xA8, unsigned int) #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 2871fde4..1d5002b0 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -201,45 +201,30 @@ int testMode(int fd, drmModeResPtr res) int ret = 0; int error = 0; -#if 0 printf("Test: adding mode to output %i\n", output); /* printMode(&mode); */ - printf("\tAdding mode\n"); - newMode = drmModeAddMode(fd, &mode); - if (!newMode) - goto err; - printf("\tAttaching mode %i to output %i\n", newMode, output); - ret = drmModeAttachMode(fd, output, newMode); + ret = drmModeAttachMode(fd, output, &mode); if (ret) goto err_mode; printf("\tDetaching mode %i from output %i\n", newMode, output); - ret = drmModeDetachMode(fd, output, newMode); + ret = drmModeDetachMode(fd, output, &mode); if (ret) goto err_mode; - - printf("\tRemoveing new mode %i\n", newMode); - ret = drmModeRmMode(fd, newMode); - if (ret) - goto err; - return 0; err_mode: - error = drmModeRmMode(fd, newMode); -err: printf("\tFailed\n"); if (error) printf("\tFailed to delete mode %i\n", newMode); -#endif return 1; } -- cgit v1.2.3 From 34bb2e733a612de49a390babddd8477825deb895 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 15:27:49 +1000 Subject: mode: copy back the mode if is valid correctly --- libdrm/xf86drmMode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index cf596730..bb7be13c 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -263,7 +263,9 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) r->crtc_id = crtc.crtc_id; r->x = crtc.x; r->y = crtc.y; - r->mode = crtc.mode; + r->mode_valid = crtc.mode_valid; + if (r->mode_valid) + memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo)); r->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; r->count_outputs = crtc.count_outputs; -- cgit v1.2.3 From 9a843d3bc79ae529f56e2f19e463b1b31c869a5b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 15:27:57 +1000 Subject: add flags to mode debug print --- linux-core/drm_modes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index fd00841e..3763ca69 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -46,12 +46,12 @@ void drm_mode_debug_printmodeline(struct drm_device *dev, struct drm_display_mode *mode) { - DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x\n", + DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", mode->mode_id, mode->name, mode->vrefresh, mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->vdisplay, mode->vsync_start, - mode->vsync_end, mode->vtotal, mode->type); + mode->vsync_end, mode->vtotal, mode->type, mode->flags); } EXPORT_SYMBOL(drm_mode_debug_printmodeline); -- cgit v1.2.3 From 1a07dd5ffd014aae8f767ab1f5166131aa27ef3f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Dec 2007 15:28:26 +1000 Subject: hooks up sync and flags and also clocks to get mode matching better --- linux-core/intel_fb.c | 52 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index a8c9188d..0a3a00b5 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -216,6 +216,32 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, return 0; } +bool i915_drmfb_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2, unsigned int pixclock) +{ + + if (mode1->hdisplay == mode2->hdisplay && + mode1->hsync_start == mode2->hsync_start && + mode1->hsync_end == mode2->hsync_end && + mode1->htotal == mode2->htotal && + mode1->hskew == mode2->hskew && + mode1->vdisplay == mode2->vdisplay && + mode1->vsync_start == mode2->vsync_start && + mode1->vsync_end == mode2->vsync_end && + mode1->vtotal == mode2->vtotal && + mode1->vscan == mode2->vscan && + mode1->flags == mode2->flags) + { + if (mode1->clock == mode2->clock) + return true; + + if (KHZ2PICOS(mode2->clock) == pixclock) + return true; + return false; + } + + return false; +} + /* this will let fbcon do the mode init */ /* FIXME: take mode config lock? */ static int intelfb_set_par(struct fb_info *info) @@ -260,6 +286,10 @@ static int intelfb_set_par(struct fb_info *info) drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode->flags = 0; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); @@ -270,9 +300,8 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_debug_printmodeline(dev, drm_mode); list_for_each_entry(search_mode, &output->modes, head) { - DRM_ERROR("mode %s : %s\n", drm_mode->name, search_mode->name); drm_mode_debug_printmodeline(dev, search_mode); - if (drm_mode_equal(drm_mode, search_mode)) { + if (i915_drmfb_mode_equal(drm_mode, search_mode, var->pixclock)) { drm_mode_destroy(dev, drm_mode); drm_mode = search_mode; found = 1; @@ -550,7 +579,6 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.activate = FB_ACTIVATE_NOW; info->var.height = -1; info->var.width = -1; - info->var.vmode = FB_VMODE_NONINTERLACED; info->var.xres = mode->hdisplay; info->var.right_margin = mode->hsync_start - mode->hdisplay; @@ -560,10 +588,20 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.lower_margin = mode->vsync_start - mode->vdisplay; info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = 10000000 / mode->htotal * 1000 / - mode->vtotal * 100; - /* avoid overflow */ - info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + info->var.pixclock = KHZ2PICOS(mode->clock); + + if (mode->flags & V_PHSYNC) + info->var.sync |= FB_SYNC_HOR_HIGH_ACT; + + if (mode->flags & V_PVSYNC) + info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + + if (mode->flags & V_INTERLACE) + info->var.vmode = FB_VMODE_INTERLACED; + else if (mode->flags & V_DBLSCAN) + info->var.vmode = FB_VMODE_DOUBLE; + else + info->var.vmode = FB_VMODE_NONINTERLACED; info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; -- cgit v1.2.3 From 34797ff67c16beb9c331920f663bdf8387c14c78 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 2 Dec 2007 23:48:45 +0100 Subject: radeon_ms: radeon modesetting first commit. This should work on all radeon but there is still many things todo: - add crtc2 - tmds - lvds - add bios data table so we don't need to hardcode dac/crtc infos - separate clock control to make power saving easier & cleaner - tiling (warning tiling shouldn't be enable in double scan or interlace) - surface reg manager (this goes along with tiling) - suspend/resume hook - avivo & r500 family support - atom bios support (for posting card mostly) - finish superioctl skeleton - what else ? :) --- linux-core/Makefile | 4 +- linux-core/Makefile.kernel | 8 + linux-core/radeon_ms.h | 1 + linux-core/radeon_ms_bo.c | 1 + linux-core/radeon_ms_bus.c | 1 + linux-core/radeon_ms_compat.c | 67 ++ linux-core/radeon_ms_cp.c | 1 + linux-core/radeon_ms_cp_mc.c | 1 + linux-core/radeon_ms_crtc.c | 1 + linux-core/radeon_ms_dac.c | 1 + linux-core/radeon_ms_drm.c | 1 + linux-core/radeon_ms_drm.h | 1 + linux-core/radeon_ms_drv.c | 146 ++++ linux-core/radeon_ms_drv.h | 45 ++ linux-core/radeon_ms_exec.c | 1 + linux-core/radeon_ms_family.c | 1 + linux-core/radeon_ms_fb.c | 384 ++++++++++ linux-core/radeon_ms_fence.c | 1 + linux-core/radeon_ms_gpu.c | 1 + linux-core/radeon_ms_i2c.c | 1 + linux-core/radeon_ms_irq.c | 1 + linux-core/radeon_ms_output.c | 1 + linux-core/radeon_ms_reg.h | 1 + linux-core/radeon_ms_state.c | 1 + shared-core/drm_pciids.txt | 4 + shared-core/radeon_ms.h | 607 +++++++++++++++ shared-core/radeon_ms_bo.c | 311 ++++++++ shared-core/radeon_ms_bus.c | 443 +++++++++++ shared-core/radeon_ms_cp.c | 341 +++++++++ shared-core/radeon_ms_cp_mc.c | 801 +++++++++++++++++++ shared-core/radeon_ms_crtc.c | 769 +++++++++++++++++++ shared-core/radeon_ms_dac.c | 400 ++++++++++ shared-core/radeon_ms_drm.c | 299 ++++++++ shared-core/radeon_ms_drm.h | 60 ++ shared-core/radeon_ms_exec.c | 242 ++++++ shared-core/radeon_ms_family.c | 229 ++++++ shared-core/radeon_ms_fence.c | 129 ++++ shared-core/radeon_ms_gpu.c | 589 ++++++++++++++ shared-core/radeon_ms_i2c.c | 279 +++++++ shared-core/radeon_ms_irq.c | 160 ++++ shared-core/radeon_ms_output.c | 333 ++++++++ shared-core/radeon_ms_reg.h | 1655 ++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_ms_state.c | 45 ++ 43 files changed, 8367 insertions(+), 1 deletion(-) create mode 120000 linux-core/radeon_ms.h create mode 120000 linux-core/radeon_ms_bo.c create mode 120000 linux-core/radeon_ms_bus.c create mode 100644 linux-core/radeon_ms_compat.c create mode 120000 linux-core/radeon_ms_cp.c create mode 120000 linux-core/radeon_ms_cp_mc.c create mode 120000 linux-core/radeon_ms_crtc.c create mode 120000 linux-core/radeon_ms_dac.c create mode 120000 linux-core/radeon_ms_drm.c create mode 120000 linux-core/radeon_ms_drm.h create mode 100644 linux-core/radeon_ms_drv.c create mode 100644 linux-core/radeon_ms_drv.h create mode 120000 linux-core/radeon_ms_exec.c create mode 120000 linux-core/radeon_ms_family.c create mode 100644 linux-core/radeon_ms_fb.c create mode 120000 linux-core/radeon_ms_fence.c create mode 120000 linux-core/radeon_ms_gpu.c create mode 120000 linux-core/radeon_ms_i2c.c create mode 120000 linux-core/radeon_ms_irq.c create mode 120000 linux-core/radeon_ms_output.c create mode 120000 linux-core/radeon_ms_reg.h create mode 120000 linux-core/radeon_ms_state.c create mode 100644 shared-core/radeon_ms.h create mode 100644 shared-core/radeon_ms_bo.c create mode 100644 shared-core/radeon_ms_bus.c create mode 100644 shared-core/radeon_ms_cp.c create mode 100644 shared-core/radeon_ms_cp_mc.c create mode 100644 shared-core/radeon_ms_crtc.c create mode 100644 shared-core/radeon_ms_dac.c create mode 100644 shared-core/radeon_ms_drm.c create mode 100644 shared-core/radeon_ms_drm.h create mode 100644 shared-core/radeon_ms_exec.c create mode 100644 shared-core/radeon_ms_family.c create mode 100644 shared-core/radeon_ms_fence.c create mode 100644 shared-core/radeon_ms_gpu.c create mode 100644 shared-core/radeon_ms_i2c.c create mode 100644 shared-core/radeon_ms_irq.c create mode 100644 shared-core/radeon_ms_output.c create mode 100644 shared-core/radeon_ms_reg.h create mode 100644 shared-core/radeon_ms_state.c diff --git a/linux-core/Makefile b/linux-core/Makefile index 7f6b123e..76ed3e39 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -58,7 +58,7 @@ endif # Modules for all architectures MODULE_LIST := drm.o tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o \ - mach64.o nv.o nouveau.o xgi.o + mach64.o nv.o nouveau.o xgi.o radeon_ms.o # Modules only for ix86 architectures ifneq (,$(findstring 86,$(MACHINE))) @@ -92,6 +92,7 @@ NVHEADERS = nv_drv.h $(DRMHEADERS) FFBHEADERS = ffb_drv.h $(DRMHEADERS) NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS) XGIHEADERS = xgi_cmdlist.h xgi_drv.h xgi_misc.h xgi_regs.h $(DRMHEADERS) +RADEONMSHEADERS = radeon_ms_driver.h $(DRMHEADERS) PROGS = dristat drmstat @@ -286,6 +287,7 @@ CONFIG_DRM_MACH64 := n CONFIG_DRM_NV := n CONFIG_DRM_NOUVEAU := n CONFIG_DRM_XGI := n +CONFIG_DRM_RADEON_MS := m # Enable module builds for the modules requested/supported. diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 63c93f08..7ef504ad 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -34,6 +34,12 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv40_graph.o nv50_graph.o \ nv04_instmem.o nv50_instmem.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_fence.o radeon_buffer.o +radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ + radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \ + radeon_ms_bus.o radeon_ms_fence.o \ + radeon_ms_cp.o radeon_ms_cp_mc.o radeon_ms_i2c.o \ + radeon_ms_output.o radeon_ms_crtc.o radeon_ms_fb.o \ + radeon_ms_exec.o radeon_ms_gpu.o radeon_ms_dac.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o @@ -47,6 +53,7 @@ xgi-objs := xgi_cmdlist.o xgi_drv.o xgi_fb.o xgi_misc.o xgi_pcie.o \ ifeq ($(CONFIG_COMPAT),y) drm-objs += drm_ioc32.o radeon-objs += radeon_ioc32.o +radeon_ms-objs += radeon_ms_compat.o mga-objs += mga_ioc32.o r128-objs += r128_ioc32.o i915-objs += i915_ioc32.o @@ -69,3 +76,4 @@ obj-$(CONFIG_DRM_MACH64)+= mach64.o obj-$(CONFIG_DRM_NV) += nv.o obj-$(CONFIG_DRM_NOUVEAU) += nouveau.o obj-$(CONFIG_DRM_XGI) += xgi.o +obj-$(CONFIG_DRM_RADEON_MS) += radeon_ms.o diff --git a/linux-core/radeon_ms.h b/linux-core/radeon_ms.h new file mode 120000 index 00000000..da340c5d --- /dev/null +++ b/linux-core/radeon_ms.h @@ -0,0 +1 @@ +../shared-core/radeon_ms.h \ No newline at end of file diff --git a/linux-core/radeon_ms_bo.c b/linux-core/radeon_ms_bo.c new file mode 120000 index 00000000..d05df59f --- /dev/null +++ b/linux-core/radeon_ms_bo.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_bo.c \ No newline at end of file diff --git a/linux-core/radeon_ms_bus.c b/linux-core/radeon_ms_bus.c new file mode 120000 index 00000000..50f649d0 --- /dev/null +++ b/linux-core/radeon_ms_bus.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_bus.c \ No newline at end of file diff --git a/linux-core/radeon_ms_compat.c b/linux-core/radeon_ms_compat.c new file mode 100644 index 00000000..6efdc786 --- /dev/null +++ b/linux-core/radeon_ms_compat.c @@ -0,0 +1,67 @@ +/* + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * Copyright 2007 Michel Dänzer + * Copyright 2007 Roland Scheidegger + * Copyright 2007 Vladimir Dergachev + * Copyright 2007 Nicolai Haehnle + * Copyright 2007 Aapo Tahkola + * Copyright 2007 Ben Skeggs + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +/** + * Called whenever a 32-bit process running under a 64-bit kernel + * performs an ioctl on /dev/dri/card. + + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + */ +long radeon_ms_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + unsigned int nr = DRM_IOCTL_NR(cmd); + drm_ioctl_compat_t *fn = NULL; + int ret; + + if (nr < DRM_COMMAND_BASE) + return drm_compat_ioctl(filp, cmd, arg); + + lock_kernel(); + if (fn != NULL) + ret = (*fn)(filp, cmd, arg); + else + ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + unlock_kernel(); + + return ret; +} diff --git a/linux-core/radeon_ms_cp.c b/linux-core/radeon_ms_cp.c new file mode 120000 index 00000000..6aee3e6e --- /dev/null +++ b/linux-core/radeon_ms_cp.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_cp.c \ No newline at end of file diff --git a/linux-core/radeon_ms_cp_mc.c b/linux-core/radeon_ms_cp_mc.c new file mode 120000 index 00000000..0ae1a647 --- /dev/null +++ b/linux-core/radeon_ms_cp_mc.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_cp_mc.c \ No newline at end of file diff --git a/linux-core/radeon_ms_crtc.c b/linux-core/radeon_ms_crtc.c new file mode 120000 index 00000000..31f11447 --- /dev/null +++ b/linux-core/radeon_ms_crtc.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_crtc.c \ No newline at end of file diff --git a/linux-core/radeon_ms_dac.c b/linux-core/radeon_ms_dac.c new file mode 120000 index 00000000..cb523cfb --- /dev/null +++ b/linux-core/radeon_ms_dac.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_dac.c \ No newline at end of file diff --git a/linux-core/radeon_ms_drm.c b/linux-core/radeon_ms_drm.c new file mode 120000 index 00000000..8bbf19a5 --- /dev/null +++ b/linux-core/radeon_ms_drm.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_drm.c \ No newline at end of file diff --git a/linux-core/radeon_ms_drm.h b/linux-core/radeon_ms_drm.h new file mode 120000 index 00000000..5d9d7319 --- /dev/null +++ b/linux-core/radeon_ms_drm.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_drm.h \ No newline at end of file diff --git a/linux-core/radeon_ms_drv.c b/linux-core/radeon_ms_drv.c new file mode 100644 index 00000000..4b52a7d7 --- /dev/null +++ b/linux-core/radeon_ms_drv.c @@ -0,0 +1,146 @@ +/* + * Copyright 2007 Jerome Glisse. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#include "drm_pciids.h" +#include "radeon_ms.h" + +extern struct drm_fence_driver radeon_ms_fence_driver; +extern struct drm_bo_driver radeon_ms_bo_driver; +extern struct drm_ioctl_desc radeon_ms_ioctls[]; +extern int radeon_ms_num_ioctls; + +static int radeon_ms_driver_dri_library_name(struct drm_device * dev, + char * buf); +static int radeon_ms_driver_probe(struct pci_dev *pdev, + const struct pci_device_id *ent); + +static struct pci_device_id pciidlist[] = { + radeon_ms_PCI_IDS +}; + +static struct drm_driver driver = { + .load = radeon_ms_driver_load, + .firstopen = NULL, + .open = radeon_ms_driver_open, + .preclose = NULL, + .postclose = NULL, + .lastclose = radeon_ms_driver_lastclose, + .unload = radeon_ms_driver_unload, + .dma_ioctl = radeon_ms_driver_dma_ioctl, + .dma_ready = NULL, + .dma_quiescent = NULL, + .context_ctor = NULL, + .context_dtor = NULL, + .kernel_context_switch = NULL, + .kernel_context_switch_unlock = NULL, + .vblank_wait = NULL, + .vblank_wait2 = NULL, + .dri_library_name = radeon_ms_driver_dri_library_name, + .device_is_agp = NULL, + .irq_handler = radeon_ms_irq_handler, + .irq_preinstall = radeon_ms_irq_preinstall, + .irq_postinstall = radeon_ms_irq_postinstall, + .irq_uninstall = radeon_ms_irq_uninstall, + .reclaim_buffers = drm_core_reclaim_buffers, + .reclaim_buffers_locked = NULL, + .reclaim_buffers_idlelocked = NULL, + .get_map_ofs = drm_core_get_map_ofs, + .get_reg_ofs = drm_core_get_reg_ofs, + .set_version = NULL, + .fb_probe = radeonfb_probe, + .fb_remove = radeonfb_remove, + .fence_driver = &radeon_ms_fence_driver, + .bo_driver = &radeon_ms_bo_driver, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .driver_features = + DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | + DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | + DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2, + .dev_priv_size = 0, + .ioctls = radeon_ms_ioctls, + .num_ioctls = 0, + .fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .ioctl = drm_ioctl, + .mmap = drm_mmap, + .poll = drm_poll, + .fasync = drm_fasync, +#if defined(CONFIG_COMPAT) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) + .compat_ioctl = radeon_ms_compat_ioctl, +#endif + }, + .pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .probe = radeon_ms_driver_probe, + .remove = __devexit_p(drm_cleanup_pci), + }, +}; + +static int radeon_ms_driver_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + return drm_get_dev(pdev, ent, &driver); +} + +static int radeon_ms_driver_dri_library_name(struct drm_device * dev, + char * buf) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int ret; + + switch (dev_priv->family) { + default: + ret = snprintf(buf, PAGE_SIZE, "\n"); + } + return ret; +} + +static void __exit radeon_ms_driver_exit(void) +{ + drm_exit(&driver); +} + +static int __init radeon_ms_driver_init(void) +{ + driver.num_ioctls = radeon_ms_num_ioctls; + return drm_init(&driver, pciidlist); +} + +module_init(radeon_ms_driver_init); +module_exit(radeon_ms_driver_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); diff --git a/linux-core/radeon_ms_drv.h b/linux-core/radeon_ms_drv.h new file mode 100644 index 00000000..529f9c42 --- /dev/null +++ b/linux-core/radeon_ms_drv.h @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * Copyright 2007 Michel Dänzer + * Copyright 2007 Roland Scheidegger + * Copyright 2007 Vladimir Dergachev + * Copyright 2007 Nicolai Haehnle + * Copyright 2007 Aapo Tahkola + * Copyright 2007 Ben Skeggs + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jérôme Glisse + */ +#ifndef __RADEON_MS_DRV_H__ +#define __RADEON_MS_DRV_H__ + +#include +#include +#include +#include "drm.h" +#include "drmP.h" + +#endif diff --git a/linux-core/radeon_ms_exec.c b/linux-core/radeon_ms_exec.c new file mode 120000 index 00000000..cb397fbf --- /dev/null +++ b/linux-core/radeon_ms_exec.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_exec.c \ No newline at end of file diff --git a/linux-core/radeon_ms_family.c b/linux-core/radeon_ms_family.c new file mode 120000 index 00000000..1f12e092 --- /dev/null +++ b/linux-core/radeon_ms_family.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_family.c \ No newline at end of file diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c new file mode 100644 index 00000000..ef7c5cf1 --- /dev/null +++ b/linux-core/radeon_ms_fb.c @@ -0,0 +1,384 @@ +/* + * Copyright © 2007 David Airlie + * Copyright © 2007 Jerome Glisse + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "radeon_ms.h" + +struct radeonfb_par { + struct drm_device *dev; + struct drm_crtc *crtc; +}; + +static int radeonfb_setcolreg(unsigned regno, unsigned red, + unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) +{ + struct radeonfb_par *par = info->par; + struct drm_crtc *crtc = par->crtc; + + if (regno > 255) + return 1; + if (crtc->funcs->gamma_set) + crtc->funcs->gamma_set(crtc, red, green, blue, regno); + return 0; +} + +static int radeonfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct radeonfb_par *par = info->par; + struct drm_framebuffer *fb = par->crtc->fb; + + if (!var->pixclock) + return -EINVAL; + + /* Need to resize the fb object !!! */ + if (var->xres > fb->width || var->yres > fb->height) { + DRM_ERROR("Requested width/height is greater than " + "current fb object %dx%d > %dx%d\n", + var->xres, var->yres, fb->width, fb->height); + DRM_ERROR("Need resizing code.\n"); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + if (var->green.length == 5) { + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + } else { + var->red.offset = 11; + var->green.offset = 6; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + } + break; + case 32: + if (var->transp.length) { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 24; + } else { + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int radeonfb_set_par(struct fb_info *info) +{ + struct radeonfb_par *par = info->par; + struct drm_framebuffer *fb = par->crtc->fb; + struct drm_device *dev = par->dev; + struct drm_display_mode *drm_mode; + struct fb_var_screeninfo *var = &info->var; + + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + return -EINVAL; + } + fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = fb->pitch; + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->screen_size = info->fix.smem_len; /* ??? */ + + /* Should we walk the output's modelist or just create our own ??? + * For now, we create and destroy a mode based on the incoming + * parameters. But there's commented out code below which scans + * the output list too. + */ + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + + drm_mode_debug_printmodeline(dev, drm_mode); + + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + return -EINVAL; + + /* Have to destroy our created mode if we're not searching the mode + * list for it. + */ + drm_mode_destroy(dev, drm_mode); + + return 0; +} + +static struct fb_ops radeonfb_ops = { + .owner = THIS_MODULE, + // .fb_open = radeonfb_open, + // .fb_read = radeonfb_read, + // .fb_write = radeonfb_write, + // .fb_release = radeonfb_release, + // .fb_ioctl = radeonfb_ioctl, + .fb_check_var = radeonfb_check_var, + .fb_set_par = radeonfb_set_par, + .fb_setcolreg = radeonfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct fb_info *info; + struct radeonfb_par *par; + struct device *device = &dev->pdev->dev; + struct drm_framebuffer *fb; + struct drm_display_mode *mode = crtc->desired_mode; + int ret; + + info = framebuffer_alloc(sizeof(struct radeonfb_par), device); + if (!info){ + DRM_INFO("[radeon_ms] framebuffer_alloc failed\n"); + return -EINVAL; + } + + fb = drm_framebuffer_create(dev); + if (!fb) { + framebuffer_release(info); + DRM_ERROR("[radeon_ms] failed to allocate fb.\n"); + return -EINVAL; + } + crtc->fb = fb; + + fb->width = crtc->desired_mode->hdisplay; + fb->height = crtc->desired_mode->vdisplay; + fb->bits_per_pixel = 32; + fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); + fb->depth = 24; + /* one page alignment should be fine for constraint (micro|macro tiling, + * bit depth, color buffer offset, ...) */ + ret = drm_buffer_object_create(dev, fb->width * fb->height * 4, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_NO_EVICT | + DRM_BO_FLAG_MEM_VRAM, + DRM_BO_HINT_DONT_FENCE, + 1, + 0, + &fb->bo); + if (ret || fb->bo == NULL) { + DRM_ERROR("[radeon_ms] failed to allocate framebuffer\n"); + drm_framebuffer_destroy(fb); + framebuffer_release(info); + return -EINVAL; + } + + fb->offset = fb->bo->offset; + DRM_INFO("[radeon_ms] framebuffer %dx%d at 0x%08lX\n", + fb->width, fb->height, fb->bo->offset); + + fb->fbdev = info; + par = info->par; + par->dev = dev; + par->crtc = crtc; + info->fbops = &radeonfb_ops; + strcpy(info->fix.id, "radeonfb"); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.type_aux = 0; + info->fix.xpanstep = 8; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + info->fix.accel = FB_ACCEL_ATI_RADEON; + info->fix.type_aux = 0; + info->fix.mmio_start = 0; + info->fix.mmio_len = 0; + info->fix.line_length = fb->pitch; + info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_len = info->fix.line_length * fb->height; + info->flags = FBINFO_DEFAULT; + DRM_INFO("[radeon_ms] fb physical start : 0x%lX\n", info->fix.smem_start); + DRM_INFO("[radeon_ms] fb physical size : %d\n", info->fix.smem_len); + + ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); + if (ret) { + DRM_ERROR("error mapping fb: %d\n", ret); + } + + info->screen_base = fb->virtual_base; + info->screen_size = info->fix.smem_len; /* FIXME */ + info->pseudo_palette = fb->pseudo_palette; + info->var.xres_virtual = fb->width; + info->var.yres_virtual = fb->height; + info->var.bits_per_pixel = fb->bits_per_pixel; + info->var.xoffset = 0; + info->var.yoffset = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + info->var.vmode = FB_VMODE_NONINTERLACED; + + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = 10000000 / mode->htotal * 1000 / + mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + + info->pixmap.size = 64*1024; + info->pixmap.buf_align = 8; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + info->pixmap.scan_align = 1; + + DRM_DEBUG("fb depth is %d\n", fb->depth); + DRM_DEBUG(" pitch is %d\n", fb->pitch); + switch(fb->depth) { + case 15: + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 5; + info->var.transp.offset = 15; + info->var.transp.length = 1; + break; + case 16: + info->var.red.offset = 11; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 6; + info->var.blue.length = 5; + info->var.transp.offset = 0; + break; + case 24: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; + case 32: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = 8; + info->var.transp.offset = 24; + info->var.transp.length = 8; + break; + default: + DRM_ERROR("only support 15, 16, 24 or 32bits per pixel " + "got %d\n", fb->depth); + return -EINVAL; + break; + } + + if (register_framebuffer(info) < 0) { + return -EINVAL; + } + + DRM_INFO("[radeon_ms] fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} +EXPORT_SYMBOL(radeonfb_probe); + +int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct drm_framebuffer *fb = crtc->fb; + struct fb_info *info = fb->fbdev; + + if (info) { + unregister_framebuffer(info); + framebuffer_release(info); + drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + drm_bo_usage_deref_unlocked(&fb->bo); + drm_framebuffer_destroy(fb); + } + return 0; +} +EXPORT_SYMBOL(radeonfb_remove); +MODULE_LICENSE("GPL"); diff --git a/linux-core/radeon_ms_fence.c b/linux-core/radeon_ms_fence.c new file mode 120000 index 00000000..383cc070 --- /dev/null +++ b/linux-core/radeon_ms_fence.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_fence.c \ No newline at end of file diff --git a/linux-core/radeon_ms_gpu.c b/linux-core/radeon_ms_gpu.c new file mode 120000 index 00000000..fa5e05bf --- /dev/null +++ b/linux-core/radeon_ms_gpu.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_gpu.c \ No newline at end of file diff --git a/linux-core/radeon_ms_i2c.c b/linux-core/radeon_ms_i2c.c new file mode 120000 index 00000000..1863e6d6 --- /dev/null +++ b/linux-core/radeon_ms_i2c.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_i2c.c \ No newline at end of file diff --git a/linux-core/radeon_ms_irq.c b/linux-core/radeon_ms_irq.c new file mode 120000 index 00000000..c4e60ba6 --- /dev/null +++ b/linux-core/radeon_ms_irq.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_irq.c \ No newline at end of file diff --git a/linux-core/radeon_ms_output.c b/linux-core/radeon_ms_output.c new file mode 120000 index 00000000..6a38b671 --- /dev/null +++ b/linux-core/radeon_ms_output.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_output.c \ No newline at end of file diff --git a/linux-core/radeon_ms_reg.h b/linux-core/radeon_ms_reg.h new file mode 120000 index 00000000..24b01b42 --- /dev/null +++ b/linux-core/radeon_ms_reg.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_reg.h \ No newline at end of file diff --git a/linux-core/radeon_ms_state.c b/linux-core/radeon_ms_state.c new file mode 120000 index 00000000..2d2e2ef7 --- /dev/null +++ b/linux-core/radeon_ms_state.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_state.c \ No newline at end of file diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 05d32f2e..a76413d4 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -1,3 +1,7 @@ +[radeon_ms] +0x1002 0x4150 CHIP_RV350|RADEON_AGP "ATI Radeon RV350 9600" +0x1002 0x5b63 CHIP_RV370|RADEON_PCIE "ATI Radeon RV370 X550" + [radeon] 0x1002 0x3150 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 M24" 0x1002 0x3152 CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X300 M24" diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h new file mode 100644 index 00000000..ee795f3a --- /dev/null +++ b/shared-core/radeon_ms.h @@ -0,0 +1,607 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jérôme Glisse + */ +#ifndef __RADEON_MS_H__ +#define __RADEON_MS_H__ + +#include "radeon_ms_drv.h" +#include "radeon_ms_reg.h" +#include "radeon_ms_drm.h" + +#define DRIVER_AUTHOR "Jerome Glisse, Dave Airlie, Gareth Hughes, "\ + "Keith Whitwell, others." +#define DRIVER_NAME "radeon_ms" +#define DRIVER_DESC "radeon kernel modesetting" +#define DRIVER_DATE "20071108" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 + +#define RADEON_PAGE_SIZE 4096 +#define RADEON_MAX_CONNECTORS 8 +#define RADEON_MAX_OUTPUTS 8 + +enum radeon_bus_type { + RADEON_PCI = 0x10000, + RADEON_AGP = 0x20000, + RADEON_PCIE = 0x30000, +}; + +enum radeon_family { + CHIP_R100, + CHIP_RV100, + CHIP_RS100, + CHIP_RV200, + CHIP_RS200, + CHIP_R200, + CHIP_RV250, + CHIP_RS300, + CHIP_RV280, + CHIP_R300, + CHIP_R350, + CHIP_R360, + CHIP_RV350, + CHIP_RV370, + CHIP_RV380, + CHIP_RS400, + CHIP_RV410, + CHIP_R420, + CHIP_R430, + CHIP_R480, + CHIP_LAST, +}; + +enum radeon_monitor_type { + MT_UNKNOWN = -1, + MT_NONE = 0, + MT_CRT = 1, + MT_LCD = 2, + MT_DFP = 3, + MT_CTV = 4, + MT_STV = 5 +}; + +enum radeon_connector_type { + CONNECTOR_NONE, + CONNECTOR_PROPRIETARY, + CONNECTOR_VGA, + CONNECTOR_DVI_I, + CONNECTOR_DVI_D, + CONNECTOR_CTV, + CONNECTOR_STV, + CONNECTOR_UNSUPPORTED +}; + +enum radeon_output_type { + OUTPUT_NONE, + OUTPUT_DAC1, + OUTPUT_DAC2, + OUTPUT_TMDS, + OUTPUT_LVDS +}; + +struct radeon_state; + +struct radeon_ms_crtc { + int crtc; + uint16_t lut_r[256]; + uint16_t lut_g[256]; + uint16_t lut_b[256]; +}; + +struct radeon_ms_i2c { + struct drm_device *drm_dev; + uint32_t reg; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + +struct radeon_ms_connector { + struct radeon_ms_i2c *i2c; + struct edid *edid; + struct drm_output *output; + int type; + int monitor_type; + int crtc; + uint32_t i2c_reg; + char outputs[RADEON_MAX_OUTPUTS]; + char name[32]; +}; + +struct radeon_ms_output { + int type; + struct drm_device *dev; + struct radeon_ms_connector *connector; + int (*initialize)(struct radeon_ms_output *output); + enum drm_output_status (*detect)(struct radeon_ms_output *output); + void (*dpms)(struct radeon_ms_output *output, int mode); + int (*get_modes)(struct radeon_ms_output *output); + bool (*mode_fixup)(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + int (*mode_set)(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*restore)(struct radeon_ms_output *output, + struct radeon_state *state); + void (*save)(struct radeon_ms_output *output, + struct radeon_state *state); +}; + +struct radeon_ms_properties { + uint16_t subvendor; + uint16_t subdevice; + int16_t pll_reference_freq; + int32_t pll_min_pll_freq; + int32_t pll_max_pll_freq; + char pll_use_bios; + char pll_dummy_reads; + char pll_delay; + char pll_r300_errata; + struct radeon_ms_output *outputs[RADEON_MAX_OUTPUTS]; + struct radeon_ms_connector *connectors[RADEON_MAX_CONNECTORS]; +}; + +struct radeon_state { + /* memory */ + uint32_t config_aper_0_base; + uint32_t config_aper_1_base; + uint32_t config_aper_size; + uint32_t mc_fb_location; + uint32_t display_base_addr; + /* irq */ + uint32_t gen_int_cntl; + /* pci */ + uint32_t aic_ctrl; + uint32_t aic_pt_base; + uint32_t aic_pt_base_lo; + uint32_t aic_pt_base_hi; + uint32_t aic_lo_addr; + uint32_t aic_hi_addr; + /* agp */ + uint32_t agp_cntl; + uint32_t agp_command; + uint32_t agp_base; + uint32_t agp_base_2; + uint32_t bus_cntl; + uint32_t mc_agp_location; + /* cp */ + uint32_t cp_rb_cntl; + uint32_t cp_rb_base; + uint32_t cp_rb_rptr_addr; + uint32_t cp_rb_wptr; + uint32_t cp_rb_wptr_delay; + uint32_t scratch_umsk; + uint32_t scratch_addr; + /* pcie */ + uint32_t pcie_tx_gart_cntl; + uint32_t pcie_tx_gart_discard_rd_addr_lo; + uint32_t pcie_tx_gart_discard_rd_addr_hi; + uint32_t pcie_tx_gart_base; + uint32_t pcie_tx_gart_start_lo; + uint32_t pcie_tx_gart_start_hi; + uint32_t pcie_tx_gart_end_lo; + uint32_t pcie_tx_gart_end_hi; + /* surface */ + uint32_t surface_cntl; + uint32_t surface0_info; + uint32_t surface0_lower_bound; + uint32_t surface0_upper_bound; + uint32_t surface1_info; + uint32_t surface1_lower_bound; + uint32_t surface1_upper_bound; + uint32_t surface2_info; + uint32_t surface2_lower_bound; + uint32_t surface2_upper_bound; + uint32_t surface3_info; + uint32_t surface3_lower_bound; + uint32_t surface3_upper_bound; + uint32_t surface4_info; + uint32_t surface4_lower_bound; + uint32_t surface4_upper_bound; + uint32_t surface5_info; + uint32_t surface5_lower_bound; + uint32_t surface5_upper_bound; + uint32_t surface6_info; + uint32_t surface6_lower_bound; + uint32_t surface6_upper_bound; + uint32_t surface7_info; + uint32_t surface7_lower_bound; + uint32_t surface7_upper_bound; + /* crtc */ + uint32_t crtc_gen_cntl; + uint32_t crtc_ext_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_h_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_offset; + uint32_t crtc_offset_cntl; + uint32_t crtc_pitch; + uint32_t crtc_more_cntl; + uint32_t crtc_tile_x0_y0; + uint32_t fp_h_sync_strt_wid; + uint32_t fp_v_sync_strt_wid; + uint32_t fp_crtc_h_total_disp; + uint32_t fp_crtc_v_total_disp; + /* pll */ + uint32_t clock_cntl_index; + uint32_t ppll_cntl; + uint32_t ppll_ref_div; + uint32_t ppll_div_0; + uint32_t ppll_div_1; + uint32_t ppll_div_2; + uint32_t ppll_div_3; + uint32_t vclk_ecp_cntl; + uint32_t htotal_cntl; + /* dac */ + uint32_t dac_cntl; + uint32_t dac_cntl2; + uint32_t dac_ext_cntl; + uint32_t disp_misc_cntl; + uint32_t dac_macro_cntl; + uint32_t disp_pwr_man; + uint32_t disp_merge_cntl; + uint32_t disp_output_cntl; + uint32_t disp2_merge_cntl; + uint32_t dac_embedded_sync_cntl; + uint32_t dac_broad_pulse; + uint32_t dac_skew_clks; + uint32_t dac_incr; + uint32_t dac_neg_sync_level; + uint32_t dac_pos_sync_level; + uint32_t dac_blank_level; + uint32_t dac_sync_equalization; + uint32_t tv_dac_cntl; + uint32_t tv_master_cntl; +}; + +struct drm_radeon_private { + /* driver family specific functions */ + int (*bus_finish)(struct drm_device *dev); + int (*bus_init)(struct drm_device *dev); + void (*bus_restore)(struct drm_device *dev, struct radeon_state *state); + void (*bus_save)(struct drm_device *dev, struct radeon_state *state); + struct drm_ttm_backend *(*create_ttm)(struct drm_device *dev); + void (*irq_emit)(struct drm_device *dev); + void (*flush_cache)(struct drm_device *dev); + /* bus informations */ + void *bus; + uint32_t bus_type; + /* cp */ + uint32_t ring_buffer_size; + uint32_t ring_rptr; + uint32_t ring_wptr; + uint32_t ring_mask; + int ring_free; + uint32_t ring_tail_mask; + uint32_t write_back_area_size; + struct drm_buffer_object *ring_buffer_object; + struct drm_bo_kmap_obj ring_buffer_map; + uint32_t *ring_buffer; + uint32_t *write_back_area; + const uint32_t *microcode; + /* card family */ + uint32_t usec_timeout; + uint32_t family; + struct radeon_ms_properties *properties; + struct radeon_ms_output *outputs[RADEON_MAX_OUTPUTS]; + struct radeon_ms_connector *connectors[RADEON_MAX_CONNECTORS]; + /* drm map (MMIO, FB) */ + struct drm_map mmio; + struct drm_map vram; + /* gpu address space */ + uint32_t gpu_vram_size; + uint32_t gpu_vram_start; + uint32_t gpu_vram_end; + uint32_t gpu_gart_size; + uint32_t gpu_gart_start; + uint32_t gpu_gart_end; + /* state of the card when module was loaded */ + struct radeon_state load_state; + /* state the driver wants */ + struct radeon_state driver_state; + /* last emitted fence */ + uint32_t fence_id_last; + uint32_t fence_reg; + /* when doing gpu stop we save here current state */ + uint32_t crtc_ext_cntl; + uint32_t crtc_gen_cntl; + uint32_t crtc2_gen_cntl; + uint32_t ov0_scale_cntl; + /* bool & type on the hw */ + uint8_t crtc1_dpms; + uint8_t crtc2_dpms; + uint8_t restore_state; + uint8_t cp_ready; + uint8_t bus_ready; + uint8_t write_back; +}; + + +/* radeon_ms_bo.c */ +int radeon_ms_bo_get_gpu_addr(struct drm_device *dev, + struct drm_bo_mem_reg *mem, + uint32_t *gpu_addr); +int radeon_ms_bo_move(struct drm_buffer_object * bo, int evict, + int no_wait, struct drm_bo_mem_reg * new_mem); +struct drm_ttm_backend *radeon_ms_create_ttm_backend(struct drm_device * dev); +uint32_t radeon_ms_evict_mask(struct drm_buffer_object *bo); +int radeon_ms_init_mem_type(struct drm_device * dev, uint32_t type, + struct drm_mem_type_manager * man); +int radeon_ms_invalidate_caches(struct drm_device * dev, uint64_t flags); +void radeon_ms_ttm_flush(struct drm_ttm *ttm); + +/* radeon_ms_bus.c */ +int radeon_ms_agp_finish(struct drm_device *dev); +int radeon_ms_agp_init(struct drm_device *dev); +void radeon_ms_agp_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_agp_save(struct drm_device *dev, struct radeon_state *state); +struct drm_ttm_backend *radeon_ms_pcie_create_ttm(struct drm_device *dev); +int radeon_ms_pcie_finish(struct drm_device *dev); +int radeon_ms_pcie_init(struct drm_device *dev); +void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_compat.c */ +long radeon_ms_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); + +/* radeon_ms_cp.c */ +int radeon_ms_cp_finish(struct drm_device *dev); +int radeon_ms_cp_init(struct drm_device *dev); +void radeon_ms_cp_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_cp_stop(struct drm_device *dev); +int radeon_ms_cp_wait(struct drm_device *dev, int n); +int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count); + +/* radeon_ms_crtc.c */ +int radeon_ms_crtc_create(struct drm_device *dev, int crtc); +void radeon_ms_crtc1_restore(struct drm_device *dev, + struct radeon_state *state); +void radeon_ms_crtc1_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_dac.c */ +int radeon_ms_dac1_initialize(struct radeon_ms_output *output); +enum drm_output_status radeon_ms_dac1_detect(struct radeon_ms_output *output); +void radeon_ms_dac1_dpms(struct radeon_ms_output *output, int mode); +int radeon_ms_dac1_get_modes(struct radeon_ms_output *output); +bool radeon_ms_dac1_mode_fixup(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +int radeon_ms_dac1_mode_set(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void radeon_ms_dac1_restore(struct radeon_ms_output *output, + struct radeon_state *state); +void radeon_ms_dac1_save(struct radeon_ms_output *output, + struct radeon_state *state); +int radeon_ms_dac2_initialize(struct radeon_ms_output *output); +enum drm_output_status radeon_ms_dac2_detect(struct radeon_ms_output *output); +void radeon_ms_dac2_dpms(struct radeon_ms_output *output, int mode); +int radeon_ms_dac2_get_modes(struct radeon_ms_output *output); +bool radeon_ms_dac2_mode_fixup(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void radeon_ms_dac2_restore(struct radeon_ms_output *output, + struct radeon_state *state); +void radeon_ms_dac2_save(struct radeon_ms_output *output, + struct radeon_state *state); + +/* radeon_ms_drm.c */ +int radeon_ms_driver_dma_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +void radeon_ms_driver_lastclose(struct drm_device * dev); +int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags); +int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv); +int radeon_ms_driver_unload(struct drm_device *dev); + +/* radeon_ms_exec.c */ +int radeon_ms_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +/* radeon_ms_family.c */ +int radeon_ms_family_init(struct drm_device *dev); + +/* radeon_ms_fence.c */ +int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type); +void radeon_ms_fence_handler(struct drm_device * dev); +int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class, + uint32_t flags); +int radeon_ms_fence_types(struct drm_buffer_object *bo, + uint32_t * class, uint32_t * type); +void radeon_ms_poke_flush(struct drm_device * dev, uint32_t class); + +/* radeon_ms_fb.c */ +int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc); +int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc); + +/* radeon_ms_gpu.c */ +int radeon_ms_gpu_initialize(struct drm_device *dev); +void radeon_ms_gpu_dpms(struct drm_device *dev); +void radeon_ms_gpu_flush(struct drm_device *dev); +void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state); +int radeon_ms_wait_for_idle(struct drm_device *dev); + +/* radeon_ms_i2c.c */ +void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c); +struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, + const uint32_t reg, + const char *name); + +/* radeon_ms_irq.c */ +void radeon_ms_irq_emit(struct drm_device *dev); +irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS); +void radeon_ms_irq_preinstall(struct drm_device * dev); +void radeon_ms_irq_postinstall(struct drm_device * dev); +int radeon_ms_irq_init(struct drm_device *dev); +void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_irq_uninstall(struct drm_device * dev); + +/* radeon_ms_output.c */ +void radeon_ms_connectors_destroy(struct drm_device *dev); +int radeon_ms_connectors_from_properties(struct drm_device *dev); +void radeon_ms_outputs_destroy(struct drm_device *dev); +int radeon_ms_outputs_from_properties(struct drm_device *dev); +void radeon_ms_outputs_restore(struct drm_device *dev, + struct radeon_state *state); +void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state); + +/* radeon_ms_state.c */ +void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state); +void radeon_ms_state_restore(struct drm_device *dev, + struct radeon_state *state); + + +/* packect stuff **************************************************************/ +#define RADEON_CP_PACKET0 0x00000000 +#define CP_PACKET0(reg, n) \ + (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2)) +#define CP_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 +# define GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +# define GMC_BRUSH_NONE (15 << 4) +# define GMC_SRC_DATATYPE_COLOR (3 << 12) +# define ROP3_S 0x00cc0000 +# define DP_SRC_SOURCE_MEMORY (2 << 24) +# define GMC_CLR_CMP_CNTL_DIS (1 << 28) +# define GMC_WR_MSK_DIS (1 << 30) + +/* helper macro & functions ***************************************************/ +#define REG_S(rn, bn, v) (((v) << rn##__##bn##__SHIFT) & rn##__##bn##__MASK) +#define REG_G(rn, bn, v) (((v) & rn##__##bn##__MASK) >> rn##__##bn##__SHIFT) +#define MMIO_R(rid) mmio_read(dev_priv, rid) +#define MMIO_W(rid, v) mmio_write(dev_priv, rid, v) +#define PCIE_R(rid) pcie_read(dev_priv, rid) +#define PCIE_W(rid, v) pcie_write(dev_priv, rid, v) +#define PPLL_R(rid) pll_read(dev_priv, rid) +#define PPLL_W(rid, v) pll_write(dev_priv, rid, v) + +static __inline__ uint32_t mmio_read(struct drm_radeon_private *dev_priv, + uint32_t offset) +{ + return DRM_READ32(&dev_priv->mmio, offset); +} + + +static __inline__ void mmio_write(struct drm_radeon_private *dev_priv, + uint32_t offset, uint32_t v) +{ + DRM_WRITE32(&dev_priv->mmio, offset, v); +} + +static __inline__ uint32_t pcie_read(struct drm_radeon_private *dev_priv, + uint32_t offset) +{ + MMIO_W(PCIE_INDEX, REG_S(PCIE_INDEX, PCIE_INDEX, offset)); + return MMIO_R(PCIE_DATA); +} + +static __inline__ void pcie_write(struct drm_radeon_private *dev_priv, + uint32_t offset, uint32_t v) +{ + MMIO_W(PCIE_INDEX, REG_S(PCIE_INDEX, PCIE_INDEX, offset)); + MMIO_W(PCIE_DATA, v); +} + +static __inline__ void pll_index_errata(struct drm_radeon_private *dev_priv) +{ + uint32_t tmp, save; + + /* This workaround is necessary on rv200 and RS200 or PLL + * reads may return garbage (among others...) + */ + if (dev_priv->properties->pll_dummy_reads) { + tmp = MMIO_R(CLOCK_CNTL_DATA); + tmp = MMIO_R(CRTC_GEN_CNTL); + } + /* This function is required to workaround a hardware bug in some (all?) + * revisions of the R300. This workaround should be called after every + * CLOCK_CNTL_INDEX register access. If not, register reads afterward + * may not be correct. + */ + if (dev_priv->properties->pll_r300_errata) { + tmp = save = MMIO_R(CLOCK_CNTL_INDEX); + tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; + tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_WR_EN; + MMIO_W(CLOCK_CNTL_INDEX, tmp); + tmp = MMIO_R(CLOCK_CNTL_DATA); + MMIO_W(CLOCK_CNTL_INDEX, save); + } +} + +static __inline__ void pll_data_errata(struct drm_radeon_private *dev_priv) +{ + /* This workarounds is necessary on RV100, RS100 and RS200 chips + * or the chip could hang on a subsequent access + */ + if (dev_priv->properties->pll_delay) { + /* we can't deal with posted writes here ... */ + udelay(5000); + } +} + +static __inline__ uint32_t pll_read(struct drm_radeon_private *dev_priv, + uint32_t offset) +{ + uint32_t clock_cntl_index = dev_priv->driver_state.clock_cntl_index; + uint32_t data; + + clock_cntl_index &= ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; + clock_cntl_index |= REG_S(CLOCK_CNTL_INDEX, PLL_ADDR, offset); + MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); + pll_index_errata(dev_priv); + data = MMIO_R(CLOCK_CNTL_DATA); + pll_data_errata(dev_priv); + return data; +} + +static __inline__ void pll_write(struct drm_radeon_private *dev_priv, + uint32_t offset, uint32_t value) +{ + uint32_t clock_cntl_index = dev_priv->driver_state.clock_cntl_index; + + clock_cntl_index &= ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; + clock_cntl_index |= REG_S(CLOCK_CNTL_INDEX, PLL_ADDR, offset); + clock_cntl_index |= CLOCK_CNTL_INDEX__PLL_WR_EN; + MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); + pll_index_errata(dev_priv); + MMIO_W(CLOCK_CNTL_DATA, value); + pll_data_errata(dev_priv); +} + +#endif diff --git a/shared-core/radeon_ms_bo.c b/shared-core/radeon_ms_bo.c new file mode 100644 index 00000000..cedad689 --- /dev/null +++ b/shared-core/radeon_ms_bo.c @@ -0,0 +1,311 @@ +/* + * Copyright 2007 Dave Airlie + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" + +#include "radeon_ms.h" + +void radeon_ms_bo_copy_blit(struct drm_device *dev, + uint32_t src_offset, + uint32_t dst_offset, + uint32_t pages) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t num_pages, stride, c; + uint32_t offset_inc = 0; + uint32_t cmd[7]; + + if (!dev_priv) { + return; + } + + /* radeon limited to 16320=255*64 bytes per row so copy at + * most 2 pages */ + num_pages = 2; + stride = ((num_pages * PAGE_SIZE) / 64) & 0xff; + while(pages > 0) { + if (num_pages > pages) { + num_pages = pages; + stride = ((num_pages * PAGE_SIZE) / 64) & 0xff; + } + c = pages / num_pages; + if (c >= 8192) { + c = 8191; + } + cmd[0] = CP_PACKET3_CNTL_BITBLT_MULTI | (5 << 16); + cmd[1] = GMC_SRC_PITCH_OFFSET_CNTL | + GMC_DST_PITCH_OFFSET_CNTL | + GMC_BRUSH_NONE | + (0x6 << 8) | + GMC_SRC_DATATYPE_COLOR | + ROP3_S | + DP_SRC_SOURCE_MEMORY | + GMC_CLR_CMP_CNTL_DIS | + GMC_WR_MSK_DIS; + cmd[2] = (stride << 22) | (src_offset >> 10); + cmd[3] = (stride << 22) | (dst_offset >> 10); + cmd[4] = (0 << 16) | 0; + cmd[5] = (0 << 16) | 0; + cmd[6] = ((stride * 16) << 16) | c; + radeon_ms_ring_emit(dev, cmd, 7); + offset_inc = num_pages * c * PAGE_SIZE; + src_offset += offset_inc; + dst_offset += offset_inc; + pages -= num_pages * c; + } + /* wait for 2d engine to go busy so wait_until stall */ + for (c = 0; c < dev_priv->usec_timeout; c++) { + uint32_t status = MMIO_R(RBBM_STATUS); + if ((RBBM_STATUS__E2_BUSY & status) || + (RBBM_STATUS__CBA2D_BUSY & status)) { + DRM_INFO("[radeon_ms] RBBM_STATUS 0x%08X\n", status); + break; + } + DRM_UDELAY(1); + } + /* Sync everything up */ + cmd[0] = CP_PACKET0(WAIT_UNTIL, 0); + cmd[1] = WAIT_UNTIL__WAIT_2D_IDLECLEAN | + WAIT_UNTIL__WAIT_HOST_IDLECLEAN; + radeon_ms_ring_emit(dev, cmd, 2); + return; +} + +static int radeon_ms_bo_move_blit(struct drm_buffer_object *bo, + int evict, int no_wait, + struct drm_bo_mem_reg *new_mem) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg *old_mem = &bo->mem; + uint32_t gpu_src_addr; + uint32_t gpu_dst_addr; + int ret; + + ret = radeon_ms_bo_get_gpu_addr(dev, old_mem, &gpu_src_addr); + if (ret) { + return ret; + } + ret = radeon_ms_bo_get_gpu_addr(dev, new_mem, &gpu_dst_addr); + if (ret) { + return ret; + } + + radeon_ms_bo_copy_blit(bo->dev, + gpu_src_addr, + gpu_dst_addr, + new_mem->num_pages); + + ret = drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, + DRM_FENCE_TYPE_EXE | + DRM_RADEON_FENCE_TYPE_RW, + DRM_RADEON_FENCE_FLAG_FLUSHED, + new_mem); + return ret; +} + +static int radeon_ms_bo_move_flip(struct drm_buffer_object *bo, + int evict, int no_wait, + struct drm_bo_mem_reg *new_mem) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg tmp_mem; + int ret; + + tmp_mem = *new_mem; + tmp_mem.mm_node = NULL; + tmp_mem.mask = DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_CACHED | + DRM_BO_FLAG_FORCE_CACHING; + ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); + if (ret) { + return ret; + } + + ret = drm_bind_ttm(bo->ttm, &tmp_mem); + if (ret) { + goto out_cleanup; + } + ret = radeon_ms_bo_move_blit(bo, 1, no_wait, &tmp_mem); + if (ret) { + goto out_cleanup; + } + ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); +out_cleanup: + if (tmp_mem.mm_node) { + mutex_lock(&dev->struct_mutex); + if (tmp_mem.mm_node != bo->pinned_node) + drm_mm_put_block(tmp_mem.mm_node); + tmp_mem.mm_node = NULL; + mutex_unlock(&dev->struct_mutex); + } + return ret; +} + +int radeon_ms_bo_get_gpu_addr(struct drm_device *dev, + struct drm_bo_mem_reg *mem, + uint32_t *gpu_addr) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + *gpu_addr = mem->mm_node->start << PAGE_SHIFT; + switch (mem->flags & DRM_BO_MASK_MEM) { + case DRM_BO_FLAG_MEM_TT: + *gpu_addr += dev_priv->gpu_gart_start; + DRM_INFO("[radeon_ms] GPU TT: 0x%08X\n", *gpu_addr); + break; + case DRM_BO_FLAG_MEM_VRAM: + *gpu_addr += dev_priv->gpu_vram_start; + DRM_INFO("[radeon_ms] GPU VRAM: 0x%08X\n", *gpu_addr); + break; + default: + DRM_ERROR("[radeon_ms] memory not accessible by GPU\n"); + return -EINVAL; + } + return 0; +} + +int radeon_ms_bo_move(struct drm_buffer_object *bo, int evict, + int no_wait, struct drm_bo_mem_reg *new_mem) +{ + struct drm_bo_mem_reg *old_mem = &bo->mem; + if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + if (radeon_ms_bo_move_flip(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } else { + if (radeon_ms_bo_move_blit(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } + return 0; +} + +struct drm_ttm_backend *radeon_ms_create_ttm_backend(struct drm_device * dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (dev_priv && dev_priv->create_ttm) + return dev_priv->create_ttm(dev); + return NULL; +} + +uint32_t radeon_ms_evict_mask(struct drm_buffer_object *bo) +{ + switch (bo->mem.mem_type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return DRM_BO_FLAG_MEM_LOCAL; + case DRM_BO_MEM_VRAM: + if (bo->mem.num_pages > 128) + return DRM_BO_MEM_TT; + else + return DRM_BO_MEM_LOCAL; + default: + return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; + } +} + +int radeon_ms_init_mem_type(struct drm_device * dev, uint32_t type, + struct drm_mem_type_manager * man) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (type) { + case DRM_BO_MEM_LOCAL: + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CACHED; + man->drm_bus_maptype = 0; + break; + case DRM_BO_MEM_VRAM: + man->flags = _DRM_FLAG_MEMTYPE_FIXED | + _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_NEEDS_IOREMAP; + man->io_addr = NULL; + man->drm_bus_maptype = _DRM_FRAME_BUFFER; + man->io_offset = dev_priv->vram.offset; + man->io_size = dev_priv->vram.size; + break; + case DRM_BO_MEM_TT: + if (!dev_priv->bus_ready) { + DRM_ERROR("Bus isn't initialized while " + "intializing TT memory type\n"); + return -EINVAL; + } + switch(dev_priv->bus_type) { + case RADEON_AGP: + if (!(drm_core_has_AGP(dev) && dev->agp)) { + DRM_ERROR("AGP is not enabled for memory " + "type %u\n", (unsigned)type); + return -EINVAL; + } + man->io_offset = dev->agp->agp_info.aper_base; + man->io_size = dev->agp->agp_info.aper_size * + 1024 * 1024; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CSELECT | + _DRM_FLAG_NEEDS_IOREMAP; + man->drm_bus_maptype = _DRM_AGP; + man->gpu_offset = 0; + break; + default: + man->io_offset = dev_priv->gpu_gart_start; + man->io_size = dev_priv->gpu_gart_size; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_CSELECT | + _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CMA; + man->drm_bus_maptype = _DRM_SCATTER_GATHER; + break; + } + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; + } + return 0; +} + +int radeon_ms_invalidate_caches(struct drm_device * dev, uint64_t flags) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + dev_priv->flush_cache(dev); + return 0; +} + +void radeon_ms_ttm_flush(struct drm_ttm *ttm) +{ + if (!ttm) + return; + + DRM_MEMORYBARRIER(); +} diff --git a/shared-core/radeon_ms_bus.c b/shared-core/radeon_ms_bus.c new file mode 100644 index 00000000..6a782b1c --- /dev/null +++ b/shared-core/radeon_ms_bus.c @@ -0,0 +1,443 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +struct radeon_pcie { + uint32_t gart_table_size; + struct drm_buffer_object *gart_table_object; + volatile uint32_t *gart_table; + struct drm_device *dev; + unsigned long page_last; +}; + +struct radeon_pcie_gart { + struct drm_ttm_backend backend; + struct radeon_pcie *pcie; + unsigned long page_first; + struct page **pages; + unsigned long num_pages; + int populated; + int bound; +}; + +static int pcie_ttm_bind(struct drm_ttm_backend *backend, + struct drm_bo_mem_reg *bo_mem); +static void pcie_ttm_clear(struct drm_ttm_backend *backend); +static void pcie_ttm_destroy(struct drm_ttm_backend *backend); +static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend); +static int pcie_ttm_populate(struct drm_ttm_backend *backend, + unsigned long num_pages, struct page **pages); +static int pcie_ttm_unbind(struct drm_ttm_backend *backend); + +static struct drm_ttm_backend_func radeon_pcie_gart_ttm_backend = +{ + .needs_ub_cache_adjust = pcie_ttm_needs_ub_cache_adjust, + .populate = pcie_ttm_populate, + .clear = pcie_ttm_clear, + .bind = pcie_ttm_bind, + .unbind = pcie_ttm_unbind, + .destroy = pcie_ttm_destroy, +}; + +static void pcie_gart_flush(struct radeon_pcie *pcie) +{ + struct drm_device *dev; + struct drm_radeon_private *dev_priv; + uint32_t flush; + + if (pcie == NULL) { + return; + } + dev = pcie->dev; + dev_priv = dev->dev_private; + flush = dev_priv->driver_state.pcie_tx_gart_cntl; + flush |= PCIE_TX_GART_CNTL__GART_INVALIDATE_TLB; + PCIE_W(PCIE_TX_GART_CNTL, flush); + PCIE_W(PCIE_TX_GART_CNTL, dev_priv->driver_state.pcie_tx_gart_cntl); +} + +static __inline__ uint32_t pcie_gart_get_page_base(struct radeon_pcie *pcie, + unsigned long page) +{ + if (pcie == NULL || pcie->gart_table == NULL) { + return 0; + } + return ((pcie->gart_table[page] & (~0xC)) << 8); +} + +static __inline__ void pcie_gart_set_page_base(struct radeon_pcie *pcie, + unsigned long page, + uint32_t page_base) +{ + if (pcie == NULL || pcie->gart_table == NULL) { + return; + } + pcie->gart_table[page] = cpu_to_le32((page_base >> 8) | 0xC); +} + +static int pcie_ttm_bind(struct drm_ttm_backend *backend, + struct drm_bo_mem_reg *bo_mem) +{ + struct radeon_pcie_gart *pcie_gart; + unsigned long page_first; + unsigned long page_last; + unsigned long page, i; + uint32_t page_base; + + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + page = page_first = bo_mem->mm_node->start; + page_last = page_first + pcie_gart->num_pages; + if (page_first >= pcie_gart->pcie->page_last || + page_last >= pcie_gart->pcie->page_last) + return -EINVAL; + while (page < page_last) { + if (pcie_gart_get_page_base(pcie_gart->pcie, page)) { + return -EBUSY; + } + page++; + } + + for (i = 0, page = page_first; i < pcie_gart->num_pages; i++, page++) { + struct page *cur_page = pcie_gart->pages[i]; + /* write value */ + page_base = page_to_phys(cur_page); + pcie_gart_set_page_base(pcie_gart->pcie, page, page_base); + } + DRM_MEMORYBARRIER(); + pcie_gart_flush(pcie_gart->pcie); + pcie_gart->bound = 1; + pcie_gart->page_first = page_first; + return 0; +} + +static void pcie_ttm_clear(struct drm_ttm_backend *backend) +{ + struct radeon_pcie_gart *pcie_gart; + + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + if (pcie_gart->pages) { + backend->func->unbind(backend); + pcie_gart->pages = NULL; + } + pcie_gart->num_pages = 0; +} + +static void pcie_ttm_destroy(struct drm_ttm_backend *backend) +{ + struct radeon_pcie_gart *pcie_gart; + + if (backend == NULL) { + return; + } + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + if (pcie_gart->pages) { + backend->func->clear(backend); + } + drm_ctl_free(pcie_gart, sizeof(*pcie_gart), DRM_MEM_TTM); +} + +static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend) +{ + return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); +} + +static int pcie_ttm_populate(struct drm_ttm_backend *backend, + unsigned long num_pages, struct page **pages) +{ + struct radeon_pcie_gart *pcie_gart; + + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + pcie_gart->pages = pages; + pcie_gart->num_pages = num_pages; + pcie_gart->populated = 1; + return 0; +} + +static int pcie_ttm_unbind(struct drm_ttm_backend *backend) +{ + struct radeon_pcie_gart *pcie_gart; + unsigned long page, i; + + pcie_gart = container_of(backend, struct radeon_pcie_gart, backend); + if (pcie_gart->bound != 1 || pcie_gart->pcie->gart_table == NULL) { + return -EINVAL; + } + for (i = 0, page = pcie_gart->page_first; i < pcie_gart->num_pages; + i++, page++) { + pcie_gart->pcie->gart_table[page] = 0; + } + pcie_gart_flush(pcie_gart->pcie); + pcie_gart->bound = 0; + pcie_gart->page_first = 0; + return 0; +} + +int radeon_ms_agp_finish(struct drm_device *dev) +{ + drm_agp_release(dev); + return 0; +} + +int radeon_ms_agp_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + struct drm_agp_mode mode; + uint32_t agp_status; + int ret; + + if (dev->agp == NULL) { + DRM_ERROR("[radeon_ms] can't initialize AGP\n"); + return -EINVAL; + } + ret = drm_agp_acquire(dev); + if (ret) { + DRM_ERROR("[radeon_ms] error failed to acquire agp\n"); + return ret; + } + agp_status = MMIO_R(AGP_STATUS); + if ((AGP_STATUS__MODE_AGP30 & agp_status)) { + mode.mode = AGP_STATUS__RATE4X; + } else { + mode.mode = AGP_STATUS__RATE2X_8X; + } + ret = drm_agp_enable(dev, mode); + if (ret) { + DRM_ERROR("[radeon_ms] error failed to enable agp\n"); + return ret; + } + state->agp_command = MMIO_R(AGP_COMMAND) | AGP_COMMAND__AGP_EN; + state->agp_command &= ~AGP_COMMAND__FW_EN; + state->agp_command &= ~AGP_COMMAND__MODE_4G_EN; + state->aic_ctrl = 0; + state->agp_base = REG_S(AGP_BASE, AGP_BASE_ADDR, dev->agp->base); + state->agp_base_2 = 0; + state->bus_cntl = MMIO_R(BUS_CNTL); + state->bus_cntl &= ~BUS_CNTL__BUS_MASTER_DIS; + state->mc_agp_location = + REG_S(MC_AGP_LOCATION, MC_AGP_START, + dev_priv->gpu_gart_start >> 16) | + REG_S(MC_AGP_LOCATION, MC_AGP_TOP, + dev_priv->gpu_gart_end >> 16); + DRM_INFO("[radeon_ms] gpu agp base 0x%08X\n", MMIO_R(AGP_BASE)); + DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n", + MMIO_R(MC_AGP_LOCATION)); + DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n", + state->mc_agp_location); + DRM_INFO("[radeon_ms] bus ready\n"); + return 0; +} + +void radeon_ms_agp_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + MMIO_W(MC_AGP_LOCATION, state->mc_agp_location); + MMIO_W(AGP_BASE, state->agp_base); + MMIO_W(AGP_BASE_2, state->agp_base_2); + MMIO_W(AGP_COMMAND, state->agp_command); +} + +void radeon_ms_agp_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->agp_command = MMIO_R(AGP_COMMAND); + state->agp_base = MMIO_R(AGP_BASE); + state->agp_base_2 = MMIO_R(AGP_BASE_2); + state->mc_agp_location = MMIO_R(MC_AGP_LOCATION); +} + +struct drm_ttm_backend *radeon_ms_pcie_create_ttm(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_pcie_gart *pcie_gart; + + pcie_gart = drm_ctl_calloc(1, sizeof (*pcie_gart), DRM_MEM_TTM); + if (pcie_gart == NULL) { + return NULL; + } + memset(pcie_gart, 0, sizeof(struct radeon_pcie_gart)); + pcie_gart->populated = 0; + pcie_gart->pcie = dev_priv->bus; + pcie_gart->backend.func = &radeon_pcie_gart_ttm_backend; + + return &pcie_gart->backend; +} + +int radeon_ms_pcie_finish(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_pcie *pcie = dev_priv->bus; + + if (!dev_priv->bus_ready || pcie == NULL) { + dev_priv->bus_ready = 0; + return 0; + } + dev_priv->bus_ready = 0; + if (pcie->gart_table) { + drm_mem_reg_iounmap(dev, &pcie->gart_table_object->mem, + (void *)pcie->gart_table); + } + pcie->gart_table = NULL; + if (pcie->gart_table_object) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&pcie->gart_table_object); + mutex_unlock(&dev->struct_mutex); + } + dev_priv->bus = NULL; + drm_free(pcie, sizeof(*pcie), DRM_MEM_DRIVER); + return 0; +} + +int radeon_ms_pcie_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + struct radeon_pcie *pcie; + int ret = 0; + + /* allocate and clear device private structure */ + pcie = drm_alloc(sizeof(struct radeon_pcie), DRM_MEM_DRIVER); + if (pcie == NULL) { + return -ENOMEM; + } + memset(pcie, 0, sizeof(struct radeon_pcie)); + pcie->dev = dev; + dev_priv->bus = (void *)pcie; + pcie->gart_table_size = (dev_priv->gpu_gart_size / RADEON_PAGE_SIZE) * + 4; + /* gart table start must be aligned on 16bytes, align it on one page */ + ret = drm_buffer_object_create(dev, + pcie->gart_table_size, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, + 1, + 0, + &pcie->gart_table_object); + if (ret) { + return ret; + } + ret = drm_mem_reg_ioremap(dev, &pcie->gart_table_object->mem, + (void **) &pcie->gart_table); + if (ret) { + DRM_ERROR("[radeon_ms] error mapping gart table: %d\n", ret); + return ret; + } + DRM_INFO("[radeon_ms] gart table in vram at 0x%08lX\n", + pcie->gart_table_object->offset); + memset((void *)pcie->gart_table, 0, pcie->gart_table_size); + pcie->page_last = pcie->gart_table_size >> 2; + state->pcie_tx_gart_discard_rd_addr_lo = + REG_S(PCIE_TX_GART_DISCARD_RD_ADDR_LO, + GART_DISCARD_RD_ADDR_LO, + dev_priv->gpu_gart_start); + state->pcie_tx_gart_discard_rd_addr_hi = + REG_S(PCIE_TX_GART_DISCARD_RD_ADDR_HI, + GART_DISCARD_RD_ADDR_HI, 0); + state->pcie_tx_gart_base = + REG_S(PCIE_TX_GART_BASE, GART_BASE, + pcie->gart_table_object->offset); + state->pcie_tx_gart_start_lo = + REG_S(PCIE_TX_GART_START_LO, GART_START_LO, + dev_priv->gpu_gart_start); + state->pcie_tx_gart_start_hi = + REG_S(PCIE_TX_GART_START_HI, GART_START_HI, 0); + state->pcie_tx_gart_end_lo = + REG_S(PCIE_TX_GART_END_LO, GART_END_LO, dev_priv->gpu_gart_end); + state->pcie_tx_gart_end_hi = + REG_S(PCIE_TX_GART_END_HI, GART_END_HI, 0); + /* FIXME: why this ? */ + state->aic_ctrl = 0; + state->agp_base = 0; + state->agp_base_2 = 0; + state->bus_cntl = MMIO_R(BUS_CNTL); + state->mc_agp_location = REG_S(MC_AGP_LOCATION, MC_AGP_START, 0xffc0) | + REG_S(MC_AGP_LOCATION, MC_AGP_TOP, 0xffff); + state->pcie_tx_gart_cntl = + PCIE_TX_GART_CNTL__GART_EN | + REG_S(PCIE_TX_GART_CNTL, GART_UNMAPPED_ACCESS, + GART_UNMAPPED_ACCESS__DISCARD) | + REG_S(PCIE_TX_GART_CNTL, GART_MODE, GART_MODE__CACHE_32x128) | + REG_S(PCIE_TX_GART_CNTL, GART_RDREQPATH_SEL, + GART_RDREQPATH_SEL__HDP); + DRM_INFO("[radeon_ms] gpu gart start 0x%08X\n", + PCIE_R(PCIE_TX_GART_START_LO)); + DRM_INFO("[radeon_ms] gpu gart end 0x%08X\n", + PCIE_R(PCIE_TX_GART_END_LO)); + DRM_INFO("[radeon_ms] bus ready\n"); + return 0; +} + +void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + /* disable gart before programing other registers */ + radeon_ms_agp_restore(dev, state); + PCIE_W(PCIE_TX_GART_CNTL, 0); + PCIE_W(PCIE_TX_GART_BASE, state->pcie_tx_gart_base); + PCIE_W(PCIE_TX_GART_BASE, state->pcie_tx_gart_base); + PCIE_W(PCIE_TX_GART_DISCARD_RD_ADDR_HI, + state->pcie_tx_gart_discard_rd_addr_hi); + PCIE_W(PCIE_TX_GART_DISCARD_RD_ADDR_LO, + state->pcie_tx_gart_discard_rd_addr_lo); + PCIE_W(PCIE_TX_GART_START_HI, state->pcie_tx_gart_start_hi); + PCIE_W(PCIE_TX_GART_START_LO, state->pcie_tx_gart_start_lo); + PCIE_W(PCIE_TX_GART_END_HI, state->pcie_tx_gart_end_hi); + PCIE_W(PCIE_TX_GART_END_LO, state->pcie_tx_gart_end_lo); + PCIE_W(PCIE_TX_GART_CNTL, state->pcie_tx_gart_cntl); +} + +void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + radeon_ms_agp_save(dev, state); + state->pcie_tx_gart_base = PCIE_R(PCIE_TX_GART_BASE); + state->pcie_tx_gart_base = PCIE_R(PCIE_TX_GART_BASE); + state->pcie_tx_gart_discard_rd_addr_hi = + PCIE_R(PCIE_TX_GART_DISCARD_RD_ADDR_HI); + state->pcie_tx_gart_discard_rd_addr_lo = + PCIE_R(PCIE_TX_GART_DISCARD_RD_ADDR_LO); + state->pcie_tx_gart_start_hi = PCIE_R(PCIE_TX_GART_START_HI); + state->pcie_tx_gart_start_lo = PCIE_R(PCIE_TX_GART_START_LO); + state->pcie_tx_gart_end_hi = PCIE_R(PCIE_TX_GART_END_HI); + state->pcie_tx_gart_end_lo = PCIE_R(PCIE_TX_GART_END_LO); + state->pcie_tx_gart_cntl = PCIE_R(PCIE_TX_GART_CNTL); +} diff --git a/shared-core/radeon_ms_cp.c b/shared-core/radeon_ms_cp.c new file mode 100644 index 00000000..7426facb --- /dev/null +++ b/shared-core/radeon_ms_cp.c @@ -0,0 +1,341 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#include "radeon_ms.h" + +static int radeon_ms_test_ring_buffer(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i, ret; + uint32_t cmd[4]; + + MMIO_W(SCRATCH_REG4, 0); + cmd[0] = CP_PACKET0(SCRATCH_REG4, 0); + cmd[1] = 0xdeadbeef; + cmd[2] = CP_PACKET0(WAIT_UNTIL, 0); + cmd[3] = WAIT_UNTIL__WAIT_2D_IDLECLEAN | + WAIT_UNTIL__WAIT_HOST_IDLECLEAN; + DRM_MEMORYBARRIER(); + ret = radeon_ms_ring_emit(dev, cmd, 4); + if (ret) { + return 0; + } + DRM_UDELAY(100); + + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (MMIO_R(SCRATCH_REG4) == 0xdeadbeef) { + DRM_INFO("[radeon_ms] cp test succeeded in %d usecs\n", + i); + return 1; + } + DRM_UDELAY(1); + } + DRM_INFO("[radeon_ms] cp test failed\n"); + return 0; +} + +static int radeon_ms_test_write_back(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + if (dev_priv->ring_buffer_object == NULL || + dev_priv->ring_buffer == NULL) + return 0; + dev_priv->write_back_area[0] = 0x0; + MMIO_W(SCRATCH_REG0, 0xdeadbeef); + for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { + if (dev_priv->write_back_area[0] == 0xdeadbeef) + break; + DRM_UDELAY(1); + } + if (tmp < dev_priv->usec_timeout) { + DRM_INFO("[radeon_ms] writeback test succeeded in %d usecs\n", + tmp); + return 1; + } + MMIO_W(SCRATCH_UMSK, 0x0); + DRM_INFO("[radeon_ms] writeback test failed\n"); + return 0; +} + +static __inline__ void radeon_ms_load_mc(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + MMIO_W(CP_ME_RAM_ADDR, 0); + for (i = 0; i < 256; i++) { + MMIO_W(CP_ME_RAM_DATAH, dev_priv->microcode[(i * 2) + 1]); + MMIO_W(CP_ME_RAM_DATAL, dev_priv->microcode[(i * 2) + 0]); + } +} + +int radeon_ms_cp_finish(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + dev_priv->cp_ready = 0; + radeon_ms_wait_for_idle(dev); + DRM_INFO("[radeon_ms] cp idle\n"); + radeon_ms_cp_stop(dev); + + DRM_INFO("[radeon_ms] ring buffer %p\n", dev_priv->ring_buffer); + if (dev_priv->ring_buffer) { + drm_bo_kunmap(&dev_priv->ring_buffer_map); + } + dev_priv->ring_buffer = NULL; + DRM_INFO("[radeon_ms] ring buffer object %p\n", dev_priv->ring_buffer_object); + if (dev_priv->ring_buffer_object) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&dev_priv->ring_buffer_object); + mutex_unlock(&dev->struct_mutex); + } + return 0; +} + +int radeon_ms_cp_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + int ret = 0; + + if (dev_priv->microcode == NULL) { + DRM_INFO("[radeon_ms] no microcode not starting cp"); + return 0; + } + /* we allocate an extra page for all write back stuff */ + ret = drm_buffer_object_create(dev, + dev_priv->ring_buffer_size + + dev_priv->write_back_area_size, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, + 1, + 0, + &dev_priv->ring_buffer_object); + if (ret) { + return ret; + } + memset(&dev_priv->ring_buffer_map, 0, sizeof(struct drm_bo_kmap_obj)); + ret = drm_bo_kmap(dev_priv->ring_buffer_object, + dev_priv->ring_buffer_object->mem.mm_node->start, + dev_priv->ring_buffer_object->mem.num_pages, + &dev_priv->ring_buffer_map); + if (ret) { + DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); + return ret; + } + dev_priv->ring_buffer = dev_priv->ring_buffer_map.virtual; + dev_priv->write_back_area = + &dev_priv->ring_buffer[dev_priv->ring_buffer_size >> 2]; + /* setup write back offset */ + state->scratch_umsk = 0x7; + state->scratch_addr = + REG_S(SCRATCH_ADDR, SCRATCH_ADDR, + (dev_priv->ring_buffer_object->offset + + dev_priv->ring_buffer_size + + dev_priv->gpu_gart_start) >> 5); + MMIO_W(SCRATCH_ADDR, state->scratch_addr); + MMIO_W(SCRATCH_UMSK, REG_S(SCRATCH_UMSK, SCRATCH_UMSK, 0x7)); + DRM_INFO("[radeon_ms] write back at 0x%08X in gpu space\n", + MMIO_R(SCRATCH_ADDR)); + dev_priv->write_back = radeon_ms_test_write_back(dev); + + /* stop cp so it's in know state */ + radeon_ms_cp_stop(dev); + if (dev_priv->ring_rptr) { + DRM_INFO("[radeon_ms] failed to set cp read ptr to 0\n"); + } else { + DRM_INFO("[radeon_ms] set cp read ptr to 0\n"); + } + dev_priv->ring_mask = (dev_priv->ring_buffer_size / 4) - 1; + + /* load microcode */ + DRM_INFO("[radeon_ms] load microcode\n"); + radeon_ms_load_mc(dev); + /* initialize CP registers */ + state->cp_rb_cntl = + REG_S(CP_RB_CNTL, RB_BUFSZ, + drm_order(dev_priv->ring_buffer_size / 8)) | + REG_S(CP_RB_CNTL, RB_BLKSZ, drm_order(4096 / 8)) | + REG_S(CP_RB_CNTL, MAX_FETCH, 2); + if (!dev_priv->write_back) { + state->cp_rb_cntl |= CP_RB_CNTL__RB_NO_UPDATE; + } + state->cp_rb_base = + REG_S(CP_RB_BASE, RB_BASE, + (dev_priv->ring_buffer_object->offset + + dev_priv->gpu_gart_start) >> 2); + /* read ptr writeback just after the + * 8 scratch registers 32 = 8*4 */ + state->cp_rb_rptr_addr = + REG_S(CP_RB_RPTR_ADDR, RB_RPTR_ADDR, + (dev_priv->ring_buffer_object->offset + + dev_priv->ring_buffer_size + 32 + + dev_priv->gpu_gart_start) >> 2); + state->cp_rb_wptr = dev_priv->ring_wptr; + state->cp_rb_wptr_delay = + REG_S(CP_RB_WPTR_DELAY, PRE_WRITE_TIMER, 64) | + REG_S(CP_RB_WPTR_DELAY, PRE_WRITE_LIMIT, 8); + state->cp_rb_wptr_delay = 0; + + radeon_ms_cp_restore(dev, state); + DRM_INFO("[radeon_ms] ring buffer at 0x%08X in gpu space\n", + MMIO_R(CP_RB_BASE)); + + /* compute free space */ + dev_priv->ring_free = 0; + ret = radeon_ms_cp_wait(dev, 64); + if (ret) { + /* we shouldn't fail here */ + DRM_INFO("[radeon_ms] failed to get ring free space\n"); + return ret; + } + DRM_INFO("[radeon_ms] free ring size: %d\n", dev_priv->ring_free * 4); + + MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE, + CSQ_MODE__CSQ_PRIBM_INDBM)); + if (!radeon_ms_test_ring_buffer(dev)) { + DRM_INFO("[radeon_ms] cp doesn't work\n"); + /* disable ring should wait idle before */ + radeon_ms_cp_stop(dev); + return -EBUSY; + } + /* waaooo the cp is ready & working */ + DRM_INFO("[radeon_ms] cp ready, enjoy\n"); + dev_priv->cp_ready = 1; + return 0; +} + +void radeon_ms_cp_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + radeon_ms_wait_for_idle(dev); + MMIO_W(SCRATCH_ADDR, state->scratch_addr); + MMIO_W(SCRATCH_UMSK, state->scratch_umsk); + MMIO_W(CP_RB_BASE, state->cp_rb_base); + MMIO_W(CP_RB_RPTR_ADDR, state->cp_rb_rptr_addr); + MMIO_W(CP_RB_WPTR_DELAY, state->cp_rb_wptr_delay); + MMIO_W(CP_RB_CNTL, state->cp_rb_cntl); + /* Sync everything up */ + MMIO_W(ISYNC_CNTL, ISYNC_CNTL__ISYNC_ANY2D_IDLE3D | + ISYNC_CNTL__ISYNC_ANY3D_IDLE2D | + ISYNC_CNTL__ISYNC_WAIT_IDLEGUI | + ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI); +} + +void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->scratch_addr = MMIO_R(SCRATCH_ADDR); + state->scratch_umsk = MMIO_R(SCRATCH_UMSK); + state->cp_rb_base = MMIO_R(CP_RB_BASE); + state->cp_rb_rptr_addr = MMIO_R(CP_RB_RPTR_ADDR); + state->cp_rb_wptr_delay = MMIO_R(CP_RB_WPTR_DELAY); + state->cp_rb_wptr = MMIO_R(CP_RB_WPTR); + state->cp_rb_cntl = MMIO_R(CP_RB_CNTL); +} + +void radeon_ms_cp_stop(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE, + CSQ_MODE__CSQ_PRIDIS_INDDIS)); + MMIO_W(CP_RB_CNTL, CP_RB_CNTL__RB_RPTR_WR_ENA); + MMIO_W(CP_RB_RPTR_WR, 0); + MMIO_W(CP_RB_WPTR, 0); + DRM_UDELAY(5); + dev_priv->ring_wptr = dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR); + MMIO_W(CP_RB_WPTR, dev_priv->ring_wptr); +} + +int radeon_ms_cp_wait(struct drm_device *dev, int n) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t i, last_rptr, p = 0; + + last_rptr = MMIO_R(CP_RB_RPTR); + for (i = 0; i < dev_priv->usec_timeout; i++) { + dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR); + if (last_rptr != dev_priv->ring_rptr) { + /* the ring is progressing no lockup */ + p = 1; + } + dev_priv->ring_free = (((int)dev_priv->ring_rptr) - + ((int)dev_priv->ring_wptr)); + if (dev_priv->ring_free <= 0) + dev_priv->ring_free += (dev_priv->ring_buffer_size / 4); + if (dev_priv->ring_free > n) + return 0; + last_rptr = dev_priv->ring_rptr; + DRM_UDELAY(1); + } + if (p) { + DRM_INFO("[radeon_ms] timed out waiting free slot\n"); + } else { + DRM_INFO("[radeon_ms] cp have lickely locked up\n"); + } + return -EBUSY; +} + +int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count) +{ + static spinlock_t ring_lock = SPIN_LOCK_UNLOCKED; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t i = 0; + + if (!count) + return -EINVAL; + + spin_lock(&ring_lock); + if (dev_priv->ring_free <= (count)) { + spin_unlock(&ring_lock); + return -EBUSY; + } + dev_priv->ring_free -= count; + for (i = 0; i < count; i++) { + dev_priv->ring_buffer[dev_priv->ring_wptr] = cmd[i]; + dev_priv->ring_wptr++; + dev_priv->ring_wptr &= dev_priv->ring_mask; + } + /* commit ring */ + DRM_MEMORYBARRIER(); + MMIO_W(CP_RB_WPTR, REG_S(CP_RB_WPTR, RB_WPTR, dev_priv->ring_wptr)); + /* read from PCI bus to ensure correct posting */ + MMIO_R(CP_RB_WPTR); + spin_unlock(&ring_lock); + return 0; +} diff --git a/shared-core/radeon_ms_cp_mc.c b/shared-core/radeon_ms_cp_mc.c new file mode 100644 index 00000000..f0397d87 --- /dev/null +++ b/shared-core/radeon_ms_cp_mc.c @@ -0,0 +1,801 @@ +/* + * Copyright 2007 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. + */ +#include "radeon_ms.h" + +/* CP microcode (from ATI) */ + +const uint32_t radeon_cp_microcode[] = { + 0x21007000, 0000000000, + 0x20007000, 0000000000, + 0x000000b4, 0x00000004, + 0x000000b8, 0x00000004, + 0x6f5b4d4c, 0000000000, + 0x4c4c427f, 0000000000, + 0x5b568a92, 0000000000, + 0x4ca09c6d, 0000000000, + 0xad4c4c4c, 0000000000, + 0x4ce1af3d, 0000000000, + 0xd8afafaf, 0000000000, + 0xd64c4cdc, 0000000000, + 0x4cd10d10, 0000000000, + 0x000f0000, 0x00000016, + 0x362f242d, 0000000000, + 0x00000012, 0x00000004, + 0x000f0000, 0x00000016, + 0x362f282d, 0000000000, + 0x000380e7, 0x00000002, + 0x04002c97, 0x00000002, + 0x000f0001, 0x00000016, + 0x333a3730, 0000000000, + 0x000077ef, 0x00000002, + 0x00061000, 0x00000002, + 0x00000021, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00061000, 0x00000002, + 0x00000021, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00061000, 0x00000002, + 0x00000021, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00000017, 0x00000004, + 0x0003802b, 0x00000002, + 0x040067e0, 0x00000002, + 0x00000017, 0x00000004, + 0x000077e0, 0x00000002, + 0x00065000, 0x00000002, + 0x000037e1, 0x00000002, + 0x040067e1, 0x00000006, + 0x000077e0, 0x00000002, + 0x000077e1, 0x00000002, + 0x000077e1, 0x00000006, + 0xffffffff, 0000000000, + 0x10000000, 0000000000, + 0x0003802b, 0x00000002, + 0x040067e0, 0x00000006, + 0x00007675, 0x00000002, + 0x00007676, 0x00000002, + 0x00007677, 0x00000002, + 0x00007678, 0x00000006, + 0x0003802c, 0x00000002, + 0x04002676, 0x00000002, + 0x00007677, 0x00000002, + 0x00007678, 0x00000006, + 0x0000002f, 0x00000018, + 0x0000002f, 0x00000018, + 0000000000, 0x00000006, + 0x00000030, 0x00000018, + 0x00000030, 0x00000018, + 0000000000, 0x00000006, + 0x01605000, 0x00000002, + 0x00065000, 0x00000002, + 0x00098000, 0x00000002, + 0x00061000, 0x00000002, + 0x64c0603e, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00080000, 0x00000016, + 0000000000, 0000000000, + 0x0400251d, 0x00000002, + 0x00007580, 0x00000002, + 0x00067581, 0x00000002, + 0x04002580, 0x00000002, + 0x00067581, 0x00000002, + 0x00000049, 0x00000004, + 0x00005000, 0000000000, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00061000, 0x00000002, + 0x0000750e, 0x00000002, + 0x00019000, 0x00000002, + 0x00011055, 0x00000014, + 0x00000055, 0x00000012, + 0x0400250f, 0x00000002, + 0x0000504f, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00007565, 0x00000002, + 0x00007566, 0x00000002, + 0x00000058, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x01e655b4, 0x00000002, + 0x4401b0e4, 0x00000002, + 0x01c110e4, 0x00000002, + 0x26667066, 0x00000018, + 0x040c2565, 0x00000002, + 0x00000066, 0x00000018, + 0x04002564, 0x00000002, + 0x00007566, 0x00000002, + 0x0000005d, 0x00000004, + 0x00401069, 0x00000008, + 0x00101000, 0x00000002, + 0x000d80ff, 0x00000002, + 0x0080006c, 0x00000008, + 0x000f9000, 0x00000002, + 0x000e00ff, 0x00000002, + 0000000000, 0x00000006, + 0x0000008f, 0x00000018, + 0x0000005b, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00007576, 0x00000002, + 0x00065000, 0x00000002, + 0x00009000, 0x00000002, + 0x00041000, 0x00000002, + 0x0c00350e, 0x00000002, + 0x00049000, 0x00000002, + 0x00051000, 0x00000002, + 0x01e785f8, 0x00000002, + 0x00200000, 0x00000002, + 0x0060007e, 0x0000000c, + 0x00007563, 0x00000002, + 0x006075f0, 0x00000021, + 0x20007073, 0x00000004, + 0x00005073, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00007576, 0x00000002, + 0x00007577, 0x00000002, + 0x0000750e, 0x00000002, + 0x0000750f, 0x00000002, + 0x00a05000, 0x00000002, + 0x00600083, 0x0000000c, + 0x006075f0, 0x00000021, + 0x000075f8, 0x00000002, + 0x00000083, 0x00000004, + 0x000a750e, 0x00000002, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x0020750f, 0x00000002, + 0x00600086, 0x00000004, + 0x00007570, 0x00000002, + 0x00007571, 0x00000002, + 0x00007572, 0x00000006, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00005000, 0x00000002, + 0x00a05000, 0x00000002, + 0x00007568, 0x00000002, + 0x00061000, 0x00000002, + 0x00000095, 0x0000000c, + 0x00058000, 0x00000002, + 0x0c607562, 0x00000002, + 0x00000097, 0x00000004, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x00600096, 0x00000004, + 0x400070e5, 0000000000, + 0x000380e6, 0x00000002, + 0x040025c5, 0x00000002, + 0x000380e5, 0x00000002, + 0x000000a8, 0x0000001c, + 0x000650aa, 0x00000018, + 0x040025bb, 0x00000002, + 0x000610ab, 0x00000018, + 0x040075bc, 0000000000, + 0x000075bb, 0x00000002, + 0x000075bc, 0000000000, + 0x00090000, 0x00000006, + 0x00090000, 0x00000002, + 0x000d8002, 0x00000006, + 0x00007832, 0x00000002, + 0x00005000, 0x00000002, + 0x000380e7, 0x00000002, + 0x04002c97, 0x00000002, + 0x00007820, 0x00000002, + 0x00007821, 0x00000002, + 0x00007800, 0000000000, + 0x01200000, 0x00000002, + 0x20077000, 0x00000002, + 0x01200000, 0x00000002, + 0x20007000, 0x00000002, + 0x00061000, 0x00000002, + 0x0120751b, 0x00000002, + 0x8040750a, 0x00000002, + 0x8040750b, 0x00000002, + 0x00110000, 0x00000002, + 0x000380e5, 0x00000002, + 0x000000c6, 0x0000001c, + 0x000610ab, 0x00000018, + 0x844075bd, 0x00000002, + 0x000610aa, 0x00000018, + 0x840075bb, 0x00000002, + 0x000610ab, 0x00000018, + 0x844075bc, 0x00000002, + 0x000000c9, 0x00000004, + 0x804075bd, 0x00000002, + 0x800075bb, 0x00000002, + 0x804075bc, 0x00000002, + 0x00108000, 0x00000002, + 0x01400000, 0x00000002, + 0x006000cd, 0x0000000c, + 0x20c07000, 0x00000020, + 0x000000cf, 0x00000012, + 0x00800000, 0x00000006, + 0x0080751d, 0x00000006, + 0000000000, 0000000000, + 0x0000775c, 0x00000002, + 0x00a05000, 0x00000002, + 0x00661000, 0x00000002, + 0x0460275d, 0x00000020, + 0x00004000, 0000000000, + 0x01e00830, 0x00000002, + 0x21007000, 0000000000, + 0x6464614d, 0000000000, + 0x69687420, 0000000000, + 0x00000073, 0000000000, + 0000000000, 0000000000, + 0x00005000, 0x00000002, + 0x000380d0, 0x00000002, + 0x040025e0, 0x00000002, + 0x000075e1, 0000000000, + 0x00000001, 0000000000, + 0x000380e0, 0x00000002, + 0x04002394, 0x00000002, + 0x00005000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0x00000008, 0000000000, + 0x00000004, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, +}; + +const uint32_t r200_cp_microcode[] = { + 0x21007000, 0000000000, + 0x20007000, 0000000000, + 0x000000ab, 0x00000004, + 0x000000af, 0x00000004, + 0x66544a49, 0000000000, + 0x49494174, 0000000000, + 0x54517d83, 0000000000, + 0x498d8b64, 0000000000, + 0x49494949, 0000000000, + 0x49da493c, 0000000000, + 0x49989898, 0000000000, + 0xd34949d5, 0000000000, + 0x9dc90e11, 0000000000, + 0xce9b9b9b, 0000000000, + 0x000f0000, 0x00000016, + 0x352e232c, 0000000000, + 0x00000013, 0x00000004, + 0x000f0000, 0x00000016, + 0x352e272c, 0000000000, + 0x000f0001, 0x00000016, + 0x3239362f, 0000000000, + 0x000077ef, 0x00000002, + 0x00061000, 0x00000002, + 0x00000020, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00061000, 0x00000002, + 0x00000020, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00061000, 0x00000002, + 0x00000020, 0x0000001a, + 0x00004000, 0x0000001e, + 0x00000016, 0x00000004, + 0x0003802a, 0x00000002, + 0x040067e0, 0x00000002, + 0x00000016, 0x00000004, + 0x000077e0, 0x00000002, + 0x00065000, 0x00000002, + 0x000037e1, 0x00000002, + 0x040067e1, 0x00000006, + 0x000077e0, 0x00000002, + 0x000077e1, 0x00000002, + 0x000077e1, 0x00000006, + 0xffffffff, 0000000000, + 0x10000000, 0000000000, + 0x0003802a, 0x00000002, + 0x040067e0, 0x00000006, + 0x00007675, 0x00000002, + 0x00007676, 0x00000002, + 0x00007677, 0x00000002, + 0x00007678, 0x00000006, + 0x0003802b, 0x00000002, + 0x04002676, 0x00000002, + 0x00007677, 0x00000002, + 0x00007678, 0x00000006, + 0x0000002e, 0x00000018, + 0x0000002e, 0x00000018, + 0000000000, 0x00000006, + 0x0000002f, 0x00000018, + 0x0000002f, 0x00000018, + 0000000000, 0x00000006, + 0x01605000, 0x00000002, + 0x00065000, 0x00000002, + 0x00098000, 0x00000002, + 0x00061000, 0x00000002, + 0x64c0603d, 0x00000004, + 0x00080000, 0x00000016, + 0000000000, 0000000000, + 0x0400251d, 0x00000002, + 0x00007580, 0x00000002, + 0x00067581, 0x00000002, + 0x04002580, 0x00000002, + 0x00067581, 0x00000002, + 0x00000046, 0x00000004, + 0x00005000, 0000000000, + 0x00061000, 0x00000002, + 0x0000750e, 0x00000002, + 0x00019000, 0x00000002, + 0x00011055, 0x00000014, + 0x00000055, 0x00000012, + 0x0400250f, 0x00000002, + 0x0000504a, 0x00000004, + 0x00007565, 0x00000002, + 0x00007566, 0x00000002, + 0x00000051, 0x00000004, + 0x01e655b4, 0x00000002, + 0x4401b0dc, 0x00000002, + 0x01c110dc, 0x00000002, + 0x2666705d, 0x00000018, + 0x040c2565, 0x00000002, + 0x0000005d, 0x00000018, + 0x04002564, 0x00000002, + 0x00007566, 0x00000002, + 0x00000054, 0x00000004, + 0x00401060, 0x00000008, + 0x00101000, 0x00000002, + 0x000d80ff, 0x00000002, + 0x00800063, 0x00000008, + 0x000f9000, 0x00000002, + 0x000e00ff, 0x00000002, + 0000000000, 0x00000006, + 0x00000080, 0x00000018, + 0x00000054, 0x00000004, + 0x00007576, 0x00000002, + 0x00065000, 0x00000002, + 0x00009000, 0x00000002, + 0x00041000, 0x00000002, + 0x0c00350e, 0x00000002, + 0x00049000, 0x00000002, + 0x00051000, 0x00000002, + 0x01e785f8, 0x00000002, + 0x00200000, 0x00000002, + 0x00600073, 0x0000000c, + 0x00007563, 0x00000002, + 0x006075f0, 0x00000021, + 0x20007068, 0x00000004, + 0x00005068, 0x00000004, + 0x00007576, 0x00000002, + 0x00007577, 0x00000002, + 0x0000750e, 0x00000002, + 0x0000750f, 0x00000002, + 0x00a05000, 0x00000002, + 0x00600076, 0x0000000c, + 0x006075f0, 0x00000021, + 0x000075f8, 0x00000002, + 0x00000076, 0x00000004, + 0x000a750e, 0x00000002, + 0x0020750f, 0x00000002, + 0x00600079, 0x00000004, + 0x00007570, 0x00000002, + 0x00007571, 0x00000002, + 0x00007572, 0x00000006, + 0x00005000, 0x00000002, + 0x00a05000, 0x00000002, + 0x00007568, 0x00000002, + 0x00061000, 0x00000002, + 0x00000084, 0x0000000c, + 0x00058000, 0x00000002, + 0x0c607562, 0x00000002, + 0x00000086, 0x00000004, + 0x00600085, 0x00000004, + 0x400070dd, 0000000000, + 0x000380dd, 0x00000002, + 0x00000093, 0x0000001c, + 0x00065095, 0x00000018, + 0x040025bb, 0x00000002, + 0x00061096, 0x00000018, + 0x040075bc, 0000000000, + 0x000075bb, 0x00000002, + 0x000075bc, 0000000000, + 0x00090000, 0x00000006, + 0x00090000, 0x00000002, + 0x000d8002, 0x00000006, + 0x00005000, 0x00000002, + 0x00007821, 0x00000002, + 0x00007800, 0000000000, + 0x00007821, 0x00000002, + 0x00007800, 0000000000, + 0x01665000, 0x00000002, + 0x000a0000, 0x00000002, + 0x000671cc, 0x00000002, + 0x0286f1cd, 0x00000002, + 0x000000a3, 0x00000010, + 0x21007000, 0000000000, + 0x000000aa, 0x0000001c, + 0x00065000, 0x00000002, + 0x000a0000, 0x00000002, + 0x00061000, 0x00000002, + 0x000b0000, 0x00000002, + 0x38067000, 0x00000002, + 0x000a00a6, 0x00000004, + 0x20007000, 0000000000, + 0x01200000, 0x00000002, + 0x20077000, 0x00000002, + 0x01200000, 0x00000002, + 0x20007000, 0000000000, + 0x00061000, 0x00000002, + 0x0120751b, 0x00000002, + 0x8040750a, 0x00000002, + 0x8040750b, 0x00000002, + 0x00110000, 0x00000002, + 0x000380dd, 0x00000002, + 0x000000bd, 0x0000001c, + 0x00061096, 0x00000018, + 0x844075bd, 0x00000002, + 0x00061095, 0x00000018, + 0x840075bb, 0x00000002, + 0x00061096, 0x00000018, + 0x844075bc, 0x00000002, + 0x000000c0, 0x00000004, + 0x804075bd, 0x00000002, + 0x800075bb, 0x00000002, + 0x804075bc, 0x00000002, + 0x00108000, 0x00000002, + 0x01400000, 0x00000002, + 0x006000c4, 0x0000000c, + 0x20c07000, 0x00000020, + 0x000000c6, 0x00000012, + 0x00800000, 0x00000006, + 0x0080751d, 0x00000006, + 0x000025bb, 0x00000002, + 0x000040c0, 0x00000004, + 0x0000775c, 0x00000002, + 0x00a05000, 0x00000002, + 0x00661000, 0x00000002, + 0x0460275d, 0x00000020, + 0x00004000, 0000000000, + 0x00007999, 0x00000002, + 0x00a05000, 0x00000002, + 0x00661000, 0x00000002, + 0x0460299b, 0x00000020, + 0x00004000, 0000000000, + 0x01e00830, 0x00000002, + 0x21007000, 0000000000, + 0x00005000, 0x00000002, + 0x00038042, 0x00000002, + 0x040025e0, 0x00000002, + 0x000075e1, 0000000000, + 0x00000001, 0000000000, + 0x000380d9, 0x00000002, + 0x04007394, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, +}; + +const uint32_t r300_cp_microcode[] = { + 0x4200e000, 0000000000, + 0x4000e000, 0000000000, + 0x000000af, 0x00000008, + 0x000000b3, 0x00000008, + 0x6c5a504f, 0000000000, + 0x4f4f497a, 0000000000, + 0x5a578288, 0000000000, + 0x4f91906a, 0000000000, + 0x4f4f4f4f, 0000000000, + 0x4fe24f44, 0000000000, + 0x4f9c9c9c, 0000000000, + 0xdc4f4fde, 0000000000, + 0xa1cd4f4f, 0000000000, + 0xd29d9d9d, 0000000000, + 0x4f0f9fd7, 0000000000, + 0x000ca000, 0x00000004, + 0x000d0012, 0x00000038, + 0x0000e8b4, 0x00000004, + 0x000d0014, 0x00000038, + 0x0000e8b6, 0x00000004, + 0x000d0016, 0x00000038, + 0x0000e854, 0x00000004, + 0x000d0018, 0x00000038, + 0x0000e855, 0x00000004, + 0x000d001a, 0x00000038, + 0x0000e856, 0x00000004, + 0x000d001c, 0x00000038, + 0x0000e857, 0x00000004, + 0x000d001e, 0x00000038, + 0x0000e824, 0x00000004, + 0x000d0020, 0x00000038, + 0x0000e825, 0x00000004, + 0x000d0022, 0x00000038, + 0x0000e830, 0x00000004, + 0x000d0024, 0x00000038, + 0x0000f0c0, 0x00000004, + 0x000d0026, 0x00000038, + 0x0000f0c1, 0x00000004, + 0x000d0028, 0x00000038, + 0x0000f041, 0x00000004, + 0x000d002a, 0x00000038, + 0x0000f184, 0x00000004, + 0x000d002c, 0x00000038, + 0x0000f185, 0x00000004, + 0x000d002e, 0x00000038, + 0x0000f186, 0x00000004, + 0x000d0030, 0x00000038, + 0x0000f187, 0x00000004, + 0x000d0032, 0x00000038, + 0x0000f180, 0x00000004, + 0x000d0034, 0x00000038, + 0x0000f393, 0x00000004, + 0x000d0036, 0x00000038, + 0x0000f38a, 0x00000004, + 0x000d0038, 0x00000038, + 0x0000f38e, 0x00000004, + 0x0000e821, 0x00000004, + 0x0140a000, 0x00000004, + 0x00000043, 0x00000018, + 0x00cce800, 0x00000004, + 0x001b0001, 0x00000004, + 0x08004800, 0x00000004, + 0x001b0001, 0x00000004, + 0x08004800, 0x00000004, + 0x001b0001, 0x00000004, + 0x08004800, 0x00000004, + 0x0000003a, 0x00000008, + 0x0000a000, 0000000000, + 0x02c0a000, 0x00000004, + 0x000ca000, 0x00000004, + 0x00130000, 0x00000004, + 0x000c2000, 0x00000004, + 0xc980c045, 0x00000008, + 0x2000451d, 0x00000004, + 0x0000e580, 0x00000004, + 0x000ce581, 0x00000004, + 0x08004580, 0x00000004, + 0x000ce581, 0x00000004, + 0x0000004c, 0x00000008, + 0x0000a000, 0000000000, + 0x000c2000, 0x00000004, + 0x0000e50e, 0x00000004, + 0x00032000, 0x00000004, + 0x00022056, 0x00000028, + 0x00000056, 0x00000024, + 0x0800450f, 0x00000004, + 0x0000a050, 0x00000008, + 0x0000e565, 0x00000004, + 0x0000e566, 0x00000004, + 0x00000057, 0x00000008, + 0x03cca5b4, 0x00000004, + 0x05432000, 0x00000004, + 0x00022000, 0x00000004, + 0x4ccce063, 0x00000030, + 0x08274565, 0x00000004, + 0x00000063, 0x00000030, + 0x08004564, 0x00000004, + 0x0000e566, 0x00000004, + 0x0000005a, 0x00000008, + 0x00802066, 0x00000010, + 0x00202000, 0x00000004, + 0x001b00ff, 0x00000004, + 0x01000069, 0x00000010, + 0x001f2000, 0x00000004, + 0x001c00ff, 0x00000004, + 0000000000, 0x0000000c, + 0x00000085, 0x00000030, + 0x0000005a, 0x00000008, + 0x0000e576, 0x00000004, + 0x000ca000, 0x00000004, + 0x00012000, 0x00000004, + 0x00082000, 0x00000004, + 0x1800650e, 0x00000004, + 0x00092000, 0x00000004, + 0x000a2000, 0x00000004, + 0x000f0000, 0x00000004, + 0x00400000, 0x00000004, + 0x00000079, 0x00000018, + 0x0000e563, 0x00000004, + 0x00c0e5f9, 0x000000c2, + 0x0000006e, 0x00000008, + 0x0000a06e, 0x00000008, + 0x0000e576, 0x00000004, + 0x0000e577, 0x00000004, + 0x0000e50e, 0x00000004, + 0x0000e50f, 0x00000004, + 0x0140a000, 0x00000004, + 0x0000007c, 0x00000018, + 0x00c0e5f9, 0x000000c2, + 0x0000007c, 0x00000008, + 0x0014e50e, 0x00000004, + 0x0040e50f, 0x00000004, + 0x00c0007f, 0x00000008, + 0x0000e570, 0x00000004, + 0x0000e571, 0x00000004, + 0x0000e572, 0x0000000c, + 0x0000a000, 0x00000004, + 0x0140a000, 0x00000004, + 0x0000e568, 0x00000004, + 0x000c2000, 0x00000004, + 0x00000089, 0x00000018, + 0x000b0000, 0x00000004, + 0x18c0e562, 0x00000004, + 0x0000008b, 0x00000008, + 0x00c0008a, 0x00000008, + 0x000700e4, 0x00000004, + 0x00000097, 0x00000038, + 0x000ca099, 0x00000030, + 0x080045bb, 0x00000004, + 0x000c209a, 0x00000030, + 0x0800e5bc, 0000000000, + 0x0000e5bb, 0x00000004, + 0x0000e5bc, 0000000000, + 0x00120000, 0x0000000c, + 0x00120000, 0x00000004, + 0x001b0002, 0x0000000c, + 0x0000a000, 0x00000004, + 0x0000e821, 0x00000004, + 0x0000e800, 0000000000, + 0x0000e821, 0x00000004, + 0x0000e82e, 0000000000, + 0x02cca000, 0x00000004, + 0x00140000, 0x00000004, + 0x000ce1cc, 0x00000004, + 0x050de1cd, 0x00000004, + 0x000000a7, 0x00000020, + 0x4200e000, 0000000000, + 0x000000ae, 0x00000038, + 0x000ca000, 0x00000004, + 0x00140000, 0x00000004, + 0x000c2000, 0x00000004, + 0x00160000, 0x00000004, + 0x700ce000, 0x00000004, + 0x001400aa, 0x00000008, + 0x4000e000, 0000000000, + 0x02400000, 0x00000004, + 0x400ee000, 0x00000004, + 0x02400000, 0x00000004, + 0x4000e000, 0000000000, + 0x000c2000, 0x00000004, + 0x0240e51b, 0x00000004, + 0x0080e50a, 0x00000005, + 0x0080e50b, 0x00000005, + 0x00220000, 0x00000004, + 0x000700e4, 0x00000004, + 0x000000c1, 0x00000038, + 0x000c209a, 0x00000030, + 0x0880e5bd, 0x00000005, + 0x000c2099, 0x00000030, + 0x0800e5bb, 0x00000005, + 0x000c209a, 0x00000030, + 0x0880e5bc, 0x00000005, + 0x000000c4, 0x00000008, + 0x0080e5bd, 0x00000005, + 0x0000e5bb, 0x00000005, + 0x0080e5bc, 0x00000005, + 0x00210000, 0x00000004, + 0x02800000, 0x00000004, + 0x00c000c8, 0x00000018, + 0x4180e000, 0x00000040, + 0x000000ca, 0x00000024, + 0x01000000, 0x0000000c, + 0x0100e51d, 0x0000000c, + 0x000045bb, 0x00000004, + 0x000080c4, 0x00000008, + 0x0000f3ce, 0x00000004, + 0x0140a000, 0x00000004, + 0x00cc2000, 0x00000004, + 0x08c053cf, 0x00000040, + 0x00008000, 0000000000, + 0x0000f3d2, 0x00000004, + 0x0140a000, 0x00000004, + 0x00cc2000, 0x00000004, + 0x08c053d3, 0x00000040, + 0x00008000, 0000000000, + 0x0000f39d, 0x00000004, + 0x0140a000, 0x00000004, + 0x00cc2000, 0x00000004, + 0x08c0539e, 0x00000040, + 0x00008000, 0000000000, + 0x03c00830, 0x00000004, + 0x4200e000, 0000000000, + 0x0000a000, 0x00000004, + 0x200045e0, 0x00000004, + 0x0000e5e1, 0000000000, + 0x00000001, 0000000000, + 0x000700e1, 0x00000004, + 0x0800e394, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, + 0000000000, 0000000000, +}; diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c new file mode 100644 index 00000000..a9387f96 --- /dev/null +++ b/shared-core/radeon_ms_crtc.c @@ -0,0 +1,769 @@ +/* + * Copyright © 2007 Alex Deucher + * Copyright © 2007 Dave Airlie + * Copyright © 2007 Michel Dänzer + * Copyright © 2007 Jerome Glisse + * + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "radeon_ms.h" + +static void radeon_pll1_init(struct drm_radeon_private *dev_priv, + struct radeon_state *state); +static void radeon_pll1_restore(struct drm_radeon_private *dev_priv, + struct radeon_state *state); +static void radeon_pll1_save(struct drm_radeon_private *dev_priv, + struct radeon_state *state); +static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc); + +/** + * radeon_ms_crtc1_init - initialize CRTC state + * @dev_priv: radeon private structure + * @state: state structure to initialize to default value + * + * Initialize CRTC state to default values + */ +static void radeon_ms_crtc1_init(struct drm_radeon_private *dev_priv, + struct radeon_state *state) +{ + state->surface_cntl = SURFACE_CNTL__SURF_TRANSLATION_DIS; + state->surface0_info = 0; + state->surface0_lower_bound = 0; + state->surface0_upper_bound = 0; + state->surface1_info = 0; + state->surface1_lower_bound = 0; + state->surface1_upper_bound = 0; + state->surface2_info = 0; + state->surface2_lower_bound = 0; + state->surface2_upper_bound = 0; + state->surface3_info = 0; + state->surface3_lower_bound = 0; + state->surface3_upper_bound = 0; + state->surface4_info = 0; + state->surface4_lower_bound = 0; + state->surface4_upper_bound = 0; + state->surface5_info = 0; + state->surface5_lower_bound = 0; + state->surface5_upper_bound = 0; + state->surface6_info = 0; + state->surface6_lower_bound = 0; + state->surface6_upper_bound = 0; + state->surface7_info = 0; + state->surface7_lower_bound = 0; + state->surface7_upper_bound = 0; + state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN | + CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; + state->crtc_ext_cntl = CRTC_EXT_CNTL__VGA_ATI_LINEAR | + CRTC_EXT_CNTL__VGA_XCRT_CNT_EN | + CRTC_EXT_CNTL__CRT_ON; + state->crtc_h_total_disp = 0; + state->crtc_h_sync_strt_wid = 0; + state->crtc_v_total_disp = 0; + state->crtc_v_sync_strt_wid = 0; + state->crtc_offset = 0; + state->crtc_pitch = 0; + state->crtc_more_cntl = 0; + state->crtc_tile_x0_y0 = 0; + state->crtc_offset_cntl = 0; + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + state->crtc_offset_cntl |= REG_S(CRTC_OFFSET_CNTL, + CRTC_MICRO_TILE_BUFFER_MODE, + CRTC_MICRO_TILE_BUFFER_MODE__DIS); + break; + default: + DRM_ERROR("Unknown radeon family, aborting\n"); + return; + } + radeon_pll1_init(dev_priv, state); +} + +/** + * radeon_pll1_init - initialize PLL1 state + * @dev_priv: radeon private structure + * @state: state structure to initialize to default value + * + * Initialize PLL1 state to default values + */ +static void radeon_pll1_init(struct drm_radeon_private *dev_priv, + struct radeon_state *state) +{ + state->clock_cntl_index = 0; + state->ppll_cntl = PPLL_R(PPLL_CNTL); + state->ppll_cntl |= PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN | + PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC | + PPLL_CNTL__PPLL_VGA_ATOMIC_UPDATE_EN; + state->ppll_cntl &= ~PPLL_CNTL__PPLL_TST_EN; + state->ppll_cntl &= ~PPLL_CNTL__PPLL_TCPOFF; + state->ppll_cntl &= ~PPLL_CNTL__PPLL_TVCOMAX; + state->ppll_cntl &= ~PPLL_CNTL__PPLL_DISABLE_AUTO_RESET; + state->ppll_ref_div = 0; + state->ppll_ref_div = REG_S(PPLL_REF_DIV, PPLL_REF_DIV, 12) | + REG_S(PPLL_REF_DIV, PPLL_REF_DIV_SRC, PPLL_REF_DIV_SRC__XTALIN); + state->ppll_div_0 = 0; + state->ppll_div_1 = 0; + state->ppll_div_2 = 0; + state->ppll_div_3 = 0; + state->vclk_ecp_cntl = 0; + state->htotal_cntl = 0; +} + +/** + * radeon_ms_crtc1_restore - restore CRTC state + * @dev_priv: radeon private structure + * @state: CRTC state to restore + */ +void radeon_ms_crtc1_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + /* We prevent the CRTC from hitting the memory controller until + * fully programmed + */ + MMIO_W(CRTC_GEN_CNTL, ~CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B & + state->crtc_gen_cntl); + MMIO_W(CRTC_EXT_CNTL, CRTC_EXT_CNTL__CRTC_VSYNC_DIS | + CRTC_EXT_CNTL__CRTC_HSYNC_DIS | + CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | + state->crtc_ext_cntl); + MMIO_W(SURFACE_CNTL, state->surface_cntl); + MMIO_W(SURFACE0_INFO, state->surface0_info); + MMIO_W(SURFACE0_LOWER_BOUND, state->surface0_lower_bound); + MMIO_W(SURFACE0_UPPER_BOUND, state->surface0_upper_bound); + MMIO_W(SURFACE1_INFO, state->surface1_info); + MMIO_W(SURFACE1_LOWER_BOUND, state->surface1_lower_bound); + MMIO_W(SURFACE1_UPPER_BOUND, state->surface1_upper_bound); + MMIO_W(SURFACE2_INFO, state->surface2_info); + MMIO_W(SURFACE2_LOWER_BOUND, state->surface2_lower_bound); + MMIO_W(SURFACE2_UPPER_BOUND, state->surface2_upper_bound); + MMIO_W(SURFACE3_INFO, state->surface3_info); + MMIO_W(SURFACE3_LOWER_BOUND, state->surface3_lower_bound); + MMIO_W(SURFACE3_UPPER_BOUND, state->surface3_upper_bound); + MMIO_W(SURFACE4_INFO, state->surface4_info); + MMIO_W(SURFACE4_LOWER_BOUND, state->surface4_lower_bound); + MMIO_W(SURFACE4_UPPER_BOUND, state->surface4_upper_bound); + MMIO_W(SURFACE5_INFO, state->surface5_info); + MMIO_W(SURFACE5_LOWER_BOUND, state->surface5_lower_bound); + MMIO_W(SURFACE5_UPPER_BOUND, state->surface5_upper_bound); + MMIO_W(SURFACE6_INFO, state->surface6_info); + MMIO_W(SURFACE6_LOWER_BOUND, state->surface6_lower_bound); + MMIO_W(SURFACE6_UPPER_BOUND, state->surface6_upper_bound); + MMIO_W(SURFACE7_INFO, state->surface7_info); + MMIO_W(SURFACE7_LOWER_BOUND, state->surface7_lower_bound); + MMIO_W(SURFACE7_UPPER_BOUND, state->surface7_upper_bound); + MMIO_W(CRTC_H_TOTAL_DISP, state->crtc_h_total_disp); + MMIO_W(CRTC_H_SYNC_STRT_WID, state->crtc_h_sync_strt_wid); + MMIO_W(CRTC_V_TOTAL_DISP, state->crtc_v_total_disp); + MMIO_W(CRTC_V_SYNC_STRT_WID, state->crtc_v_sync_strt_wid); + MMIO_W(FP_H_SYNC_STRT_WID, state->fp_h_sync_strt_wid); + MMIO_W(FP_V_SYNC_STRT_WID, state->fp_v_sync_strt_wid); + MMIO_W(FP_CRTC_H_TOTAL_DISP, state->fp_crtc_h_total_disp); + MMIO_W(FP_CRTC_V_TOTAL_DISP, state->fp_crtc_v_total_disp); + MMIO_W(CRTC_TILE_X0_Y0, state->crtc_tile_x0_y0); + MMIO_W(CRTC_OFFSET_CNTL, state->crtc_offset_cntl); + MMIO_W(CRTC_OFFSET, state->crtc_offset); + MMIO_W(CRTC_PITCH, state->crtc_pitch); + radeon_pll1_restore(dev_priv, state); + MMIO_W(CRTC_MORE_CNTL, state->crtc_more_cntl); + MMIO_W(CRTC_GEN_CNTL, state->crtc_gen_cntl); + MMIO_W(CRTC_EXT_CNTL, state->crtc_ext_cntl); +} + +/** + * radeon_pll1_restore - restore PLL1 state + * @dev_priv: radeon private structure + * @state: PLL1 state to restore + */ +static void radeon_pll1_restore(struct drm_radeon_private *dev_priv, + struct radeon_state *state) +{ + uint32_t tmp; + + /* switch to gpu clock while programing new clock */ + MMIO_W(CLOCK_CNTL_INDEX, state->clock_cntl_index); + tmp = state->vclk_ecp_cntl; + tmp = REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL, VCLK_SRC_SEL__CPUCLK); + PPLL_W(VCLK_ECP_CNTL, tmp); + /* reset PLL and update atomicly */ + state->ppll_cntl |= PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN | + PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC; + + PPLL_W(PPLL_CNTL, state->ppll_cntl | PPLL_CNTL__PPLL_RESET); + PPLL_W(PPLL_REF_DIV, state->ppll_ref_div); + PPLL_W(PPLL_DIV_0, state->ppll_div_0); + PPLL_W(PPLL_DIV_1, state->ppll_div_1); + PPLL_W(PPLL_DIV_2, state->ppll_div_2); + PPLL_W(PPLL_DIV_3, state->ppll_div_3); + PPLL_W(HTOTAL_CNTL, state->htotal_cntl); + + /* update */ + PPLL_W(PPLL_REF_DIV, state->ppll_ref_div | + PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_W); + for (tmp = 0; tmp < 100; tmp++) { + if (!(PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_R & + PPLL_R(PPLL_REF_DIV))) { + break; + } + DRM_UDELAY(10); + } + state->ppll_cntl &= ~PPLL_CNTL__PPLL_RESET; + PPLL_W(PPLL_CNTL, state->ppll_cntl); + PPLL_W(VCLK_ECP_CNTL, state->vclk_ecp_cntl); +} + +/** + * radeon_ms_crtc1_save - save CRTC state + * @dev_priv: radeon private structure + * @state: state where saving current CRTC state + */ +void radeon_ms_crtc1_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->surface_cntl = MMIO_R(SURFACE_CNTL); + state->surface0_info = MMIO_R(SURFACE0_INFO); + state->surface0_lower_bound = MMIO_R(SURFACE0_LOWER_BOUND); + state->surface0_upper_bound = MMIO_R(SURFACE0_UPPER_BOUND); + state->surface1_info = MMIO_R(SURFACE1_INFO); + state->surface1_lower_bound = MMIO_R(SURFACE1_LOWER_BOUND); + state->surface1_upper_bound = MMIO_R(SURFACE1_UPPER_BOUND); + state->surface2_info = MMIO_R(SURFACE2_INFO); + state->surface2_lower_bound = MMIO_R(SURFACE2_LOWER_BOUND); + state->surface2_upper_bound = MMIO_R(SURFACE2_UPPER_BOUND); + state->surface3_info = MMIO_R(SURFACE3_INFO); + state->surface3_lower_bound = MMIO_R(SURFACE3_LOWER_BOUND); + state->surface3_upper_bound = MMIO_R(SURFACE3_UPPER_BOUND); + state->surface4_info = MMIO_R(SURFACE4_INFO); + state->surface4_lower_bound = MMIO_R(SURFACE4_LOWER_BOUND); + state->surface4_upper_bound = MMIO_R(SURFACE4_UPPER_BOUND); + state->surface5_info = MMIO_R(SURFACE5_INFO); + state->surface5_lower_bound = MMIO_R(SURFACE5_LOWER_BOUND); + state->surface5_upper_bound = MMIO_R(SURFACE5_UPPER_BOUND); + state->surface6_info = MMIO_R(SURFACE6_INFO); + state->surface6_lower_bound = MMIO_R(SURFACE6_LOWER_BOUND); + state->surface6_upper_bound = MMIO_R(SURFACE6_UPPER_BOUND); + state->surface7_info = MMIO_R(SURFACE7_INFO); + state->surface7_lower_bound = MMIO_R(SURFACE7_LOWER_BOUND); + state->surface7_upper_bound = MMIO_R(SURFACE7_UPPER_BOUND); + state->crtc_gen_cntl = MMIO_R(CRTC_GEN_CNTL); + state->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL); + state->crtc_h_total_disp = MMIO_R(CRTC_H_TOTAL_DISP); + state->crtc_h_sync_strt_wid = MMIO_R(CRTC_H_SYNC_STRT_WID); + state->crtc_v_total_disp = MMIO_R(CRTC_V_TOTAL_DISP); + state->crtc_v_sync_strt_wid = MMIO_R(CRTC_V_SYNC_STRT_WID); + state->fp_h_sync_strt_wid = MMIO_R(FP_H_SYNC_STRT_WID); + state->fp_v_sync_strt_wid = MMIO_R(FP_V_SYNC_STRT_WID); + state->fp_crtc_h_total_disp = MMIO_R(FP_CRTC_H_TOTAL_DISP); + state->fp_crtc_v_total_disp = MMIO_R(FP_CRTC_V_TOTAL_DISP); + state->crtc_offset = MMIO_R(CRTC_OFFSET); + state->crtc_offset_cntl = MMIO_R(CRTC_OFFSET_CNTL); + state->crtc_pitch = MMIO_R(CRTC_PITCH); + state->crtc_more_cntl = MMIO_R(CRTC_MORE_CNTL); + state->crtc_tile_x0_y0 = MMIO_R(CRTC_TILE_X0_Y0); + radeon_pll1_save(dev_priv,state); +} + +/** + * radeon_pll1_save - save PLL1 state + * @dev_priv: radeon private structure + * @state: state where saving current PLL1 state + */ +static void radeon_pll1_save(struct drm_radeon_private *dev_priv, + struct radeon_state *state) +{ + state->clock_cntl_index = MMIO_R(CLOCK_CNTL_INDEX); + state->ppll_cntl = PPLL_R(PPLL_CNTL); + state->ppll_ref_div = PPLL_R(PPLL_REF_DIV); + state->ppll_div_0 = PPLL_R(PPLL_DIV_0); + state->ppll_div_1 = PPLL_R(PPLL_DIV_1); + state->ppll_div_2 = PPLL_R(PPLL_DIV_2); + state->ppll_div_3 = PPLL_R(PPLL_DIV_3); + state->vclk_ecp_cntl = PPLL_R(VCLK_ECP_CNTL); + state->htotal_cntl = PPLL_R(HTOTAL_CNTL); +} + +static void radeon_ms_crtc1_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + state->crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; + state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_DISPLAY_DIS; + state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_HSYNC_DIS; + state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_VSYNC_DIS; + switch(mode) { + case DPMSModeOn: + break; + case DPMSModeStandby: + state->crtc_ext_cntl |= + CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | + CRTC_EXT_CNTL__CRTC_HSYNC_DIS; + break; + case DPMSModeSuspend: + state->crtc_ext_cntl |= + CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | + CRTC_EXT_CNTL__CRTC_VSYNC_DIS; + break; + case DPMSModeOff: + state->crtc_ext_cntl |= + CRTC_EXT_CNTL__CRTC_DISPLAY_DIS | + CRTC_EXT_CNTL__CRTC_HSYNC_DIS | + CRTC_EXT_CNTL__CRTC_VSYNC_DIS; + state->crtc_gen_cntl |= + CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; + break; + } + MMIO_W(CRTC_GEN_CNTL, state->crtc_gen_cntl); + MMIO_W(CRTC_EXT_CNTL, state->crtc_ext_cntl); + + dev_priv->crtc1_dpms = mode; + /* FIXME: once adding crtc2 remove this */ + dev_priv->crtc2_dpms = mode; + radeon_ms_gpu_dpms(crtc->dev); + + if (mode != DPMSModeOff) { + radeon_ms_crtc_load_lut(crtc); + } +} + +static bool radeon_ms_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_ms_crtc_mode_prepare(struct drm_crtc *crtc) +{ + crtc->funcs->dpms(crtc, DPMSModeOff); +} + +/* Compute n/d with rounding */ +static int radeon_div(int n, int d) +{ + return (n + (d / 2)) / d; +} + +/* compute PLL registers values for requested video mode */ +static void radeon_pll1_compute(struct drm_crtc *crtc, + struct drm_display_mode *mode) +{ + struct { + int divider; + int divider_id; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 16, 5 }, /* VCLK_SRC/16 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + unsigned long freq = mode->clock / 10; + int pll_output_freq; + int min_rcenter_dist; + int rcenter_dist; + int post_divider; + int post_divider_id; + int ref_div; + int fb_div; + int vco_freq; + int vco_gain; + + /* clamp frequency into pll [min; max] frequency range */ + if (freq > dev_priv->properties->pll_max_pll_freq) { + freq = dev_priv->properties->pll_max_pll_freq; + } + if (freq < dev_priv->properties->pll_min_pll_freq) { + freq = dev_priv->properties->pll_min_pll_freq; + } + /* select divider so that pll output frequency is the nearest to + * the center of [350; 125]Mhz range */ + min_rcenter_dist = 350 * 100; + post_divider = post_divs[0].divider; + post_divider_id = post_divs[0].divider_id; + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + if (post_div->divider == 0) + break; + /* pll output frequency (before post divider) */ + pll_output_freq = post_div->divider * freq; + /* compute distance to [350; 125] range center*/ + rcenter_dist = abs(pll_output_freq - 11250); + if (rcenter_dist < min_rcenter_dist) { + min_rcenter_dist = rcenter_dist; + post_divider = post_div->divider; + post_divider_id = post_div->divider_id; + } + } + pll_output_freq = post_divider * freq; + /* select first feedback */ + state->clock_cntl_index = REG_S(CLOCK_CNTL_INDEX, PPLL_DIV_SEL, 0); + /* set ref div so that ref_freq/ref_div is in middle of [2; 3.3]Mhz */ + ref_div = dev_priv->properties->pll_reference_freq / 265; + state->ppll_ref_div = REG_S(PPLL_REF_DIV, PPLL_REF_DIV, ref_div) | + REG_S(PPLL_REF_DIV, PPLL_REF_DIV_ACC, ref_div); + fb_div = radeon_div(pll_output_freq * ref_div, + dev_priv->properties->pll_reference_freq); + state->ppll_div_0 = REG_S(PPLL_DIV_0, PPLL_FB0_DIV, fb_div) | + REG_S(PPLL_DIV_0, PPLL_POST0_DIV, post_divider_id); + /* configure vco gain */ + state->ppll_cntl = PPLL_R(PPLL_CNTL); + vco_gain = REG_G(PPLL_CNTL, PPLL_PVG, state->ppll_cntl); + vco_freq = (fb_div * dev_priv->properties->pll_reference_freq) / + ref_div; + /* This is horribly crude: the VCO frequency range is divided into + * 3 parts, each part having a fixed PLL gain value. + */ + if (vco_freq >= 30000) { + /* [300..max] MHz : 7 */ + vco_gain = 7; + } else if (vco_freq >= 18000) { + /* [180..300) MHz : 4 */ + vco_gain = 4; + } else { + /* [0..180) MHz : 1 */ + vco_gain = 1; + } + state->ppll_cntl |= REG_S(PPLL_CNTL, PPLL_PVG, vco_gain); + state->vclk_ecp_cntl |= REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL, + VCLK_SRC_SEL__PPLLCLK); + state->htotal_cntl = 0; +} + +static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + int format, hsync_wid, vsync_wid, pitch; + + DRM_INFO("[radeon_ms] set modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x\n", + mode->mode_id, mode->name, mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, mode->type); + DRM_INFO("[radeon_ms] set modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x (adjusted)\n", + adjusted_mode->mode_id, adjusted_mode->name, adjusted_mode->vrefresh, adjusted_mode->clock, + adjusted_mode->hdisplay, adjusted_mode->hsync_start, + adjusted_mode->hsync_end, adjusted_mode->htotal, + adjusted_mode->vdisplay, adjusted_mode->vsync_start, + adjusted_mode->vsync_end, adjusted_mode->vtotal, adjusted_mode->type); + + /* only support RGB555,RGB565,ARGB8888 should satisfy all users */ + switch (crtc->fb->bits_per_pixel) { + case 16: + if (crtc->fb->depth == 15) { + format = 3; + } else { + format = 4; + } + break; + case 32: + format = 6; + break; + default: + DRM_ERROR("Unknown color depth\n"); + return; + } + radeon_pll1_compute(crtc, adjusted_mode); + + state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->offset); + state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN | + CRTC_GEN_CNTL__CRTC_EN | + REG_S(CRTC_GEN_CNTL, CRTC_PIX_WIDTH, format); + if (adjusted_mode->flags & V_DBLSCAN) { + state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_DBL_SCAN_EN; + } + if (adjusted_mode->flags & V_CSYNC) { + state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_C_SYNC_EN; + } + if (adjusted_mode->flags & V_INTERLACE) { + state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_INTERLACE_EN; + } + state->crtc_more_cntl = 0; + state->crtc_h_total_disp = + REG_S(CRTC_H_TOTAL_DISP, + CRTC_H_TOTAL, + (adjusted_mode->crtc_htotal/8) - 1) | + REG_S(CRTC_H_TOTAL_DISP, + CRTC_H_DISP, + (adjusted_mode->crtc_hdisplay/8) - 1); + hsync_wid = (adjusted_mode->crtc_hsync_end - + adjusted_mode->crtc_hsync_start) / 8; + if (!hsync_wid) { + hsync_wid = 1; + } + if (hsync_wid > 0x3f) { + hsync_wid = 0x3f; + } + state->crtc_h_sync_strt_wid = + REG_S(CRTC_H_SYNC_STRT_WID, + CRTC_H_SYNC_WID, hsync_wid) | + REG_S(CRTC_H_SYNC_STRT_WID, + CRTC_H_SYNC_STRT_PIX, + adjusted_mode->crtc_hsync_start) | + REG_S(CRTC_H_SYNC_STRT_WID, + CRTC_H_SYNC_STRT_CHAR, + adjusted_mode->crtc_hsync_start/8); + if (adjusted_mode->flags & V_NHSYNC) { + state->crtc_h_sync_strt_wid |= + CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_POL; + } + + state->crtc_v_total_disp = + REG_S(CRTC_V_TOTAL_DISP, CRTC_V_TOTAL, + adjusted_mode->crtc_vtotal - 1) | + REG_S(CRTC_V_TOTAL_DISP, CRTC_V_DISP, + adjusted_mode->crtc_vdisplay - 1); + vsync_wid = adjusted_mode->crtc_vsync_end - + adjusted_mode->crtc_vsync_start; + if (!vsync_wid) { + vsync_wid = 1; + } + if (vsync_wid > 0x1f) { + vsync_wid = 0x1f; + } + state->crtc_v_sync_strt_wid = + REG_S(CRTC_V_SYNC_STRT_WID, + CRTC_V_SYNC_WID, + vsync_wid) | + REG_S(CRTC_V_SYNC_STRT_WID, + CRTC_V_SYNC_STRT, + adjusted_mode->crtc_vsync_start); + if (adjusted_mode->flags & V_NVSYNC) { + state->crtc_v_sync_strt_wid |= + CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_POL; + } + + pitch = (crtc->fb->width * crtc->fb->bits_per_pixel + + ((crtc->fb->bits_per_pixel * 8)- 1)) / + (crtc->fb->bits_per_pixel * 8); + state->crtc_pitch = REG_S(CRTC_PITCH, CRTC_PITCH, pitch) | + REG_S(CRTC_PITCH, CRTC_PITCH_RIGHT, pitch); + + state->fp_h_sync_strt_wid = state->crtc_h_sync_strt_wid; + state->fp_v_sync_strt_wid = state->crtc_v_sync_strt_wid; + state->fp_crtc_h_total_disp = state->crtc_h_total_disp; + state->fp_crtc_v_total_disp = state->crtc_v_total_disp; + + radeon_ms_crtc1_restore(dev, state); +} + +static void radeon_ms_crtc_mode_commit(struct drm_crtc *crtc) +{ + crtc->funcs->dpms(crtc, DPMSModeOn); +} + +static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r, + u16 g, u16 b, int regno) +{ + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct radeon_ms_crtc *radeon_ms_crtc = crtc->driver_private; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t color; + + switch(radeon_ms_crtc->crtc) { + case 1: + state->dac_cntl2 &= ~DAC_CNTL2__PALETTE_ACCESS_CNTL; + break; + case 2: + state->dac_cntl2 |= DAC_CNTL2__PALETTE_ACCESS_CNTL; + break; + } + MMIO_W(DAC_CNTL2, state->dac_cntl2); + if (crtc->fb->bits_per_pixel == 16 && crtc->fb->depth == 16) { + if (regno >= 64) { + return; + } + MMIO_W(PALETTE_INDEX, + REG_S(PALETTE_INDEX, PALETTE_W_INDEX, + regno * 4)); + color = 0; + color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); + MMIO_W(PALETTE_DATA, color); + MMIO_W(PALETTE_INDEX, + REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno * 4)); + color = 0; + color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); + MMIO_W(PALETTE_30_DATA, color); + radeon_ms_crtc->lut_r[regno * 4] = r; + radeon_ms_crtc->lut_g[regno * 4] = g; + radeon_ms_crtc->lut_b[regno * 4] = b; + if (regno < 32) { + MMIO_W(PALETTE_INDEX, + REG_S(PALETTE_INDEX, PALETTE_W_INDEX, + regno * 8)); + color = 0; + color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); + MMIO_W(PALETTE_DATA, color); + MMIO_W(PALETTE_INDEX, + REG_S(PALETTE_INDEX, PALETTE_W_INDEX, + regno * 8)); + color = 0; + color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R,r >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_G,g >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_B,b >> 6); + MMIO_W(PALETTE_30_DATA, color); + radeon_ms_crtc->lut_r[regno * 8] = r; + radeon_ms_crtc->lut_g[regno * 8] = g; + radeon_ms_crtc->lut_b[regno * 8] = b; + } + } else { + if (regno >= 256) { + return; + } + radeon_ms_crtc->lut_r[regno] = r; + radeon_ms_crtc->lut_g[regno] = g; + radeon_ms_crtc->lut_b[regno] = b; + MMIO_W(PALETTE_INDEX, + REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); + color = 0; + color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); + MMIO_W(PALETTE_DATA, color); + MMIO_W(PALETTE_INDEX, + REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); + color = 0; + color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); + } +} + +static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc) +{ + struct radeon_ms_crtc *radeon_ms_crtc = crtc->driver_private; + int i; + + if (!crtc->enabled) + return; + + for (i = 0; i < 256; i++) { + radeon_ms_crtc_gamma_set(crtc, + radeon_ms_crtc->lut_r[i], + radeon_ms_crtc->lut_g[i], + radeon_ms_crtc->lut_b[i], + i); + } +} + +static bool radeon_ms_crtc_lock(struct drm_crtc *crtc) +{ + return true; +} + +static void radeon_ms_crtc_unlock(struct drm_crtc *crtc) +{ +} + +static const struct drm_crtc_funcs radeon_ms_crtc1_funcs= { + .dpms = radeon_ms_crtc1_dpms, + .save = NULL, /* XXX */ + .restore = NULL, /* XXX */ + .lock = radeon_ms_crtc_lock, + .unlock = radeon_ms_crtc_unlock, + .prepare = radeon_ms_crtc_mode_prepare, + .commit = radeon_ms_crtc_mode_commit, + .mode_fixup = radeon_ms_crtc_mode_fixup, + .mode_set = radeon_ms_crtc1_mode_set, + .gamma_set = radeon_ms_crtc_gamma_set, + .cleanup = NULL, /* XXX */ +}; + +int radeon_ms_crtc_create(struct drm_device *dev, int crtc) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_crtc *drm_crtc; + struct radeon_ms_crtc *radeon_ms_crtc; + int i; + + switch (crtc) { + case 1: + radeon_ms_crtc1_init(dev_priv, &dev_priv->driver_state); + drm_crtc = drm_crtc_create(dev, &radeon_ms_crtc1_funcs); + break; + case 2: + default: + return -EINVAL; + } + if (drm_crtc == NULL) { + return -ENOMEM; + } + + radeon_ms_crtc = drm_alloc(sizeof(struct radeon_ms_crtc), DRM_MEM_DRIVER); + if (radeon_ms_crtc == NULL) { + kfree(drm_crtc); + return -ENOMEM; + } + + radeon_ms_crtc->crtc = crtc; + for (i = 0; i < 256; i++) { + radeon_ms_crtc->lut_r[i] = i << 8; + radeon_ms_crtc->lut_g[i] = i << 8; + radeon_ms_crtc->lut_b[i] = i << 8; + } + drm_crtc->driver_private = radeon_ms_crtc; + return 0; +} diff --git a/shared-core/radeon_ms_dac.c b/shared-core/radeon_ms_dac.c new file mode 100644 index 00000000..297623a0 --- /dev/null +++ b/shared-core/radeon_ms_dac.c @@ -0,0 +1,400 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "radeon_ms.h" + +int radeon_ms_dac1_initialize(struct radeon_ms_output *output) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + state->dac_cntl = + REG_S(DAC_CNTL, DAC_RANGE_CNTL, DAC_RANGE_CNTL__PS2) | + DAC_CNTL__DAC_8BIT_EN | + DAC_CNTL__DAC_VGA_ADR_EN | + DAC_CNTL__DAC_PDWN | + REG_S(DAC_CNTL, DAC, 0xff); + state->dac_ext_cntl = 0; + state->dac_macro_cntl = + DAC_MACRO_CNTL__DAC_PDWN_R | + DAC_MACRO_CNTL__DAC_PDWN_G | + DAC_MACRO_CNTL__DAC_PDWN_B | + REG_S(DAC_MACRO_CNTL, DAC_WHITE_CNTL, 7) | + REG_S(DAC_MACRO_CNTL, DAC_BG_ADJ, 7); + state->dac_embedded_sync_cntl = + DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_Y_G; + state->dac_broad_pulse = 0; + state->dac_skew_clks = 0; + state->dac_incr = 0; + state->dac_neg_sync_level = 0; + state->dac_pos_sync_level = 0; + state->dac_blank_level = 0; + state->dac_sync_equalization = 0; + state->disp_output_cntl = 0; + radeon_ms_dac1_restore(output, state); + return 0; +} + +enum drm_output_status radeon_ms_dac1_detect(struct radeon_ms_output *output) +{ + return output_status_unknown; +} + +void radeon_ms_dac1_dpms(struct radeon_ms_output *output, int mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t dac_cntl; + uint32_t dac_macro_cntl; + + dac_cntl = DAC_CNTL__DAC_PDWN; + dac_macro_cntl = DAC_MACRO_CNTL__DAC_PDWN_R | + DAC_MACRO_CNTL__DAC_PDWN_G | + DAC_MACRO_CNTL__DAC_PDWN_B; + switch(mode) { + case DPMSModeOn: + state->dac_cntl &= ~dac_cntl; + state->dac_macro_cntl &= ~dac_macro_cntl; + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + state->dac_cntl |= dac_cntl; + state->dac_macro_cntl |= dac_macro_cntl; + break; + default: + /* error */ + break; + } + MMIO_W(DAC_CNTL, state->dac_cntl); + MMIO_W(DAC_MACRO_CNTL, state->dac_macro_cntl); +} + +int radeon_ms_dac1_get_modes(struct radeon_ms_output *output) +{ + return 0; +} + +bool radeon_ms_dac1_mode_fixup(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +int radeon_ms_dac1_mode_set(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_ms_connector *connector = output->connector; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t v = 0; + + if (connector == NULL) { + /* output not associated with a connector */ + return -EINVAL; + } + state->disp_output_cntl &= ~DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__MASK; + state->dac_cntl2 &= ~DAC_CNTL2__DAC_CLK_SEL; + switch (connector->crtc) { + case 1: + v = DISP_DAC_SOURCE__PRIMARYCRTC; + break; + case 2: + v = DISP_DAC_SOURCE__SECONDARYCRTC; + state->dac_cntl2 |= DAC_CNTL2__DAC_CLK_SEL; + break; + } + state->disp_output_cntl |= REG_S(DISP_OUTPUT_CNTL, DISP_DAC_SOURCE, v); + MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); + MMIO_W(DAC_CNTL2, state->dac_cntl2); + return 0; +} + +void radeon_ms_dac1_restore(struct radeon_ms_output *output, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + + MMIO_W(DAC_CNTL, state->dac_cntl); + MMIO_W(DAC_EXT_CNTL, state->dac_ext_cntl); + MMIO_W(DAC_MACRO_CNTL, state->dac_macro_cntl); + MMIO_W(DAC_EMBEDDED_SYNC_CNTL, state->dac_embedded_sync_cntl); + MMIO_W(DAC_BROAD_PULSE, state->dac_broad_pulse); + MMIO_W(DAC_SKEW_CLKS, state->dac_skew_clks); + MMIO_W(DAC_INCR, state->dac_incr); + MMIO_W(DAC_NEG_SYNC_LEVEL, state->dac_neg_sync_level); + MMIO_W(DAC_POS_SYNC_LEVEL, state->dac_pos_sync_level); + MMIO_W(DAC_BLANK_LEVEL, state->dac_blank_level); + MMIO_W(DAC_SYNC_EQUALIZATION, state->dac_sync_equalization); +} + +void radeon_ms_dac1_save(struct radeon_ms_output *output, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + + state->dac_cntl = MMIO_R(DAC_CNTL); + state->dac_ext_cntl = MMIO_R(DAC_EXT_CNTL); + state->dac_macro_cntl = MMIO_R(DAC_MACRO_CNTL); + state->dac_embedded_sync_cntl = MMIO_R(DAC_EMBEDDED_SYNC_CNTL); + state->dac_broad_pulse = MMIO_R(DAC_BROAD_PULSE); + state->dac_skew_clks = MMIO_R(DAC_SKEW_CLKS); + state->dac_incr = MMIO_R(DAC_INCR); + state->dac_neg_sync_level = MMIO_R(DAC_NEG_SYNC_LEVEL); + state->dac_pos_sync_level = MMIO_R(DAC_POS_SYNC_LEVEL); + state->dac_blank_level = MMIO_R(DAC_BLANK_LEVEL); + state->dac_sync_equalization = MMIO_R(DAC_SYNC_EQUALIZATION); +} + +int radeon_ms_dac2_initialize(struct radeon_ms_output *output) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + state->tv_dac_cntl = TV_DAC_CNTL__BGSLEEP | + REG_S(TV_DAC_CNTL, STD, STD__PS2) | + REG_S(TV_DAC_CNTL, BGADJ, 0); + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + state->tv_dac_cntl |= TV_DAC_CNTL__RDACPD | + TV_DAC_CNTL__GDACPD | + TV_DAC_CNTL__BDACPD | + REG_S(TV_DAC_CNTL, DACADJ, 0); + break; + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + state->tv_dac_cntl |= TV_DAC_CNTL__RDACPD_R4 | + TV_DAC_CNTL__GDACPD_R4 | + TV_DAC_CNTL__BDACPD_R4 | + REG_S(TV_DAC_CNTL, DACADJ_R4, 0); + break; + } + state->tv_master_cntl = TV_MASTER_CNTL__TV_ASYNC_RST | + TV_MASTER_CNTL__CRT_ASYNC_RST | + TV_MASTER_CNTL__RESTART_PHASE_FIX | + TV_MASTER_CNTL__CRT_FIFO_CE_EN | + TV_MASTER_CNTL__TV_FIFO_CE_EN; + state->dac_cntl2 = 0; + state->disp_output_cntl = 0; + radeon_ms_dac2_restore(output, state); + return 0; +} + +enum drm_output_status radeon_ms_dac2_detect(struct radeon_ms_output *output) +{ + return output_status_unknown; +} + +void radeon_ms_dac2_dpms(struct radeon_ms_output *output, int mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t tv_dac_cntl_on, tv_dac_cntl_off; + + tv_dac_cntl_off = TV_DAC_CNTL__BGSLEEP; + tv_dac_cntl_on = TV_DAC_CNTL__NBLANK | + TV_DAC_CNTL__NHOLD; + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + tv_dac_cntl_off |= TV_DAC_CNTL__RDACPD | + TV_DAC_CNTL__GDACPD | + TV_DAC_CNTL__BDACPD; + break; + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + tv_dac_cntl_off |= TV_DAC_CNTL__RDACPD_R4 | + TV_DAC_CNTL__GDACPD_R4 | + TV_DAC_CNTL__BDACPD_R4; + break; + } + switch(mode) { + case DPMSModeOn: + state->tv_dac_cntl &= ~tv_dac_cntl_off; + state->tv_dac_cntl |= tv_dac_cntl_on; + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + state->tv_dac_cntl &= ~tv_dac_cntl_on; + state->tv_dac_cntl |= tv_dac_cntl_off; + break; + default: + /* error */ + break; + } + MMIO_W(TV_DAC_CNTL, state->tv_dac_cntl); +} + +int radeon_ms_dac2_get_modes(struct radeon_ms_output *output) +{ + return 0; +} + +bool radeon_ms_dac2_mode_fixup(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_ms_connector *connector = output->connector; + struct radeon_state *state = &dev_priv->driver_state; + + if (connector == NULL) { + /* output not associated with a connector */ + return -EINVAL; + } + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + state->disp_output_cntl &= ~DISP_OUTPUT_CNTL__DISP_TV_SOURCE; + switch (connector->crtc) { + case 1: + break; + case 2: + state->disp_output_cntl |= + DISP_OUTPUT_CNTL__DISP_TV_SOURCE; + break; + } + break; + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + state->disp_output_cntl &= + ~DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__MASK; + switch (connector->crtc) { + case 1: + state->disp_output_cntl |= + REG_S(DISP_OUTPUT_CNTL, + DISP_TVDAC_SOURCE, + DISP_TVDAC_SOURCE__PRIMARYCRTC); + break; + case 2: + state->disp_output_cntl |= + REG_S(DISP_OUTPUT_CNTL, + DISP_TVDAC_SOURCE, + DISP_TVDAC_SOURCE__SECONDARYCRTC); + break; + } + break; + } + switch (dev_priv->family) { + case CHIP_R200: + break; + case CHIP_R100: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + if (connector->type != CONNECTOR_CTV && + connector->type != CONNECTOR_STV) { + state->dac_cntl2 |= DAC_CNTL2__DAC2_CLK_SEL; + } + } + MMIO_W(DAC_CNTL2, state->dac_cntl2); + MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); + return 0; +} + +void radeon_ms_dac2_restore(struct radeon_ms_output *output, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + + MMIO_W(DAC_CNTL2, state->dac_cntl2); + MMIO_W(TV_DAC_CNTL, state->tv_dac_cntl); + MMIO_W(TV_MASTER_CNTL, state->tv_master_cntl); +} + +void radeon_ms_dac2_save(struct radeon_ms_output *output, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + + state->dac_cntl2 = MMIO_R(DAC_CNTL2); + state->tv_dac_cntl = MMIO_R(TV_DAC_CNTL); + state->tv_master_cntl = MMIO_R(TV_MASTER_CNTL); +} diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c new file mode 100644 index 00000000..b22c83a7 --- /dev/null +++ b/shared-core/radeon_ms_drm.c @@ -0,0 +1,299 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#include "drm_pciids.h" +#include "radeon_ms.h" + + +static uint32_t radeon_ms_mem_prios[] = { + DRM_BO_MEM_VRAM, + DRM_BO_MEM_TT, + DRM_BO_MEM_LOCAL, +}; + +static uint32_t radeon_ms_busy_prios[] = { + DRM_BO_MEM_TT, + DRM_BO_MEM_VRAM, + DRM_BO_MEM_LOCAL, +}; + +struct drm_fence_driver radeon_ms_fence_driver = { + .num_classes = 1, + .wrap_diff = (1 << 30), + .flush_diff = (1 << 29), + .sequence_mask = 0xffffffffU, + .lazy_capable = 1, + .emit = radeon_ms_fence_emit_sequence, + .poke_flush = radeon_ms_poke_flush, + .has_irq = radeon_ms_fence_has_irq, +}; + +struct drm_bo_driver radeon_ms_bo_driver = { + .mem_type_prio = radeon_ms_mem_prios, + .mem_busy_prio = radeon_ms_busy_prios, + .num_mem_type_prio = sizeof(radeon_ms_mem_prios)/sizeof(uint32_t), + .num_mem_busy_prio = sizeof(radeon_ms_busy_prios)/sizeof(uint32_t), + .create_ttm_backend_entry = radeon_ms_create_ttm_backend, + .fence_type = radeon_ms_fence_types, + .invalidate_caches = radeon_ms_invalidate_caches, + .init_mem_type = radeon_ms_init_mem_type, + .evict_mask = radeon_ms_evict_mask, + .move = radeon_ms_bo_move, + .ttm_cache_flush = radeon_ms_ttm_flush, +}; + +struct drm_ioctl_desc radeon_ms_ioctls[] = { + DRM_IOCTL_DEF(DRM_RADEON_EXECBUFFER, radeon_ms_execbuffer, DRM_AUTH), +}; +int radeon_ms_num_ioctls = DRM_ARRAY_SIZE(radeon_ms_ioctls); + +int radeon_ms_driver_dma_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_device_dma *dma = dev->dma; + struct drm_dma *d = data; + + LOCK_TEST_WITH_RETURN(dev, file_priv); + + /* Please don't send us buffers. + */ + if (d->send_count != 0) { + DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", + DRM_CURRENTPID, d->send_count); + return -EINVAL; + } + + /* Don't ask us buffer neither :) + */ + DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", + DRM_CURRENTPID, d->request_count, dma->buf_count); + return -EINVAL; +} + +void radeon_ms_driver_lastclose(struct drm_device * dev) +{ +} + +int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) +{ + struct drm_radeon_private *dev_priv; + int ret = 0; + + DRM_INFO("[radeon_ms] loading\n"); + /* allocate and clear device private structure */ + dev_priv = drm_alloc(sizeof(struct drm_radeon_private), DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + memset(dev_priv, 0, sizeof(struct drm_radeon_private)); + dev->dev_private = (void *)dev_priv; + + /* initialize modesetting structure (must be done here) */ + drm_mode_config_init(dev); + + /* flags correspond to chipset family */ + dev_priv->usec_timeout = 100; + dev_priv->family = flags & 0xffffU; + dev_priv->bus_type = flags & 0xff0000U; + /* initialize family functions */ + ret = radeon_ms_family_init(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* we don't want userspace to be able to map this so don't use + * drm_addmap */ + dev_priv->mmio.offset = drm_get_resource_start(dev, 2); + dev_priv->mmio.size = drm_get_resource_len(dev, 2); + dev_priv->mmio.type = _DRM_REGISTERS; + dev_priv->mmio.flags = _DRM_RESTRICTED; + drm_core_ioremap(&dev_priv->mmio, dev); + /* map vram FIXME: IGP likely don't have any of this */ + dev_priv->vram.offset = drm_get_resource_start(dev, 0); + dev_priv->vram.size = drm_get_resource_len(dev, 0); + dev_priv->vram.type = _DRM_FRAME_BUFFER; + dev_priv->vram.flags = _DRM_RESTRICTED; + drm_core_ioremap(&dev_priv->vram, dev); + + /* save radeon initial state which will be restored upon module + * exit */ + radeon_ms_state_save(dev, &dev_priv->load_state); + dev_priv->restore_state = 1; + memcpy(&dev_priv->driver_state, &dev_priv->load_state, + sizeof(struct radeon_state)); + + /* initialize irq */ + ret = radeon_ms_irq_init(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* init bo driver */ + dev_priv->fence_id_last = 1; + dev_priv->fence_reg = SCRATCH_REG2; + drm_bo_driver_init(dev); + /* initialize vram */ + ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* initialize gpu address space (only after) VRAM initialization */ + ret = radeon_ms_gpu_initialize(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + radeon_ms_gpu_restore(dev, &dev_priv->driver_state); + dev_priv->bus_ready = 1; + + /* initialize ttm */ + ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, + dev_priv->gpu_gart_size / RADEON_PAGE_SIZE); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* initialize ring buffer */ + /* set ring size to 4Mo FIXME: should make a parameter for this */ + dev_priv->write_back_area_size = 4 * 1024; + dev_priv->ring_buffer_size = 4 * 1024 * 1024; + ret = radeon_ms_cp_init(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + /* initialize modesetting */ + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; + dev->mode_config.fb_base = dev_priv->vram.offset; + ret = radeon_ms_crtc_create(dev, 1); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + ret = radeon_ms_outputs_from_properties(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + ret = radeon_ms_connectors_from_properties(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + radeon_ms_outputs_save(dev, &dev_priv->load_state); + drm_initial_config(dev, false); + + ret = drm_irq_install(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + + DRM_INFO("[radeon_ms] successfull initialization\n"); + return 0; +} + +int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv) +{ + return 0; +} + + +int radeon_ms_driver_unload(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (dev_priv == NULL) { + return 0; + } + + /* cleanup modesetting */ + drm_mode_config_cleanup(dev); + DRM_INFO("[radeon_ms] modesetting clean\n"); + radeon_ms_outputs_restore(dev, &dev_priv->load_state); + radeon_ms_connectors_destroy(dev); + radeon_ms_outputs_destroy(dev); + + /* shutdown cp engine */ + radeon_ms_cp_finish(dev); + DRM_INFO("[radeon_ms] cp clean\n"); + + drm_irq_uninstall(dev); + DRM_INFO("[radeon_ms] irq uninstalled\n"); + + DRM_INFO("[radeon_ms] unloading\n"); + /* clean ttm memory manager */ + mutex_lock(&dev->struct_mutex); + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) { + DRM_ERROR("TT memory manager not clean. Delaying takedown\n"); + } + mutex_unlock(&dev->struct_mutex); + DRM_INFO("[radeon_ms] TT memory clean\n"); + /* finish */ + if (dev_priv->bus_finish) { + dev_priv->bus_finish(dev); + } + DRM_INFO("[radeon_ms] bus down\n"); + /* clean vram memory manager */ + mutex_lock(&dev->struct_mutex); + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { + DRM_ERROR("VRAM memory manager not clean. Delaying takedown\n"); + } + mutex_unlock(&dev->struct_mutex); + DRM_INFO("[radeon_ms] VRAM memory clean\n"); + /* clean memory manager */ + drm_bo_driver_finish(dev); + DRM_INFO("[radeon_ms] memory manager clean\n"); + /* restore card state */ + if (dev_priv->restore_state) { + radeon_ms_state_restore(dev, &dev_priv->load_state); + } + DRM_INFO("[radeon_ms] state restored\n"); + if (dev_priv->mmio.handle) { + drm_core_ioremapfree(&dev_priv->mmio, dev); + } + if (dev_priv->vram.handle) { + drm_core_ioremapfree(&dev_priv->vram, dev); + } + DRM_INFO("[radeon_ms] map released\n"); + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + dev->dev_private = NULL; + + DRM_INFO("[radeon_ms] that's all the folks\n"); + return 0; +} + diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h new file mode 100644 index 00000000..842d5331 --- /dev/null +++ b/shared-core/radeon_ms_drm.h @@ -0,0 +1,60 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Dave Airlie + * Copyright 2007 Alex Deucher + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jérôme Glisse + */ +#ifndef __RADEON_MS_DRM_H__ +#define __RADEON_MS_DRM_H__ + +/* fence definitions */ +/* The only fence class we support */ +#define DRM_RADEON_FENCE_CLASS_ACCEL 0 +/* Fence type that guarantees read-write flush */ +#define DRM_RADEON_FENCE_TYPE_RW 2 +/* cache flushes programmed just before the fence */ +#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000 + +/* radeon ms ioctl */ +#define DRM_RADEON_EXECBUFFER 0x00 + +struct drm_radeon_execbuffer_arg { + uint64_t next; + uint32_t reloc_offset; + union { + struct drm_bo_op_req req; + struct drm_bo_arg_rep rep; + } d; +}; + +struct drm_radeon_execbuffer { + uint32_t args_count; + uint64_t args; + uint32_t cmd_size; + struct drm_fence_arg fence_arg; +}; + +#endif diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c new file mode 100644 index 00000000..b2ce3cbb --- /dev/null +++ b/shared-core/radeon_ms_exec.c @@ -0,0 +1,242 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#include "radeon_ms.h" + +static void radeon_ms_execbuffer_args_clean(struct drm_device *dev, + struct drm_buffer_object **buffers, + uint32_t args_count) +{ + mutex_lock(&dev->struct_mutex); + while (args_count--) { + drm_bo_usage_deref_locked(&buffers[args_count]); + } + mutex_unlock(&dev->struct_mutex); +} + +static int radeon_ms_execbuffer_args(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_radeon_execbuffer *execbuffer, + struct drm_buffer_object **buffers, + uint32_t *relocs) +{ + struct drm_radeon_execbuffer_arg arg; + struct drm_bo_arg_rep rep; + uint32_t args_count = 0; + uint64_t next = 0; + uint64_t data = execbuffer->args; + int ret = 0; + + do { + if (args_count >= execbuffer->args_count) { + DRM_ERROR("[radeon_ms] buffer count exceeded %d\n.", + execbuffer->args_count); + ret = -EINVAL; + goto out_err; + } + buffers[args_count] = NULL; + if (copy_from_user(&arg, (void __user *)((unsigned)data), + sizeof(struct drm_radeon_execbuffer_arg))) { + ret = -EFAULT; + goto out_err; + } + mutex_lock(&dev->struct_mutex); + buffers[args_count] = + drm_lookup_buffer_object(file_priv, + arg.d.req.arg_handle, 1); + relocs[args_count] = arg.reloc_offset; + mutex_unlock(&dev->struct_mutex); + if (arg.d.req.op != drm_bo_validate) { + DRM_ERROR("[radeon_ms] buffer object operation wasn't " + "validate.\n"); + ret = -EINVAL; + goto out_err; + } + memset(&rep, 0, sizeof(struct drm_bo_arg_rep)); + if (args_count >= 1) { + ret = drm_bo_handle_validate(file_priv, + arg.d.req.bo_req.handle, + arg.d.req.bo_req.fence_class, + arg.d.req.bo_req.flags, + arg.d.req.bo_req.mask, + arg.d.req.bo_req.hint, + 0, + &rep.bo_info, + &buffers[args_count]); + } + if (ret) { + DRM_ERROR("[radeon_ms] error on handle validate %d\n", + ret); + rep.ret = ret; + goto out_err; + } + next = arg.next; + arg.d.rep = rep; + if (copy_to_user((void __user *)((unsigned)data), &arg, + sizeof(struct drm_radeon_execbuffer_arg))) { + ret = -EFAULT; + goto out_err; + } + data = next; + args_count++; + } while (next != 0); + if (args_count != execbuffer->args_count) { + DRM_ERROR("[radeon_ms] not enought buffer got %d waited %d\n.", + args_count, execbuffer->args_count); + ret = -EINVAL; + goto out_err; + } + return 0; +out_err: + radeon_ms_execbuffer_args_clean(dev, buffers, args_count); + return ret; +} + +static int radeon_ms_execbuffer_check(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_radeon_execbuffer *execbuffer, + struct drm_buffer_object **buffers, + uint32_t *relocs, + uint32_t *cmd) +{ + uint32_t i, gpu_addr; + int ret; + + for (i = 0; i < execbuffer->args_count; i++) { + if (relocs[i]) { + ret = radeon_ms_bo_get_gpu_addr(dev, &buffers[i]->mem, + &gpu_addr); + if (ret) { + return ret; + } + cmd[relocs[i]] |= (gpu_addr) >> 10; + } + } + for (i = 0; i < execbuffer->cmd_size; i++) { +#if 0 + DRM_INFO("cmd[%d]=0x%08X\n", i, cmd[i]); +#endif + } + return 0; +} + +int radeon_ms_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_execbuffer *execbuffer = data; + struct drm_fence_arg *fence_arg = &execbuffer->fence_arg; + struct drm_buffer_object **buffers; + struct drm_bo_kmap_obj cmd_kmap; + struct drm_fence_object *fence; + uint32_t *relocs; + uint32_t *cmd; + int cmd_is_iomem; + int ret = 0; + + + ret = drm_bo_read_lock(&dev->bm.bm_lock); + if (ret) { + return ret; + } + + relocs = drm_calloc(execbuffer->args_count, sizeof(uint32_t), + DRM_MEM_DRIVER); + if (relocs == NULL) { + drm_bo_read_unlock(&dev->bm.bm_lock); + return -ENOMEM; + } + buffers = drm_calloc(execbuffer->args_count, + sizeof(struct drm_buffer_object *), + DRM_MEM_DRIVER); + if (buffers == NULL) { + drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)), + DRM_MEM_DRIVER); + drm_bo_read_unlock(&dev->bm.bm_lock); + return -ENOMEM; + } + /* process arguments */ + ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer, + buffers, relocs); + if (ret) { + DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n"); + goto out_free; + } + /* map command buffer */ + memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj)); + ret = drm_bo_kmap(buffers[0], + 0, + buffers[0]->mem.num_pages, + &cmd_kmap); + if (ret) { + DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); + goto out_free_release; + } + cmd = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem); + /* do cmd checking & relocations */ + ret = radeon_ms_execbuffer_check(dev, file_priv, execbuffer, + buffers, relocs, cmd); + if (ret) { + drm_putback_buffer_objects(dev); + goto out_free_release; + } + + ret = radeon_ms_ring_emit(dev, cmd, execbuffer->cmd_size); + if (ret) { + drm_putback_buffer_objects(dev); + goto out_free_release; + } + + /* fence */ + ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); + if (ret) { + drm_putback_buffer_objects(dev); + DRM_ERROR("[radeon_ms] fence buffer objects failed\n"); + goto out_free_release; + } + if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) { + ret = drm_fence_add_user_object(file_priv, fence, + fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE); + if (!ret) { + fence_arg->handle = fence->base.hash.key; + fence_arg->fence_class = fence->fence_class; + fence_arg->type = fence->type; + fence_arg->signaled = fence->signaled; + fence_arg->sequence = fence->sequence; + } + } + drm_fence_usage_deref_unlocked(&fence); +out_free_release: + drm_bo_kunmap(&cmd_kmap); + radeon_ms_execbuffer_args_clean(dev, buffers, execbuffer->args_count); +out_free: + drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)), + DRM_MEM_DRIVER); + drm_free(buffers, + (execbuffer->args_count * sizeof(struct drm_buffer_object *)), + DRM_MEM_DRIVER); + drm_bo_read_unlock(&dev->bm.bm_lock); + return ret; +} diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c new file mode 100644 index 00000000..ea5f6ca3 --- /dev/null +++ b/shared-core/radeon_ms_family.c @@ -0,0 +1,229 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +static struct radeon_ms_output radeon_ms_dac1 = { + OUTPUT_DAC1, + NULL, + NULL, + radeon_ms_dac1_initialize, + radeon_ms_dac1_detect, + radeon_ms_dac1_dpms, + radeon_ms_dac1_get_modes, + radeon_ms_dac1_mode_fixup, + radeon_ms_dac1_mode_set, + radeon_ms_dac1_restore, + radeon_ms_dac1_save +}; + +static struct radeon_ms_output radeon_ms_dac2 = { + OUTPUT_DAC2, + NULL, + NULL, + radeon_ms_dac2_initialize, + radeon_ms_dac2_detect, + radeon_ms_dac2_dpms, + radeon_ms_dac2_get_modes, + radeon_ms_dac2_mode_fixup, + radeon_ms_dac2_mode_set, + radeon_ms_dac2_restore, + radeon_ms_dac2_save +}; + +static struct radeon_ms_connector radeon_ms_vga = { + NULL, NULL, NULL, CONNECTOR_VGA, MT_NONE, 0, GPIO_DDC1, + { + 0, -1, -1, -1, -1, -1, -1, -1 + }, + "VGA" +}; + +static struct radeon_ms_connector radeon_ms_dvi_i_2 = { + NULL, NULL, NULL, CONNECTOR_DVI_I, MT_NONE, 0, GPIO_DDC2, + { + 1, -1, -1, -1, -1, -1, -1, -1 + }, + "DVI-I" +}; + +static struct radeon_ms_properties properties[] = { + /* default only one VGA connector */ + { + 0, 0, 2700, 2500, 20000, 1, 1, 1, 1, + { + &radeon_ms_dac1, NULL, NULL, NULL, NULL, NULL, NULL, + NULL + }, + { + &radeon_ms_vga, NULL, NULL, NULL, NULL, NULL, NULL, + NULL + } + }, + { + 0x1043, 0x176, 2700, 2500, 20000, 1, 1, 1, 1, + { + &radeon_ms_dac1, &radeon_ms_dac2, NULL, NULL, NULL, + NULL, NULL, NULL + }, + { + &radeon_ms_vga, &radeon_ms_dvi_i_2, NULL, NULL, NULL, + NULL, NULL, NULL + } + }, + { + 0x1002, 0x4150, 2700, 2500, 20000, 1, 1, 1, 1, + { + &radeon_ms_dac1, &radeon_ms_dac2, NULL, NULL, NULL, + NULL, NULL, NULL + }, + { + &radeon_ms_vga, &radeon_ms_dvi_i_2, NULL, NULL, NULL, + NULL, NULL, NULL + } + }, +}; + +extern const uint32_t radeon_cp_microcode[]; +extern const uint32_t r200_cp_microcode[]; +extern const uint32_t r300_cp_microcode[]; + +static void radeon_flush_cache(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t cmd[6]; + int i, ret; + + cmd[0] = CP_PACKET0(RB2D_DSTCACHE_CTLSTAT, 0); + cmd[1] = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); + cmd[2] = CP_PACKET0(RB3D_DSTCACHE_CTLSTAT, 0); + cmd[3] = REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); + cmd[4] = CP_PACKET0(RB3D_ZCACHE_CTLSTAT, 0); + cmd[5] = RB3D_ZCACHE_CTLSTAT__ZC_FLUSH; + /* try to wait but if we timeout we likely are in bad situation */ + for (i = 0; i < dev_priv->usec_timeout; i++) { + ret = radeon_ms_ring_emit(dev, cmd, 6); + if (!ret) { + break; + } + } +} + +static void r300_flush_cache(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t cmd[6]; + int i, ret; + + cmd[0] = CP_PACKET0(RB2D_DSTCACHE_CTLSTAT, 0); + cmd[1] = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3); + cmd[2] = CP_PACKET0(RB3D_DSTCACHE_CTLSTAT_R3, 0); + cmd[3] = REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FLUSH, 3); + cmd[4] = CP_PACKET0(RB3D_ZCACHE_CTLSTAT_R3, 0); + cmd[5] = RB3D_ZCACHE_CTLSTAT_R3__ZC_FLUSH; + /* try to wait but if we timeout we likely are in bad situation */ + for (i = 0; i < dev_priv->usec_timeout; i++) { + ret = radeon_ms_ring_emit(dev, cmd, 6); + if (!ret) { + break; + } + } +} + +int radeon_ms_family_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + dev_priv->microcode = radeon_cp_microcode; + dev_priv->irq_emit = radeon_ms_irq_emit; + + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + dev_priv->microcode = radeon_cp_microcode; + dev_priv->flush_cache = radeon_flush_cache; + break; + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + dev_priv->microcode = r200_cp_microcode; + dev_priv->flush_cache = radeon_flush_cache; + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + dev_priv->microcode = r300_cp_microcode; + dev_priv->flush_cache = r300_flush_cache; + break; + default: + DRM_ERROR("Unknown radeon family, aborting\n"); + return -EINVAL; + } + switch (dev_priv->bus_type) { + case RADEON_AGP: + dev_priv->create_ttm = drm_agp_init_ttm; + dev_priv->bus_init = radeon_ms_agp_init; + dev_priv->bus_restore = radeon_ms_agp_restore; + dev_priv->bus_save = radeon_ms_agp_save; + break; + case RADEON_PCIE: + dev_priv->create_ttm = radeon_ms_pcie_create_ttm; + dev_priv->bus_finish = radeon_ms_pcie_finish; + dev_priv->bus_init = radeon_ms_pcie_init; + dev_priv->bus_restore = radeon_ms_pcie_restore; + dev_priv->bus_save = radeon_ms_pcie_save; + break; + default: + DRM_ERROR("Unknown radeon bus type, aborting\n"); + return -EINVAL; + } + dev_priv->properties = NULL; + for (i = 1; i < sizeof(properties)/sizeof(properties[0]); i++) { + if (dev->pdev->subsystem_vendor == properties[i].subvendor && + dev->pdev->subsystem_device == properties[i].subdevice) { + DRM_INFO("[radeon_ms] found properties for 0x%04X:0x%04X\n", + properties[i].subvendor, properties[i].subdevice); + dev_priv->properties = &properties[i]; + } + } + if (dev_priv->properties == NULL) { + dev_priv->properties = &properties[0]; + } + return 0; +} diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c new file mode 100644 index 00000000..96bb0858 --- /dev/null +++ b/shared-core/radeon_ms_fence.c @@ -0,0 +1,129 @@ +/* + * Copyright 2007 Dave Airlie. + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Dave Airlie + * Jerome Glisse + */ +#include "radeon_ms.h" + +static void radeon_ms_fence_flush(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_fence_class_manager *fc = &dev->fm.fence_class[0]; + uint32_t pending_flush_types = 0; + uint32_t sequence; + + if (dev_priv == NULL) { + return; + } + pending_flush_types = fc->pending_flush | + ((fc->pending_exe_flush) ? + DRM_FENCE_TYPE_EXE : 0); + if (pending_flush_types) { + sequence = mmio_read(dev_priv, dev_priv->fence_reg); + drm_fence_handler(dev, 0, sequence, pending_flush_types, 0); + } +} + +int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t fence_id, cmd[2], i, ret; + + if (!dev_priv || !dev_priv->cp_ready) { + return -EINVAL; + } + fence_id = (++dev_priv->fence_id_last); + if (dev_priv->fence_id_last > 0x7FFFFFFF) { + fence_id = dev_priv->fence_id_last = 1; + } + *sequence = fence_id; + *native_type = DRM_FENCE_TYPE_EXE; + if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) { + *native_type |= DRM_RADEON_FENCE_TYPE_RW; + dev_priv->flush_cache(dev); + } + cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0); + cmd[1] = fence_id; + for (i = 0; i < dev_priv->usec_timeout; i++) { + ret = radeon_ms_ring_emit(dev, cmd, 2); + if (!ret) { + dev_priv->irq_emit(dev); + return 0; + } + } + return -EBUSY; +} + +void radeon_ms_fence_handler(struct drm_device * dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_fence_manager *fm = &dev->fm; + + if (dev_priv == NULL) { + return; + } + + write_lock(&fm->lock); + radeon_ms_fence_flush(dev); + write_unlock(&fm->lock); +} + +int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class, + uint32_t flags) +{ + /* + * We have an irq that tells us when we have a new breadcrumb. + */ + if (class == 0 && flags == DRM_FENCE_TYPE_EXE) + return 1; + + return 0; +} + +int radeon_ms_fence_types(struct drm_buffer_object *bo, + uint32_t *class, uint32_t *type) +{ + *class = 0; + if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) + *type = 3; + else + *type = 1; + return 0; +} + +void radeon_ms_poke_flush(struct drm_device *dev, uint32_t class) +{ + struct drm_fence_manager *fm = &dev->fm; + unsigned long flags; + + if (class != 0) + return; + write_lock_irqsave(&fm->lock, flags); + radeon_ms_fence_flush(dev); + write_unlock_irqrestore(&fm->lock, flags); +} diff --git a/shared-core/radeon_ms_gpu.c b/shared-core/radeon_ms_gpu.c new file mode 100644 index 00000000..28683781 --- /dev/null +++ b/shared-core/radeon_ms_gpu.c @@ -0,0 +1,589 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "radeon_ms.h" + +static int radeon_ms_gpu_address_space_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + /* initialize gpu mapping */ + dev_priv->gpu_vram_start = dev_priv->vram.offset; + dev_priv->gpu_vram_end = dev_priv->gpu_vram_start + dev_priv->vram.size; + /* align it on 16Mo boundary (clamp memory which is then + * unreachable but not manufacturer should use strange + * memory size */ + dev_priv->gpu_vram_end = dev_priv->gpu_vram_end & (~0xFFFFFF); + dev_priv->gpu_vram_end -= 1; + dev_priv->gpu_vram_size = dev_priv->gpu_vram_end - + dev_priv->gpu_vram_start + 1; + /* set gart size to 32Mo FIXME: should make a parameter for this */ + dev_priv->gpu_gart_size = 1024 * 1024 * 32; + if (dev_priv->gpu_gart_size > (0xffffffffU - dev_priv->gpu_vram_end)) { + /* align gart start to next 4Ko in gpu address space */ + dev_priv->gpu_gart_start = (dev_priv->gpu_vram_end + 1) + 0xfff; + dev_priv->gpu_gart_start = dev_priv->gpu_gart_start & (~0xfff); + dev_priv->gpu_gart_end = dev_priv->gpu_gart_start + + dev_priv->gpu_gart_size; + dev_priv->gpu_gart_end = (dev_priv->gpu_gart_end & (~0xfff)) - + 0x1000; + } else { + /* align gart start to next 4Ko in gpu address space */ + dev_priv->gpu_gart_start = (dev_priv->gpu_vram_start & ~0xfff) - + dev_priv->gpu_gart_size; + dev_priv->gpu_gart_start = dev_priv->gpu_gart_start & (~0xfff); + dev_priv->gpu_gart_end = dev_priv->gpu_gart_start + + dev_priv->gpu_gart_size; + dev_priv->gpu_gart_end = (dev_priv->gpu_gart_end & (~0xfff)) - + 0x1000; + } + state->mc_fb_location = + REG_S(MC_FB_LOCATION, MC_FB_START, + dev_priv->gpu_vram_start >> 16) | + REG_S(MC_FB_LOCATION, MC_FB_TOP, dev_priv->gpu_vram_end >> 16); + state->display_base_addr = + REG_S(DISPLAY_BASE_ADDR, DISPLAY_BASE_ADDR, + dev_priv->gpu_vram_start); + state->config_aper_0_base = dev_priv->gpu_vram_start; + state->config_aper_1_base = dev_priv->gpu_vram_start; + state->config_aper_size = dev_priv->gpu_vram_size; + DRM_INFO("[radeon_ms] gpu vram start 0x%08X\n", + dev_priv->gpu_vram_start); + DRM_INFO("[radeon_ms] gpu vram end 0x%08X\n", + dev_priv->gpu_vram_end); + DRM_INFO("[radeon_ms] gpu gart start 0x%08X\n", + dev_priv->gpu_gart_start); + DRM_INFO("[radeon_ms] gpu gart end 0x%08X\n", + dev_priv->gpu_gart_end); + return 0; +} + +static void radeon_ms_gpu_reset(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t clock_cntl_index, mclk_cntl, rbbm_soft_reset; + uint32_t reset_mask, host_path_cntl, cache_mode; + + radeon_ms_cp_stop(dev); + radeon_ms_gpu_flush(dev); + + /* reset clock */ + clock_cntl_index = MMIO_R(CLOCK_CNTL_INDEX); + pll_index_errata(dev_priv); + mclk_cntl = PPLL_R(MCLK_CNTL); + PPLL_W(MCLK_CNTL, + mclk_cntl | + MCLK_CNTL__FORCE_MCLKA | + MCLK_CNTL__FORCE_MCLKB | + MCLK_CNTL__FORCE_YCLKA | + MCLK_CNTL__FORCE_YCLKB | + MCLK_CNTL__FORCE_MC | + MCLK_CNTL__FORCE_AIC); + PPLL_W(SCLK_CNTL, + PPLL_R(SCLK_CNTL) | + SCLK_CNTL__FORCE_CP | + SCLK_CNTL__FORCE_VIP); + + /* Soft resetting HDP thru RBBM_SOFT_RESET register can cause some + * unexpected behaviour on some machines. Here we use + * RADEON_HOST_PATH_CNTL to reset it. + */ + host_path_cntl = MMIO_R(HOST_PATH_CNTL); + rbbm_soft_reset = MMIO_R(RBBM_SOFT_RESET); + reset_mask = RBBM_SOFT_RESET__SOFT_RESET_CP | + RBBM_SOFT_RESET__SOFT_RESET_HI | + RBBM_SOFT_RESET__SOFT_RESET_VAP | + RBBM_SOFT_RESET__SOFT_RESET_SE | + RBBM_SOFT_RESET__SOFT_RESET_RE | + RBBM_SOFT_RESET__SOFT_RESET_PP | + RBBM_SOFT_RESET__SOFT_RESET_E2 | + RBBM_SOFT_RESET__SOFT_RESET_RB; + MMIO_W(RBBM_SOFT_RESET, rbbm_soft_reset | reset_mask); + MMIO_R(RBBM_SOFT_RESET); + MMIO_W(RBBM_SOFT_RESET, 0); + MMIO_R(RBBM_SOFT_RESET); + + cache_mode = MMIO_R(RB2D_DSTCACHE_MODE); + MMIO_W(RB2D_DSTCACHE_MODE, + cache_mode | RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE); + + MMIO_W(HOST_PATH_CNTL, host_path_cntl | HOST_PATH_CNTL__HDP_SOFT_RESET); + MMIO_R(HOST_PATH_CNTL); + MMIO_W(HOST_PATH_CNTL, host_path_cntl); + MMIO_R(HOST_PATH_CNTL); + + MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index); + pll_index_errata(dev_priv); + PPLL_W(MCLK_CNTL, mclk_cntl); +} + +static void radeon_ms_gpu_resume(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t a; + uint32_t i; + + /* make sure we have sane offset before restoring crtc */ + a = (MMIO_R(MC_FB_LOCATION) & MC_FB_LOCATION__MC_FB_START__MASK) << 16; + MMIO_W(DISPLAY_BASE_ADDR, a); + MMIO_W(CRTC2_DISPLAY_BASE_ADDR, a); + MMIO_W(CRTC_OFFSET, 0); + MMIO_W(CUR_OFFSET, 0); + MMIO_W(CRTC_OFFSET_CNTL, CRTC_OFFSET_CNTL__CRTC_OFFSET_FLIP_CNTL); + MMIO_W(CRTC2_OFFSET, 0); + MMIO_W(CUR2_OFFSET, 0); + MMIO_W(CRTC2_OFFSET_CNTL, CRTC2_OFFSET_CNTL__CRTC2_OFFSET_FLIP_CNTL); + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(CRTC_OFFSET__CRTC_GUI_TRIG_OFFSET & + MMIO_R(CRTC_OFFSET))) { + break; + } + DRM_UDELAY(1); + } + if (i >= dev_priv->usec_timeout) { + DRM_ERROR("[radeon_ms] timeout waiting for crtc...\n"); + } + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET & + MMIO_R(CRTC2_OFFSET))) { + break; + } + DRM_UDELAY(1); + } + if (i >= dev_priv->usec_timeout) { + DRM_ERROR("[radeon_ms] timeout waiting for crtc...\n"); + } + DRM_UDELAY(10000); +} + +static void radeon_ms_gpu_stop(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl; + uint32_t crtc2_gen_cntl, i; + + radeon_ms_wait_for_idle(dev); + /* Capture MC_STATUS in case things go wrong ... */ + ov0_scale_cntl = dev_priv->ov0_scale_cntl = MMIO_R(OV0_SCALE_CNTL); + crtc_ext_cntl = dev_priv->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL); + crtc_gen_cntl = dev_priv->crtc_gen_cntl = MMIO_R(CRTC_GEN_CNTL); + crtc2_gen_cntl = dev_priv->crtc2_gen_cntl = MMIO_R(CRTC2_GEN_CNTL); + ov0_scale_cntl &= ~OV0_SCALE_CNTL__OV0_OVERLAY_EN__MASK; + crtc_ext_cntl |= CRTC_EXT_CNTL__CRTC_DISPLAY_DIS; + crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_CUR_EN; + crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_ICON_EN; + crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_EXT_DISP_EN; + crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B; + crtc2_gen_cntl &= ~CRTC2_GEN_CNTL__CRTC2_CUR_EN; + crtc2_gen_cntl &= ~CRTC2_GEN_CNTL__CRTC2_ICON_EN; + crtc2_gen_cntl |= CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B; + MMIO_W(OV0_SCALE_CNTL, ov0_scale_cntl); + MMIO_W(CRTC_EXT_CNTL, crtc_ext_cntl); + MMIO_W(CRTC_GEN_CNTL, crtc_gen_cntl); + MMIO_W(CRTC2_GEN_CNTL, crtc2_gen_cntl); + DRM_UDELAY(10000); + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + for (i = 0; i < dev_priv->usec_timeout; i++) { + if ((MC_STATUS__MC_IDLE & MMIO_R(MC_STATUS))) { + DRM_INFO("[radeon_ms] gpu stoped in %d usecs\n", + i); + return; + } + DRM_UDELAY(1); + } + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + for (i = 0; i < dev_priv->usec_timeout; i++) { + if ((MC_STATUS__MC_IDLE_R3 & MMIO_R(MC_STATUS))) { + DRM_INFO("[radeon_ms] gpu stoped in %d usecs\n", + i); + return; + } + DRM_UDELAY(1); + } + break; + default: + DRM_ERROR("Unknown radeon family, aborting\n"); + return; + } + DRM_ERROR("[radeon_ms] failed to stop gpu...will proceed anyway\n"); + DRM_UDELAY(20000); +} + +static int radeon_ms_wait_for_fifo(struct drm_device *dev, int num_fifo) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->usec_timeout; i++) { + int t; + t = RBBM_STATUS__CMDFIFO_AVAIL__MASK & MMIO_R(RBBM_STATUS); + t = t >> RBBM_STATUS__CMDFIFO_AVAIL__SHIFT; + if (t >= num_fifo) + return 0; + DRM_UDELAY(1); + } + DRM_ERROR("[radeon_ms] failed to wait for fifo\n"); + return -EBUSY; +} + +int radeon_ms_gpu_initialize(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + int ret; + + state->disp_misc_cntl = DISP_MISC_CNTL__SYNC_PAD_FLOP_EN | + REG_S(DISP_MISC_CNTL, SYNC_STRENGTH, 2) | + REG_S(DISP_MISC_CNTL, PALETTE_MEM_RD_MARGIN, 0xb) | + REG_S(DISP_MISC_CNTL, PALETTE2_MEM_RD_MARGIN, 0xb) | + REG_S(DISP_MISC_CNTL, RMX_BUF_MEM_RD_MARGIN, 0x5); + state->disp_merge_cntl = REG_S(DISP_MERGE_CNTL, DISP_GRPH_ALPHA, 0xff) | + REG_S(DISP_MERGE_CNTL, DISP_OV0_ALPHA, 0xff); + state->disp_pwr_man = DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN | + DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN | + REG_S(DISP_PWR_MAN, DISP_PWR_MAN_DPMS, DISP_PWR_MAN_DPMS__OFF) | + DISP_PWR_MAN__DISP_D3_RST | + DISP_PWR_MAN__DISP_D3_REG_RST | + DISP_PWR_MAN__DISP_D3_GRPH_RST | + DISP_PWR_MAN__DISP_D3_SUBPIC_RST | + DISP_PWR_MAN__DISP_D3_OV0_RST | + DISP_PWR_MAN__DISP_D1D2_GRPH_RST | + DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST | + DISP_PWR_MAN__DISP_D1D2_OV0_RST | + DISP_PWR_MAN__DISP_DVO_ENABLE_RST | + DISP_PWR_MAN__TV_ENABLE_RST; + state->disp2_merge_cntl = 0; + ret = radeon_ms_gpu_address_space_init(dev); + if (ret) { + return ret; + } + + /* initialize bus */ + ret = dev_priv->bus_init(dev); + if (ret != 0) { + return ret; + } + return 0; +} + +void radeon_ms_gpu_dpms(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + if (dev_priv->crtc1_dpms == dev_priv->crtc2_dpms) { + /* both crtc are in same state so use global display pwr */ + state->disp_pwr_man &= ~DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK; + switch(dev_priv->crtc1_dpms) { + case DPMSModeOn: + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__ON); + break; + case DPMSModeStandby: + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__STANDBY); + break; + case DPMSModeSuspend: + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__SUSPEND); + break; + case DPMSModeOff: + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__OFF); + break; + default: + /* error */ + break; + } + MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); + } else { + state->disp_pwr_man &= ~DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK; + state->disp_pwr_man |= REG_S(DISP_PWR_MAN, + DISP_PWR_MAN_DPMS, + DISP_PWR_MAN_DPMS__ON); + MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); + } +} + +void radeon_ms_gpu_flush(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t i; + uint32_t purge2d; + uint32_t purge3d; + + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + purge2d = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | + REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FREE, 3); + purge3d = REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | + REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FREE, 3); + MMIO_W(RB2D_DSTCACHE_CTLSTAT, purge2d); + MMIO_W(RB3D_DSTCACHE_CTLSTAT, purge3d); + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + purge2d = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) | + REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FREE, 3); + purge3d = REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FLUSH, 3) | + REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FREE, 3); + MMIO_W(RB2D_DSTCACHE_CTLSTAT, purge2d); + MMIO_W(RB3D_DSTCACHE_CTLSTAT_R3, purge3d); + break; + default: + DRM_ERROR("Unknown radeon family, aborting\n"); + return; + } + for (i = 0; i < dev_priv->usec_timeout; i++) { + if (!(RB2D_DSTCACHE_CTLSTAT__DC_BUSY & + MMIO_R(RB2D_DSTCACHE_CTLSTAT))) { + return; + } + DRM_UDELAY(1); + } + DRM_ERROR("[radeon_ms] gpu flush timeout\n"); +} + +void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t wait_until; + uint32_t fbstart; + int ret, ok = 1; + + radeon_ms_gpu_reset(dev); + radeon_ms_wait_for_idle(dev); + radeon_ms_gpu_stop(dev); + + MMIO_W(AIC_CTRL, state->aic_ctrl); + MMIO_W(MC_FB_LOCATION, state->mc_fb_location); + MMIO_R(MC_FB_LOCATION); + MMIO_W(CONFIG_APER_0_BASE, state->config_aper_0_base); + MMIO_W(CONFIG_APER_1_BASE, state->config_aper_1_base); + MMIO_W(CONFIG_APER_SIZE, state->config_aper_size); + MMIO_W(DISPLAY_BASE_ADDR, state->display_base_addr); + if (dev_priv->bus_restore) { + dev_priv->bus_restore(dev, state); + } + + radeon_ms_gpu_reset(dev); + radeon_ms_gpu_resume(dev); + + MMIO_W(BUS_CNTL, state->bus_cntl); + wait_until = WAIT_UNTIL__WAIT_DMA_VIPH0_IDLE | + WAIT_UNTIL__WAIT_DMA_VIPH1_IDLE | + WAIT_UNTIL__WAIT_DMA_VIPH2_IDLE | + WAIT_UNTIL__WAIT_DMA_VIPH3_IDLE | + WAIT_UNTIL__WAIT_DMA_VID_IDLE | + WAIT_UNTIL__WAIT_DMA_GUI_IDLE | + WAIT_UNTIL__WAIT_2D_IDLE | + WAIT_UNTIL__WAIT_3D_IDLE | + WAIT_UNTIL__WAIT_2D_IDLECLEAN | + WAIT_UNTIL__WAIT_3D_IDLECLEAN | + WAIT_UNTIL__WAIT_HOST_IDLECLEAN; + switch (dev_priv->family) { + case CHIP_R100: + case CHIP_R200: + case CHIP_RV200: + case CHIP_RV250: + case CHIP_RV280: + case CHIP_RS300: + break; + case CHIP_R300: + case CHIP_R350: + case CHIP_R360: + case CHIP_RV350: + case CHIP_RV370: + case CHIP_RV380: + case CHIP_RS400: + case CHIP_RV410: + case CHIP_R420: + case CHIP_R430: + case CHIP_R480: + wait_until |= WAIT_UNTIL__WAIT_VAP_IDLE; + break; + } + MMIO_W(WAIT_UNTIL, wait_until); + MMIO_W(DISP_MISC_CNTL, state->disp_misc_cntl); + MMIO_W(DISP_PWR_MAN, state->disp_pwr_man); + MMIO_W(DISP_MERGE_CNTL, state->disp_merge_cntl); + MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl); + MMIO_W(DISP2_MERGE_CNTL, state->disp2_merge_cntl); + + /* Setup engine location. This shouldn't be necessary since we + * set them appropriately before any accel ops, but let's avoid + * random bogus DMA in case we inadvertently trigger the engine + * in the wrong place (happened). + */ + ret = radeon_ms_wait_for_fifo(dev, 2); + if (ret) { + ok = 0; + DRM_ERROR("[radeon_ms] no fifo for setting up dst & src gui\n"); + DRM_ERROR("[radeon_ms] proceed anyway\n"); + } + fbstart = (MC_FB_LOCATION__MC_FB_START__MASK & + MMIO_R(MC_FB_LOCATION)) << 16; + MMIO_W(DST_PITCH_OFFSET, + REG_S(DST_PITCH_OFFSET, DST_OFFSET, fbstart >> 10)); + MMIO_W(SRC_PITCH_OFFSET, + REG_S(SRC_PITCH_OFFSET, SRC_OFFSET, fbstart >> 10)); + + ret = radeon_ms_wait_for_fifo(dev, 1); + if (ret) { + ok = 0; + DRM_ERROR("[radeon_ms] no fifo for setting up dp data type\n"); + DRM_ERROR("[radeon_ms] proceed anyway\n"); + } +#ifdef __BIG_ENDIAN + MMIO_W(DP_DATATYPE, DP_DATATYPE__DP_BYTE_PIX_ORDER); +#else + MMIO_W(DP_DATATYPE, 0); +#endif + + ret = radeon_ms_wait_for_fifo(dev, 1); + if (ret) { + ok = 0; + DRM_ERROR("[radeon_ms] no fifo for setting up surface cntl\n"); + DRM_ERROR("[radeon_ms] proceed anyway\n"); + } + MMIO_W(SURFACE_CNTL, SURFACE_CNTL__SURF_TRANSLATION_DIS); + + ret = radeon_ms_wait_for_fifo(dev, 2); + if (ret) { + ok = 0; + DRM_ERROR("[radeon_ms] no fifo for setting scissor\n"); + DRM_ERROR("[radeon_ms] proceed anyway\n"); + } + MMIO_W(DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff); + MMIO_W(DEFAULT2_SC_BOTTOM_RIGHT, 0x1fff1fff); + + ret = radeon_ms_wait_for_fifo(dev, 1); + if (ret) { + ok = 0; + DRM_ERROR("[radeon_ms] no fifo for setting up gui cntl\n"); + DRM_ERROR("[radeon_ms] proceed anyway\n"); + } + MMIO_W(DP_GUI_MASTER_CNTL, 0); + + ret = radeon_ms_wait_for_fifo(dev, 5); + if (ret) { + ok = 0; + DRM_ERROR("[radeon_ms] no fifo for setting up clear color\n"); + DRM_ERROR("[radeon_ms] proceed anyway\n"); + } + MMIO_W(DP_BRUSH_BKGD_CLR, 0x00000000); + MMIO_W(DP_BRUSH_FRGD_CLR, 0xffffffff); + MMIO_W(DP_SRC_BKGD_CLR, 0x00000000); + MMIO_W(DP_SRC_FRGD_CLR, 0xffffffff); + MMIO_W(DP_WRITE_MSK, 0xffffffff); + + if (!ok) { + DRM_ERROR("[radeon_ms] engine restore not enough fifo\n"); + } +} + +void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->aic_ctrl = MMIO_R(AIC_CTRL); + state->bus_cntl = MMIO_R(BUS_CNTL); + state->mc_fb_location = MMIO_R(MC_FB_LOCATION); + state->display_base_addr = MMIO_R(DISPLAY_BASE_ADDR); + state->config_aper_0_base = MMIO_R(CONFIG_APER_0_BASE); + state->config_aper_1_base = MMIO_R(CONFIG_APER_1_BASE); + state->config_aper_size = MMIO_R(CONFIG_APER_SIZE); + state->disp_misc_cntl = MMIO_R(DISP_MISC_CNTL); + state->disp_pwr_man = MMIO_R(DISP_PWR_MAN); + state->disp_merge_cntl = MMIO_R(DISP_MERGE_CNTL); + state->disp_output_cntl = MMIO_R(DISP_OUTPUT_CNTL); + state->disp2_merge_cntl = MMIO_R(DISP2_MERGE_CNTL); + if (dev_priv->bus_save) { + dev_priv->bus_save(dev, state); + } +} + +int radeon_ms_wait_for_idle(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i, j, ret; + + for (i = 0; i < 2; i++) { + ret = radeon_ms_wait_for_fifo(dev, 64); + if (ret) { + DRM_ERROR("[radeon_ms] fifo not empty\n"); + } + for (j = 0; j < dev_priv->usec_timeout; j++) { + if (!(RBBM_STATUS__GUI_ACTIVE & MMIO_R(RBBM_STATUS))) { + radeon_ms_gpu_flush(dev); + return 0; + } + DRM_UDELAY(1); + } + DRM_ERROR("[radeon_ms] idle timed out: status=0x%08x\n", + MMIO_R(RBBM_STATUS)); + radeon_ms_gpu_stop(dev); + radeon_ms_gpu_reset(dev); + } + return -EBUSY; +} diff --git a/shared-core/radeon_ms_i2c.c b/shared-core/radeon_ms_i2c.c new file mode 100644 index 00000000..1801c496 --- /dev/null +++ b/shared-core/radeon_ms_i2c.c @@ -0,0 +1,279 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "radeon_ms.h" + +static int get_clock(void *data) +{ + struct radeon_ms_i2c *i2c = data; + struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; + int v; + + switch (i2c->reg) { + case VIPPAD_EN: + v = MMIO_R(VIPPAD_Y); + if ((REG_G(VIPPAD_Y, VIPPAD_Y_VHAD, v) & 2)) { + v = 1; + } else { + v = 0; + } + break; + case VIPPAD1_EN: + v = MMIO_R(VIPPAD1_Y); + if ((REG_G(VIPPAD1_Y, VIPPAD_Y_DVODATA, v) & 8)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_DDC1: + v = MMIO_R(GPIO_DDC1); + if ((GPIO_DDC1__DDC1_CLK_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_DDC2: + v = MMIO_R(GPIO_DDC2); + if ((GPIO_DDC2__DDC2_CLK_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + default: + v = 0; + break; + } + return v; +} + +static int get_data(void *data) +{ + struct radeon_ms_i2c *i2c = data; + struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; + int v; + + switch (i2c->reg) { + case VIPPAD_EN: + v = MMIO_R(VIPPAD_Y); + if ((REG_G(VIPPAD_Y, VIPPAD_Y_VHAD, v) & 1)) { + v = 1; + } else { + v = 0; + } + break; + case VIPPAD1_EN: + v = MMIO_R(VIPPAD1_Y); + if ((REG_G(VIPPAD1_Y, VIPPAD_Y_DVODATA, v) & 4)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_DDC1: + v = MMIO_R(GPIO_DDC1); + if ((GPIO_DDC1__DDC1_DATA_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_DDC2: + v = MMIO_R(GPIO_DDC2); + if ((GPIO_DDC2__DDC2_DATA_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + default: + v = 0; + break; + } + return v; +} + +static void set_clock(void *i2c_priv, int clock) +{ + struct radeon_ms_i2c *i2c = i2c_priv; + struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; + int v, line; + + v = MMIO_R(i2c->reg); + switch (i2c->reg) { + case VIPPAD_EN: + line = REG_G(VIPPAD_EN, VIPPAD_EN_VHAD, v) & ~2; + v &= ~VIPPAD_EN__VIPPAD_EN_VHAD__MASK; + if (!clock) { + v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line | 2); + } else { + v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line); + } + break; + case VIPPAD1_EN: + line = REG_G(VIPPAD1_EN, VIPPAD_EN_DVODATA, v) & ~8; + v &= ~VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK; + if (!clock) { + v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line | 8); + } else { + v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line); + } + break; + case GPIO_DDC1: + v &= ~GPIO_DDC1__DDC1_CLK_OUT_EN; + if (!clock) { + v |= GPIO_DDC1__DDC1_CLK_OUT_EN; + } + break; + case GPIO_DDC2: + v &= ~GPIO_DDC2__DDC2_CLK_OUT_EN; + if (!clock) { + v |= GPIO_DDC2__DDC2_CLK_OUT_EN; + } + break; + default: + return; + } + MMIO_W(i2c->reg, v); +} + +static void set_data(void *i2c_priv, int data) +{ + struct radeon_ms_i2c *i2c = i2c_priv; + struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private; + int v, line; + + v = MMIO_R(i2c->reg); + switch (i2c->reg) { + case VIPPAD_EN: + line = REG_G(VIPPAD_EN, VIPPAD_EN_VHAD, v) & ~1; + v &= ~VIPPAD_EN__VIPPAD_EN_VHAD__MASK; + if (!data) { + v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line | 1); + } else { + v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line); + } + break; + case VIPPAD1_EN: + line = REG_G(VIPPAD1_EN, VIPPAD_EN_DVODATA, v) & ~4; + v &= ~VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK; + if (!data) { + v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line | 4); + } else { + v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line); + } + break; + case GPIO_DDC1: + v &= ~GPIO_DDC1__DDC1_DATA_OUT_EN; + if (!data) { + v |= GPIO_DDC1__DDC1_DATA_OUT_EN; + } + break; + case GPIO_DDC2: + v &= ~GPIO_DDC2__DDC2_DATA_OUT_EN; + if (!data) { + v |= GPIO_DDC2__DDC2_DATA_OUT_EN; + } + break; + default: + return; + } + MMIO_W(i2c->reg, v); +} + +/** + * radeon_ms_i2c_create - instantiate an radeon i2c bus on specified GPIO reg + * @dev: DRM device + * @output: driver specific output device + * @reg: GPIO reg to use + * @name: name for this bus + * + * Creates and registers a new i2c bus with the Linux i2c layer, for use + * in output probing and control (e.g. DDC or SDVO control functions). + * + */ +struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, + const uint32_t reg, + const char *name) +{ + struct radeon_ms_i2c *i2c; + int ret; + + i2c = drm_alloc(sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); + if (i2c == NULL) { + return NULL; + } + memset(i2c, 0, sizeof(struct radeon_ms_i2c)); + + i2c->drm_dev = dev; + i2c->reg = reg; + snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-%s", name); + i2c->adapter.owner = THIS_MODULE; + /* fixme need to take a look at what its needed for */ + i2c->adapter.id = I2C_HW_B_RADEON; + i2c->adapter.algo_data = &i2c->algo; + i2c->adapter.dev.parent = &dev->pdev->dev; + i2c->algo.setsda = set_data; + i2c->algo.setscl = set_clock; + i2c->algo.getsda = get_data; + i2c->algo.getscl = get_clock; + i2c->algo.udelay = 20; + i2c->algo.timeout = usecs_to_jiffies(2200); + i2c->algo.data = i2c; + + i2c_set_adapdata(&i2c->adapter, i2c); + + ret = i2c_bit_add_bus(&i2c->adapter); + if(ret) { + DRM_INFO("[radeon_ms] failed to register I2C '%s' bus\n", + i2c->adapter.name); + goto out_free; + } + DRM_INFO("[radeon_ms] registered I2C '%s' bus\n", i2c->adapter.name); + return i2c; + +out_free: + drm_free(i2c, sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); + return NULL; +} + +/** + * radeon_ms_i2c_destroy - unregister and free i2c bus resources + * @output: channel to free + * + * Unregister the adapter from the i2c layer, then free the structure. + */ +void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c) +{ + if (i2c == NULL) { + return; + } + i2c_del_adapter(&i2c->adapter); + drm_free(i2c, sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER); +} diff --git a/shared-core/radeon_ms_irq.c b/shared-core/radeon_ms_irq.c new file mode 100644 index 00000000..24182c75 --- /dev/null +++ b/shared-core/radeon_ms_irq.c @@ -0,0 +1,160 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +static uint32_t radeon_ack_irqs(struct drm_radeon_private *dev_priv, + uint32_t mask) +{ + uint32_t irqs; + + irqs = MMIO_R(GEN_INT_STATUS); + if (irqs) { + MMIO_W(GEN_INT_STATUS, irqs); + } + if (irqs & (~mask)) { + /* reprogram irq */ + MMIO_W(GEN_INT_CNTL, dev_priv->driver_state.gen_int_cntl); + } + return irqs; +} + +void radeon_ms_irq_emit(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t cmd[4]; + int i, ret; + + cmd[0] = CP_PACKET0(GEN_INT_CNTL, 1); + cmd[1] = dev_priv->driver_state.gen_int_cntl | GEN_INT_CNTL__SW_INT_EN; + cmd[2] = GEN_INT_STATUS__SW_INT_SET; + /* try to wait but if we timeout we likely are in bad situation */ + for (i = 0; i < dev_priv->usec_timeout; i++) { + ret = radeon_ms_ring_emit(dev, cmd, 3); + if (!ret) { + break; + } + } +} + +static void radeon_ms_irq_enable(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + state->gen_int_cntl = GEN_INT_CNTL__SW_INT_EN; + radeon_ms_irq_restore(dev, state); +} + +irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS) +{ + struct drm_device *dev = (struct drm_device *)arg; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t status, mask; + + /* Only consider the bits we're interested in - others could be used + * outside the DRM + */ + mask = GEN_INT_STATUS__SW_INT | + GEN_INT_STATUS__CRTC_VBLANK_STAT | + GEN_INT_STATUS__CRTC2_VBLANK_STAT; + status = radeon_ack_irqs(dev_priv, mask); + if (!status) { + return IRQ_NONE; + } + + /* SW interrupt */ + if (GEN_INT_STATUS__SW_INT & status) { + radeon_ms_fence_handler(dev); + } + radeon_ms_fence_handler(dev); + return IRQ_HANDLED; +} + +void radeon_ms_irq_preinstall(struct drm_device * dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + uint32_t mask; + + /* Disable *all* interrupts */ + state->gen_int_cntl = 0; + radeon_ms_irq_restore(dev, state); + + /* Clear bits if they're already high */ + mask = GEN_INT_STATUS__SW_INT | + GEN_INT_STATUS__CRTC_VBLANK_STAT | + GEN_INT_STATUS__CRTC2_VBLANK_STAT; + radeon_ack_irqs(dev_priv, mask); +} + +void radeon_ms_irq_postinstall(struct drm_device * dev) +{ + radeon_ms_irq_enable(dev); +} + +int radeon_ms_irq_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + /* Disable *all* interrupts */ + state->gen_int_cntl = 0; + radeon_ms_irq_restore(dev, state); + return 0; +} + +void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + MMIO_W(GEN_INT_CNTL, state->gen_int_cntl); +} + +void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + state->gen_int_cntl = MMIO_R(GEN_INT_CNTL); +} + +void radeon_ms_irq_uninstall(struct drm_device * dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + if (dev_priv == NULL) { + return; + } + + /* Disable *all* interrupts */ + state->gen_int_cntl = 0; + radeon_ms_irq_restore(dev, state); +} diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c new file mode 100644 index 00000000..4d6cb01e --- /dev/null +++ b/shared-core/radeon_ms_output.c @@ -0,0 +1,333 @@ +/* + * Copyright 2007 Jérôme Glisse + * Copyright 2007 Alex Deucher + * Copyright 2007 Dave Airlie + * 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 on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "radeon_ms.h" + +static struct radeon_ms_output *radeon_ms_connector_get_output( + struct drm_radeon_private *dev_priv, + struct radeon_ms_connector *connector, int i) +{ + if (connector->outputs[i] < 0) { + return NULL; + } + if (connector->outputs[i] >= RADEON_MAX_OUTPUTS) { + return NULL; + } + i = connector->outputs[i]; + if (dev_priv->outputs[i] == NULL) { + return NULL; + } + if (dev_priv->outputs[i]->connector == NULL) { + return dev_priv->outputs[i]; + } + if (dev_priv->outputs[i]->connector == connector) { + return dev_priv->outputs[i]; + } + return NULL; +} + +static void radeon_ms_output_dpms(struct drm_output *output, int mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_ms_connector *connector = output->driver_private; + struct radeon_ms_output *routput = NULL; + int i; + + if (connector == NULL) { + return; + } + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + routput = radeon_ms_connector_get_output(dev_priv, + connector, i); + + if (routput) { + routput->connector = connector; + routput->dpms(routput, mode); + } + } + radeon_ms_gpu_dpms(output->dev); +} + +static int radeon_ms_output_mode_valid(struct drm_output *output, + struct drm_display_mode *mode) +{ + struct radeon_ms_connector *connector = output->driver_private; + + if (connector == NULL) { + return MODE_ERROR; + } + return MODE_OK; +} + +static bool radeon_ms_output_mode_fixup(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_ms_output_prepare(struct drm_output *output) +{ + if (output->funcs->dpms) { + output->funcs->dpms(output, DPMSModeOff); + } +} + +static void radeon_ms_output_commit(struct drm_output *output) +{ + if (output->funcs->dpms) { + output->funcs->dpms(output, DPMSModeOn); + } +} + +static void radeon_ms_output_mode_set(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_radeon_private *dev_priv = output->dev->dev_private; + struct radeon_ms_connector *connector = output->driver_private; + struct radeon_ms_crtc *crtc; + struct radeon_ms_output *routput = NULL; + int i; + + if (connector == NULL) { + return; + } + if (output->crtc == NULL) { + return; + } + crtc = output->crtc->driver_private; + connector->crtc = crtc->crtc; + /* catch unknown crtc */ + switch (connector->crtc) { + case 1: + case 2: + break; + default: + /* error */ + return; + } + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + routput = radeon_ms_connector_get_output(dev_priv, + connector, i); + if (routput) { + routput->connector = connector; + routput->mode_set(routput, mode, adjusted_mode); + } + } +} + +static enum drm_output_status radeon_ms_output_detect(struct drm_output *output) +{ + struct radeon_ms_connector *connector = output->driver_private; + + if (connector == NULL || connector->i2c == NULL) { + return output_status_unknown; + } + kfree(connector->edid); + connector->edid = drm_get_edid(output, &connector->i2c->adapter); + if (connector->edid == NULL) { + return output_status_unknown; + } + return output_status_connected; +} + +static int radeon_ms_output_get_modes(struct drm_output *output) +{ + struct radeon_ms_connector *connector = output->driver_private; + int ret = 0; + + if (connector == NULL || connector->i2c == NULL) { + return 0; + } + ret = drm_add_edid_modes(output, connector->edid); + kfree(connector->edid); + connector->edid = NULL; + return ret; +} + +static void radeon_ms_output_cleanup(struct drm_output *output) +{ + struct radeon_ms_connector *connector = output->driver_private; + + if (connector == NULL) { + return; + } + if (connector->edid) { + kfree(connector->edid); + } + connector->edid = NULL; + connector->output = NULL; + output->driver_private = NULL; +} + +static const struct drm_output_funcs radeon_ms_output_funcs = { + .dpms = radeon_ms_output_dpms, + .save = NULL, + .restore = NULL, + .mode_valid = radeon_ms_output_mode_valid, + .mode_fixup = radeon_ms_output_mode_fixup, + .prepare = radeon_ms_output_prepare, + .mode_set = radeon_ms_output_mode_set, + .commit = radeon_ms_output_commit, + .detect = radeon_ms_output_detect, + .get_modes = radeon_ms_output_get_modes, + .cleanup = radeon_ms_output_cleanup, +}; + +void radeon_ms_connectors_destroy(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_connector *connector = NULL; + int i = 0; + + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { + if (dev_priv->connectors[i]) { + connector = dev_priv->connectors[i]; + dev_priv->connectors[i] = NULL; + if (connector->output) { + drm_output_destroy(connector->output); + connector->output = NULL; + } + if (connector->i2c) { + radeon_ms_i2c_destroy(connector->i2c); + connector->i2c = NULL; + } + drm_free(connector, + sizeof(struct radeon_ms_connector), + DRM_MEM_DRIVER); + } + } +} + +int radeon_ms_connectors_from_properties(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_connector *connector = NULL; + struct drm_output *output = NULL; + int i = 0; + + radeon_ms_connectors_destroy(dev); + for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { + if (dev_priv->properties->connectors[i]) { + connector = + drm_alloc(sizeof(struct radeon_ms_connector), + DRM_MEM_DRIVER); + if (connector == NULL) { + radeon_ms_connectors_destroy(dev); + return -ENOMEM; + } + memcpy(connector, + dev_priv->properties->connectors[i], + sizeof(struct radeon_ms_connector)); + connector->i2c = radeon_ms_i2c_create(dev, + connector->i2c_reg, connector->name); + if (connector->i2c == NULL) { + radeon_ms_connectors_destroy(dev); + return -ENOMEM; + } + output = drm_output_create(dev, + &radeon_ms_output_funcs, + connector->name); + if (output == NULL) { + radeon_ms_connectors_destroy(dev); + return -EINVAL; + } + connector->output = output; + output->driver_private = connector; + output->possible_crtcs = 0x3; + dev_priv->connectors[i] = connector; + } + } + return 0; +} + +void radeon_ms_outputs_destroy(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i = 0; + + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + if (dev_priv->outputs[i]) { + drm_free(dev_priv->outputs[i], + sizeof(struct radeon_ms_output), + DRM_MEM_DRIVER); + dev_priv->outputs[i] = NULL; + } + } +} + +int radeon_ms_outputs_from_properties(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i = 0; + + radeon_ms_outputs_destroy(dev); + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + if (dev_priv->properties->outputs[i]) { + dev_priv->outputs[i] = + drm_alloc(sizeof(struct radeon_ms_output), + DRM_MEM_DRIVER); + if (dev_priv->outputs[i] == NULL) { + radeon_ms_outputs_destroy(dev); + return -ENOMEM; + } + memcpy(dev_priv->outputs[i], + dev_priv->properties->outputs[i], + sizeof(struct radeon_ms_output)); + dev_priv->outputs[i]->dev = dev; + dev_priv->outputs[i]->initialize(dev_priv->outputs[i]); + } + } + return 0; +} + +void radeon_ms_outputs_restore(struct drm_device *dev, + struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + if (dev_priv->outputs[i]) { + dev_priv->outputs[i]->restore(dev_priv->outputs[i], + state); + } + } +} + +void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { + if (dev_priv->outputs[i]) { + dev_priv->outputs[i]->save(dev_priv->outputs[i], state); + } + } +} diff --git a/shared-core/radeon_ms_reg.h b/shared-core/radeon_ms_reg.h new file mode 100644 index 00000000..d450280c --- /dev/null +++ b/shared-core/radeon_ms_reg.h @@ -0,0 +1,1655 @@ +/* + * Copyright 2007 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. + */ +#ifndef __RADEON_REG_H__ +#define __RADEON_REG_H__ + +#define MC_FB_LOCATION 0x00000148 +#define MC_FB_LOCATION__MC_FB_START__MASK 0x0000FFFF +#define MC_FB_LOCATION__MC_FB_START__SHIFT 0 +#define MC_FB_LOCATION__MC_FB_TOP__MASK 0xFFFF0000 +#define MC_FB_LOCATION__MC_FB_TOP__SHIFT 16 +#define MC_AGP_LOCATION 0x0000014C +#define MC_AGP_LOCATION__MC_AGP_START__MASK 0x0000FFFF +#define MC_AGP_LOCATION__MC_AGP_START__SHIFT 0 +#define MC_AGP_LOCATION__MC_AGP_TOP__MASK 0xFFFF0000 +#define MC_AGP_LOCATION__MC_AGP_TOP__SHIFT 16 +#define AGP_COMMAND 0x00000F60 +#define AGP_COMMAND__DATA_RATE__MASK 0x00000007 +#define AGP_COMMAND__DATA_RATE__SHIFT 0 +#define DATA_RATE__v2_1X 0x1 +#define DATA_RATE__v2_2X 0x2 +#define DATA_RATE__v2_4X 0x4 +#define DATA_RATE__v3_4X 0x1 +#define DATA_RATE__v3_8X 0x2 +#define AGP_COMMAND__AGP_EN 0x00000100 +#define AGP_COMMAND__SBA_EN 0x00000200 +#define AGP_COMMAND__RQ_DEPTH__MASK 0xFF000000 +#define AGP_COMMAND__RQ_DEPTH__SHIFT 24 +#define AGP_COMMAND__FW_EN 0x00000010 +#define AGP_COMMAND__MODE_4G_EN 0x00000020 +#define AGP_COMMAND__PARQSZ__MASK 0x0000E000 +#define AGP_COMMAND__PARQSZ__SHIFT 13 +#define AGP_STATUS 0x00000F5C +#define AGP_STATUS__RATE1X 0x00000001 +#define AGP_STATUS__RATE2X 0x00000002 +#define AGP_STATUS__RATE4X 0x00000004 +#define AGP_STATUS__SBA 0x00000200 +#define AGP_STATUS__RQ__MASK 0xFF000000 +#define AGP_STATUS__RQ__SHIFT 24 +#define AGP_STATUS__FW 0x00000010 +#define AGP_STATUS__MODE_4G 0x00000020 +#define AGP_STATUS__RATE1X_4X 0x00000001 +#define AGP_STATUS__RATE2X_8X 0x00000002 +#define AGP_STATUS__MODE_AGP30 0x00000008 +#define AGP_STATUS__CAL_CYCLE__MASK 0x00001C00 +#define AGP_STATUS__CAL_CYCLE__SHIFT 10 +#define AGP_STATUS__ISOCH_SUPPORT 0x00020000 +#define AGP_BASE 0x00000170 +#define AGP_BASE__AGP_BASE_ADDR__MASK 0xFFFFFFFF +#define AGP_BASE__AGP_BASE_ADDR__SHIFT 0 +#define AGP_BASE_2 0x0000015C +#define AGP_BASE_2__AGP_BASE_ADDR_2__MASK 0x0000000F +#define AGP_BASE_2__AGP_BASE_ADDR_2__SHIFT 0 +#define CONFIG_MEMSIZE 0x000000F8 +#define CONFIG_MEMSIZE__CONFIG_MEMSIZE__MASK 0x1F000000 +#define CONFIG_MEMSIZE__CONFIG_MEMSIZE__SHIFT 24 +#define CONFIG_MEMSIZE__CONFIG_MEMSIZE_R2__MASK 0x1FF00000 +#define CONFIG_MEMSIZE__CONFIG_MEMSIZE_R2__SHIFT 20 +#define CONFIG_APER_0_BASE 0x00000100 +#define CONFIG_APER_0_BASE__APER_0_BASE__MASK 0xFE000000 +#define CONFIG_APER_0_BASE__APER_0_BASE__SHIFT 25 +#define CONFIG_APER_1_BASE 0x00000104 +#define CONFIG_APER_1_BASE__APER_1_BASE__MASK 0xFF000000 +#define CONFIG_APER_1_BASE__APER_1_BASE__SHIFT 24 +#define CONFIG_APER_SIZE 0x00000108 +#define CONFIG_APER_SIZE__APER_SIZE__MASK 0x0F000000 +#define CONFIG_APER_SIZE__APER_SIZE__SHIFT 24 +#define GEN_INT_CNTL 0x00000040 +#define GEN_INT_CNTL__CRTC_VBLANK 0x00000001 +#define GEN_INT_CNTL__CRTC_VLINE 0x00000002 +#define GEN_INT_CNTL__CRTC_VSYNC 0x00000004 +#define GEN_INT_CNTL__SNAPSHOT 0x00000008 +#define GEN_INT_CNTL__FP_DETECT 0x00000010 +#define GEN_INT_CNTL__CRTC2_VLINE 0x00000020 +#define GEN_INT_CNTL__DMA_VIPH0_INT_EN 0x00001000 +#define GEN_INT_CNTL__CRTC2_VSYNC 0x00000040 +#define GEN_INT_CNTL__SNAPSHOT2 0x00000080 +#define GEN_INT_CNTL__CRTC2_VBLANK 0x00000200 +#define GEN_INT_CNTL__FP2_DETECT 0x00000400 +#define GEN_INT_CNTL__VSYNC_DIFF_OVER_LIMIT 0x00000800 +#define GEN_INT_CNTL__DMA_VIPH1_INT_EN 0x00002000 +#define GEN_INT_CNTL__DMA_VIPH2_INT_EN 0x00004000 +#define GEN_INT_CNTL__DMA_VIPH3_INT_EN 0x00008000 +#define GEN_INT_CNTL__I2C_INT_EN 0x00020000 +#define GEN_INT_CNTL__GUI_IDLE 0x00080000 +#define GEN_INT_CNTL__VIPH_INT_EN 0x01000000 +#define GEN_INT_CNTL__SW_INT_EN 0x02000000 +#define GEN_INT_CNTL__GEYSERVILLE 0x08000000 +#define GEN_INT_CNTL__DVI_I2C_INT 0x20000000 +#define GEN_INT_CNTL__GUIDMA 0x40000000 +#define GEN_INT_CNTL__VIDDMA 0x80000000 +#define GEN_INT_CNTL__TIMER_INT 0x00010000 +#define GEN_INT_CNTL__IDCT_INT_EN 0x08000000 +#define GEN_INT_STATUS 0x00000044 +#define GEN_INT_STATUS__CRTC_VBLANK_STAT 0x00000001 +#define GEN_INT_STATUS__CRTC_VBLANK_STAT_AK 0x00000001 +#define GEN_INT_STATUS__CRTC_VLINE_STAT 0x00000002 +#define GEN_INT_STATUS__CRTC_VLINE_STAT_AK 0x00000002 +#define GEN_INT_STATUS__CRTC_VSYNC_STAT 0x00000004 +#define GEN_INT_STATUS__CRTC_VSYNC_STAT_AK 0x00000004 +#define GEN_INT_STATUS__SNAPSHOT_STAT 0x00000008 +#define GEN_INT_STATUS__SNAPSHOT_STAT_AK 0x00000008 +#define GEN_INT_STATUS__FP_DETECT_STAT 0x00000010 +#define GEN_INT_STATUS__FP_DETECT_STAT_AK 0x00000010 +#define GEN_INT_STATUS__CRTC2_VLINE_STAT 0x00000020 +#define GEN_INT_STATUS__CRTC2_VLINE_STAT_AK 0x00000020 +#define GEN_INT_STATUS__CRTC2_VSYNC_STAT 0x00000040 +#define GEN_INT_STATUS__CRTC2_VSYNC_STAT_AK 0x00000040 +#define GEN_INT_STATUS__SNAPSHOT2_STAT 0x00000080 +#define GEN_INT_STATUS__SNAPSHOT2_STAT_AK 0x00000080 +#define GEN_INT_STATUS__CAP0_INT_ACTIVE 0x00000100 +#define GEN_INT_STATUS__CRTC2_VBLANK_STAT 0x00000200 +#define GEN_INT_STATUS__CRTC2_VBLANK_STAT_AK 0x00000200 +#define GEN_INT_STATUS__FP2_DETECT_STAT 0x00000400 +#define GEN_INT_STATUS__FP2_DETECT_STAT_AK 0x00000400 +#define GEN_INT_STATUS__VSYNC_DIFF_OVER_LIMIT_STAT 0x00000800 +#define GEN_INT_STATUS__VSYNC_DIFF_OVER_LIMIT_STAT_AK 0x00000800 +#define GEN_INT_STATUS__DMA_VIPH0_INT 0x00001000 +#define GEN_INT_STATUS__DMA_VIPH0_INT_AK 0x00001000 +#define GEN_INT_STATUS__DMA_VIPH1_INT 0x00002000 +#define GEN_INT_STATUS__DMA_VIPH1_INT_AK 0x00002000 +#define GEN_INT_STATUS__DMA_VIPH2_INT 0x00004000 +#define GEN_INT_STATUS__DMA_VIPH2_INT_AK 0x00004000 +#define GEN_INT_STATUS__DMA_VIPH3_INT 0x00008000 +#define GEN_INT_STATUS__DMA_VIPH3_INT_AK 0x00008000 +#define GEN_INT_STATUS__I2C_INT 0x00020000 +#define GEN_INT_STATUS__I2C_INT_AK 0x00020000 +#define GEN_INT_STATUS__GUI_IDLE_STAT 0x00080000 +#define GEN_INT_STATUS__GUI_IDLE_STAT_AK 0x00080000 +#define GEN_INT_STATUS__VIPH_INT 0x01000000 +#define GEN_INT_STATUS__SW_INT 0x02000000 +#define GEN_INT_STATUS__SW_INT_AK 0x02000000 +#define GEN_INT_STATUS__SW_INT_SET 0x04000000 +#define GEN_INT_STATUS__GEYSERVILLE_STAT 0x08000000 +#define GEN_INT_STATUS__GEYSERVILLE_STAT_AK 0x08000000 +#define GEN_INT_STATUS__DVI_I2C_INT_STAT 0x20000000 +#define GEN_INT_STATUS__DVI_I2C_INT_AK 0x20000000 +#define GEN_INT_STATUS__GUIDMA_STAT 0x40000000 +#define GEN_INT_STATUS__GUIDMA_AK 0x40000000 +#define GEN_INT_STATUS__VIDDMA_STAT 0x80000000 +#define GEN_INT_STATUS__VIDDMA_AK 0x80000000 +#define GEN_INT_STATUS__TIMER_INT_STAT 0x00010000 +#define GEN_INT_STATUS__TIMER_INT_STAT_AK 0x00010000 +#define GEN_INT_STATUS__IDCT_INT_STAT 0x08000000 +#define GEN_INT_STATUS__IDCT_INT_STAT_AK 0x08000000 +#define RB2D_DSTCACHE_MODE 0x00003428 +#define RB2D_DSTCACHE_MODE__DC_BYPASS__MASK 0x00000003 +#define RB2D_DSTCACHE_MODE__DC_BYPASS__SHIFT 0 +#define RB2D_DSTCACHE_MODE__DC_LINE_SIZE__MASK 0x0000000C +#define RB2D_DSTCACHE_MODE__DC_LINE_SIZE__SHIFT 2 +#define RB2D_DSTCACHE_MODE__DC_AUTOFLUSH_ENABLE__MASK 0x00000300 +#define RB2D_DSTCACHE_MODE__DC_AUTOFLUSH_ENABLE__SHIFT 8 +#define RB2D_DSTCACHE_MODE__DC_FORCE_RMW 0x00010000 +#define RB2D_DSTCACHE_MODE__DC_DISABLE_RI_FILL 0x01000000 +#define RB2D_DSTCACHE_MODE__DC_DISABLE_RI_READ 0x02000000 +#define RB2D_DSTCACHE_MODE__DC_AUTOFREE_ENABLE__MASK 0x00000C00 +#define RB2D_DSTCACHE_MODE__DC_AUTOFREE_ENABLE__SHIFT 10 +#define RB2D_DSTCACHE_MODE__DC_DISABLE 0x04000000 +#define RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE 0x00020000 +#define RB2D_DSTCACHE_CTLSTAT 0x0000342C +#define RB2D_DSTCACHE_CTLSTAT__DC_FLUSH__MASK 0x00000003 +#define RB2D_DSTCACHE_CTLSTAT__DC_FLUSH__SHIFT 0 +#define RB2D_DSTCACHE_CTLSTAT__DC_FREE__MASK 0x0000000C +#define RB2D_DSTCACHE_CTLSTAT__DC_FREE__SHIFT 2 +#define RB2D_DSTCACHE_CTLSTAT__DC_BUSY 0x80000000 +#define RB3D_DSTCACHE_CTLSTAT 0x0000325C +#define RB3D_DSTCACHE_CTLSTAT__DC_FLUSH__MASK 0x00000003 +#define RB3D_DSTCACHE_CTLSTAT__DC_FLUSH__SHIFT 0 +#define RB3D_DSTCACHE_CTLSTAT__DC_FREE__MASK 0x0000000C +#define RB3D_DSTCACHE_CTLSTAT__DC_FREE__SHIFT 2 +#define RB3D_DSTCACHE_CTLSTAT__DC_BUSY 0x80000000 +#define RB3D_DSTCACHE_CTLSTAT_R3 0x00004E4C +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FLUSH__MASK 0x00000003 +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FLUSH__SHIFT 0 +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FREE__MASK 0x0000000C +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FREE__SHIFT 2 +#define RB3D_DSTCACHE_CTLSTAT_R3__DC_FINISH 0x00000010 +#define RB3D_ZCACHE_CTLSTAT 0x00003254 +#define RB3D_ZCACHE_CTLSTAT__ZC_FLUSH 0x00000001 +#define RB3D_ZCACHE_CTLSTAT__ZC_FREE 0x00000004 +#define RB3D_ZCACHE_CTLSTAT__ZC_DIRTY 0x40000000 +#define RB3D_ZCACHE_CTLSTAT__ZC_BUSY 0x80000000 +#define RB3D_ZCACHE_CTLSTAT_R3 0x00004F18 +#define RB3D_ZCACHE_CTLSTAT_R3__ZC_FLUSH 0x00000001 +#define RB3D_ZCACHE_CTLSTAT_R3__ZC_FREE 0x00000002 +#define RB3D_ZCACHE_CTLSTAT_R3__ZC_BUSY 0x80000000 +#define SCRATCH_REG0 0x000015E0 +#define SCRATCH_REG0__SCRATCH_REG0__MASK 0xFFFFFFFF +#define SCRATCH_REG0__SCRATCH_REG0__SHIFT 0 +#define SCRATCH_REG1 0x000015E4 +#define SCRATCH_REG1__SCRATCH_REG1__MASK 0xFFFFFFFF +#define SCRATCH_REG1__SCRATCH_REG1__SHIFT 0 +#define SCRATCH_REG2 0x000015E8 +#define SCRATCH_REG2__SCRATCH_REG2__MASK 0xFFFFFFFF +#define SCRATCH_REG2__SCRATCH_REG2__SHIFT 0 +#define SCRATCH_REG3 0x000015EC +#define SCRATCH_REG3__SCRATCH_REG3__MASK 0xFFFFFFFF +#define SCRATCH_REG3__SCRATCH_REG3__SHIFT 0 +#define SCRATCH_REG4 0x000015F0 +#define SCRATCH_REG4__SCRATCH_REG4__MASK 0xFFFFFFFF +#define SCRATCH_REG4__SCRATCH_REG4__SHIFT 0 +#define SCRATCH_REG5 0x000015F4 +#define SCRATCH_REG5__SCRATCH_REG5__MASK 0xFFFFFFFF +#define SCRATCH_REG5__SCRATCH_REG5__SHIFT 0 +#define SCRATCH_REG6 0x000015F8 +#define SCRATCH_REG6__SCRATCH_REG6__MASK 0xFFFFFFFF +#define SCRATCH_REG6__SCRATCH_REG6__SHIFT 0 +#define SCRATCH_REG7 0x000015FC +#define SCRATCH_REG7__SCRATCH_REG7__MASK 0xFFFFFFFF +#define SCRATCH_REG7__SCRATCH_REG7__SHIFT 0 +#define PCIE_INDEX 0x00000030 +#define PCIE_INDEX__PCIE_INDEX__MASK 0x000007FF +#define PCIE_INDEX__PCIE_INDEX__SHIFT 0 +#define PCIE_DATA 0x00000034 +#define PCIE_DATA__PCIE_DATA__MASK 0xFFFFFFFF +#define PCIE_DATA__PCIE_DATA__SHIFT 0 +#define PCIE_TX_GART_CNTL 0x00000010 +#define PCIE_TX_GART_CNTL__GART_EN 0x00000001 +#define PCIE_TX_GART_CNTL__GART_UNMAPPED_ACCESS__MASK 0x00000006 +#define PCIE_TX_GART_CNTL__GART_UNMAPPED_ACCESS__SHIFT 1 +#define GART_UNMAPPED_ACCESS__PTHRU 0x0 +#define GART_UNMAPPED_ACCESS__CLAMP 0x1 +#define GART_UNMAPPED_ACCESS__DISCARD 0x3 +#define PCIE_TX_GART_CNTL__GART_MODE__MASK 0x00000018 +#define PCIE_TX_GART_CNTL__GART_MODE__SHIFT 3 +#define GART_MODE__CACHE_32x128 0x0 +#define GART_MODE__CACHE_8x4x128 0x1 +#define PCIE_TX_GART_CNTL__GART_CHK_RW_VALID_EN 0x00000020 +#define PCIE_TX_GART_CNTL__GART_RDREQPATH_SEL__MASK 0x00000040 +#define PCIE_TX_GART_CNTL__GART_RDREQPATH_SEL__SHIFT 6 +#define GART_RDREQPATH_SEL__HDP 0x0 +#define GART_RDREQPATH_SEL__DRQMC 0x1 +#define PCIE_TX_GART_CNTL__GART_INVALIDATE_TLB 0x00000100 +#define PCIE_TX_GART_DISCARD_RD_ADDR_LO 0x00000011 +#define PCIE_TX_GART_DISCARD_RD_ADDR_LO__GART_DISCARD_RD_ADDR_LO__MASK 0xFFFFFFFF +#define PCIE_TX_GART_DISCARD_RD_ADDR_LO__GART_DISCARD_RD_ADDR_LO__SHIFT 0 +#define PCIE_TX_GART_DISCARD_RD_ADDR_HI 0x00000012 +#define PCIE_TX_GART_DISCARD_RD_ADDR_HI__GART_DISCARD_RD_ADDR_HI__MASK 0x000000FF +#define PCIE_TX_GART_DISCARD_RD_ADDR_HI__GART_DISCARD_RD_ADDR_HI__SHIFT 0 +#define PCIE_TX_GART_BASE 0x00000013 +#define PCIE_TX_GART_BASE__GART_BASE__MASK 0xFFFFFFFF +#define PCIE_TX_GART_BASE__GART_BASE__SHIFT 0 +#define PCIE_TX_GART_START_LO 0x00000014 +#define PCIE_TX_GART_START_LO__GART_START_LO__MASK 0xFFFFFFFF +#define PCIE_TX_GART_START_LO__GART_START_LO__SHIFT 0 +#define PCIE_TX_GART_START_HI 0x00000015 +#define PCIE_TX_GART_START_HI__GART_START_HI__MASK 0x000000FF +#define PCIE_TX_GART_START_HI__GART_START_HI__SHIFT 0 +#define PCIE_TX_GART_END_LO 0x00000016 +#define PCIE_TX_GART_END_LO__GART_END_LO__MASK 0xFFFFFFFF +#define PCIE_TX_GART_END_LO__GART_END_LO__SHIFT 0 +#define PCIE_TX_GART_END_HI 0x00000017 +#define PCIE_TX_GART_END_HI__GART_END_HI__MASK 0x000000FF +#define PCIE_TX_GART_END_HI__GART_END_HI__SHIFT 0 +#define PCIE_TX_GART_ERROR 0x00000018 +#define PCIE_TX_GART_ERROR__GART_UNMAPPED 0x00000002 +#define PCIE_TX_GART_ERROR__GART_INVALID_READ 0x00000004 +#define PCIE_TX_GART_ERROR__GART_INVALID_WRITE 0x00000008 +#define PCIE_TX_GART_ERROR__GART_INVALID_ADDR__MASK 0xFFFFFFF0 +#define PCIE_TX_GART_ERROR__GART_INVALID_ADDR__SHIFT 4 +#define CP_RB_CNTL 0x00000704 +#define CP_RB_CNTL__RB_BUFSZ__MASK 0x0000003F +#define CP_RB_CNTL__RB_BUFSZ__SHIFT 0 +#define CP_RB_CNTL__RB_BLKSZ__MASK 0x00003F00 +#define CP_RB_CNTL__RB_BLKSZ__SHIFT 8 +#define CP_RB_CNTL__BUF_SWAP__MASK 0x00030000 +#define CP_RB_CNTL__BUF_SWAP__SHIFT 16 +#define CP_RB_CNTL__MAX_FETCH__MASK 0x000C0000 +#define CP_RB_CNTL__MAX_FETCH__SHIFT 18 +#define CP_RB_CNTL__RB_NO_UPDATE 0x08000000 +#define CP_RB_CNTL__RB_RPTR_WR_ENA 0x80000000 +#define CP_RB_BASE 0x00000700 +#define CP_RB_BASE__RB_BASE__MASK 0xFFFFFFFC +#define CP_RB_BASE__RB_BASE__SHIFT 2 +#define CP_RB_RPTR_ADDR 0x0000070C +#define CP_RB_RPTR_ADDR__RB_RPTR_SWAP__MASK 0x00000003 +#define CP_RB_RPTR_ADDR__RB_RPTR_SWAP__SHIFT 0 +#define CP_RB_RPTR_ADDR__RB_RPTR_ADDR__MASK 0xFFFFFFFC +#define CP_RB_RPTR_ADDR__RB_RPTR_ADDR__SHIFT 2 +#define CP_RB_RPTR 0x00000710 +#define CP_RB_RPTR__RB_RPTR__MASK 0x007FFFFF +#define CP_RB_RPTR__RB_RPTR__SHIFT 0 +#define CP_RB_RPTR_WR 0x0000071C +#define CP_RB_RPTR_WR__RB_RPTR_WR__MASK 0x007FFFFF +#define CP_RB_RPTR_WR__RB_RPTR_WR__SHIFT 0 +#define CP_RB_WPTR 0x00000714 +#define CP_RB_WPTR__RB_WPTR__MASK 0x007FFFFF +#define CP_RB_WPTR__RB_WPTR__SHIFT 0 +#define CP_RB_WPTR_DELAY 0x00000718 +#define CP_RB_WPTR_DELAY__PRE_WRITE_TIMER__MASK 0x0FFFFFFF +#define CP_RB_WPTR_DELAY__PRE_WRITE_TIMER__SHIFT 0 +#define CP_RB_WPTR_DELAY__PRE_WRITE_LIMIT__MASK 0xF0000000 +#define CP_RB_WPTR_DELAY__PRE_WRITE_LIMIT__SHIFT 28 +#define SCRATCH_UMSK 0x00000770 +#define SCRATCH_UMSK__SCRATCH_UMSK__MASK 0x0000003F +#define SCRATCH_UMSK__SCRATCH_UMSK__SHIFT 0 +#define SCRATCH_UMSK__SCRATCH_SWAP__MASK 0x00030000 +#define SCRATCH_UMSK__SCRATCH_SWAP__SHIFT 16 +#define SCRATCH_UMSK__SCRATCH_UMSK_R2__MASK 0x000000FF +#define SCRATCH_UMSK__SCRATCH_UMSK_R2__SHIFT 0 +#define SCRATCH_ADDR 0x00000774 +#define SCRATCH_ADDR__SCRATCH_ADDR__MASK 0xFFFFFFE0 +#define SCRATCH_ADDR__SCRATCH_ADDR__SHIFT 5 +#define CP_ME_RAM_ADDR 0x000007D4 +#define CP_ME_RAM_ADDR__ME_RAM_ADDR__MASK 0x000000FF +#define CP_ME_RAM_ADDR__ME_RAM_ADDR__SHIFT 0 +#define CP_ME_RAM_DATAH 0x000007DC +#define CP_ME_RAM_DATAH__ME_RAM_DATAH__MASK 0x0000003F +#define CP_ME_RAM_DATAH__ME_RAM_DATAH__SHIFT 0 +#define CP_ME_RAM_DATAH__ME_RAM_DATAH_R3__MASK 0x000000FF +#define CP_ME_RAM_DATAH__ME_RAM_DATAH_R3__SHIFT 0 +#define CP_ME_RAM_DATAL 0x000007E0 +#define CP_ME_RAM_DATAL__ME_RAM_DATAL__MASK 0xFFFFFFFF +#define CP_ME_RAM_DATAL__ME_RAM_DATAL__SHIFT 0 +#define CP_CSQ_CNTL 0x00000740 +#define CP_CSQ_CNTL__CSQ_CNT_PRIMARY__MASK 0x000000FF +#define CP_CSQ_CNTL__CSQ_CNT_PRIMARY__SHIFT 0 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT__MASK 0x0000FF00 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT__SHIFT 8 +#define CP_CSQ_CNTL__CSQ_MODE__MASK 0xF0000000 +#define CP_CSQ_CNTL__CSQ_MODE__SHIFT 28 +#define CSQ_MODE__CSQ_PRIDIS_INDDIS 0x0 +#define CSQ_MODE__CSQ_PRIPIO_INDDIS 0x1 +#define CSQ_MODE__CSQ_PRIBM_INDDIS 0x2 +#define CSQ_MODE__CSQ_PRIPIO_INDBM 0x3 +#define CSQ_MODE__CSQ_PRIBM_INDBM 0x4 +#define CSQ_MODE__CSQ_PRIPIO_INDPIO 0xF +#define CP_CSQ_CNTL__CSQ_CNT_PRIMARY_R2__MASK 0x000001FF +#define CP_CSQ_CNTL__CSQ_CNT_PRIMARY_R2__SHIFT 0 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT_R2__MASK 0x0003FE00 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT_R2__SHIFT 9 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT2__MASK 0x07FC0000 +#define CP_CSQ_CNTL__CSQ_CNT_INDIRECT2__SHIFT 18 +#define CRTC_GEN_CNTL 0x00000050 +#define CRTC_GEN_CNTL__CRTC_DBL_SCAN_EN 0x00000001 +#define CRTC_GEN_CNTL__CRTC_INTERLACE_EN 0x00000002 +#define CRTC_GEN_CNTL__CRTC_C_SYNC_EN 0x00000010 +#define CRTC_GEN_CNTL__CRTC_PIX_WIDTH__MASK 0x00000F00 +#define CRTC_GEN_CNTL__CRTC_PIX_WIDTH__SHIFT 8 +#define CRTC_PIX_WIDTH__4BPP 0x100 +#define CRTC_PIX_WIDTH__8BPP 0x200 +#define CRTC_PIX_WIDTH__15BPP 0x300 +#define CRTC_PIX_WIDTH__16BPP 0x400 +#define CRTC_PIX_WIDTH__24BPP 0x500 +#define CRTC_PIX_WIDTH__34BPP 0x600 +#define CRTC_PIX_WIDTH__16BPP_4444 0x700 +#define CRTC_PIX_WIDTH__16BPP_88 0x800 +#define CRTC_GEN_CNTL__CRTC_ICON_EN 0x00008000 +#define CRTC_GEN_CNTL__CRTC_CUR_EN 0x00010000 +#define CRTC_GEN_CNTL__CRTC_VSTAT_MODE__MASK 0x00060000 +#define CRTC_GEN_CNTL__CRTC_VSTAT_MODE__SHIFT 17 +#define CRTC_GEN_CNTL__CRTC_CUR_MODE__MASK 0x00700000 +#define CRTC_GEN_CNTL__CRTC_CUR_MODE__SHIFT 20 +#define CRTC_CUR_MODE__PREMULTI_ALPHA 0x2 +#define CRTC_CUR_MODE__COLOR24BPP 0x1 +#define CRTC_GEN_CNTL__CRTC_EXT_DISP_EN 0x01000000 +#define CRTC_GEN_CNTL__CRTC_EN 0x02000000 +#define CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B 0x04000000 +#define CRTC_GEN_CNTL__CRTC_MODE9_COLOR_ORDER 0x00001000 +#define CRTC_EXT_CNTL 0x00000054 +#define CRTC_EXT_CNTL__CRTC_VGA_XOVERSCAN 0x00000001 +#define CRTC_EXT_CNTL__VGA_BLINK_RATE__MASK 0x00000006 +#define CRTC_EXT_CNTL__VGA_BLINK_RATE__SHIFT 1 +#define CRTC_EXT_CNTL__VGA_ATI_LINEAR 0x00000008 +#define CRTC_EXT_CNTL__VGA_128KAP_PAGING 0x00000010 +#define CRTC_EXT_CNTL__VGA_TEXT_132 0x00000020 +#define CRTC_EXT_CNTL__VGA_XCRT_CNT_EN 0x00000040 +#define CRTC_EXT_CNTL__CRTC_HSYNC_DIS 0x00000100 +#define CRTC_EXT_CNTL__CRTC_VSYNC_DIS 0x00000200 +#define CRTC_EXT_CNTL__CRTC_DISPLAY_DIS 0x00000400 +#define CRTC_EXT_CNTL__CRTC_SYNC_TRISTATE 0x00000800 +#define CRTC_EXT_CNTL__CRTC_HSYNC_TRISTATE 0x00001000 +#define CRTC_EXT_CNTL__CRTC_VSYNC_TRISTATE 0x00002000 +#define CRTC_EXT_CNTL__CRT_ON 0x00008000 +#define CRTC_EXT_CNTL__VGA_CUR_B_TEST 0x00020000 +#define CRTC_EXT_CNTL__VGA_PACK_DIS 0x00040000 +#define CRTC_EXT_CNTL__VGA_MEM_PS_EN 0x00080000 +#define CRTC_EXT_CNTL__VCRTC_IDX_MASTER__MASK 0x7F000000 +#define CRTC_EXT_CNTL__VCRTC_IDX_MASTER__SHIFT 24 +#define CRTC_H_TOTAL_DISP 0x00000200 +#define CRTC_H_TOTAL_DISP__CRTC_H_TOTAL__MASK 0x000003FF +#define CRTC_H_TOTAL_DISP__CRTC_H_TOTAL__SHIFT 0 +#define CRTC_H_TOTAL_DISP__CRTC_H_DISP__MASK 0x01FF0000 +#define CRTC_H_TOTAL_DISP__CRTC_H_DISP__SHIFT 16 +#define CRTC_H_SYNC_STRT_WID 0x00000204 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_PIX__MASK 0x00000007 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_PIX__SHIFT 0 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_CHAR__MASK 0x00001FF8 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_CHAR__SHIFT 3 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_WID__MASK 0x003F0000 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_WID__SHIFT 16 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_POL 0x00800000 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE__MASK 0x07000000 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE__SHIFT 24 +#define CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE_MODE 0x10000000 +#define CRTC_V_TOTAL_DISP 0x00000208 +#define CRTC_V_TOTAL_DISP__CRTC_V_TOTAL__MASK 0x00000FFF +#define CRTC_V_TOTAL_DISP__CRTC_V_TOTAL__SHIFT 0 +#define CRTC_V_TOTAL_DISP__CRTC_V_DISP__MASK 0x0FFF0000 +#define CRTC_V_TOTAL_DISP__CRTC_V_DISP__SHIFT 16 +#define CRTC_V_SYNC_STRT_WID 0x0000020C +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_STRT__MASK 0x00000FFF +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_STRT__SHIFT 0 +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_WID__MASK 0x001F0000 +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_WID__SHIFT 16 +#define CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_POL 0x00800000 +#define CRTC_OFFSET 0x00000224 +#define CRTC_OFFSET__CRTC_OFFSET__MASK 0x07FFFFFF +#define CRTC_OFFSET__CRTC_OFFSET__SHIFT 0 +#define CRTC_OFFSET__CRTC_GUI_TRIG_OFFSET 0x40000000 +#define CRTC_OFFSET__CRTC_OFFSET_LOCK 0x80000000 +#define CRTC_OFFSET__CRTC_OFFSET_R3__MASK 0x0FFFFFFF +#define CRTC_OFFSET__CRTC_OFFSET_R3__SHIFT 0 +#define CRTC_OFFSET_CNTL 0x00000228 +#define CRTC_OFFSET_CNTL__CRTC_TILE_LINE__MASK 0x0000000F +#define CRTC_OFFSET_CNTL__CRTC_TILE_LINE__SHIFT 0 +#define CRTC_OFFSET_CNTL__CRTC_TILE_LINE_RIGHT__MASK 0x000000F0 +#define CRTC_OFFSET_CNTL__CRTC_TILE_LINE_RIGHT__SHIFT 4 +#define CRTC_OFFSET_CNTL__CRTC_TILE_EN_RIGHT 0x00004000 +#define CRTC_OFFSET_CNTL__CRTC_TILE_EN 0x00008000 +#define CRTC_OFFSET_CNTL__CRTC_OFFSET_FLIP_CNTL 0x00010000 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_OFFSET_EN 0x00020000 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_EN__MASK 0x000C0000 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_EN__SHIFT 18 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN 0x00100000 +#define CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC 0x00200000 +#define CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET_LEFT_EN 0x10000000 +#define CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET_RIGHT_EN 0x20000000 +#define CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET 0x40000000 +#define CRTC_OFFSET_CNTL__CRTC_OFFSET_LOCK 0x80000000 +#define CRTC_OFFSET_CNTL__CRTC_X_Y_MODE_EN_RIGHT 0x00000040 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE_RIGHT__MASK 0x00000180 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE_RIGHT__SHIFT 7 +#define CRTC_OFFSET_CNTL__CRTC_X_Y_MODE_EN 0x00000200 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE__MASK 0x00000C00 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE__SHIFT 10 +#define CRTC_MICRO_TILE_BUFFER_MODE__AUTO 0x0 +#define CRTC_MICRO_TILE_BUFFER_MODE__SLINE 0x1 +#define CRTC_MICRO_TILE_BUFFER_MODE__DLINE 0x2 +#define CRTC_MICRO_TILE_BUFFER_MODE__DIS 0x3 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_EN_RIGHT 0x00001000 +#define CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_EN 0x00002000 +#define CRTC_OFFSET_CNTL__CRTC_MACRO_TILE_EN_RIGHT 0x00004000 +#define CRTC_OFFSET_CNTL__CRTC_MACRO_TILE_EN 0x00008000 +#define CRTC_PITCH 0x0000022C +#define CRTC_PITCH__CRTC_PITCH__MASK 0x000007FF +#define CRTC_PITCH__CRTC_PITCH__SHIFT 0 +#define CRTC_PITCH__CRTC_PITCH_RIGHT__MASK 0x07FF0000 +#define CRTC_PITCH__CRTC_PITCH_RIGHT__SHIFT 16 +#define CRTC_MORE_CNTL 0x0000027C +#define CRTC_MORE_CNTL__CRTC_HORZ_BLANK_MODE_SEL 0x00000001 +#define CRTC_MORE_CNTL__CRTC_VERT_BLANK_MODE_SEL 0x00000002 +#define CRTC_MORE_CNTL__CRTC_AUTO_HORZ_CENTER_EN 0x00000004 +#define CRTC_MORE_CNTL__CRTC_AUTO_VERT_CENTER_EN 0x00000008 +#define CRTC_MORE_CNTL__CRTC_H_CUTOFF_ACTIVE_EN 0x00000010 +#define CRTC_MORE_CNTL__CRTC_V_CUTOFF_ACTIVE_EN 0x00000020 +#define CRTC_MORE_CNTL__FORCE_H_EVEN_PIXEL_COUNT 0x00000040 +#define CRTC_MORE_CNTL__RMX_H_FILT_COEFFICIENT__MASK 0x07000000 +#define CRTC_MORE_CNTL__RMX_H_FILT_COEFFICIENT__SHIFT 24 +#define CRTC_MORE_CNTL__RMX_H_FILTER_EN 0x08000000 +#define CRTC_MORE_CNTL__RMX_V_FILT_COEFFICIENT__MASK 0x70000000 +#define CRTC_MORE_CNTL__RMX_V_FILT_COEFFICIENT__SHIFT 28 +#define CRTC_MORE_CNTL__RMX_V_FILTER_EN 0x80000000 +#define CRTC_MORE_CNTL__DSP_RST_HCOUNT 0x00000100 +#define CRTC_MORE_CNTL__DSP_RST_VCOUNT 0x00000200 +#define CRTC_MORE_CNTL__HCOUNT_RST_POS 0x00000400 +#define CRTC_MORE_CNTL__VCOUNT_RST_POS 0x00000800 +#define CRTC_MORE_CNTL__CRTC_FIX_VSYNC_EDGE_POSITION_EN 0x00001000 +#define CRTC_TILE_X0_Y0 0x00000350 +#define CRTC_TILE_X0_Y0__CRTC_TILE_X0__MASK 0x00000FFF +#define CRTC_TILE_X0_Y0__CRTC_TILE_X0__SHIFT 0 +#define CRTC_TILE_X0_Y0__CRTC_TILE_Y0__MASK 0x0FFF0000 +#define CRTC_TILE_X0_Y0__CRTC_TILE_Y0__SHIFT 16 +#define CRTC_TILE_X0_Y0__CRTC_GUI_TRIG_OFFSET 0x40000000 +#define CRTC_TILE_X0_Y0__CRTC_OFFSET_LOCK 0x80000000 +#define DAC_CNTL 0x00000058 +#define DAC_CNTL__DAC_RANGE_CNTL__MASK 0x00000003 +#define DAC_CNTL__DAC_RANGE_CNTL__SHIFT 0 +#define DAC_RANGE_CNTL__PS2 0x2 +#define DAC_RANGE_CNTL__YPbPr 0x3 +#define DAC_CNTL__DAC_BLANKING 0x00000004 +#define DAC_CNTL__DAC_CMP_EN 0x00000008 +#define DAC_CNTL__DAC_CMP_OUT_R 0x00000010 +#define DAC_CNTL__DAC_CMP_OUT_G 0x00000020 +#define DAC_CNTL__DAC_CMP_OUT_B 0x00000040 +#define DAC_CNTL__DAC_CMP_OUTPUT 0x00000080 +#define DAC_CNTL__DAC_8BIT_EN 0x00000100 +#define DAC_CNTL__DAC_4BPP_PIX_ORDER 0x00000200 +#define DAC_CNTL__DAC_TVO_EN 0x00000400 +#define DAC_CNTL__DAC_VGA_ADR_EN 0x00002000 +#define DAC_CNTL__DAC_EXPAND_MODE 0x00004000 +#define DAC_CNTL__DAC_PDWN 0x00008000 +#define DAC_CNTL__CRT_SENSE 0x00010000 +#define DAC_CNTL__CRT_DETECTION_ON 0x00020000 +#define DAC_CNTL__DAC_CRC_CONT_EN 0x00040000 +#define DAC_CNTL__DAC_CRC_EN 0x00080000 +#define DAC_CNTL__DAC_CRC_FIELD 0x00100000 +#define DAC_CNTL__DAC_LUT_COUNTER_LIMIT__MASK 0x00600000 +#define DAC_CNTL__DAC_LUT_COUNTER_LIMIT__SHIFT 21 +#define DAC_CNTL__DAC_LUT_READ_SEL 0x00800000 +#define DAC_CNTL__DAC__MASK 0xFF000000 +#define DAC_CNTL__DAC__SHIFT 24 +#define DAC_CNTL__DAC_CRC_BLANKb_ONLY 0x00000800 +#define DAC_CNTL2 0x0000007C +#define DAC_CNTL2__DAC_CLK_SEL 0x00000001 +#define DAC_CNTL2__DAC2_CLK_SEL 0x00000002 +#define DAC_CNTL2__PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_CNTL2__DAC2_CMP_EN 0x00000080 +#define DAC_CNTL2__DAC2_CMP_OUT_R 0x00000100 +#define DAC_CNTL2__DAC2_CMP_OUT_G 0x00000200 +#define DAC_CNTL2__DAC2_CMP_OUT_B 0x00000400 +#define DAC_CNTL2__DAC2_CMP_OUTPUT 0x00000800 +#define DAC_CNTL2__DAC2_EXPAND_MODE 0x00004000 +#define DAC_CNTL2__CRT2_SENSE 0x00010000 +#define DAC_CNTL2__CRT2_DETECTION_ON 0x00020000 +#define DAC_CNTL2__DAC_CRC2_CONT_EN 0x00040000 +#define DAC_CNTL2__DAC_CRC2_EN 0x00080000 +#define DAC_CNTL2__DAC_CRC2_FIELD 0x00100000 +#define DAC_CNTL2__DAC2_LUT_COUNTER_LIMIT__MASK 0x00600000 +#define DAC_CNTL2__DAC2_LUT_COUNTER_LIMIT__SHIFT 21 +#define DAC_CNTL2__PALETTE_AUTOFILL_PRIMARY_W 0x00000800 +#define DAC_CNTL2__PALETTE_AUTOFILL_PRIMARY_R 0x00000800 +#define DAC_CNTL2__PALETTE_AUTOFILL_SECONDARY_W 0x00001000 +#define DAC_CNTL2__PALETTE_AUTOFILL_SECONDARY_R 0x00001000 +#define DAC_CNTL2__DAC2_CMP_EN_R3 0x00000040 +#define DAC_CNTL2__DAC2_CMP_OUT_R_R3 0x00000080 +#define DAC_CNTL2__DAC2_CMP_OUT_G_R3 0x00000100 +#define DAC_CNTL2__DAC2_CMP_OUT_B_R3 0x00000200 +#define DAC_CNTL2__DAC2_CMP_OUTPUT_R3 0x00000400 +#define DAC_CNTL2__DAC_CRC2_BLANKb_ONLY 0x00020000 +#define DAC_EXT_CNTL 0x00000280 +#define DAC_EXT_CNTL__DAC2_FORCE_BLANK_OFF_EN 0x00000001 +#define DAC_EXT_CNTL__DAC2_FORCE_DATA_EN 0x00000002 +#define DAC_EXT_CNTL__DAC_FORCE_BLANK_OFF_EN 0x00000010 +#define DAC_EXT_CNTL__DAC_FORCE_DATA_EN 0x00000020 +#define DAC_EXT_CNTL__DAC_FORCE_DATA_SEL__MASK 0x000000C0 +#define DAC_EXT_CNTL__DAC_FORCE_DATA_SEL__SHIFT 6 +#define DAC_EXT_CNTL__DAC_FORCE_DATA__MASK 0x0003FF00 +#define DAC_EXT_CNTL__DAC_FORCE_DATA__SHIFT 8 +#define DISP_MISC_CNTL 0x00000D00 +#define DISP_MISC_CNTL__SOFT_RESET_GRPH_PP 0x00000001 +#define DISP_MISC_CNTL__SOFT_RESET_SUBPIC_PP 0x00000002 +#define DISP_MISC_CNTL__SOFT_RESET_OV0_PP 0x00000004 +#define DISP_MISC_CNTL__SOFT_RESET_GRPH_SCLK 0x00000010 +#define DISP_MISC_CNTL__SOFT_RESET_SUBPIC_SCLK 0x00000020 +#define DISP_MISC_CNTL__SOFT_RESET_OV0_SCLK 0x00000040 +#define DISP_MISC_CNTL__SYNC_STRENGTH__MASK 0x00000300 +#define DISP_MISC_CNTL__SYNC_STRENGTH__SHIFT 8 +#define DISP_MISC_CNTL__SYNC_PAD_FLOP_EN 0x00000400 +#define DISP_MISC_CNTL__SOFT_RESET_GRPH2_PP 0x00001000 +#define DISP_MISC_CNTL__SOFT_RESET_GRPH2_SCLK 0x00008000 +#define DISP_MISC_CNTL__SOFT_RESET_LVDS 0x00010000 +#define DISP_MISC_CNTL__SOFT_RESET_TMDS 0x00020000 +#define DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS 0x00040000 +#define DISP_MISC_CNTL__SOFT_RESET_TV 0x00080000 +#define DISP_MISC_CNTL__PALETTE2_MEM_RD_MARGIN__MASK 0x00F00000 +#define DISP_MISC_CNTL__PALETTE2_MEM_RD_MARGIN__SHIFT 20 +#define DISP_MISC_CNTL__PALETTE_MEM_RD_MARGIN__MASK 0x0F000000 +#define DISP_MISC_CNTL__PALETTE_MEM_RD_MARGIN__SHIFT 24 +#define DISP_MISC_CNTL__RMX_BUF_MEM_RD_MARGIN__MASK 0xF0000000 +#define DISP_MISC_CNTL__RMX_BUF_MEM_RD_MARGIN__SHIFT 28 +#define DISP_MISC_CNTL__SOFT_RESET_DVO 0x00040000 +#define DISP_MISC_CNTL__SOFT_RESET_TV_R2 0x00000800 +#define DAC_MACRO_CNTL 0x00000D04 +#define DAC_MACRO_CNTL__DAC_WHITE_CNTL__MASK 0x0000000F +#define DAC_MACRO_CNTL__DAC_WHITE_CNTL__SHIFT 0 +#define DAC_MACRO_CNTL__DAC_BG_ADJ__MASK 0x00000F00 +#define DAC_MACRO_CNTL__DAC_BG_ADJ__SHIFT 8 +#define DAC_MACRO_CNTL__DAC_PDWN_R 0x00010000 +#define DAC_MACRO_CNTL__DAC_PDWN_G 0x00020000 +#define DAC_MACRO_CNTL__DAC_PDWN_B 0x00040000 +#define DISP_PWR_MAN 0x00000D08 +#define DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN 0x00000001 +#define DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN 0x00000010 +#define DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK 0x00000300 +#define DISP_PWR_MAN__DISP_PWR_MAN_DPMS__SHIFT 8 +#define DISP_PWR_MAN_DPMS__ON 0x0 +#define DISP_PWR_MAN_DPMS__STANDBY 0x1 +#define DISP_PWR_MAN_DPMS__SUSPEND 0x2 +#define DISP_PWR_MAN_DPMS__OFF 0x3 +#define DISP_PWR_MAN__DISP_D3_RST 0x00010000 +#define DISP_PWR_MAN__DISP_D3_REG_RST 0x00020000 +#define DISP_PWR_MAN__DISP_D3_GRPH_RST 0x00040000 +#define DISP_PWR_MAN__DISP_D3_SUBPIC_RST 0x00080000 +#define DISP_PWR_MAN__DISP_D3_OV0_RST 0x00100000 +#define DISP_PWR_MAN__DISP_D1D2_GRPH_RST 0x00200000 +#define DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST 0x00400000 +#define DISP_PWR_MAN__DISP_D1D2_OV0_RST 0x00800000 +#define DISP_PWR_MAN__DIG_TMDS_ENABLE_RST 0x01000000 +#define DISP_PWR_MAN__TV_ENABLE_RST 0x02000000 +#define DISP_PWR_MAN__AUTO_PWRUP_EN 0x04000000 +#define DISP_PWR_MAN__DISP_DVO_ENABLE_RST 0x01000000 +#define DISP_MERGE_CNTL 0x00000D60 +#define DISP_MERGE_CNTL__DISP_ALPHA_MODE__MASK 0x00000003 +#define DISP_MERGE_CNTL__DISP_ALPHA_MODE__SHIFT 0 +#define DISP_MERGE_CNTL__DISP_ALPHA_INV 0x00000004 +#define DISP_MERGE_CNTL__DISP_ALPHA_PREMULT 0x00000008 +#define DISP_MERGE_CNTL__DISP_RGB_OFFSET_EN 0x00000100 +#define DISP_MERGE_CNTL__DISP_LIN_TRANS_BYPASS 0x00000200 +#define DISP_MERGE_CNTL__DISP_GRPH_ALPHA__MASK 0x00FF0000 +#define DISP_MERGE_CNTL__DISP_GRPH_ALPHA__SHIFT 16 +#define DISP_MERGE_CNTL__DISP_OV0_ALPHA__MASK 0xFF000000 +#define DISP_MERGE_CNTL__DISP_OV0_ALPHA__SHIFT 24 +#define DISP_OUTPUT_CNTL 0x00000D64 +#define DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__MASK 0x00000003 +#define DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__SHIFT 0 +#define DISP_DAC_SOURCE__YPbPr 0x3 +#define DISP_DAC_SOURCE__PRIMARYCRTC 0x0 +#define DISP_DAC_SOURCE__SECONDARYCRTC 0x1 +#define DISP_DAC_SOURCE__RMX 0x2 +#define DISP_OUTPUT_CNTL__DISP_TRANS_MATRIX_SEL__MASK 0x00000030 +#define DISP_OUTPUT_CNTL__DISP_TRANS_MATRIX_SEL__SHIFT 4 +#define DISP_OUTPUT_CNTL__DISP_RMX_SOURCE 0x00000100 +#define DISP_OUTPUT_CNTL__DISP_RMX_HTAP_SEL 0x00000200 +#define DISP_OUTPUT_CNTL__DISP_RMX_DITH_EN 0x00000400 +#define DISP_OUTPUT_CNTL__DISP_TV_SOURCE 0x00010000 +#define DISP_OUTPUT_CNTL__DISP_TV_MODE__MASK 0x00060000 +#define DISP_OUTPUT_CNTL__DISP_TV_MODE__SHIFT 17 +#define DISP_OUTPUT_CNTL__DISP_TV_YG_DITH_EN 0x00080000 +#define DISP_OUTPUT_CNTL__DISP_TV_CbB_CrR_DITH_EN 0x00100000 +#define DISP_OUTPUT_CNTL__DISP_TV_BIT_WIDTH 0x00200000 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_MODE__MASK 0x00C00000 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_MODE__SHIFT 22 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_FORCE 0x01000000 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_COLOR__MASK 0x06000000 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_COLOR__SHIFT 25 +#define DISP_OUTPUT_CNTL__DISP_TV_EVEN_FLAG_CNTL__MASK 0x18000000 +#define DISP_OUTPUT_CNTL__DISP_TV_EVEN_FLAG_CNTL__SHIFT 27 +#define DISP_OUTPUT_CNTL__DISP_TV_SYNC_STATUS 0x20000000 +#define DISP_OUTPUT_CNTL__DISP_TV_H_DOWNSCALE 0x40000000 +#define DISP_OUTPUT_CNTL__DISP_TRANS_SOURCE__MASK 0x00003000 +#define DISP_OUTPUT_CNTL__DISP_TRANS_SOURCE__SHIFT 12 +#define DISP_TRANS_SOURCE__PRIMARYCRTC 0x0 +#define DISP_TRANS_SOURCE__SECONDARYCRTC 0x1 +#define DISP_TRANS_SOURCE__RMX 0x2 +#define DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__MASK 0x0000000C +#define DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__SHIFT 2 +#define DISP_TVDAC_SOURCE__PRIMARYCRTC 0x0 +#define DISP_TVDAC_SOURCE__SECONDARYCRTC 0x1 +#define DISP_TVDAC_SOURCE__RMX 0x2 +#define DISP_TVDAC_SOURCE__YPbPr 0x3 +#define DISP2_MERGE_CNTL 0x00000D68 +#define DISP2_MERGE_CNTL__DISP2_RGB_OFFSET_EN 0x00000100 +#define DAC_EMBEDDED_SYNC_CNTL 0x00000DC0 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Y_G 0x00000001 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Cb_B 0x00000002 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Cr_R 0x00000004 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_TRILEVEL_SYNC_EN 0x00000008 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_Y_G 0x00000010 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_CbCr_BR 0x00000020 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_HSYNC_WID_LSB__MASK 0x00070000 +#define DAC_EMBEDDED_SYNC_CNTL__DAC_HSYNC_WID_LSB__SHIFT 16 +#define DAC_BROAD_PULSE 0x00000DC4 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_START__MASK 0x00001FFF +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_START__SHIFT 0 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_END__MASK 0x1FFF0000 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_END__SHIFT 16 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_START_R2__MASK 0x00000FFF +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_START_R2__SHIFT 0 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_END_R2__MASK 0x0FFF0000 +#define DAC_BROAD_PULSE__DAC_BROAD_PULSE_END_R2__SHIFT 16 +#define DAC_SKEW_CLKS 0x00000DC8 +#define DAC_SKEW_CLKS__DAC_SKEW_CLKS__MASK 0x000000FF +#define DAC_SKEW_CLKS__DAC_SKEW_CLKS__SHIFT 0 +#define DAC_INCR 0x00000DCC +#define DAC_INCR__DAC_INCR_Y_G__MASK 0x000003FF +#define DAC_INCR__DAC_INCR_Y_G__SHIFT 0 +#define DAC_INCR__DAC_INCR_CrCb_RB__MASK 0x03FF0000 +#define DAC_INCR__DAC_INCR_CrCb_RB__SHIFT 16 +#define DAC_NEG_SYNC_LEVEL 0x00000DD0 +#define DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_Y_G__MASK 0x000003FF +#define DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_Y_G__SHIFT 0 +#define DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_CrCb_RB__MASK 0x03FF0000 +#define DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_CrCb_RB__SHIFT 16 +#define DAC_POS_SYNC_LEVEL 0x00000DD4 +#define DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_Y_G__MASK 0x000003FF +#define DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_Y_G__SHIFT 0 +#define DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_CrCb_RB__MASK 0x03FF0000 +#define DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_CrCb_RB__SHIFT 16 +#define DAC_BLANK_LEVEL 0x00000DD8 +#define DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_Y_G__MASK 0x000003FF +#define DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_Y_G__SHIFT 0 +#define DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_CrCb_RB__MASK 0x03FF0000 +#define DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_CrCb_RB__SHIFT 16 +#define DAC_SYNC_EQUALIZATION 0x00000DDC +#define DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_START__MASK 0x000007FF +#define DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_START__SHIFT 0 +#define DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_END__MASK 0x07FF0000 +#define DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_END__SHIFT 16 +#define TV_MASTER_CNTL 0x00000800 +#define TV_MASTER_CNTL__TV_ASYNC_RST 0x00000001 +#define TV_MASTER_CNTL__CRT_ASYNC_RST 0x00000002 +#define TV_MASTER_CNTL__RESTART_PHASE_FIX 0x00000008 +#define TV_MASTER_CNTL__TV_FIFO_ASYNC_RST 0x00000010 +#define TV_MASTER_CNTL__MV_BP_LEVEL_FIX_EN 0x00000020 +#define TV_MASTER_CNTL__EXTRA_BIT_ONE_0 0x00000040 +#define TV_MASTER_CNTL__CRT_FIFO_CE_EN 0x00000200 +#define TV_MASTER_CNTL__TV_FIFO_CE_EN 0x00000400 +#define TV_MASTER_CNTL__RE_SYNC_NOW_SEL__MASK 0x0000C000 +#define TV_MASTER_CNTL__RE_SYNC_NOW_SEL__SHIFT 14 +#define TV_MASTER_CNTL__EXTRA_BIT_ZERO_1 0x00010000 +#define TV_MASTER_CNTL__EXTRA_BIT_ONE_1 0x00020000 +#define TV_MASTER_CNTL__EXTRA_BIT_ZERO_2 0x00040000 +#define TV_MASTER_CNTL__EXTRA_BIT_ONE_2 0x00080000 +#define TV_MASTER_CNTL__TVCLK_ALWAYS_ONb 0x40000000 +#define TV_MASTER_CNTL__TV_ON 0x80000000 +#define TV_DAC_CNTL 0x0000088C +#define TV_DAC_CNTL__NBLANK 0x00000001 +#define TV_DAC_CNTL__NHOLD 0x00000002 +#define TV_DAC_CNTL__PEDESTAL 0x00000004 +#define TV_DAC_CNTL__DETECT 0x00000010 +#define TV_DAC_CNTL__CMPOUT 0x00000020 +#define TV_DAC_CNTL__BGSLEEP 0x00000040 +#define TV_DAC_CNTL__STD__MASK 0x00000300 +#define TV_DAC_CNTL__STD__SHIFT 8 +#define STD__PAL 0x0 +#define STD__NTSC 0x1 +#define STD__PS2 0x2 +#define STD__RS343 0x3 +#define TV_DAC_CNTL__MON__MASK 0x0000F000 +#define TV_DAC_CNTL__MON__SHIFT 12 +#define TV_DAC_CNTL__BGADJ__MASK 0x000F0000 +#define TV_DAC_CNTL__BGADJ__SHIFT 16 +#define TV_DAC_CNTL__DACADJ__MASK 0x00F00000 +#define TV_DAC_CNTL__DACADJ__SHIFT 20 +#define TV_DAC_CNTL__RDACPD 0x01000000 +#define TV_DAC_CNTL__GDACPD 0x02000000 +#define TV_DAC_CNTL__BDACPD 0x04000000 +#define TV_DAC_CNTL__RDACDET 0x20000000 +#define TV_DAC_CNTL__GDACDET 0x40000000 +#define TV_DAC_CNTL__BDACDET 0x80000000 +#define TV_DAC_CNTL__DACADJ_R4__MASK 0x01F00000 +#define TV_DAC_CNTL__DACADJ_R4__SHIFT 20 +#define TV_DAC_CNTL__RDACPD_R4 0x02000000 +#define TV_DAC_CNTL__GDACPD_R4 0x04000000 +#define TV_DAC_CNTL__BDACPD_R4 0x08000000 +#define TV_DAC_CNTL__TVENABLE_R4 0x10000000 +#define VIPPAD_EN 0x000001A0 +#define VIPPAD_EN__VIPPAD_EN__MASK 0x0007FFFF +#define VIPPAD_EN__VIPPAD_EN__SHIFT 0 +#define VIPPAD_EN__VIPPAD_EN_TVODATA__MASK 0x000003FF +#define VIPPAD_EN__VIPPAD_EN_TVODATA__SHIFT 0 +#define VIPPAD_EN__VIPPAD_EN_TVOCLKO 0x00000400 +#define VIPPAD_EN__VIPPAD_EN_ROMCSb 0x00000800 +#define VIPPAD_EN__VIPPAD_EN_VHAD__MASK 0x00003000 +#define VIPPAD_EN__VIPPAD_EN_VHAD__SHIFT 12 +#define VIPPAD_EN__VIPPAD_EN_VPHCTL 0x00010000 +#define VIPPAD_EN__VIPPAD_EN_VIPCLK 0x00020000 +#define VIPPAD_EN__VIPPAD_EN_SI 0x00080000 +#define VIPPAD_EN__VIPPAD_EN_SO 0x00100000 +#define VIPPAD_EN__VIPPAD_EN_SCK 0x00200000 +#define VIPPAD_Y 0x000001A4 +#define VIPPAD_Y__VIPPAD_Y__MASK 0x0007FFFF +#define VIPPAD_Y__VIPPAD_Y__SHIFT 0 +#define VIPPAD_Y__VIPPAD_Y_TVODATA__MASK 0x000003FF +#define VIPPAD_Y__VIPPAD_Y_TVODATA__SHIFT 0 +#define VIPPAD_Y__VIPPAD_Y_TVOCLKO 0x00000400 +#define VIPPAD_Y__VIPPAD_Y_ROMCSb 0x00000800 +#define VIPPAD_Y__VIPPAD_Y_VHAD__MASK 0x00003000 +#define VIPPAD_Y__VIPPAD_Y_VHAD__SHIFT 12 +#define VIPPAD_Y__VIPPAD_Y_VPHCTL 0x00010000 +#define VIPPAD_Y__VIPPAD_Y_VIPCLK 0x00020000 +#define VIPPAD_Y__VIPPAD_Y_SI 0x00080000 +#define VIPPAD_Y__VIPPAD_Y_SO 0x00100000 +#define VIPPAD_Y__VIPPAD_Y_SCK 0x00200000 +#define VIPPAD1_EN 0x000001B0 +#define VIPPAD1_EN__VIPPAD1_EN__MASK 0x0003FFFF +#define VIPPAD1_EN__VIPPAD1_EN__SHIFT 0 +#define VIPPAD1_EN__VIPPAD_EN_VID__MASK 0x000000FF +#define VIPPAD1_EN__VIPPAD_EN_VID__SHIFT 0 +#define VIPPAD1_EN__VIPPAD_EN_VPCLK0 0x00000100 +#define VIPPAD1_EN__VIPPAD_EN_DVALID 0x00000200 +#define VIPPAD1_EN__VIPPAD_EN_PSYNC 0x00000400 +#define VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK 0x0FFF0000 +#define VIPPAD1_EN__VIPPAD_EN_DVODATA__SHIFT 16 +#define VIPPAD1_EN__VIPPAD_EN_DVOCNTL__MASK 0x70000000 +#define VIPPAD1_EN__VIPPAD_EN_DVOCNTL__SHIFT 28 +#define VIPPAD1_Y 0x000001B4 +#define VIPPAD1_Y__VIPPAD1_Y__MASK 0x0003FFFF +#define VIPPAD1_Y__VIPPAD1_Y__SHIFT 0 +#define VIPPAD1_Y__VIPPAD_Y_VID__MASK 0x000000FF +#define VIPPAD1_Y__VIPPAD_Y_VID__SHIFT 0 +#define VIPPAD1_Y__VIPPAD_Y_VPCLK0 0x00000100 +#define VIPPAD1_Y__VIPPAD_Y_DVALID 0x00000200 +#define VIPPAD1_Y__VIPPAD_Y_PSYNC 0x00000400 +#define VIPPAD1_Y__VIPPAD_Y_DVODATA__MASK 0x0FFF0000 +#define VIPPAD1_Y__VIPPAD_Y_DVODATA__SHIFT 16 +#define VIPPAD1_Y__VIPPAD_Y_DVOCNTL__MASK 0x70000000 +#define VIPPAD1_Y__VIPPAD_Y_DVOCNTL__SHIFT 28 +#define GPIO_DDC1 0x00000060 +#define GPIO_DDC1__DDC1_DATA_OUTPUT 0x00000001 +#define GPIO_DDC1__DDC1_CLK_OUTPUT 0x00000002 +#define GPIO_DDC1__DDC1_DATA_INPUT 0x00000100 +#define GPIO_DDC1__DDC1_CLK_INPUT 0x00000200 +#define GPIO_DDC1__DDC1_DATA_OUT_EN 0x00010000 +#define GPIO_DDC1__DDC1_CLK_OUT_EN 0x00020000 +#define GPIO_DDC1__SW_WANTS_TO_USE_DVI_I2C 0x00100000 +#define GPIO_DDC1__SW_CAN_USE_DVI_I2C 0x00100000 +#define GPIO_DDC1__SW_DONE_USING_DVI_I2C 0x00200000 +#define GPIO_DDC1__HW_USING_DVI_I2C 0x00400000 +#define GPIO_DDC2 0x00000064 +#define GPIO_DDC2__DDC2_DATA_OUTPUT 0x00000001 +#define GPIO_DDC2__DDC2_CLK_OUTPUT 0x00000002 +#define GPIO_DDC2__DDC2_DATA_INPUT 0x00000100 +#define GPIO_DDC2__DDC2_CLK_INPUT 0x00000200 +#define GPIO_DDC2__DDC2_DATA_OUT_EN 0x00010000 +#define GPIO_DDC2__DDC2_CLK_OUT_EN 0x00020000 +#define GPIO_DDC2__SW_WANTS_TO_USE_DVI_I2C 0x00100000 +#define GPIO_DDC2__SW_CAN_USE_DVI_I2C 0x00100000 +#define GPIO_DDC2__SW_DONE_USING_DVI_I2C 0x00200000 +#define GPIO_DDC2__HW_USING_DVI_I2C 0x00400000 +#define CLOCK_CNTL_INDEX 0x00000008 +#define CLOCK_CNTL_INDEX__PLL_ADDR__MASK 0x0000001F +#define CLOCK_CNTL_INDEX__PLL_ADDR__SHIFT 0 +#define CLOCK_CNTL_INDEX__PLL_WR_EN 0x00000080 +#define CLOCK_CNTL_INDEX__PPLL_DIV_SEL__MASK 0x00000300 +#define CLOCK_CNTL_INDEX__PPLL_DIV_SEL__SHIFT 8 +#define CLOCK_CNTL_INDEX__PLL_ADDR_R2__MASK 0x0000003F +#define CLOCK_CNTL_INDEX__PLL_ADDR_R2__SHIFT 0 +#define CLOCK_CNTL_DATA 0x0000000C +#define CLOCK_CNTL_DATA__PLL_DATA__MASK 0xFFFFFFFF +#define CLOCK_CNTL_DATA__PLL_DATA__SHIFT 0 +#define MCLK_CNTL 0x00000012 +#define MCLK_CNTL__MCLKA_SRC_SEL__MASK 0x00000007 +#define MCLK_CNTL__MCLKA_SRC_SEL__SHIFT 0 +#define MCLK_CNTL__YCLKA_SRC_SEL__MASK 0x00000070 +#define MCLK_CNTL__YCLKA_SRC_SEL__SHIFT 4 +#define MCLK_CNTL__MCLKB_SRC_SEL__MASK 0x00000700 +#define MCLK_CNTL__MCLKB_SRC_SEL__SHIFT 8 +#define MCLK_CNTL__YCLKB_SRC_SEL__MASK 0x00007000 +#define MCLK_CNTL__YCLKB_SRC_SEL__SHIFT 12 +#define MCLK_CNTL__FORCE_MCLKA 0x00010000 +#define MCLK_CNTL__FORCE_MCLKB 0x00020000 +#define MCLK_CNTL__FORCE_YCLKA 0x00040000 +#define MCLK_CNTL__FORCE_YCLKB 0x00080000 +#define MCLK_CNTL__FORCE_MC 0x00100000 +#define MCLK_CNTL__FORCE_AIC 0x00200000 +#define MCLK_CNTL__MRDCKA0_SOUTSEL__MASK 0x03000000 +#define MCLK_CNTL__MRDCKA0_SOUTSEL__SHIFT 24 +#define MCLK_CNTL__MRDCKA1_SOUTSEL__MASK 0x0C000000 +#define MCLK_CNTL__MRDCKA1_SOUTSEL__SHIFT 26 +#define MCLK_CNTL__MRDCKB0_SOUTSEL__MASK 0x30000000 +#define MCLK_CNTL__MRDCKB0_SOUTSEL__SHIFT 28 +#define MCLK_CNTL__MRDCKB1_SOUTSEL__MASK 0xC0000000 +#define MCLK_CNTL__MRDCKB1_SOUTSEL__SHIFT 30 +#define MCLK_CNTL__FORCE_MC_MCLKA 0x00010000 +#define MCLK_CNTL__FORCE_MC_MCLKB 0x00020000 +#define MCLK_CNTL__FORCE_MC_MCLK 0x00100000 +#define MCLK_CNTL__DISABLE_MC_MCLKA 0x00200000 +#define MCLK_CNTL__DISABLE_MC_MCLKB 0x00400000 +#define SCLK_CNTL 0x0000000D +#define SCLK_CNTL__SCLK_SRC_SEL__MASK 0x00000007 +#define SCLK_CNTL__SCLK_SRC_SEL__SHIFT 0 +#define SCLK_CNTL__TCLK_SRC_SEL__MASK 0x00000700 +#define SCLK_CNTL__TCLK_SRC_SEL__SHIFT 8 +#define SCLK_CNTL__FORCE_CP 0x00010000 +#define SCLK_CNTL__FORCE_HDP 0x00020000 +#define SCLK_CNTL__FORCE_DISP 0x00040000 +#define SCLK_CNTL__FORCE_TOP 0x00080000 +#define SCLK_CNTL__FORCE_E2 0x00100000 +#define SCLK_CNTL__FORCE_SE 0x00200000 +#define SCLK_CNTL__FORCE_IDCT 0x00400000 +#define SCLK_CNTL__FORCE_VIP 0x00800000 +#define SCLK_CNTL__FORCE_RE 0x01000000 +#define SCLK_CNTL__FORCE_PB 0x02000000 +#define SCLK_CNTL__FORCE_TAM 0x04000000 +#define SCLK_CNTL__FORCE_TDM 0x08000000 +#define SCLK_CNTL__FORCE_RB 0x10000000 +#define SCLK_CNTL__CP_MAX_DYN_STOP_LAT 0x00000008 +#define SCLK_CNTL__HDP_MAX_DYN_STOP_LAT 0x00000010 +#define SCLK_CNTL__E2_MAX_DYN_STOP_LAT 0x00000040 +#define SCLK_CNTL__SE_MAX_DYN_STOP_LAT 0x00000080 +#define SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT 0x00000100 +#define SCLK_CNTL__VIP_MAX_DYN_STOP_LAT 0x00000200 +#define SCLK_CNTL__RE_MAX_DYN_STOP_LAT 0x00000400 +#define SCLK_CNTL__PB_MAX_DYN_STOP_LAT 0x00000800 +#define SCLK_CNTL__TAM_MAX_DYN_STOP_LAT 0x00001000 +#define SCLK_CNTL__TDM_MAX_DYN_STOP_LAT 0x00002000 +#define SCLK_CNTL__RB_MAX_DYN_STOP_LAT 0x00004000 +#define SCLK_CNTL__FORCE_DISP2 0x00008000 +#define SCLK_CNTL__FORCE_DISP1 0x00040000 +#define SCLK_CNTL__FORCE_SUBPIC 0x40000000 +#define SCLK_CNTL__FORCE_OV0 0x80000000 +#define SCLK_CNTL__TV_MAX_DYN_STOP_LAT 0x00000020 +#define SCLK_CNTL__FORCE_TV_SCLK 0x20000000 +#define SCLK_CNTL__VAP_MAX_DYN_STOP_LAT 0x00000080 +#define SCLK_CNTL__SR_MAX_DYN_STOP_LAT 0x00000400 +#define SCLK_CNTL__PX_MAX_DYN_STOP_LAT 0x00000800 +#define SCLK_CNTL__TX_MAX_DYN_STOP_LAT 0x00001000 +#define SCLK_CNTL__US_MAX_DYN_STOP_LAT 0x00002000 +#define SCLK_CNTL__SU_MAX_DYN_STOP_LAT 0x00004000 +#define SCLK_CNTL__FORCE_VAP 0x00200000 +#define SCLK_CNTL__FORCE_SR 0x02000000 +#define SCLK_CNTL__FORCE_PX 0x04000000 +#define SCLK_CNTL__FORCE_TX 0x08000000 +#define SCLK_CNTL__FORCE_US 0x10000000 +#define SCLK_CNTL__FORCE_SU 0x40000000 +#define PPLL_CNTL 0x00000002 +#define PPLL_CNTL__PPLL_RESET 0x00000001 +#define PPLL_CNTL__PPLL_SLEEP 0x00000002 +#define PPLL_CNTL__PPLL_TST_EN 0x00000004 +#define PPLL_CNTL__PPLL_REFCLK_SEL 0x00000010 +#define PPLL_CNTL__PPLL_FBCLK_SEL 0x00000020 +#define PPLL_CNTL__PPLL_TCPOFF 0x00000040 +#define PPLL_CNTL__PPLL_TVCOMAX 0x00000080 +#define PPLL_CNTL__PPLL_PCP__MASK 0x00000700 +#define PPLL_CNTL__PPLL_PCP__SHIFT 8 +#define PPLL_CNTL__PPLL_PVG__MASK 0x00003800 +#define PPLL_CNTL__PPLL_PVG__SHIFT 11 +#define PPLL_CNTL__PPLL_PDC__MASK 0x0000C000 +#define PPLL_CNTL__PPLL_PDC__SHIFT 14 +#define PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN 0x00010000 +#define PPLL_CNTL__PPLL_VGA_ATOMIC_UPDATE_EN 0x00020000 +#define PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC 0x00040000 +#define PPLL_CNTL__PPLL_DISABLE_AUTO_RESET 0x00080000 +#define PPLL_CNTL__PPLL_DIV_RESET 0x00000008 +#define PPLL_REF_DIV 0x00000003 +#define PPLL_REF_DIV__PPLL_REF_DIV__MASK 0x000003FF +#define PPLL_REF_DIV__PPLL_REF_DIV__SHIFT 0 +#define PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_REF_DIV__PPLL_REF_DIV_SRC__MASK 0x00030000 +#define PPLL_REF_DIV__PPLL_REF_DIV_SRC__SHIFT 16 +#define PPLL_REF_DIV_SRC__XTALIN 0x0 +#define PPLL_REF_DIV_SRC__PLLSCLK_2 0x1 +#define PPLL_REF_DIV_SRC__PLLSCLK_4 0x2 +#define PPLL_REF_DIV_SRC__SREFCLK 0x3 +#define PPLL_REF_DIV__PPLL_REF_DIV_ACC__MASK 0x0FFC0000 +#define PPLL_REF_DIV__PPLL_REF_DIV_ACC__SHIFT 18 +#define PPLL_DIV_0 0x00000004 +#define PPLL_DIV_0__PPLL_FB0_DIV__MASK 0x000007FF +#define PPLL_DIV_0__PPLL_FB0_DIV__SHIFT 0 +#define PPLL_DIV_0__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_DIV_0__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_DIV_0__PPLL_POST0_DIV__MASK 0x00070000 +#define PPLL_DIV_0__PPLL_POST0_DIV__SHIFT 16 +#define PPLL_DIV_0__PPLL_FB_DIV_FRACTION__MASK 0x00380000 +#define PPLL_DIV_0__PPLL_FB_DIV_FRACTION__SHIFT 19 +#define PPLL_DIV_0__PPLL_FB_DIV_FRACTION_UPDATE 0x00400000 +#define PPLL_DIV_0__PPLL_FB_DIV_FRACTION_EN 0x00800000 +#define PPLL_DIV_1 0x00000005 +#define PPLL_DIV_1__PPLL_FB1_DIV__MASK 0x000007FF +#define PPLL_DIV_1__PPLL_FB1_DIV__SHIFT 0 +#define PPLL_DIV_1__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_DIV_1__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_DIV_1__PPLL_POST1_DIV__MASK 0x00070000 +#define PPLL_DIV_1__PPLL_POST1_DIV__SHIFT 16 +#define PPLL_DIV_2 0x00000006 +#define PPLL_DIV_2__PPLL_FB2_DIV__MASK 0x000007FF +#define PPLL_DIV_2__PPLL_FB2_DIV__SHIFT 0 +#define PPLL_DIV_2__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_DIV_2__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_DIV_2__PPLL_POST2_DIV__MASK 0x00070000 +#define PPLL_DIV_2__PPLL_POST2_DIV__SHIFT 16 +#define PPLL_DIV_3 0x00000007 +#define PPLL_DIV_3__PPLL_FB3_DIV__MASK 0x000007FF +#define PPLL_DIV_3__PPLL_FB3_DIV__SHIFT 0 +#define PPLL_DIV_3__PPLL_ATOMIC_UPDATE_W 0x00008000 +#define PPLL_DIV_3__PPLL_ATOMIC_UPDATE_R 0x00008000 +#define PPLL_DIV_3__PPLL_POST3_DIV__MASK 0x00070000 +#define PPLL_DIV_3__PPLL_POST3_DIV__SHIFT 16 +#define VCLK_ECP_CNTL 0x00000008 +#define VCLK_ECP_CNTL__VCLK_SRC_SEL__MASK 0x00000003 +#define VCLK_ECP_CNTL__VCLK_SRC_SEL__SHIFT 0 +#define VCLK_SRC_SEL__CPUCLK 0x0 +#define VCLK_SRC_SEL__PSCANCLK 0x1 +#define VCLK_SRC_SEL__BYTE_CLK 0x2 +#define VCLK_SRC_SEL__PPLLCLK 0x3 +#define VCLK_ECP_CNTL__VCLK_INVERT 0x00000010 +#define VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb 0x00000040 +#define VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb 0x00000080 +#define VCLK_ECP_CNTL__ECP_DIV__MASK 0x00000300 +#define VCLK_ECP_CNTL__ECP_DIV__SHIFT 8 +#define VCLK_ECP_CNTL__ECP_FORCE_ON 0x00040000 +#define VCLK_ECP_CNTL__SUBCLK_FORCE_ON 0x00080000 +#define VCLK_ECP_CNTL__BYTE_CLK_POST_DIV__MASK 0x00030000 +#define VCLK_ECP_CNTL__BYTE_CLK_POST_DIV__SHIFT 16 +#define VCLK_ECP_CNTL__BYTE_CLK_OUT_EN 0x00100000 +#define VCLK_ECP_CNTL__BYTE_CLK_SKEW__MASK 0x07000000 +#define VCLK_ECP_CNTL__BYTE_CLK_SKEW__SHIFT 24 +#define VCLK_ECP_CNTL__PCICLK_INVERT 0x00000020 +#define VCLK_ECP_CNTL__PIXCLK_SRC_INVERT 0x00000020 +#define VCLK_ECP_CNTL__PIXCLK_SRC_INVERT_R3 0x08000000 +#define VCLK_ECP_CNTL__DISP_DAC_PIXCLK_DAC_BLANK_OFF 0x00800000 +#define HTOTAL_CNTL 0x00000009 +#define HTOTAL_CNTL__HTOT_PIX_SLIP__MASK 0x0000000F +#define HTOTAL_CNTL__HTOT_PIX_SLIP__SHIFT 0 +#define HTOTAL_CNTL__HTOT_VCLK_SLIP__MASK 0x00000F00 +#define HTOTAL_CNTL__HTOT_VCLK_SLIP__SHIFT 8 +#define HTOTAL_CNTL__HTOT_PPLL_SLIP__MASK 0x00070000 +#define HTOTAL_CNTL__HTOT_PPLL_SLIP__SHIFT 16 +#define HTOTAL_CNTL__HTOT_CNTL_EDGE 0x01000000 +#define HTOTAL_CNTL__HTOT_CNTL_VGA_EN 0x10000000 +#define FP_H_SYNC_STRT_WID 0x000002C4 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_PIX__MASK 0x00000007 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_PIX__SHIFT 0 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_CHAR__MASK 0x00001FF8 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_CHAR__SHIFT 3 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_WID__MASK 0x003F0000 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_WID__SHIFT 16 +#define FP_H_SYNC_STRT_WID__FP_H_SYNC_POL 0x00800000 +#define FP_V_SYNC_STRT_WID 0x000002C8 +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_STRT__MASK 0x00000FFF +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_STRT__SHIFT 0 +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_WID__MASK 0x001F0000 +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_WID__SHIFT 16 +#define FP_V_SYNC_STRT_WID__FP_V_SYNC_POL 0x00800000 +#define FP_CRTC_H_TOTAL_DISP 0x00000250 +#define FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_TOTAL__MASK 0x000003FF +#define FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_TOTAL__SHIFT 0 +#define FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_DISP__MASK 0x01FF0000 +#define FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_DISP__SHIFT 16 +#define FP_CRTC_V_TOTAL_DISP 0x00000254 +#define FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_TOTAL__MASK 0x00000FFF +#define FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_TOTAL__SHIFT 0 +#define FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_DISP__MASK 0x0FFF0000 +#define FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_DISP__SHIFT 16 +#define PALETTE_INDEX 0x000000B0 +#define PALETTE_INDEX__PALETTE_W_INDEX__MASK 0x000000FF +#define PALETTE_INDEX__PALETTE_W_INDEX__SHIFT 0 +#define PALETTE_INDEX__PALETTE_R_INDEX__MASK 0x00FF0000 +#define PALETTE_INDEX__PALETTE_R_INDEX__SHIFT 16 +#define PALETTE_DATA 0x000000B4 +#define PALETTE_DATA__PALETTE_DATA_B__MASK 0x000000FF +#define PALETTE_DATA__PALETTE_DATA_B__SHIFT 0 +#define PALETTE_DATA__PALETTE_DATA_G__MASK 0x0000FF00 +#define PALETTE_DATA__PALETTE_DATA_G__SHIFT 8 +#define PALETTE_DATA__PALETTE_DATA_R__MASK 0x00FF0000 +#define PALETTE_DATA__PALETTE_DATA_R__SHIFT 16 +#define PALETTE_30_DATA 0x000000B8 +#define PALETTE_30_DATA__PALETTE_DATA_B__MASK 0x000003FF +#define PALETTE_30_DATA__PALETTE_DATA_B__SHIFT 0 +#define PALETTE_30_DATA__PALETTE_DATA_G__MASK 0x000FFC00 +#define PALETTE_30_DATA__PALETTE_DATA_G__SHIFT 10 +#define PALETTE_30_DATA__PALETTE_DATA_R__MASK 0x3FF00000 +#define PALETTE_30_DATA__PALETTE_DATA_R__SHIFT 20 +#define SURFACE_CNTL 0x00000B00 +#define SURFACE_CNTL__SURF_TRANSLATION_DIS 0x00000100 +#define SURFACE_CNTL__NONSURF_AP0_SWP__MASK 0x00300000 +#define SURFACE_CNTL__NONSURF_AP0_SWP__SHIFT 20 +#define SURFACE_CNTL__NONSURF_AP1_SWP__MASK 0x00C00000 +#define SURFACE_CNTL__NONSURF_AP1_SWP__SHIFT 22 +#define SURFACE0_INFO 0x00000B0C +#define SURFACE0_INFO__SURF0_PITCHSEL__MASK 0x000003FF +#define SURFACE0_INFO__SURF0_PITCHSEL__SHIFT 0 +#define SURFACE0_INFO__SURF0_TILE_MODE__MASK 0x00030000 +#define SURFACE0_INFO__SURF0_TILE_MODE__SHIFT 16 +#define SURF0_TILE_MODE__NO_TILING(p) 0x0 +#define SURF0_TILE_MODE__MACRO_TILING(p) 0x0 +#define SURF0_TILE_MODE__MICRO_TILING(p) 0x0 +#define SURF0_TILE_MODE__MACRO_MICRO_TILING(p) 0x0 +#define SURF0_TILE_MODE__32_BIT_Z_TILING(p) 0x0 +#define SURF0_TILE_MODE__16_BIT_Z_TILING(p) 0x0 +#define SURFACE0_INFO__SURF0_AP0_SWP__MASK 0x00300000 +#define SURFACE0_INFO__SURF0_AP0_SWP__SHIFT 20 +#define SURFACE0_INFO__SURF0_AP1_SWP__MASK 0x00C00000 +#define SURFACE0_INFO__SURF0_AP1_SWP__SHIFT 22 +#define SURFACE0_INFO__SURF0_WRITE_FLAG 0x01000000 +#define SURFACE0_INFO__SURF0_READ_FLAG 0x02000000 +#define SURFACE0_INFO__SURF0_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE0_INFO__SURF0_TILE_MODE_R2__SHIFT 16 +#define SURFACE0_INFO__SURF0_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE0_INFO__SURF0_PITCHSEL_R3__SHIFT 0 +#define SURFACE0_LOWER_BOUND 0x00000B04 +#define SURFACE0_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE0_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE0_UPPER_BOUND 0x00000B08 +#define SURFACE0_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE0_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE1_INFO 0x00000B1C +#define SURFACE1_INFO__SURF1_PITCHSEL__MASK 0x000003FF +#define SURFACE1_INFO__SURF1_PITCHSEL__SHIFT 0 +#define SURFACE1_INFO__SURF1_TILE_MODE__MASK 0x00030000 +#define SURFACE1_INFO__SURF1_TILE_MODE__SHIFT 16 +#define SURFACE1_INFO__SURF1_AP0_SWP__MASK 0x00300000 +#define SURFACE1_INFO__SURF1_AP0_SWP__SHIFT 20 +#define SURFACE1_INFO__SURF1_AP1_SWP__MASK 0x00C00000 +#define SURFACE1_INFO__SURF1_AP1_SWP__SHIFT 22 +#define SURFACE1_INFO__SURF1_WRITE_FLAG 0x01000000 +#define SURFACE1_INFO__SURF1_READ_FLAG 0x02000000 +#define SURFACE1_INFO__SURF1_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE1_INFO__SURF1_TILE_MODE_R2__SHIFT 16 +#define SURFACE1_INFO__SURF1_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE1_INFO__SURF1_PITCHSEL_R3__SHIFT 0 +#define SURFACE1_LOWER_BOUND 0x00000B14 +#define SURFACE1_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE1_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE1_UPPER_BOUND 0x00000B18 +#define SURFACE1_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE1_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE2_INFO 0x00000B2C +#define SURFACE2_INFO__SURF2_PITCHSEL__MASK 0x000003FF +#define SURFACE2_INFO__SURF2_PITCHSEL__SHIFT 0 +#define SURFACE2_INFO__SURF2_TILE_MODE__MASK 0x00030000 +#define SURFACE2_INFO__SURF2_TILE_MODE__SHIFT 16 +#define SURFACE2_INFO__SURF2_AP0_SWP__MASK 0x00300000 +#define SURFACE2_INFO__SURF2_AP0_SWP__SHIFT 20 +#define SURFACE2_INFO__SURF2_AP1_SWP__MASK 0x00C00000 +#define SURFACE2_INFO__SURF2_AP1_SWP__SHIFT 22 +#define SURFACE2_INFO__SURF2_WRITE_FLAG 0x01000000 +#define SURFACE2_INFO__SURF2_READ_FLAG 0x02000000 +#define SURFACE2_INFO__SURF2_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE2_INFO__SURF2_TILE_MODE_R2__SHIFT 16 +#define SURFACE2_INFO__SURF2_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE2_INFO__SURF2_PITCHSEL_R3__SHIFT 0 +#define SURFACE2_LOWER_BOUND 0x00000B24 +#define SURFACE2_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE2_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE2_UPPER_BOUND 0x00000B28 +#define SURFACE2_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE2_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE3_INFO 0x00000B3C +#define SURFACE3_INFO__SURF3_PITCHSEL__MASK 0x000003FF +#define SURFACE3_INFO__SURF3_PITCHSEL__SHIFT 0 +#define SURFACE3_INFO__SURF3_TILE_MODE__MASK 0x00030000 +#define SURFACE3_INFO__SURF3_TILE_MODE__SHIFT 16 +#define SURFACE3_INFO__SURF3_AP0_SWP__MASK 0x00300000 +#define SURFACE3_INFO__SURF3_AP0_SWP__SHIFT 20 +#define SURFACE3_INFO__SURF3_AP1_SWP__MASK 0x00C00000 +#define SURFACE3_INFO__SURF3_AP1_SWP__SHIFT 22 +#define SURFACE3_INFO__SURF3_WRITE_FLAG 0x01000000 +#define SURFACE3_INFO__SURF3_READ_FLAG 0x02000000 +#define SURFACE3_INFO__SURF3_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE3_INFO__SURF3_TILE_MODE_R2__SHIFT 16 +#define SURFACE3_INFO__SURF3_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE3_INFO__SURF3_PITCHSEL_R3__SHIFT 0 +#define SURFACE3_LOWER_BOUND 0x00000B34 +#define SURFACE3_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE3_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE3_UPPER_BOUND 0x00000B38 +#define SURFACE3_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE3_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE4_INFO 0x00000B4C +#define SURFACE4_INFO__SURF4_PITCHSEL__MASK 0x000003FF +#define SURFACE4_INFO__SURF4_PITCHSEL__SHIFT 0 +#define SURFACE4_INFO__SURF4_TILE_MODE__MASK 0x00030000 +#define SURFACE4_INFO__SURF4_TILE_MODE__SHIFT 16 +#define SURFACE4_INFO__SURF4_AP0_SWP__MASK 0x00300000 +#define SURFACE4_INFO__SURF4_AP0_SWP__SHIFT 20 +#define SURFACE4_INFO__SURF4_AP1_SWP__MASK 0x00C00000 +#define SURFACE4_INFO__SURF4_AP1_SWP__SHIFT 22 +#define SURFACE4_INFO__SURF4_WRITE_FLAG 0x01000000 +#define SURFACE4_INFO__SURF4_READ_FLAG 0x02000000 +#define SURFACE4_INFO__SURF4_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE4_INFO__SURF4_TILE_MODE_R2__SHIFT 16 +#define SURFACE4_INFO__SURF4_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE4_INFO__SURF4_PITCHSEL_R3__SHIFT 0 +#define SURFACE4_LOWER_BOUND 0x00000B44 +#define SURFACE4_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE4_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE4_UPPER_BOUND 0x00000B48 +#define SURFACE4_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE4_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE5_INFO 0x00000B5C +#define SURFACE5_INFO__SURF5_PITCHSEL__MASK 0x000003FF +#define SURFACE5_INFO__SURF5_PITCHSEL__SHIFT 0 +#define SURFACE5_INFO__SURF5_TILE_MODE__MASK 0x00030000 +#define SURFACE5_INFO__SURF5_TILE_MODE__SHIFT 16 +#define SURFACE5_INFO__SURF5_AP0_SWP__MASK 0x00300000 +#define SURFACE5_INFO__SURF5_AP0_SWP__SHIFT 20 +#define SURFACE5_INFO__SURF5_AP1_SWP__MASK 0x00C00000 +#define SURFACE5_INFO__SURF5_AP1_SWP__SHIFT 22 +#define SURFACE5_INFO__SURF5_WRITE_FLAG 0x01000000 +#define SURFACE5_INFO__SURF5_READ_FLAG 0x02000000 +#define SURFACE5_INFO__SURF5_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE5_INFO__SURF5_TILE_MODE_R2__SHIFT 16 +#define SURFACE5_INFO__SURF5_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE5_INFO__SURF5_PITCHSEL_R3__SHIFT 0 +#define SURFACE5_LOWER_BOUND 0x00000B54 +#define SURFACE5_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE5_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE5_UPPER_BOUND 0x00000B58 +#define SURFACE5_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE5_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE6_INFO 0x00000B6C +#define SURFACE6_INFO__SURF6_PITCHSEL__MASK 0x000003FF +#define SURFACE6_INFO__SURF6_PITCHSEL__SHIFT 0 +#define SURFACE6_INFO__SURF6_TILE_MODE__MASK 0x00030000 +#define SURFACE6_INFO__SURF6_TILE_MODE__SHIFT 16 +#define SURFACE6_INFO__SURF6_AP0_SWP__MASK 0x00300000 +#define SURFACE6_INFO__SURF6_AP0_SWP__SHIFT 20 +#define SURFACE6_INFO__SURF6_AP1_SWP__MASK 0x00C00000 +#define SURFACE6_INFO__SURF6_AP1_SWP__SHIFT 22 +#define SURFACE6_INFO__SURF6_WRITE_FLAG 0x01000000 +#define SURFACE6_INFO__SURF6_READ_FLAG 0x02000000 +#define SURFACE6_INFO__SURF6_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE6_INFO__SURF6_TILE_MODE_R2__SHIFT 16 +#define SURFACE6_INFO__SURF6_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE6_INFO__SURF6_PITCHSEL_R3__SHIFT 0 +#define SURFACE6_LOWER_BOUND 0x00000B64 +#define SURFACE6_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE6_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE6_UPPER_BOUND 0x00000B68 +#define SURFACE6_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE6_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define SURFACE7_INFO 0x00000B7C +#define SURFACE7_INFO__SURF7_PITCHSEL__MASK 0x000003FF +#define SURFACE7_INFO__SURF7_PITCHSEL__SHIFT 0 +#define SURFACE7_INFO__SURF7_TILE_MODE__MASK 0x00030000 +#define SURFACE7_INFO__SURF7_TILE_MODE__SHIFT 16 +#define SURFACE7_INFO__SURF7_AP0_SWP__MASK 0x00300000 +#define SURFACE7_INFO__SURF7_AP0_SWP__SHIFT 20 +#define SURFACE7_INFO__SURF7_AP1_SWP__MASK 0x00C00000 +#define SURFACE7_INFO__SURF7_AP1_SWP__SHIFT 22 +#define SURFACE7_INFO__SURF7_WRITE_FLAG 0x01000000 +#define SURFACE7_INFO__SURF7_READ_FLAG 0x02000000 +#define SURFACE7_INFO__SURF7_TILE_MODE_R2__MASK 0x00070000 +#define SURFACE7_INFO__SURF7_TILE_MODE_R2__SHIFT 16 +#define SURFACE7_INFO__SURF7_PITCHSEL_R3__MASK 0x00001FFF +#define SURFACE7_INFO__SURF7_PITCHSEL_R3__SHIFT 0 +#define SURFACE7_LOWER_BOUND 0x00000B74 +#define SURFACE7_LOWER_BOUND__SURF_LOWER__MASK 0x0FFFFFFF +#define SURFACE7_LOWER_BOUND__SURF_LOWER__SHIFT 0 +#define SURFACE7_UPPER_BOUND 0x00000B78 +#define SURFACE7_UPPER_BOUND__SURF_UPPER__MASK 0x0FFFFFFF +#define SURFACE7_UPPER_BOUND__SURF_UPPER__SHIFT 0 +#define ISYNC_CNTL 0x00001724 +#define ISYNC_CNTL__ISYNC_ANY2D_IDLE3D 0x00000001 +#define ISYNC_CNTL__ISYNC_ANY3D_IDLE2D 0x00000002 +#define ISYNC_CNTL__ISYNC_TRIG2D_IDLE3D 0x00000004 +#define ISYNC_CNTL__ISYNC_TRIG3D_IDLE2D 0x00000008 +#define ISYNC_CNTL__ISYNC_WAIT_IDLEGUI 0x00000010 +#define ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI 0x00000020 +#define RBBM_STATUS 0x00000E40 +#define RBBM_STATUS__CMDFIFO_AVAIL__MASK 0x0000007F +#define RBBM_STATUS__CMDFIFO_AVAIL__SHIFT 0 +#define RBBM_STATUS__HIRQ_ON_RBB 0x00000100 +#define RBBM_STATUS__CPRQ_ON_RBB 0x00000200 +#define RBBM_STATUS__CFRQ_ON_RBB 0x00000400 +#define RBBM_STATUS__HIRQ_IN_RTBUF 0x00000800 +#define RBBM_STATUS__CPRQ_IN_RTBUF 0x00001000 +#define RBBM_STATUS__CFRQ_IN_RTBUF 0x00002000 +#define RBBM_STATUS__CF_PIPE_BUSY 0x00004000 +#define RBBM_STATUS__ENG_EV_BUSY 0x00008000 +#define RBBM_STATUS__CP_CMDSTRM_BUSY 0x00010000 +#define RBBM_STATUS__E2_BUSY 0x00020000 +#define RBBM_STATUS__RB2D_BUSY 0x00040000 +#define RBBM_STATUS__RB3D_BUSY 0x00080000 +#define RBBM_STATUS__SE_BUSY 0x00100000 +#define RBBM_STATUS__RE_BUSY 0x00200000 +#define RBBM_STATUS__TAM_BUSY 0x00400000 +#define RBBM_STATUS__TDM_BUSY 0x00800000 +#define RBBM_STATUS__PB_BUSY 0x01000000 +#define RBBM_STATUS__GUI_ACTIVE 0x80000000 +#define RBBM_STATUS__VAP_BUSY 0x00100000 +#define RBBM_STATUS__TIM_BUSY 0x02000000 +#define RBBM_STATUS__GA_BUSY 0x04000000 +#define RBBM_STATUS__CBA2D_BUSY 0x08000000 +#define RBBM_SOFT_RESET 0x000000F0 +#define RBBM_SOFT_RESET__SOFT_RESET_CP 0x00000001 +#define RBBM_SOFT_RESET__SOFT_RESET_HI 0x00000002 +#define RBBM_SOFT_RESET__SOFT_RESET_SE 0x00000004 +#define RBBM_SOFT_RESET__SOFT_RESET_RE 0x00000008 +#define RBBM_SOFT_RESET__SOFT_RESET_PP 0x00000010 +#define RBBM_SOFT_RESET__SOFT_RESET_E2 0x00000020 +#define RBBM_SOFT_RESET__SOFT_RESET_RB 0x00000040 +#define RBBM_SOFT_RESET__SOFT_RESET_HDP 0x00000080 +#define RBBM_SOFT_RESET__SOFT_RESET_MC 0x00000100 +#define RBBM_SOFT_RESET__SOFT_RESET_AIC 0x00000200 +#define RBBM_SOFT_RESET__SOFT_RESET_VIP 0x00000400 +#define RBBM_SOFT_RESET__SOFT_RESET_DISP 0x00000800 +#define RBBM_SOFT_RESET__SOFT_RESET_CG 0x00001000 +#define RBBM_SOFT_RESET__SOFT_RESET_VAP 0x00000004 +#define RBBM_SOFT_RESET__SOFT_RESET_GA 0x00002000 +#define RBBM_SOFT_RESET__SOFT_RESET_IDCT 0x00004000 +#define WAIT_UNTIL 0x00001720 +#define WAIT_UNTIL__WAIT_CRTC_PFLIP 0x00000001 +#define WAIT_UNTIL__WAIT_RE_CRTC_VLINE 0x00000002 +#define WAIT_UNTIL__WAIT_FE_CRTC_VLINE 0x00000004 +#define WAIT_UNTIL__WAIT_CRTC_VLINE 0x00000008 +#define WAIT_UNTIL__WAIT_DMA_VIPH0_IDLE 0x00000010 +#define WAIT_UNTIL__WAIT_DMA_VIPH1_IDLE 0x00000020 +#define WAIT_UNTIL__WAIT_DMA_VIPH2_IDLE 0x00000040 +#define WAIT_UNTIL__WAIT_DMA_VIPH3_IDLE 0x00000080 +#define WAIT_UNTIL__WAIT_DMA_VID_IDLE 0x00000100 +#define WAIT_UNTIL__WAIT_DMA_GUI_IDLE 0x00000200 +#define WAIT_UNTIL__WAIT_CMDFIFO 0x00000400 +#define WAIT_UNTIL__WAIT_OV0_FLIP 0x00000800 +#define WAIT_UNTIL__WAIT_OV0_SLICEDONE 0x00001000 +#define WAIT_UNTIL__WAIT_2D_IDLE 0x00004000 +#define WAIT_UNTIL__WAIT_3D_IDLE 0x00008000 +#define WAIT_UNTIL__WAIT_2D_IDLECLEAN 0x00010000 +#define WAIT_UNTIL__WAIT_3D_IDLECLEAN 0x00020000 +#define WAIT_UNTIL__WAIT_HOST_IDLECLEAN 0x00040000 +#define WAIT_UNTIL__WAIT_EXTERN_SIG 0x00080000 +#define WAIT_UNTIL__CMDFIFO_ENTRIES__MASK 0x07F00000 +#define WAIT_UNTIL__CMDFIFO_ENTRIES__SHIFT 20 +#define WAIT_UNTIL__WAIT_BOTH_CRTC_PFLIP 0x40000000 +#define WAIT_UNTIL__ENG_DISPLAY_SELECT 0x80000000 +#define WAIT_UNTIL__WAIT_AGP_FLUSH 0x00002000 +#define WAIT_UNTIL__WAIT_IDCT_SEMAPHORE 0x08000000 +#define WAIT_UNTIL__WAIT_VAP_IDLE 0x10000000 +#define DISPLAY_BASE_ADDR 0x0000023C +#define DISPLAY_BASE_ADDR__DISPLAY_BASE_ADDR__MASK 0xFFFFFFFF +#define DISPLAY_BASE_ADDR__DISPLAY_BASE_ADDR__SHIFT 0 +#define CRTC2_DISPLAY_BASE_ADDR 0x0000033C +#define CRTC2_DISPLAY_BASE_ADDR__CRTC2_DISPLAY_BASE_ADDR__MASK 0xFFFFFFFF +#define CRTC2_DISPLAY_BASE_ADDR__CRTC2_DISPLAY_BASE_ADDR__SHIFT 0 +#define AIC_CTRL 0x000001D0 +#define AIC_CTRL__TRANSLATE_EN 0x00000001 +#define AIC_CTRL__HW_0_DEBUG 0x00000002 +#define AIC_CTRL__HW_1_DEBUG 0x00000004 +#define AIC_CTRL__HW_2_DEBUG 0x00000008 +#define AIC_CTRL__HW_3_DEBUG 0x00000010 +#define AIC_CTRL__HW_4_DEBUG 0x00000020 +#define AIC_CTRL__HW_5_DEBUG 0x00000040 +#define AIC_CTRL__HW_6_DEBUG 0x00000080 +#define AIC_CTRL__HW_7_DEBUG 0x00000100 +#define AIC_CTRL__HW_8_DEBUG 0x00000200 +#define AIC_CTRL__HW_9_DEBUG 0x00000400 +#define AIC_CTRL__HW_A_DEBUG 0x00000800 +#define AIC_CTRL__HW_B_DEBUG 0x00001000 +#define AIC_CTRL__HW_C_DEBUG 0x00002000 +#define AIC_CTRL__HW_D_DEBUG 0x00004000 +#define AIC_CTRL__HW_E_DEBUG 0x00008000 +#define AIC_CTRL__HW_F_DEBUG 0x00010000 +#define AIC_CTRL__HW_10_DEBUG 0x00020000 +#define AIC_CTRL__HW_11_DEBUG 0x00040000 +#define AIC_CTRL__HW_12_DEBUG 0x00080000 +#define AIC_CTRL__HW_13_DEBUG 0x00100000 +#define AIC_CTRL__HW_14_DEBUG 0x00200000 +#define AIC_CTRL__HW_15_DEBUG 0x00400000 +#define AIC_CTRL__HW_16_DEBUG 0x00800000 +#define AIC_CTRL__HW_17_DEBUG 0x01000000 +#define AIC_CTRL__HW_18_DEBUG 0x02000000 +#define AIC_CTRL__HW_19_DEBUG 0x04000000 +#define AIC_CTRL__HW_1A_DEBUG 0x08000000 +#define AIC_CTRL__HW_1B_DEBUG 0x10000000 +#define AIC_CTRL__HW_1C_DEBUG 0x20000000 +#define AIC_CTRL__HW_1D_DEBUG 0x40000000 +#define AIC_CTRL__HW_1E_DEBUG 0x80000000 +#define AIC_CTRL__DIS_OUT_OF_PCI_GART_ACCESS 0x00000002 +#define AIC_CTRL__HW_02_DEBUG 0x00000004 +#define AIC_CTRL__HW_03_DEBUG 0x00000008 +#define AIC_CTRL__TEST_RBF_DIV_VAL__MASK 0x00000070 +#define AIC_CTRL__TEST_RBF_DIV_VAL__SHIFT 4 +#define AIC_CTRL__TEST_RBF_EN 0x00000080 +#define AIC_CTRL__HW_08_DEBUG 0x00000100 +#define AIC_CTRL__HW_09_DEBUG 0x00000200 +#define AIC_CTRL__HW_10_DEBUG_R3 0x00000400 +#define AIC_CTRL__HW_11_DEBUG_R3 0x00000800 +#define AIC_CTRL__HW_12_DEBUG_R3 0x00001000 +#define AIC_CTRL__HW_13_DEBUG_R3 0x00002000 +#define AIC_CTRL__HW_14_DEBUG_R3 0x00004000 +#define AIC_CTRL__HW_15_DEBUG_R3 0x00008000 +#define AIC_CTRL__HW_16_DEBUG_R3 0x00010000 +#define AIC_CTRL__HW_17_DEBUG_R3 0x00020000 +#define AIC_CTRL__HW_18_DEBUG_R3 0x00040000 +#define AIC_CTRL__HW_19_DEBUG_R3 0x00080000 +#define AIC_CTRL__HW_20_DEBUG 0x00100000 +#define AIC_CTRL__HW_21_DEBUG 0x00200000 +#define AIC_CTRL__HW_22_DEBUG 0x00400000 +#define AIC_CTRL__HW_23_DEBUG 0x00800000 +#define AIC_CTRL__HW_24_DEBUG 0x01000000 +#define AIC_CTRL__HW_25_DEBUG 0x02000000 +#define AIC_CTRL__HW_26_DEBUG 0x04000000 +#define AIC_CTRL__HW_27_DEBUG 0x08000000 +#define AIC_CTRL__HW_28_DEBUG 0x10000000 +#define AIC_CTRL__HW_29_DEBUG 0x20000000 +#define AIC_CTRL__HW_30_DEBUG 0x40000000 +#define AIC_CTRL__HW_31_DEBUG 0x80000000 +#define BUS_CNTL 0x00000030 +#define BUS_CNTL__BUS_DBL_RESYNC 0x00000001 +#define BUS_CNTL__BUS_MSTR_RESET 0x00000002 +#define BUS_CNTL__BUS_FLUSH_BUF 0x00000004 +#define BUS_CNTL__BUS_STOP_REQ_DIS 0x00000008 +#define BUS_CNTL__BUS_READ_COMBINE_EN 0x00000010 +#define BUS_CNTL__BUS_WRT_COMBINE_EN 0x00000020 +#define BUS_CNTL__BUS_MASTER_DIS 0x00000040 +#define BUS_CNTL__BIOS_ROM_WRT_EN 0x00000080 +#define BUS_CNTL__BUS_PREFETCH_MODE__MASK 0x00000300 +#define BUS_CNTL__BUS_PREFETCH_MODE__SHIFT 8 +#define BUS_CNTL__BUS_VGA_PREFETCH_EN 0x00000400 +#define BUS_CNTL__BUS_SGL_READ_DISABLE 0x00000800 +#define BUS_CNTL__BIOS_DIS_ROM 0x00001000 +#define BUS_CNTL__BUS_PCI_READ_RETRY_EN 0x00002000 +#define BUS_CNTL__BUS_AGP_AD_STEPPING_EN 0x00004000 +#define BUS_CNTL__BUS_PCI_WRT_RETRY_EN 0x00008000 +#define BUS_CNTL__BUS_RETRY_WS__MASK 0x000F0000 +#define BUS_CNTL__BUS_RETRY_WS__SHIFT 16 +#define BUS_CNTL__BUS_MSTR_RD_MULT 0x00100000 +#define BUS_CNTL__BUS_MSTR_RD_LINE 0x00200000 +#define BUS_CNTL__BUS_SUSPEND 0x00400000 +#define BUS_CNTL__LAT_16X 0x00800000 +#define BUS_CNTL__BUS_RD_DISCARD_EN 0x01000000 +#define BUS_CNTL__ENFRCWRDY 0x02000000 +#define BUS_CNTL__BUS_MSTR_WS 0x04000000 +#define BUS_CNTL__BUS_PARKING_DIS 0x08000000 +#define BUS_CNTL__BUS_MSTR_DISCONNECT_EN 0x10000000 +#define BUS_CNTL__SERR_EN 0x20000000 +#define BUS_CNTL__BUS_READ_BURST 0x40000000 +#define BUS_CNTL__BUS_RDY_READ_DLY 0x80000000 +#define BUS_CNTL__BUS_PM4_READ_COMBINE_EN 0x00000010 +#define BUS_CNTL__BM_DAC_CRIPPLE 0x00000100 +#define BUS_CNTL__BUS_NON_PM4_READ_COMBINE_EN 0x00000200 +#define BUS_CNTL__BUS_XFERD_DISCARD_EN 0x00000400 +#define MC_STATUS 0x00000150 +#define MC_STATUS__MEM_PWRUP_COMPL_A 0x00000001 +#define MC_STATUS__MEM_PWRUP_COMPL_B 0x00000002 +#define MC_STATUS__MC_IDLE 0x00000004 +#define MC_STATUS__SPARE__MASK 0x0000FFF8 +#define MC_STATUS__SPARE__SHIFT 3 +#define MC_STATUS__IMP_N_VALUE_R_BACK__MASK 0x00000078 +#define MC_STATUS__IMP_N_VALUE_R_BACK__SHIFT 3 +#define MC_STATUS__IMP_P_VALUE_R_BACK__MASK 0x00000780 +#define MC_STATUS__IMP_P_VALUE_R_BACK__SHIFT 7 +#define MC_STATUS__TEST_OUT_R_BACK 0x00000800 +#define MC_STATUS__DUMMY_OUT_R_BACK 0x00001000 +#define MC_STATUS__IMP_N_VALUE_A_R_BACK__MASK 0x0001E000 +#define MC_STATUS__IMP_N_VALUE_A_R_BACK__SHIFT 13 +#define MC_STATUS__IMP_P_VALUE_A_R_BACK__MASK 0x001E0000 +#define MC_STATUS__IMP_P_VALUE_A_R_BACK__SHIFT 17 +#define MC_STATUS__IMP_N_VALUE_CK_R_BACK__MASK 0x01E00000 +#define MC_STATUS__IMP_N_VALUE_CK_R_BACK__SHIFT 21 +#define MC_STATUS__IMP_P_VALUE_CK_R_BACK__MASK 0x1E000000 +#define MC_STATUS__IMP_P_VALUE_CK_R_BACK__SHIFT 25 +#define MC_STATUS__MEM_PWRUP_COMPL_C 0x00000004 +#define MC_STATUS__MEM_PWRUP_COMPL_D 0x00000008 +#define MC_STATUS__MC_IDLE_R3 0x00000010 +#define MC_STATUS__IMP_CAL_COUNT__MASK 0x0000F000 +#define MC_STATUS__IMP_CAL_COUNT__SHIFT 12 +#define OV0_SCALE_CNTL 0x00000420 +#define OV0_SCALE_CNTL__OV0_NO_READ_BEHIND_SCAN 0x00000002 +#define OV0_SCALE_CNTL__OV0_HORZ_PICK_NEAREST 0x00000004 +#define OV0_SCALE_CNTL__OV0_VERT_PICK_NEAREST 0x00000008 +#define OV0_SCALE_CNTL__OV0_SIGNED_UV 0x00000010 +#define OV0_SCALE_CNTL__OV0_GAMMA_SEL__MASK 0x000000E0 +#define OV0_SCALE_CNTL__OV0_GAMMA_SEL__SHIFT 5 +#define OV0_SCALE_CNTL__OV0_SURFACE_FORMAT__MASK 0x00000F00 +#define OV0_SCALE_CNTL__OV0_SURFACE_FORMAT__SHIFT 8 +#define OV0_SURFACE_FORMAT__RESERVED0 0x0 +#define OV0_SURFACE_FORMAT__RESERVED1 0x100 +#define OV0_SURFACE_FORMAT__RESERVED2 0x200 +#define OV0_SURFACE_FORMAT__16BPP_ARGB 0x300 +#define OV0_SURFACE_FORMAT__16BPP_RGB 0x400 +#define OV0_SURFACE_FORMAT__RESERVED5 0x500 +#define OV0_SURFACE_FORMAT__32BPP_ARGB 0x600 +#define OV0_SURFACE_FORMAT__RESERVED7 0x700 +#define OV0_SURFACE_FORMAT__RESERVED8 0x800 +#define OV0_SURFACE_FORMAT__IF09_PLANAR 0x900 +#define OV0_SURFACE_FORMAT__YV12_PLANAR 0xA00 +#define OV0_SURFACE_FORMAT__YUY2_PACKED 0xB00 +#define OV0_SURFACE_FORMAT__UYVY_PACKED 0xC00 +#define OV0_SURFACE_FORMAT__YYUV9_PLANAR 0xD00 +#define OV0_SURFACE_FORMAT__YYUV12_PLANAR 0xE00 +#define OV0_SURFACE_FORMAT__RESERVED15 0xF00 +#define OV0_SCALE_CNTL__OV0_ADAPTIVE_DEINT 0x00001000 +#define OV0_SCALE_CNTL__OV0_CRTC_SEL 0x00004000 +#define OV0_SCALE_CNTL__OV0_BURST_PER_PLANE__MASK 0x007F0000 +#define OV0_SCALE_CNTL__OV0_BURST_PER_PLANE__SHIFT 16 +#define OV0_SCALE_CNTL__OV0_DOUBLE_BUFFER_REGS 0x01000000 +#define OV0_SCALE_CNTL__OV0_BANDWIDTH 0x04000000 +#define OV0_SCALE_CNTL__OV0_LIN_TRANS_BYPASS 0x10000000 +#define OV0_SCALE_CNTL__OV0_INT_EMU 0x20000000 +#define OV0_SCALE_CNTL__OV0_OVERLAY_EN__MASK 0x40000000 +#define OV0_SCALE_CNTL__OV0_OVERLAY_EN__SHIFT 30 +#define OV0_OVERLAY_EN__ENABLE 0x40000000 +#define OV0_SCALE_CNTL__OV0_SOFT_RESET__MASK 0x80000000 +#define OV0_SCALE_CNTL__OV0_SOFT_RESET__SHIFT 31 +#define OV0_SOFT_RESET__RESET 0x80000000 +#define OV0_SCALE_CNTL__OV0_TEMPORAL_DEINT 0x00002000 +#define OV0_SCALE_CNTL__OV0_PULLDOWN_ON_P1_ONLY 0x00008000 +#define OV0_SCALE_CNTL__OV0_FULL_BYPASS 0x00000020 +#define OV0_SCALE_CNTL__OV0_DYNAMIC_EXT 0x00000040 +#define OV0_SCALE_CNTL__OV0_RGB30_ON 0x00000080 +#define CRTC2_GEN_CNTL 0x000003F8 +#define CRTC2_GEN_CNTL__CRTC2_DBL_SCAN_EN 0x00000001 +#define CRTC2_GEN_CNTL__CRTC2_INTERLACE_EN 0x00000002 +#define CRTC2_GEN_CNTL__CRTC2_SYNC_TRISTATE 0x00000010 +#define CRTC2_GEN_CNTL__CRTC2_HSYNC_TRISTATE 0x00000020 +#define CRTC2_GEN_CNTL__CRTC2_VSYNC_TRISTATE 0x00000040 +#define CRTC2_GEN_CNTL__CRT2_ON 0x00000080 +#define CRTC2_GEN_CNTL__CRTC2_PIX_WIDTH__MASK 0x00000F00 +#define CRTC2_GEN_CNTL__CRTC2_PIX_WIDTH__SHIFT 8 +#define CRTC2_GEN_CNTL__CRTC2_ICON_EN 0x00008000 +#define CRTC2_GEN_CNTL__CRTC2_CUR_EN 0x00010000 +#define CRTC2_GEN_CNTL__CRTC2_CUR_MODE__MASK 0x00700000 +#define CRTC2_GEN_CNTL__CRTC2_CUR_MODE__SHIFT 20 +#define CRTC2_GEN_CNTL__CRTC2_DISPLAY_DIS 0x00800000 +#define CRTC2_GEN_CNTL__CRTC2_EN 0x02000000 +#define CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B 0x04000000 +#define CRTC2_GEN_CNTL__CRTC2_C_SYNC_EN 0x08000000 +#define CRTC2_GEN_CNTL__CRTC2_HSYNC_DIS 0x10000000 +#define CRTC2_GEN_CNTL__CRTC2_VSYNC_DIS 0x20000000 +#define CRTC2_GEN_CNTL__CRTC2_MODE9_COLOR_ORDER 0x00001000 +#define CRTC2_GEN_CNTL__CRTC2_FIX_VSYNC_EDGE_POSITION_EN 0x40000000 +#define CRTC2_OFFSET 0x00000324 +#define CRTC2_OFFSET__CRTC2_OFFSET__MASK 0x07FFFFFF +#define CRTC2_OFFSET__CRTC2_OFFSET__SHIFT 0 +#define CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET 0x40000000 +#define CRTC2_OFFSET__CRTC2_OFFSET_LOCK 0x80000000 +#define CRTC2_OFFSET__CRTC2_OFFSET_R3__MASK 0x0FFFFFFF +#define CRTC2_OFFSET__CRTC2_OFFSET_R3__SHIFT 0 +#define CRTC2_OFFSET_CNTL 0x00000328 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE__MASK 0x0000000F +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE__SHIFT 0 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_EN 0x00008000 +#define CRTC2_OFFSET_CNTL__CRTC2_OFFSET_FLIP_CNTL 0x00010000 +#define CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET_LEFT_EN 0x10000000 +#define CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET 0x40000000 +#define CRTC2_OFFSET_CNTL__CRTC2_OFFSET_LOCK 0x80000000 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE_RIGHT__MASK 0x000000F0 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE_RIGHT__SHIFT 4 +#define CRTC2_OFFSET_CNTL__CRTC2_TILE_EN_RIGHT 0x00004000 +#define CRTC2_OFFSET_CNTL__CRTC2_STEREO_OFFSET_EN 0x00020000 +#define CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC_EN__MASK 0x000C0000 +#define CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC_EN__SHIFT 18 +#define CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC 0x00200000 +#define CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET_RIGHT_EN 0x20000000 +#define CRTC2_OFFSET_CNTL__CRTC2_X_Y_MODE_EN_RIGHT 0x00000100 +#define CRTC2_OFFSET_CNTL__CRTC2_X_Y_MODE_EN 0x00000200 +#define CRTC2_OFFSET_CNTL__CRTC2_MICRO_TILE_EN_RIGHT 0x00001000 +#define CRTC2_OFFSET_CNTL__CRTC2_MICRO_TILE_EN 0x00002000 +#define CRTC2_OFFSET_CNTL__CRTC2_MACRO_TILE_EN_RIGHT 0x00004000 +#define CRTC2_OFFSET_CNTL__CRTC2_MACRO_TILE_EN 0x00008000 +#define CUR_OFFSET 0x00000260 +#define CUR_OFFSET__CUR_OFFSET__MASK 0x07FFFFFF +#define CUR_OFFSET__CUR_OFFSET__SHIFT 0 +#define CUR_OFFSET__CUR_LOCK 0x80000000 +#define CUR2_OFFSET 0x00000360 +#define CUR2_OFFSET__CUR2_OFFSET__MASK 0x07FFFFFF +#define CUR2_OFFSET__CUR2_OFFSET__SHIFT 0 +#define CUR2_OFFSET__CUR2_LOCK 0x80000000 +#define HOST_PATH_CNTL 0x00000130 +#define HOST_PATH_CNTL__HDP_APER_CNTL 0x00800000 +#define HOST_PATH_CNTL__HP_LIN_RD_CACHE_DIS 0x01000000 +#define HOST_PATH_CNTL__HP_RBBM_LOCK_DIS 0x02000000 +#define HOST_PATH_CNTL__HDP_SOFT_RESET 0x04000000 +#define HOST_PATH_CNTL__HDP_WRITE_COMBINER_TIMEOUT__MASK 0x70000000 +#define HOST_PATH_CNTL__HDP_WRITE_COMBINER_TIMEOUT__SHIFT 28 +#define HOST_PATH_CNTL__HP_TEST_RST_CNTL 0x80000000 +#define HOST_PATH_CNTL__HDP_WRITE_THROUGH_CACHE_DIS 0x00400000 +#define HOST_PATH_CNTL__HDP_READ_BUFFER_INVALIDATE 0x08000000 +#define DST_PITCH_OFFSET 0x0000142C +#define DST_PITCH_OFFSET__DST_OFFSET__MASK 0x003FFFFF +#define DST_PITCH_OFFSET__DST_OFFSET__SHIFT 0 +#define DST_PITCH_OFFSET__DST_PITCH__MASK 0x3FC00000 +#define DST_PITCH_OFFSET__DST_PITCH__SHIFT 22 +#define DST_PITCH_OFFSET__DST_TILE__MASK 0xC0000000 +#define DST_PITCH_OFFSET__DST_TILE__SHIFT 30 +#define DST_TILE__MACRO 0x1 +#define DST_TILE__MICRO 0x2 +#define SRC_PITCH_OFFSET 0x00001428 +#define SRC_PITCH_OFFSET__SRC_OFFSET__MASK 0x003FFFFF +#define SRC_PITCH_OFFSET__SRC_OFFSET__SHIFT 0 +#define SRC_PITCH_OFFSET__SRC_PITCH__MASK 0x3FC00000 +#define SRC_PITCH_OFFSET__SRC_PITCH__SHIFT 22 +#define SRC_PITCH_OFFSET__SRC_TILE 0x40000000 +#define DEFAULT_SC_BOTTOM_RIGHT 0x000016E8 +#define DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__MASK 0x00003FFF +#define DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__SHIFT 0 +#define DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__MASK 0x3FFF0000 +#define DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__SHIFT 16 +#define DEFAULT2_SC_BOTTOM_RIGHT 0x000016DC +#define DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__MASK 0x00003FFF +#define DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__SHIFT 0 +#define DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__MASK 0x3FFF0000 +#define DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__SHIFT 16 +#define DP_DATATYPE 0x000016C4 +#define DP_DATATYPE__DP_DST_DATATYPE__MASK 0x0000000F +#define DP_DATATYPE__DP_DST_DATATYPE__SHIFT 0 +#define DP_DATATYPE__DP_BRUSH_DATATYPE__MASK 0x00000F00 +#define DP_DATATYPE__DP_BRUSH_DATATYPE__SHIFT 8 +#define DP_DATATYPE__DP_SRC_DATATYPE__MASK 0x00070000 +#define DP_DATATYPE__DP_SRC_DATATYPE__SHIFT 16 +#define DP_DATATYPE__DP_BYTE_PIX_ORDER 0x40000000 +#define DP_GUI_MASTER_CNTL 0x0000146C +#define DP_GUI_MASTER_CNTL__GMC_SRC_PITCH_OFFSET_CNTL 0x00000001 +#define DP_GUI_MASTER_CNTL__GMC_DST_PITCH_OFFSET_CNTL 0x00000002 +#define DP_GUI_MASTER_CNTL__GMC_SRC_CLIPPING 0x00000004 +#define DP_GUI_MASTER_CNTL__GMC_DST_CLIPPING 0x00000008 +#define DP_GUI_MASTER_CNTL__GMC_BRUSH_DATATYPE__MASK 0x000000F0 +#define DP_GUI_MASTER_CNTL__GMC_BRUSH_DATATYPE__SHIFT 4 +#define GMC_BRUSH_DATATYPE__8X8_MONO_FG_BG 0x0 +#define GMC_BRUSH_DATATYPE__8X8_MONO_FG 0x1 +#define GMC_BRUSH_DATATYPE__32X1_MONO_LINE_FG_BG 0x6 +#define GMC_BRUSH_DATATYPE__32X1_MONO_LINE_FG 0x7 +#define GMC_BRUSH_DATATYPE__8X8_COLOR 0xA +#define GMC_BRUSH_DATATYPE__SOLID_COLOR_FG 0xD +#define GMC_BRUSH_DATATYPE__SOLID_COLOR_RESERVED 0xF +#define GMC_BRUSH_DATATYPE__SOLID 0xD0 +#define GMC_BRUSH_DATATYPE__MONO8x8 0x0 +#define GMC_BRUSH_DATATYPE__COLOR8x8 0xA0 +#define DP_GUI_MASTER_CNTL__GMC_DST_DATATYPE__MASK 0x00000F00 +#define DP_GUI_MASTER_CNTL__GMC_DST_DATATYPE__SHIFT 8 +#define GMC_DST_DATATYPE__8BPP_CLUT 0x2 +#define GMC_DST_DATATYPE__16BPP_1555 0x3 +#define GMC_DST_DATATYPE__16BPP_565 0x4 +#define GMC_DST_DATATYPE__32BPP_8888 0x6 +#define GMC_DST_DATATYPE__CI8 0x200 +#define GMC_DST_DATATYPE__RGB16_1555 0x300 +#define GMC_DST_DATATYPE__RGB16_565 0x400 +#define GMC_DST_DATATYPE__RGB32 0x600 +#define DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE__MASK 0x00003000 +#define DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE__SHIFT 12 +#define GMC_SRC_DATATYPE__BUILD(x) 0x0 +#define GMC_SRC_DATATYPE__MONO_OPAQUE 0x0 +#define GMC_SRC_DATATYPE__MONO_TRANSPARENT 0x0 +#define GMC_SRC_DATATYPE__SAME_AS_DST 0x0 +#define GMC_SRC_DATATYPE__8BPP_CLUT_XLAT 0x0 +#define GMC_SRC_DATATYPE__32BPP_CLUT_XLAT 0x0 +#define GMC_SRC_DATATYPE__MONO_FG_BG 0x0 +#define GMC_SRC_DATATYPE__MONO_FG 0x1000 +#define GMC_SRC_DATATYPE__COLOR 0x3000 +#define GMC_SRC_DATATYPE__DST 0x3000 +#define DP_GUI_MASTER_CNTL__GMC_BYTE_PIX_ORDER 0x00004000 +#define DP_GUI_MASTER_CNTL__GMC_DEFAULT_SEL 0x00008000 +#define DP_GUI_MASTER_CNTL__GMC_ROP3__MASK 0x00FF0000 +#define DP_GUI_MASTER_CNTL__GMC_ROP3__SHIFT 16 +#define GMC_ROP3__SRCCPY 0xCC +#define GMC_ROP3__WHITENESS 0xFF +#define GMC_ROP3__BLACKNESS 0x0 +#define DP_GUI_MASTER_CNTL__GMC_DP_SRC_SOURCE__MASK 0x07000000 +#define DP_GUI_MASTER_CNTL__GMC_DP_SRC_SOURCE__SHIFT 24 +#define GMC_DP_SRC_SOURCE__VIDEO_MEM 0x2 +#define GMC_DP_SRC_SOURCE__HOSTDATA 0x3 +#define GMC_DP_SRC_SOURCE__HOSTDATA_BYTE 0x4 +#define DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE2 0x08000000 +#define DP_GUI_MASTER_CNTL__GMC_CLR_CMP_FCN_DIS 0x10000000 +#define DP_GUI_MASTER_CNTL__GMC_WR_MSK_DIS 0x40000000 +#define DP_BRUSH_FRGD_CLR 0x0000147C +#define DP_BRUSH_FRGD_CLR__DP_BRUSH_FRGD_CLR__MASK 0xFFFFFFFF +#define DP_BRUSH_FRGD_CLR__DP_BRUSH_FRGD_CLR__SHIFT 0 +#define DP_BRUSH_BKGD_CLR 0x00001478 +#define DP_BRUSH_BKGD_CLR__DP_BRUSH_BKGD_CLR__MASK 0xFFFFFFFF +#define DP_BRUSH_BKGD_CLR__DP_BRUSH_BKGD_CLR__SHIFT 0 +#define DP_SRC_FRGD_CLR 0x000015D8 +#define DP_SRC_FRGD_CLR__DP_SRC_FRGD_CLR__MASK 0xFFFFFFFF +#define DP_SRC_FRGD_CLR__DP_SRC_FRGD_CLR__SHIFT 0 +#define DP_SRC_BKGD_CLR 0x000015DC +#define DP_SRC_BKGD_CLR__DP_SRC_BKGD_CLR__MASK 0xFFFFFFFF +#define DP_SRC_BKGD_CLR__DP_SRC_BKGD_CLR__SHIFT 0 +#define DP_WRITE_MSK 0x000016CC +#define DP_WRITE_MSK__DP_WRITE_MSK__MASK 0xFFFFFFFF +#define DP_WRITE_MSK__DP_WRITE_MSK__SHIFT 0 + +#endif diff --git a/shared-core/radeon_ms_state.c b/shared-core/radeon_ms_state.c new file mode 100644 index 00000000..17f8b764 --- /dev/null +++ b/shared-core/radeon_ms_state.c @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +void radeon_ms_state_restore(struct drm_device *dev, struct radeon_state *state) +{ + radeon_ms_irq_restore(dev, state); + radeon_ms_gpu_restore(dev, state); + radeon_ms_cp_restore(dev, state); + radeon_ms_crtc1_restore(dev, state); +} + +void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state) +{ + radeon_ms_crtc1_save(dev, state); + radeon_ms_cp_save(dev, state); + radeon_ms_gpu_save(dev, state); + radeon_ms_irq_save(dev, state); +} -- cgit v1.2.3 From f7432d187e4b5e13c9e450bf12d5ab8c18ea5146 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 4 Dec 2007 14:38:00 -0800 Subject: Don't free driver mapped locks This fix is actually a bit of a cleanup too--it moves lock freeing to drm_rmmap_locked and out of drm_lastclose. This makes it symmetrical with addmap and also prevents the lock from being incorrectly freed from driver mappings. --- linux-core/drm_bufs.c | 2 ++ linux-core/drm_drv.c | 5 ----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index bfd3dd3d..967e9a2d 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -413,6 +413,8 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) case _DRM_SHM: vfree(map->handle); dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ + dev->lock.file_priv = NULL; + wake_up_interruptible(&dev->lock.lock_queue); break; case _DRM_AGP: case _DRM_SCATTER_GATHER: diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 6a3e7041..a88ae8b5 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -276,11 +276,6 @@ int drm_lastclose(struct drm_device * dev) if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) drm_dma_takedown(dev); - if (dev->lock.hw_lock) { - dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ - dev->lock.file_priv = NULL; - wake_up_interruptible(&dev->lock.lock_queue); - } dev->dev_mapping = NULL; mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 1a6c95ef711fce807659ab5e4fe480d65ac233b6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Dec 2007 16:03:05 +1000 Subject: arrgggh.. make all ioctl structs 32/64-bit compatible hopefully. This also starts to add blob property support. someone needs to check this work for other things like ppc/x86 alignment diffs --- libdrm/xf86drmMode.c | 75 ++++++++++++----------- libdrm/xf86drmMode.h | 6 +- linux-core/drm_crtc.c | 163 ++++++++++++++++++++++++++++++++++++------------- linux-core/drm_crtc.h | 23 +++++-- linux-core/intel_crt.c | 2 + shared-core/drm.h | 48 +++++++-------- tests/mode/modetest.c | 21 ++++--- 7 files changed, 222 insertions(+), 116 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index bb7be13c..e5191d8c 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -42,6 +42,9 @@ #include #include +#define U642VOID(x) ((void *)(unsigned long)(x)) +#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) + /* * Util functions */ @@ -149,11 +152,11 @@ drmModeResPtr drmModeGetResources(int fd) return 0; if (res.count_fbs) - res.fb_id = drmMalloc(res.count_fbs*sizeof(uint32_t)); + res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t))); if (res.count_crtcs) - res.crtc_id = drmMalloc(res.count_crtcs*sizeof(uint32_t)); + res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t))); if (res.count_outputs) - res.output_id = drmMalloc(res.count_outputs*sizeof(uint32_t)); + res.output_id_ptr = VOID2U64(drmMalloc(res.count_outputs*sizeof(uint32_t))); if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { r = NULL; @@ -168,18 +171,22 @@ drmModeResPtr drmModeGetResources(int fd) if (!(r = drmMalloc(sizeof(*r)))) return 0; + r->min_width = res.min_width; + r->max_width = res.max_width; + r->min_height = res.min_height; + r->max_height = res.max_height; r->count_fbs = res.count_fbs; r->count_crtcs = res.count_crtcs; r->count_outputs = res.count_outputs; /* TODO we realy should test if these allocs fails. */ - r->fbs = drmAllocCpy(res.fb_id, res.count_fbs, sizeof(uint32_t)); - r->crtcs = drmAllocCpy(res.crtc_id, res.count_crtcs, sizeof(uint32_t)); - r->outputs = drmAllocCpy(res.output_id, res.count_outputs, sizeof(uint32_t)); + r->fbs = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t)); + r->crtcs = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t)); + r->outputs = drmAllocCpy(U642VOID(res.output_id_ptr), res.count_outputs, sizeof(uint32_t)); err_allocs: - drmFree(res.fb_id); - drmFree(res.crtc_id); - drmFree(res.output_id); + drmFree(U642VOID(res.fb_id_ptr)); + drmFree(U642VOID(res.crtc_id_ptr)); + drmFree(U642VOID(res.output_id_ptr)); return r; } @@ -297,7 +304,7 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, crtc.y = y; crtc.crtc_id = crtcId; crtc.fb_id = bufferId; - crtc.set_outputs = outputs; + crtc.set_outputs_ptr = VOID2U64(outputs); crtc.count_outputs = count; if (mode) { memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo)); @@ -324,21 +331,21 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) out.count_clones = 0; out.clones = 0; out.count_modes = 0; - out.modes = 0; + out.modes_ptr = 0; out.count_props = 0; - out.props = NULL; - out.prop_values = NULL; + out.props_ptr = 0; + out.prop_values_ptr = 0; if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) return 0; if (out.count_props) { - out.props = drmMalloc(out.count_props*sizeof(uint32_t)); - out.prop_values = drmMalloc(out.count_props*sizeof(uint32_t)); + out.props_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint32_t))); + out.prop_values_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint64_t))); } if (out.count_modes) - out.modes = drmMalloc(out.count_modes*sizeof(struct drm_mode_modeinfo)); + out.modes_ptr = VOID2U64(drmMalloc(out.count_modes*sizeof(struct drm_mode_modeinfo))); if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) goto err_allocs; @@ -360,16 +367,16 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) r->crtcs = out.crtcs; r->clones = out.clones; r->count_props = out.count_props; - r->props = drmAllocCpy(out.props, out.count_props, sizeof(uint32_t)); - r->prop_values = drmAllocCpy(out.prop_values, out.count_props, sizeof(uint32_t)); - r->modes = drmAllocCpy(out.modes, out.count_modes, sizeof(struct drm_mode_modeinfo)); + r->props = drmAllocCpy(U642VOID(out.props_ptr), out.count_props, sizeof(uint32_t)); + r->prop_values = drmAllocCpy(U642VOID(out.prop_values_ptr), out.count_props, sizeof(uint64_t)); + r->modes = drmAllocCpy(U642VOID(out.modes_ptr), out.count_modes, sizeof(struct drm_mode_modeinfo)); strncpy(r->name, out.name, DRM_OUTPUT_NAME_LEN); r->name[DRM_OUTPUT_NAME_LEN-1] = 0; err_allocs: - drmFree(out.prop_values); - drmFree(out.props); - drmFree(out.modes); + drmFree(U642VOID(out.prop_values_ptr)); + drmFree(U642VOID(out.props_ptr)); + drmFree(U642VOID(out.modes_ptr)); return r; } @@ -401,20 +408,20 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) drmModePropertyPtr r; prop.prop_id = property_id; - prop.count_enums = 0; + prop.count_enum_blobs = 0; prop.count_values = 0; prop.flags = 0; - prop.enums = NULL; - prop.values = NULL; + prop.enum_blob_ptr = 0; + prop.values_ptr = 0; if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) return 0; if (prop.count_values) - prop.values = drmMalloc(prop.count_values * sizeof(uint32_t)); + prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t))); - if (prop.count_enums) - prop.enums = drmMalloc(prop.count_enums * sizeof(struct drm_mode_property_enum)); + if (prop.count_enum_blobs) + prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum))); if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) { r = NULL; @@ -426,16 +433,16 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) r->prop_id = prop.prop_id; r->count_values = prop.count_values; - r->count_enums = prop.count_enums; - - r->values = drmAllocCpy(prop.values, prop.count_values, sizeof(uint32_t)); - r->enums = drmAllocCpy(prop.enums, prop.count_enums, sizeof(struct drm_mode_property_enum)); + r->count_enums = prop.count_enum_blobs; + r->flags = prop.flags; + r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t)); + r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); strncpy(r->name, prop.name, DRM_PROP_NAME_LEN); r->name[DRM_PROP_NAME_LEN-1] = 0; err_allocs: - drmFree(prop.values); - drmFree(prop.enums); + drmFree(U642VOID(prop.values_ptr)); + drmFree(U642VOID(prop.enum_blob_ptr)); return r; } diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index a1d717f9..ec77174b 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -63,6 +63,8 @@ typedef struct _drmModeRes { int count_outputs; uint32_t *outputs; + uint32_t min_width, max_width; + uint32_t min_height, max_height; } drmModeRes, *drmModeResPtr; typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr; @@ -72,7 +74,7 @@ typedef struct _drmModeProperty { unsigned int flags; unsigned char name[DRM_PROP_NAME_LEN]; int count_values; - uint32_t *values; + uint64_t *values; int count_enums; struct drm_mode_property_enum *enums; @@ -132,7 +134,7 @@ typedef struct _drmModeOutput { int count_props; uint32_t *props; /**< List of property ids */ - uint32_t *prop_values; /**< List of property values */ + uint64_t *prop_values; /**< List of property values */ } drmModeOutput, *drmModeOutputPtr; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 26aa5206..c2680319 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -722,7 +722,11 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); INIT_LIST_HEAD(&dev->mode_config.property_list); + INIT_LIST_HEAD(&dev->mode_config.property_blob_list); idr_init(&dev->mode_config.crtc_idr); + dev->mode_config.edid_property = drm_property_create(dev, + DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, + "EDID", 0); } EXPORT_SYMBOL(drm_mode_config_init); @@ -1013,7 +1017,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) changed = true; - if (new_mode && (crtc->mode.mode_id != new_mode->mode_id)) + if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) changed = true; list_for_each_entry(output, &dev->mode_config.output_list, head) { @@ -1152,6 +1156,9 @@ int drm_mode_getresources(struct drm_device *dev, int crtc_count = 0; int fb_count = 0; int copied = 0; + uint32_t __user *fb_id; + uint32_t __user *crtc_id; + uint32_t __user *output_id; mutex_lock(&dev->mode_config.mutex); @@ -1164,12 +1171,18 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each(lh, &dev->mode_config.output_list) output_count++; + card_res->max_height = dev->mode_config.max_height; + card_res->min_height = dev->mode_config.min_height; + card_res->max_width = dev->mode_config.max_width; + card_res->min_width = dev->mode_config.min_width; + /* handle this in 4 parts */ /* FBs */ if (card_res->count_fbs >= fb_count) { copied = 0; + fb_id = (uint32_t *)(unsigned long)card_res->fb_id_ptr; list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - if (put_user(fb->id, card_res->fb_id + copied)) { + if (put_user(fb->id, fb_id + copied)) { ret = -EFAULT; goto out; } @@ -1181,9 +1194,10 @@ int drm_mode_getresources(struct drm_device *dev, /* CRTCs */ if (card_res->count_crtcs >= crtc_count) { copied = 0; + crtc_id = (uint32_t *)(unsigned long)card_res->crtc_id_ptr; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ DRM_DEBUG("CRTC ID is %d\n", crtc->id); - if (put_user(crtc->id, card_res->crtc_id + copied)) { + if (put_user(crtc->id, crtc_id + copied)) { ret = -EFAULT; goto out; } @@ -1196,10 +1210,11 @@ int drm_mode_getresources(struct drm_device *dev, /* Outputs */ if (card_res->count_outputs >= output_count) { copied = 0; + output_id = (uint32_t *)(unsigned long)card_res->output_id_ptr; list_for_each_entry(output, &dev->mode_config.output_list, head) { DRM_DEBUG("OUTPUT ID is %d\n", output->id); - if (put_user(output->id, card_res->output_id + copied)) { + if (put_user(output->id, output_id + copied)) { ret = -EFAULT; goto out; } @@ -1211,7 +1226,6 @@ int drm_mode_getresources(struct drm_device *dev, DRM_DEBUG("Counted %d %d\n", card_res->count_crtcs, card_res->count_outputs); - out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1307,6 +1321,9 @@ int drm_mode_getoutput(struct drm_device *dev, int copied = 0; int i; struct drm_mode_modeinfo u_mode; + struct drm_mode_modeinfo __user *mode_ptr; + uint32_t __user *prop_ptr; + uint64_t __user *prop_values; memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); @@ -1349,9 +1366,10 @@ int drm_mode_getoutput(struct drm_device *dev, if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; + mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr; list_for_each_entry(mode, &output->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); - if (copy_to_user(out_resp->modes + copied, + if (copy_to_user(mode_ptr + copied, &u_mode, sizeof(u_mode))) { ret = -EFAULT; goto out; @@ -1364,14 +1382,16 @@ int drm_mode_getoutput(struct drm_device *dev, if ((out_resp->count_props >= props_count) && props_count) { copied = 0; + prop_ptr = (uint32_t *)(unsigned long)(out_resp->props_ptr); + prop_values = (uint64_t *)(unsigned long)(out_resp->prop_values_ptr); for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { if (output->property_ids[i] != 0) { - if (put_user(output->property_ids[i], out_resp->props + copied)) { + if (put_user(output->property_ids[i], prop_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(output->property_values[i], out_resp->prop_values + copied)) { + if (put_user(output->property_values[i], prop_values + copied)) { ret = -EFAULT; goto out; } @@ -1410,10 +1430,10 @@ int drm_mode_setcrtc(struct drm_device *dev, struct drm_crtc *crtc; struct drm_output **output_set = NULL, *output; struct drm_framebuffer *fb = NULL; - struct drm_display_mode mode; - int mode_valid = 0; + struct drm_display_mode *mode = NULL; int ret = 0; int i; + uint32_t __user *set_outputs_ptr; mutex_lock(&dev->mode_config.mutex); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req->crtc_id); @@ -1434,18 +1454,17 @@ int drm_mode_setcrtc(struct drm_device *dev, } } - mode_valid = 1; - drm_crtc_convert_umode(&mode, &crtc_req->mode); - } else - mode_valid = 0; + mode = drm_mode_create(dev); + drm_crtc_convert_umode(mode, &crtc_req->mode); + } - if (crtc_req->count_outputs == 0 && mode_valid) { + if (crtc_req->count_outputs == 0 && mode) { DRM_DEBUG("Count outputs is 0 but mode set\n"); ret = -EINVAL; goto out; } - if (crtc_req->count_outputs > 0 && !mode_valid && !fb) { + if (crtc_req->count_outputs > 0 && !mode && !fb) { DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req->count_outputs); ret = -EINVAL; goto out; @@ -1461,7 +1480,8 @@ int drm_mode_setcrtc(struct drm_device *dev, } for (i = 0; i < crtc_req->count_outputs; i++) { - if (get_user(out_id, &crtc_req->set_outputs[i])) { + set_outputs_ptr = (uint32_t *)(unsigned long)crtc_req->set_outputs_ptr; + if (get_user(out_id, &set_outputs_ptr[i])) { ret = -EFAULT; goto out; } @@ -1477,11 +1497,7 @@ int drm_mode_setcrtc(struct drm_device *dev, } } - if (mode_valid) { - ret = drm_crtc_set_config(crtc, crtc_req, &mode, output_set, fb); - } else { - ret = drm_crtc_set_config(crtc, crtc_req, NULL, output_set, fb); - } + ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb); out: mutex_unlock(&dev->mode_config.mutex); @@ -1847,15 +1863,17 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, property = kzalloc(sizeof(struct drm_output), GFP_KERNEL); if (!property) return NULL; - - property->values = kzalloc(sizeof(uint32_t)*num_values, GFP_KERNEL); - if (!property->values) - goto fail; + + if (num_values) { + property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL); + if (!property->values) + goto fail; + } property->id = drm_idr_get(dev, property); property->flags = flags; property->num_values = num_values; - INIT_LIST_HEAD(&property->enum_list); + INIT_LIST_HEAD(&property->enum_blob_list); if (name) strncpy(property->name, name, DRM_PROP_NAME_LEN); @@ -1869,15 +1887,15 @@ fail: EXPORT_SYMBOL(drm_property_create); int drm_property_add_enum(struct drm_property *property, int index, - uint32_t value, const char *name) + uint64_t value, const char *name) { struct drm_property_enum *prop_enum; if (!(property->flags & DRM_MODE_PROP_ENUM)) return -EINVAL; - if (!list_empty(&property->enum_list)) { - list_for_each_entry(prop_enum, &property->enum_list, head) { + if (!list_empty(&property->enum_blob_list)) { + list_for_each_entry(prop_enum, &property->enum_blob_list, head) { if (prop_enum->value == value) { strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; @@ -1895,7 +1913,7 @@ int drm_property_add_enum(struct drm_property *property, int index, prop_enum->value = value; property->values[index] = value; - list_add_tail(&prop_enum->head, &property->enum_list); + list_add_tail(&prop_enum->head, &property->enum_blob_list); return 0; } EXPORT_SYMBOL(drm_property_add_enum); @@ -1904,12 +1922,13 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) { struct drm_property_enum *prop_enum, *pt; - list_for_each_entry_safe(prop_enum, pt, &property->enum_list, head) { + list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) { list_del(&prop_enum->head); kfree(prop_enum); } - kfree(property->values); + if (property->num_values) + kfree(property->values); drm_idr_put(dev, property->id); list_del(&property->head); kfree(property); @@ -1918,7 +1937,7 @@ EXPORT_SYMBOL(drm_property_destroy); int drm_output_attach_property(struct drm_output *output, - struct drm_property *property, int init_val) + struct drm_property *property, uint64_t init_val) { int i; @@ -1942,10 +1961,14 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, struct drm_mode_get_property *out_resp = data; struct drm_property *property; int enum_count = 0; + int blob_count = 0; int value_count = 0; int ret = 0, i; int copied; struct drm_property_enum *prop_enum; + struct drm_property_enum __user *enum_ptr; + struct drm_property_blob *prop_blob; + uint64_t __user *values_ptr; mutex_lock(&dev->mode_config.mutex); property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); @@ -1954,9 +1977,13 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, goto done; } - - list_for_each_entry(prop_enum, &property->enum_list, head) - enum_count++; + if (property->flags & DRM_MODE_PROP_ENUM) { + list_for_each_entry(prop_enum, &property->enum_blob_list, head) + enum_count++; + } else if (property->flags & DRM_MODE_PROP_BLOB) { + list_for_each_entry(prop_blob, &property->enum_blob_list, head) + blob_count++; + } value_count = property->num_values; @@ -1965,8 +1992,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, out_resp->flags = property->flags; if ((out_resp->count_values >= value_count) && value_count) { + values_ptr = (uint64_t *)(unsigned long)out_resp->values_ptr; for (i = 0; i < value_count; i++) { - if (put_user(property->values[i], out_resp->values + i)) { + if (put_user(property->values[i], values_ptr + i)) { ret = -EFAULT; goto done; } @@ -1974,10 +2002,30 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } out_resp->count_values = value_count; - if ((out_resp->count_enums >= enum_count) && enum_count) { + if ((out_resp->count_enum_blobs >= enum_count) && enum_count && (property->flags & DRM_MODE_PROP_ENUM)) { + copied = 0; + enum_ptr = (struct drm_property_enum *)(unsigned long)out_resp->enum_blob_ptr; + list_for_each_entry(prop_enum, &property->enum_blob_list, head) { + if (put_user(prop_enum->value, &enum_ptr[copied].value)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user(&enum_ptr[copied].name, + prop_enum->name, DRM_PROP_NAME_LEN)) { + ret = -EFAULT; + goto done; + } + copied++; + } + } + out_resp->count_enum_blobs = enum_count; + +#if 0 + if ((out_resp->count_blobs >= enum_count) && blob_count && (property->flags & DRM_MODE_PROP_BLOB)) { copied = 0; - list_for_each_entry(prop_enum, &property->enum_list, head) { - if (put_user(prop_enum->value, &out_resp->enums[copied].value)) { + list_for_each_entry(prop_blob, &property->enum_list, head) { + if (put_user(prop_enum->value, &out_resp->blobs[copied].value)) { ret = -EFAULT; goto done; } @@ -1991,8 +2039,39 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } } out_resp->count_enums = enum_count; - +#endif done: mutex_unlock(&dev->mode_config.mutex); return ret; } + +static int drm_property_create_blob(struct drm_device *dev, int length, + void *data) +{ + struct drm_property_blob *blob; + + if (!length || !data) + return -EINVAL; + + blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); + if (!blob) + return -EINVAL; + + blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob)); + blob->length = length; + + memcpy(blob->data, data, length); + + blob->id = drm_idr_get(dev, blob); + + list_add_tail(&blob->head, &dev->mode_config.property_blob_list); + return blob->id; +} + +static void drm_property_destroy_blob(struct drm_device *dev, + struct drm_property_blob *blob) +{ + drm_idr_put(dev, blob->id); + list_del(&blob->head); + kfree(blob); +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 90d6104f..d028f75f 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -234,9 +234,16 @@ struct drm_framebuffer { struct list_head filp_head; }; +struct drm_property_blob { + struct list_head head; + unsigned int id; + unsigned int length; + void *data; +}; + struct drm_property_enum { struct list_head head; - uint32_t value; + uint64_t value; unsigned char name[DRM_PROP_NAME_LEN]; }; @@ -246,9 +253,9 @@ struct drm_property { uint32_t flags; char name[DRM_PROP_NAME_LEN]; uint32_t num_values; - uint32_t *values; + uint64_t *values; - struct list_head enum_list; + struct list_head enum_blob_list; }; struct drm_crtc; @@ -451,7 +458,7 @@ struct drm_output { struct list_head user_modes; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; - u32 property_values[DRM_OUTPUT_MAX_PROPERTY]; + uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; }; /** @@ -492,6 +499,10 @@ struct drm_mode_config { /* DGA stuff? */ struct drm_mode_config_funcs *funcs; unsigned long fb_base; + + /* pointers to standard properties */ + struct list_head property_blob_list; + struct drm_property *edid_property; }; struct drm_output *drm_output_create(struct drm_device *dev, @@ -549,12 +560,12 @@ extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo int x, int y); extern int drm_output_attach_property(struct drm_output *output, - struct drm_property *property, int init_val); + struct drm_property *property, uint64_t init_val); extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values); extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, - uint32_t value, const char *name); + uint64_t value, const char *name); /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 29c2e611..d3ad4654 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -245,4 +245,6 @@ void intel_crt_init(struct drm_device *dev) output->driver_private = intel_output; output->interlace_allowed = 0; output->doublescan_allowed = 0; + + drm_output_attach_property(output, dev->mode_config.edid_property, 0); } diff --git a/shared-core/drm.h b/shared-core/drm.h index f4f75cf5..6317f142 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -920,18 +920,19 @@ struct drm_mode_modeinfo { }; struct drm_mode_card_res { - + uint64_t fb_id_ptr; + uint64_t crtc_id_ptr; + uint64_t output_id_ptr; int count_fbs; - unsigned int __user *fb_id; - int count_crtcs; - unsigned int __user *crtc_id; - int count_outputs; - unsigned int __user *output_id; + int min_width, max_width; + int min_height, max_height; }; struct drm_mode_crtc { + uint64_t set_outputs_ptr; + unsigned int crtc_id; /**< Id */ unsigned int fb_id; /**< Id of framebuffer */ @@ -942,9 +943,6 @@ struct drm_mode_crtc { int count_possibles; unsigned int possibles; /**< Outputs that can be connected */ - - unsigned int __user *set_outputs; /**< Outputs to be connected */ - int gamma_size; int mode_valid; struct drm_mode_modeinfo mode; @@ -952,6 +950,12 @@ struct drm_mode_crtc { struct drm_mode_get_output { + uint64_t modes_ptr; + uint64_t props_ptr; + uint64_t prop_values_ptr; + + int count_modes; + int count_props; unsigned int output; /**< Id */ unsigned int crtc; /**< Id of crtc */ unsigned char name[DRM_OUTPUT_NAME_LEN]; @@ -959,42 +963,37 @@ struct drm_mode_get_output { unsigned int connection; unsigned int mm_width, mm_height; /**< HxW in millimeters */ unsigned int subpixel; - int count_crtcs; - unsigned int crtcs; /**< possible crtc to connect to */ - int count_clones; + unsigned int crtcs; /**< possible crtc to connect to */ unsigned int clones; /**< list of clones */ - - int count_modes; - struct drm_mode_modeinfo *modes; - - int count_props; - unsigned int __user *props; - unsigned int __user *prop_values; }; #define DRM_MODE_PROP_PENDING (1<<0) #define DRM_MODE_PROP_RANGE (1<<1) #define DRM_MODE_PROP_IMMUTABLE (1<<2) #define DRM_MODE_PROP_ENUM (1<<3) // enumerated type with text strings +#define DRM_MODE_PROP_BLOB (1<<4) struct drm_mode_property_enum { - uint32_t value; + uint64_t value; unsigned char name[DRM_PROP_NAME_LEN]; }; + +struct drm_mode_property_blob { + uint32_t length; +}; struct drm_mode_get_property { + uint64_t values_ptr; + uint64_t enum_blob_ptr; unsigned int prop_id; unsigned int flags; unsigned char name[DRM_PROP_NAME_LEN]; int count_values; - uint32_t __user *values; - - int count_enums; - struct drm_mode_property_enum *enums; + int count_enum_blobs; }; struct drm_mode_fb_cmd { @@ -1111,6 +1110,7 @@ struct drm_mode_mode_cmd { #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_propblob) #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 1d5002b0..46f88d82 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -76,16 +76,21 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) printf("\n\tenums %d: \n", props->count_enums); - for (j = 0; j < props->count_enums; j++) { - if (output->prop_values[i] == props->enums[j].value) - name = props->enums[j].name; - printf("\t\t%d = %s\n", props->enums[j].value, props->enums[j].name); - } + if (prop->flags & DRM_MODE_PROP_BLOB) { + - if (props->count_enums && name) { - printf("\toutput property name %s %s\n", props->name, name); } else { - printf("\toutput property id %s %i\n", props->name, output->prop_values[i]); + for (j = 0; j < props->count_enums; j++) { + if (output->prop_values[i] == props->enums[j].value) + name = props->enums[j].name; + printf("\t\t%d = %s\n", props->enums[j].value, props->enums[j].name); + } + + if (props->count_enums && name) { + printf("\toutput property name %s %s\n", props->name, name); + } else { + printf("\toutput property id %s %i\n", props->name, output->prop_values[i]); + } } drmModeFreeProperty(props); -- cgit v1.2.3 From c9cda51af5a8bea1d30ce575ae260de52950fe2f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Dec 2007 16:31:35 +1000 Subject: more WIP on blobs.. I'm going to pass back a list of blob ids and lengths in the getproperty. will need another ioctl to return the blob data as it is variable length. --- libdrm/xf86drmMode.c | 24 ++++++++++++++---- libdrm/xf86drmMode.h | 11 +++++++-- linux-core/drm_crtc.c | 67 ++++++++++++++++++++++++++++----------------------- shared-core/drm.h | 5 ++-- 4 files changed, 68 insertions(+), 39 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index e5191d8c..f4ec004c 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -406,7 +406,8 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) { struct drm_mode_get_property prop; drmModePropertyPtr r; - + struct drm_mode_property_blob *blob_tmp; + int i; prop.prop_id = property_id; prop.count_enum_blobs = 0; prop.count_values = 0; @@ -420,9 +421,14 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) if (prop.count_values) prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t))); - if (prop.count_enum_blobs) + if (prop.count_enum_blobs & (prop.flags & DRM_MODE_PROP_ENUM)) prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum))); + if (prop.count_enum_blobs & (prop.flags & DRM_MODE_PROP_BLOB)) { + prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); + prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); + } + if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) { r = NULL; goto err_allocs; @@ -433,10 +439,18 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) r->prop_id = prop.prop_id; r->count_values = prop.count_values; - r->count_enums = prop.count_enum_blobs; + r->flags = prop.flags; - r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t)); - r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); + if (prop.count_values) + r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t)); + if (prop.flags & DRM_MODE_PROP_ENUM) { + r->count_enums = prop.count_enum_blobs; + r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); + } else if (prop.flags & DRM_MODE_PROP_ENUM) { + r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t)); + r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t)); + r->count_blobs = prop.count_enum_blobs; + } strncpy(r->name, prop.name, DRM_PROP_NAME_LEN); r->name[DRM_PROP_NAME_LEN-1] = 0; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index ec77174b..e936044b 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -69,15 +69,22 @@ typedef struct _drmModeRes { typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr; +typedef struct _drmModePropertyBlob { + uint32_t id; + uint32_t length; + void *data; +} drmModePropertyBlobRes, *drmModePropertyBlobPtr; + typedef struct _drmModeProperty { unsigned int prop_id; unsigned int flags; unsigned char name[DRM_PROP_NAME_LEN]; int count_values; - uint64_t *values; + uint64_t *values; // store the blob lengths int count_enums; struct drm_mode_property_enum *enums; - + int count_blobs; + uint32_t *blob_ids; // store the blob IDs } drmModePropertyRes, *drmModePropertyPtr; typedef struct _drmModeCrtc { diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c2680319..a3aa783b 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1968,7 +1968,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, struct drm_property_enum *prop_enum; struct drm_property_enum __user *enum_ptr; struct drm_property_blob *prop_blob; + uint32_t *blob_id_ptr; uint64_t __user *values_ptr; + uint32_t __user *blob_length_ptr; mutex_lock(&dev->mode_config.mutex); property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); @@ -1980,7 +1982,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, if (property->flags & DRM_MODE_PROP_ENUM) { list_for_each_entry(prop_enum, &property->enum_blob_list, head) enum_count++; - } else if (property->flags & DRM_MODE_PROP_BLOB) { + } else if (property->flags & DRM_MODE_PROP_BLOB) { list_for_each_entry(prop_blob, &property->enum_blob_list, head) blob_count++; } @@ -2002,44 +2004,49 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, } out_resp->count_values = value_count; - if ((out_resp->count_enum_blobs >= enum_count) && enum_count && (property->flags & DRM_MODE_PROP_ENUM)) { - copied = 0; - enum_ptr = (struct drm_property_enum *)(unsigned long)out_resp->enum_blob_ptr; - list_for_each_entry(prop_enum, &property->enum_blob_list, head) { - if (put_user(prop_enum->value, &enum_ptr[copied].value)) { - ret = -EFAULT; - goto done; - } - - if (copy_to_user(&enum_ptr[copied].name, - prop_enum->name, DRM_PROP_NAME_LEN)) { + if (property->flags & DRM_MODE_PROP_ENUM) { + if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { + copied = 0; + enum_ptr = (struct drm_property_enum *)(unsigned long)out_resp->enum_blob_ptr; + list_for_each_entry(prop_enum, &property->enum_blob_list, head) { + if (put_user(prop_enum->value, &enum_ptr[copied].value)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user(&enum_ptr[copied].name, + prop_enum->name, DRM_PROP_NAME_LEN)) { ret = -EFAULT; goto done; + } + copied++; } - copied++; } + out_resp->count_enum_blobs = enum_count; } - out_resp->count_enum_blobs = enum_count; -#if 0 - if ((out_resp->count_blobs >= enum_count) && blob_count && (property->flags & DRM_MODE_PROP_BLOB)) { - copied = 0; - list_for_each_entry(prop_blob, &property->enum_list, head) { - if (put_user(prop_enum->value, &out_resp->blobs[copied].value)) { - ret = -EFAULT; - goto done; - } - - if (copy_to_user(&out_resp->enums[copied].name, - prop_enum->name, DRM_PROP_NAME_LEN)) { - ret = -EFAULT; - goto done; + if (property->flags & DRM_MODE_PROP_BLOB) { + if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { + copied = 0; + blob_id_ptr = (uint32_t *)(unsigned long)out_resp->enum_blob_ptr; + blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr; + + list_for_each_entry(prop_blob, &property->enum_blob_list, head) { + if (put_user(prop_blob->id, blob_id_ptr + copied)) { + ret = -EFAULT; + goto done; + } + + if (put_user(prop_blob->length, blob_length_ptr + copied)) { + ret = -EFAULT; + goto done; + } + + copied++; } - copied++; } + out_resp->count_enum_blobs = enum_count; } - out_resp->count_enums = enum_count; -#endif done: mutex_unlock(&dev->mode_config.mutex); return ret; diff --git a/shared-core/drm.h b/shared-core/drm.h index 6317f142..7649abd6 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -981,12 +981,13 @@ struct drm_mode_property_enum { }; struct drm_mode_property_blob { + uint64_t data_ptr; uint32_t length; }; struct drm_mode_get_property { - uint64_t values_ptr; - uint64_t enum_blob_ptr; + uint64_t values_ptr; /* values and blob lengths */ + uint64_t enum_blob_ptr; /* enum and blob id ptrs */ unsigned int prop_id; unsigned int flags; -- cgit v1.2.3 From 67f6eb1eb8d3dc5bb5fdb097655d3da326f637c1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 10:44:51 +1000 Subject: add property blobs and edid reporting support --- libdrm/xf86drmMode.c | 41 ++++++++++++++++++++++++++ libdrm/xf86drmMode.h | 3 ++ linux-core/drm_crtc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++---- linux-core/drm_crtc.h | 8 ++++-- linux-core/drm_drv.c | 1 + linux-core/intel_crt.c | 1 - linux-core/intel_modes.c | 1 + shared-core/drm.h | 13 +++++---- tests/mode/modetest.c | 9 ++++-- 9 files changed, 134 insertions(+), 18 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index f4ec004c..03bd15f1 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -470,3 +470,44 @@ void drmModeFreeProperty(drmModePropertyPtr ptr) drmFree(ptr->enums); drmFree(ptr); } + +drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id) +{ + struct drm_mode_get_blob blob; + drmModePropertyBlobPtr r; + + blob.length = 0; + blob.data = 0; + blob.blob_id = blob_id; + + if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) + return NULL; + + if (blob.length) + blob.data = VOID2U64(drmMalloc(blob.length)); + + if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) { + r = NULL; + goto err_allocs; + } + + if (!(r = drmMalloc(sizeof(*r)))) + return NULL; + + r->id = blob.blob_id; + r->length = blob.length; + r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length); + +err_allocs: + drmFree(U642VOID(blob.data)); + return r; +} + +void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->data); + drmFree(ptr); +} diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index e936044b..6fcf6a19 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -220,3 +220,6 @@ extern int drmModeDetachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId); extern void drmModeFreeProperty(drmModePropertyPtr ptr); + +extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id); +extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a3aa783b..70844237 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -590,6 +590,8 @@ struct drm_output *drm_output_create(struct drm_device *dev, list_add_tail(&output->head, &dev->mode_config.output_list); dev->mode_config.num_output++; + drm_output_attach_property(output, dev->mode_config.edid_property, 0); + mutex_unlock(&dev->mode_config.mutex); return output; @@ -1935,7 +1937,6 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) } EXPORT_SYMBOL(drm_property_destroy); - int drm_output_attach_property(struct drm_output *output, struct drm_property *property, uint64_t init_val) { @@ -1955,6 +1956,24 @@ int drm_output_attach_property(struct drm_output *output, } EXPORT_SYMBOL(drm_output_attach_property); +int drm_output_property_set_value(struct drm_output *output, + struct drm_property *property, uint64_t value) +{ + int i; + + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] == property->id) { + output->property_values[i] = value; + break; + } + } + + if (i == DRM_OUTPUT_MAX_PROPERTY) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(drm_output_property_set_value); + int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -2052,17 +2071,17 @@ done: return ret; } -static int drm_property_create_blob(struct drm_device *dev, int length, - void *data) +static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length, + void *data) { struct drm_property_blob *blob; if (!length || !data) - return -EINVAL; + return NULL; blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL); if (!blob) - return -EINVAL; + return NULL; blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob)); blob->length = length; @@ -2072,7 +2091,7 @@ static int drm_property_create_blob(struct drm_device *dev, int length, blob->id = drm_idr_get(dev, blob); list_add_tail(&blob->head, &dev->mode_config.property_blob_list); - return blob->id; + return blob; } static void drm_property_destroy_blob(struct drm_device *dev, @@ -2082,3 +2101,47 @@ static void drm_property_destroy_blob(struct drm_device *dev, list_del(&blob->head); kfree(blob); } + +int drm_mode_getblob_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_get_blob *out_resp = data; + struct drm_property_blob *blob; + int ret = 0; + void *blob_ptr; + + mutex_lock(&dev->mode_config.mutex); + + blob = idr_find(&dev->mode_config.crtc_idr, out_resp->blob_id); + if (!blob || (blob->id != out_resp->blob_id)) { + ret = -EINVAL; + goto done; + } + + if (out_resp->length == blob->length) { + blob_ptr = (void *)(unsigned long)out_resp->data; + if (copy_to_user(blob_ptr, blob->data, blob->length)){ + ret = -EFAULT; + goto done; + } + } + out_resp->length = blob->length; + +done: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +int drm_mode_output_update_edid_property(struct drm_output *output, unsigned char *edid) +{ + struct drm_device *dev = output->dev; + int ret = 0; + if (output->edid_blob_ptr) + drm_property_destroy_blob(dev, output->edid_blob_ptr); + + output->edid_blob_ptr = drm_property_create_blob(output->dev, 128, edid); + + ret = drm_output_property_set_value(output, dev->mode_config.edid_property, output->edid_blob_ptr->id); + return ret; +} +EXPORT_SYMBOL(drm_mode_output_update_edid_property); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d028f75f..2c77d9d7 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -236,8 +236,8 @@ struct drm_framebuffer { struct drm_property_blob { struct list_head head; - unsigned int id; unsigned int length; + unsigned int id; void *data; }; @@ -456,7 +456,7 @@ struct drm_output { void *driver_private; struct list_head user_modes; - + struct drm_property_blob *edid_blob_ptr; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; }; @@ -547,7 +547,7 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); extern void drm_mode_output_list_update(struct drm_output *output); - +extern int drm_mode_output_update_edid_property(struct drm_output *output, unsigned char *edid); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, @@ -594,5 +594,7 @@ extern int drm_mode_detachmode_ioctl(struct drm_device *dev, extern int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_getblob_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index a88ae8b5..f8665be7 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -125,6 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY), diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index d3ad4654..2ab6a27b 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -246,5 +246,4 @@ void intel_crt_init(struct drm_device *dev) output->interlace_allowed = 0; output->doublescan_allowed = 0; - drm_output_attach_property(output, dev->mode_config.edid_property, 0); } diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c index 346cf1ac..f8bf496c 100644 --- a/linux-core/intel_modes.c +++ b/linux-core/intel_modes.c @@ -55,6 +55,7 @@ int intel_ddc_get_modes(struct drm_output *output) edid = drm_get_edid(output, &intel_output->ddc_bus->adapter); if (edid) { + drm_mode_output_update_edid_property(output, edid); ret = drm_add_edid_modes(output, edid); kfree(edid); } diff --git a/shared-core/drm.h b/shared-core/drm.h index 7649abd6..0c66f85c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -980,11 +980,6 @@ struct drm_mode_property_enum { unsigned char name[DRM_PROP_NAME_LEN]; }; -struct drm_mode_property_blob { - uint64_t data_ptr; - uint32_t length; -}; - struct drm_mode_get_property { uint64_t values_ptr; /* values and blob lengths */ uint64_t enum_blob_ptr; /* enum and blob id ptrs */ @@ -997,6 +992,12 @@ struct drm_mode_get_property { int count_enum_blobs; }; +struct drm_mode_get_blob { + uint32_t blob_id; + uint32_t length; + uint64_t data; +}; + struct drm_mode_fb_cmd { unsigned int buffer_id; unsigned int width, height; @@ -1111,7 +1112,7 @@ struct drm_mode_mode_cmd { #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) -#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_propblob) +#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_blob) #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 46f88d82..c396da41 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -75,9 +75,14 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) printf("%d ", props->values[j]); printf("\n\tenums %d: \n", props->count_enums); + + if (props->flags & DRM_MODE_PROP_BLOB) { + drmModePropertyBlobPtr blob; - if (prop->flags & DRM_MODE_PROP_BLOB) { - + blob = drmModeGetPropertyBlob(fd, output->prop_values[i]); + + printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); + drmModeFreePropertyBlob(blob); } else { for (j = 0; j < props->count_enums; j++) { -- cgit v1.2.3 From 1ba2bb3a7e77576333b09f296abac4c01c895c48 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 11:35:37 +1000 Subject: oops initialise variable to false --- linux-core/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 70844237..fba275b7 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1005,7 +1005,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_device *dev = crtc->dev; struct drm_crtc **save_crtcs, *new_crtc; bool save_enabled = crtc->enabled; - bool changed; + bool changed = false; struct drm_output *output; int count = 0, ro; -- cgit v1.2.3 From 8020724615eb6f334d5f90b1e83e6a46d4a126ac Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 11:46:54 +1000 Subject: check previous mode first --- linux-core/intel_fb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 0a3a00b5..c81e4408 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -320,9 +320,11 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); } - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + if (par->crtc->enabled) { + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) return -EINVAL; - + } return 0; } -- cgit v1.2.3 From 9814e87016ff90556ae34e3395c10d29add2ba08 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Dec 2007 11:47:29 +1000 Subject: retab intelfb code --- linux-core/intel_fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index c81e4408..32c7dc31 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -321,9 +321,9 @@ static int intelfb_set_par(struct fb_info *info) } if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) - return -EINVAL; + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + return -EINVAL; } return 0; } -- cgit v1.2.3 From 3a51a8077bf55ba9d18805f2f03b78eb980fa982 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 6 Dec 2007 22:38:44 +0100 Subject: radeon_ms: avoid to unintialize things which haven't been initialized --- shared-core/radeon_ms_bus.c | 10 ++++++++++ shared-core/radeon_ms_cp.c | 4 ++++ shared-core/radeon_ms_drm.c | 1 - shared-core/radeon_ms_fence.c | 2 +- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_ms_bus.c b/shared-core/radeon_ms_bus.c index 6a782b1c..d50c9fb8 100644 --- a/shared-core/radeon_ms_bus.c +++ b/shared-core/radeon_ms_bus.c @@ -205,6 +205,12 @@ static int pcie_ttm_unbind(struct drm_ttm_backend *backend) int radeon_ms_agp_finish(struct drm_device *dev) { + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (!dev_priv->bus_ready) { + return 0; + } + dev_priv->bus_ready = 0; drm_agp_release(dev); return 0; } @@ -217,6 +223,7 @@ int radeon_ms_agp_init(struct drm_device *dev) uint32_t agp_status; int ret; + dev_priv->bus_ready = -1; if (dev->agp == NULL) { DRM_ERROR("[radeon_ms] can't initialize AGP\n"); return -EINVAL; @@ -256,6 +263,7 @@ int radeon_ms_agp_init(struct drm_device *dev) DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n", state->mc_agp_location); DRM_INFO("[radeon_ms] bus ready\n"); + dev_priv->bus_ready = 1; return 0; } @@ -328,6 +336,7 @@ int radeon_ms_pcie_init(struct drm_device *dev) struct radeon_pcie *pcie; int ret = 0; + dev_priv->bus_ready = -1; /* allocate and clear device private structure */ pcie = drm_alloc(sizeof(struct radeon_pcie), DRM_MEM_DRIVER); if (pcie == NULL) { @@ -401,6 +410,7 @@ int radeon_ms_pcie_init(struct drm_device *dev) DRM_INFO("[radeon_ms] gpu gart end 0x%08X\n", PCIE_R(PCIE_TX_GART_END_LO)); DRM_INFO("[radeon_ms] bus ready\n"); + dev_priv->bus_ready = 1; return 0; } diff --git a/shared-core/radeon_ms_cp.c b/shared-core/radeon_ms_cp.c index 7426facb..c01769bd 100644 --- a/shared-core/radeon_ms_cp.c +++ b/shared-core/radeon_ms_cp.c @@ -101,6 +101,9 @@ int radeon_ms_cp_finish(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; + if (!dev_priv->cp_ready) { + return 0; + } dev_priv->cp_ready = 0; radeon_ms_wait_for_idle(dev); DRM_INFO("[radeon_ms] cp idle\n"); @@ -126,6 +129,7 @@ int radeon_ms_cp_init(struct drm_device *dev) struct radeon_state *state = &dev_priv->driver_state; int ret = 0; + dev_priv->cp_ready = -1; if (dev_priv->microcode == NULL) { DRM_INFO("[radeon_ms] no microcode not starting cp"); return 0; diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index b22c83a7..8d0481e1 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -173,7 +173,6 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) return ret; } radeon_ms_gpu_restore(dev, &dev_priv->driver_state); - dev_priv->bus_ready = 1; /* initialize ttm */ ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c index 96bb0858..6fcf5437 100644 --- a/shared-core/radeon_ms_fence.c +++ b/shared-core/radeon_ms_fence.c @@ -54,7 +54,7 @@ int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class, struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t fence_id, cmd[2], i, ret; - if (!dev_priv || !dev_priv->cp_ready) { + if (!dev_priv || dev_priv->cp_ready != 1) { return -EINVAL; } fence_id = (++dev_priv->fence_id_last); -- cgit v1.2.3 From a39560e767f8d66508f7cf98222199b2cc96fcaf Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 6 Dec 2007 23:19:52 +0100 Subject: radeon_ms: update to lastest fb change --- linux-core/radeon_ms_fb.c | 70 ++++++++++++++++++++++++++++++++++++------ shared-core/radeon_ms_output.c | 4 +++ 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index ef7c5cf1..b629b9eb 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -42,8 +42,9 @@ #include "radeon_ms.h" struct radeonfb_par { - struct drm_device *dev; - struct drm_crtc *crtc; + struct drm_device *dev; + struct drm_crtc *crtc; + struct drm_display_mode *fb_mode; }; static int radeonfb_setcolreg(unsigned regno, unsigned red, @@ -127,13 +128,38 @@ static int radeonfb_check_var(struct fb_var_screeninfo *var, return 0; } +static bool radeonfb_mode_equal(struct drm_display_mode *mode1, + struct drm_display_mode *mode2) +{ + if (mode1->hdisplay == mode2->hdisplay && + mode1->hsync_start == mode2->hsync_start && + mode1->hsync_end == mode2->hsync_end && + mode1->htotal == mode2->htotal && + mode1->hskew == mode2->hskew && + mode1->vdisplay == mode2->vdisplay && + mode1->vsync_start == mode2->vsync_start && + mode1->vsync_end == mode2->vsync_end && + mode1->vtotal == mode2->vtotal && + mode1->vscan == mode2->vscan && + mode1->flags == mode2->flags) { + /* FIXME: what about adding a margin for clock ? */ + if (mode1->clock == mode2->clock) + return true; + return false; + } + + return false; +} + static int radeonfb_set_par(struct fb_info *info) { struct radeonfb_par *par = info->par; struct drm_framebuffer *fb = par->crtc->fb; struct drm_device *dev = par->dev; - struct drm_display_mode *drm_mode; + struct drm_display_mode *drm_mode, *search_mode; + struct drm_output *output; struct fb_var_screeninfo *var = &info->var; + int found = 0; switch (var->bits_per_pixel) { case 16: @@ -171,15 +197,39 @@ static int radeonfb_set_par(struct fb_info *info) drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); - drm_mode_debug_printmodeline(dev, drm_mode); + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) - return -EINVAL; + drm_mode_debug_printmodeline(dev, drm_mode); + list_for_each_entry(search_mode, &output->modes, head) { + drm_mode_debug_printmodeline(dev, search_mode); + if (radeonfb_mode_equal(drm_mode, search_mode)) { + drm_mode_destroy(dev, drm_mode); + drm_mode = search_mode; + found = 1; + break; + } + } - /* Have to destroy our created mode if we're not searching the mode - * list for it. - */ - drm_mode_destroy(dev, drm_mode); + if (!found) { + if (par->fb_mode) { + drm_mode_detachmode_crtc(dev, par->fb_mode); + } + par->fb_mode = drm_mode; + drm_mode_debug_printmodeline(dev, drm_mode); + /* attach mode */ + drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); + } + + if (par->crtc->enabled) { + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { + if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) { + return -EINVAL; + } + } + } return 0; } diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c index 4d6cb01e..35e5c376 100644 --- a/shared-core/radeon_ms_output.c +++ b/shared-core/radeon_ms_output.c @@ -164,6 +164,10 @@ static int radeon_ms_output_get_modes(struct drm_output *output) if (connector == NULL || connector->i2c == NULL) { return 0; } + if (connector->edid == NULL) { + return 0; + } + drm_mode_output_update_edid_property(output, connector->edid); ret = drm_add_edid_modes(output, connector->edid); kfree(connector->edid); connector->edid = NULL; -- cgit v1.2.3 From a693e8ab12432787a3c02fa5b8f7649a08122012 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 6 Dec 2007 23:36:58 +0100 Subject: radeon_ms: fix fbcon by fixing palette --- linux-core/radeon_ms_fb.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index b629b9eb..fc9e99ec 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -52,12 +52,35 @@ static int radeonfb_setcolreg(unsigned regno, unsigned red, unsigned transp, struct fb_info *info) { struct radeonfb_par *par = info->par; + struct drm_framebuffer *fb = par->crtc->fb; struct drm_crtc *crtc = par->crtc; - if (regno > 255) + if (regno > 255) { return 1; - if (crtc->funcs->gamma_set) + } + if (crtc->funcs->gamma_set) { crtc->funcs->gamma_set(crtc, red, green, blue, regno); + } + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } return 0; } -- cgit v1.2.3 From 9d064966d8495038921d0e731c0bfca0cd58d244 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sat, 8 Dec 2007 00:45:33 +0100 Subject: radeon_ms: fix pll computation to follow hw constraint --- shared-core/radeon_ms_crtc.c | 127 +++++++++++++++++++++++++---------------- shared-core/radeon_ms_family.c | 6 +- 2 files changed, 82 insertions(+), 51 deletions(-) diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c index a9387f96..fe89e5e4 100644 --- a/shared-core/radeon_ms_crtc.c +++ b/shared-core/radeon_ms_crtc.c @@ -379,13 +379,26 @@ static void radeon_ms_crtc_mode_prepare(struct drm_crtc *crtc) crtc->funcs->dpms(crtc, DPMSModeOff); } -/* Compute n/d with rounding */ -static int radeon_div(int n, int d) +/* compute PLL registers values for requested video mode */ +static int radeon_pll1_constraint(int clock, int rdiv, + int fdiv, int pdiv, + int rfrq, int pfrq) { - return (n + (d / 2)) / d; + int dfrq; + + if (rdiv < 2 || fdiv < 4) { + return 0; + } + dfrq = rfrq / rdiv; + if (dfrq < 2000 || dfrq > 3300) { + return 0; + } + if (pfrq < 125000 || pfrq > 250000) { + return 0; + } + return 1; } -/* compute PLL registers values for requested video mode */ static void radeon_pll1_compute(struct drm_crtc *crtc, struct drm_display_mode *mode) { @@ -410,65 +423,73 @@ static void radeon_pll1_compute(struct drm_crtc *crtc, }; struct drm_radeon_private *dev_priv = crtc->dev->dev_private; struct radeon_state *state = &dev_priv->driver_state; - unsigned long freq = mode->clock / 10; - int pll_output_freq; - int min_rcenter_dist; - int rcenter_dist; - int post_divider; - int post_divider_id; - int ref_div; - int fb_div; + int clock = mode->clock; + int rfrq = dev_priv->properties->pll_reference_freq; + int pdiv = 1; + int pdiv_id = 0; + int rdiv_best = 2; + int fdiv_best = 4; + int tfrq_best = 0; + int pfrq_best = 0; + int diff_cpfrq_best = 350000; int vco_freq; int vco_gain; + int rdiv = 0; + int fdiv = 0; + int tfrq = 35000; + int pfrq = 35000; + int diff_cpfrq = 350000; /* clamp frequency into pll [min; max] frequency range */ - if (freq > dev_priv->properties->pll_max_pll_freq) { - freq = dev_priv->properties->pll_max_pll_freq; + if (clock > dev_priv->properties->pll_max_pll_freq) { + clock = dev_priv->properties->pll_max_pll_freq; } - if (freq < dev_priv->properties->pll_min_pll_freq) { - freq = dev_priv->properties->pll_min_pll_freq; + if ((clock * 12) < dev_priv->properties->pll_min_pll_freq) { + clock = dev_priv->properties->pll_min_pll_freq / 12; } - /* select divider so that pll output frequency is the nearest to - * the center of [350; 125]Mhz range */ - min_rcenter_dist = 350 * 100; - post_divider = post_divs[0].divider; - post_divider_id = post_divs[0].divider_id; + + /* maximize pll_ref_div while staying in boundary and minimizing + * the difference btw target frequency and programmed frequency */ for (post_div = &post_divs[0]; post_div->divider; ++post_div) { - if (post_div->divider == 0) + if (post_div->divider == 0) { break; - /* pll output frequency (before post divider) */ - pll_output_freq = post_div->divider * freq; - /* compute distance to [350; 125] range center*/ - rcenter_dist = abs(pll_output_freq - 11250); - if (rcenter_dist < min_rcenter_dist) { - min_rcenter_dist = rcenter_dist; - post_divider = post_div->divider; - post_divider_id = post_div->divider_id; + } + tfrq = clock * post_div->divider; + for (fdiv = 1023; fdiv >= 4; fdiv--) { + rdiv = (fdiv * rfrq) / tfrq; + if (radeon_pll1_constraint(clock, rdiv, fdiv, + pdiv, rfrq, tfrq)) { + pfrq = (fdiv * rfrq) / rdiv; + diff_cpfrq = pfrq - tfrq; + if ((diff_cpfrq >= 0 && + diff_cpfrq < diff_cpfrq_best) || + (diff_cpfrq == diff_cpfrq_best && + rdiv > rdiv_best)) { + rdiv_best = rdiv; + fdiv_best = fdiv; + tfrq_best = tfrq; + pfrq_best = pfrq; + pdiv = post_div->divider; + pdiv_id = post_div->divider_id; + diff_cpfrq_best = diff_cpfrq; + } + } } } - pll_output_freq = post_divider * freq; - /* select first feedback */ - state->clock_cntl_index = REG_S(CLOCK_CNTL_INDEX, PPLL_DIV_SEL, 0); - /* set ref div so that ref_freq/ref_div is in middle of [2; 3.3]Mhz */ - ref_div = dev_priv->properties->pll_reference_freq / 265; - state->ppll_ref_div = REG_S(PPLL_REF_DIV, PPLL_REF_DIV, ref_div) | - REG_S(PPLL_REF_DIV, PPLL_REF_DIV_ACC, ref_div); - fb_div = radeon_div(pll_output_freq * ref_div, - dev_priv->properties->pll_reference_freq); - state->ppll_div_0 = REG_S(PPLL_DIV_0, PPLL_FB0_DIV, fb_div) | - REG_S(PPLL_DIV_0, PPLL_POST0_DIV, post_divider_id); - /* configure vco gain */ - state->ppll_cntl = PPLL_R(PPLL_CNTL); - vco_gain = REG_G(PPLL_CNTL, PPLL_PVG, state->ppll_cntl); - vco_freq = (fb_div * dev_priv->properties->pll_reference_freq) / - ref_div; + state->ppll_ref_div = + REG_S(PPLL_REF_DIV, PPLL_REF_DIV, rdiv_best) | + REG_S(PPLL_REF_DIV, PPLL_REF_DIV_ACC, rdiv_best); + state->ppll_div_0 = REG_S(PPLL_DIV_0, PPLL_FB0_DIV, fdiv_best) | + REG_S(PPLL_DIV_0, PPLL_POST0_DIV, pdiv_id); + + vco_freq = (fdiv_best * rfrq) / rdiv_best; /* This is horribly crude: the VCO frequency range is divided into * 3 parts, each part having a fixed PLL gain value. */ - if (vco_freq >= 30000) { + if (vco_freq >= 300000) { /* [300..max] MHz : 7 */ vco_gain = 7; - } else if (vco_freq >= 18000) { + } else if (vco_freq >= 180000) { /* [180..300) MHz : 4 */ vco_gain = 4; } else { @@ -479,6 +500,16 @@ static void radeon_pll1_compute(struct drm_crtc *crtc, state->vclk_ecp_cntl |= REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL, VCLK_SRC_SEL__PPLLCLK); state->htotal_cntl = 0; + DRM_INFO("rdiv: %d\n", rdiv_best); + DRM_INFO("fdiv: %d\n", fdiv_best); + DRM_INFO("pdiv: %d\n", pdiv); + DRM_INFO("pdiv: %d\n", pdiv_id); + DRM_INFO("tfrq: %d\n", tfrq_best); + DRM_INFO("pfrq: %d\n", pfrq_best); + DRM_INFO("PPLL_REF_DIV: 0x%08X\n", state->ppll_ref_div); + DRM_INFO("PPLL_DIV_0: 0x%08X\n", state->ppll_div_0); + DRM_INFO("PPLL_CNTL: 0x%08X\n", state->ppll_cntl); + DRM_INFO("VCLK_ECP_CNTL: 0x%08X\n", state->vclk_ecp_cntl); } static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c index ea5f6ca3..779595d6 100644 --- a/shared-core/radeon_ms_family.c +++ b/shared-core/radeon_ms_family.c @@ -76,7 +76,7 @@ static struct radeon_ms_connector radeon_ms_dvi_i_2 = { static struct radeon_ms_properties properties[] = { /* default only one VGA connector */ { - 0, 0, 2700, 2500, 20000, 1, 1, 1, 1, + 0, 0, 27000, 25000, 200000, 1, 1, 1, 1, { &radeon_ms_dac1, NULL, NULL, NULL, NULL, NULL, NULL, NULL @@ -87,7 +87,7 @@ static struct radeon_ms_properties properties[] = { } }, { - 0x1043, 0x176, 2700, 2500, 20000, 1, 1, 1, 1, + 0x1043, 0x176, 27000, 25000, 200000, 1, 1, 1, 1, { &radeon_ms_dac1, &radeon_ms_dac2, NULL, NULL, NULL, NULL, NULL, NULL @@ -98,7 +98,7 @@ static struct radeon_ms_properties properties[] = { } }, { - 0x1002, 0x4150, 2700, 2500, 20000, 1, 1, 1, 1, + 0x1002, 0x4150, 27000, 25000, 200000, 1, 1, 1, 1, { &radeon_ms_dac1, &radeon_ms_dac2, NULL, NULL, NULL, NULL, NULL, NULL -- cgit v1.2.3 From 3b6786e3e6523b1ceca3645ea4c6081f170d2134 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 11 Dec 2007 14:46:51 +1000 Subject: modesetting: add dpms property and initial settable property ioctl --- libdrm/xf86drmMode.c | 4 ++-- linux-core/drm_crtc.c | 59 +++++++++++++++++++++++++++++++++++++++++++++------ linux-core/drm_crtc.h | 5 +++-- shared-core/drm.h | 7 ++++++ tests/mode/Makefile | 2 +- tests/mode/modetest.c | 10 +++++---- 6 files changed, 71 insertions(+), 16 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 03bd15f1..7e2683ea 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -421,10 +421,10 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) if (prop.count_values) prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t))); - if (prop.count_enum_blobs & (prop.flags & DRM_MODE_PROP_ENUM)) + if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_ENUM)) prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum))); - if (prop.count_enum_blobs & (prop.flags & DRM_MODE_PROP_BLOB)) { + if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) { prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); } diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fba275b7..871f8994 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -592,6 +592,8 @@ struct drm_output *drm_output_create(struct drm_device *dev, drm_output_attach_property(output, dev->mode_config.edid_property, 0); + drm_output_attach_property(output, dev->mode_config.dpms_property, 0); + mutex_unlock(&dev->mode_config.mutex); return output; @@ -729,6 +731,15 @@ void drm_mode_config_init(struct drm_device *dev) dev->mode_config.edid_property = drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, "EDID", 0); + + dev->mode_config.dpms_property = drm_property_create(dev, + DRM_MODE_PROP_ENUM, + "DPMS", 4); + drm_property_add_enum(dev->mode_config.dpms_property, 0, DPMSModeOn, "On"); + drm_property_add_enum(dev->mode_config.dpms_property, 1, DPMSModeStandby, "Standby"); + drm_property_add_enum(dev->mode_config.dpms_property, 2, DPMSModeSuspend, "Suspend"); + drm_property_add_enum(dev->mode_config.dpms_property, 3, DPMSModeOff, "Off"); + } EXPORT_SYMBOL(drm_mode_config_init); @@ -1985,7 +1996,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, int ret = 0, i; int copied; struct drm_property_enum *prop_enum; - struct drm_property_enum __user *enum_ptr; + struct drm_mode_property_enum __user *enum_ptr; struct drm_property_blob *prop_blob; uint32_t *blob_id_ptr; uint64_t __user *values_ptr; @@ -2015,7 +2026,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, if ((out_resp->count_values >= value_count) && value_count) { values_ptr = (uint64_t *)(unsigned long)out_resp->values_ptr; for (i = 0; i < value_count; i++) { - if (put_user(property->values[i], values_ptr + i)) { + if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { ret = -EFAULT; goto done; } @@ -2024,19 +2035,21 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, out_resp->count_values = value_count; if (property->flags & DRM_MODE_PROP_ENUM) { + if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { copied = 0; - enum_ptr = (struct drm_property_enum *)(unsigned long)out_resp->enum_blob_ptr; + enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr; list_for_each_entry(prop_enum, &property->enum_blob_list, head) { - if (put_user(prop_enum->value, &enum_ptr[copied].value)) { + + if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { ret = -EFAULT; goto done; } if (copy_to_user(&enum_ptr[copied].name, - prop_enum->name, DRM_PROP_NAME_LEN)) { - ret = -EFAULT; - goto done; + &prop_enum->name, DRM_PROP_NAME_LEN)) { + ret = -EFAULT; + goto done; } copied++; } @@ -2145,3 +2158,35 @@ int drm_mode_output_update_edid_property(struct drm_output *output, unsigned cha return ret; } EXPORT_SYMBOL(drm_mode_output_update_edid_property); + +int drm_mode_output_property_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_output_set_property *out_resp = data; + struct drm_output *output; + int ret = -EINVAL; + int i; + + mutex_lock(&dev->mode_config.mutex); + output= idr_find(&dev->mode_config.crtc_idr, out_resp->output_id); + if (!output || (output->id != out_resp->output_id)) { + goto out; + } + + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] == out_resp->prop_id) + break; + } + + if (i == DRM_OUTPUT_MAX_PROPERTY) { + goto out; + } + + if (output->funcs->set_property) + ret = output->funcs->set_property(output, out_resp->prop_id, out_resp->value); + +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 2c77d9d7..ad5ecc5d 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -242,8 +242,8 @@ struct drm_property_blob { }; struct drm_property_enum { - struct list_head head; uint64_t value; + struct list_head head; unsigned char name[DRM_PROP_NAME_LEN]; }; @@ -396,7 +396,7 @@ struct drm_output_funcs { enum drm_output_status (*detect)(struct drm_output *output); int (*get_modes)(struct drm_output *output); /* JJJ: type checking for properties via property value type */ - bool (*set_property)(struct drm_output *output, int prop, void *val); + bool (*set_property)(struct drm_output *output, int prop, uint64_t val); void (*cleanup)(struct drm_output *output); }; @@ -503,6 +503,7 @@ struct drm_mode_config { /* pointers to standard properties */ struct list_head property_blob_list; struct drm_property *edid_property; + struct drm_property *dpms_property; }; struct drm_output *drm_output_create(struct drm_device *dev, diff --git a/shared-core/drm.h b/shared-core/drm.h index 0c66f85c..df43802f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -992,6 +992,12 @@ struct drm_mode_get_property { int count_enum_blobs; }; +struct drm_mode_output_set_property { + uint64_t value; + unsigned int prop_id; + unsigned int output_id; +}; + struct drm_mode_get_blob { uint32_t blob_id; uint32_t length; @@ -1112,6 +1118,7 @@ struct drm_mode_mode_cmd { #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_set_output_property) #define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_blob) #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) diff --git a/tests/mode/Makefile b/tests/mode/Makefile index 205c2ba1..a3d3b49a 100644 --- a/tests/mode/Makefile +++ b/tests/mode/Makefile @@ -5,7 +5,7 @@ all: modetest # -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ modetest: modetest.c - @gcc -o modetest -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c + @gcc $(CFLAGS) -o modetest -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c clean: @rm -f modetest diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index c396da41..4a8c6a17 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -80,15 +80,17 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) drmModePropertyBlobPtr blob; blob = drmModeGetPropertyBlob(fd, output->prop_values[i]); - - printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); - drmModeFreePropertyBlob(blob); + if (blob) { + printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); + drmModeFreePropertyBlob(blob); + } } else { for (j = 0; j < props->count_enums; j++) { + printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); if (output->prop_values[i] == props->enums[j].value) name = props->enums[j].name; - printf("\t\t%d = %s\n", props->enums[j].value, props->enums[j].name); + } if (props->count_enums && name) { -- cgit v1.2.3 From f99dea7db00dd46aa96eaed3a61dff9c956fd86f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 11 Dec 2007 15:56:48 +1000 Subject: modesetting: fixup property setting and add connector property --- libdrm/xf86drmMode.c | 18 +++++++++ libdrm/xf86drmMode.h | 2 + linux-core/drm_crtc.c | 102 +++++++++++++++++++++++++++++++++++++++++------- linux-core/drm_crtc.h | 22 ++++++++++- linux-core/drm_drv.c | 1 + linux-core/intel_crt.c | 15 +++++++ linux-core/intel_lvds.c | 1 + linux-core/intel_sdvo.c | 7 ++++ shared-core/drm.h | 2 +- tests/mode/modetest.c | 31 +++++++++++++-- 10 files changed, 181 insertions(+), 20 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 7e2683ea..726c55ab 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -214,6 +214,8 @@ int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, int drmModeRmFB(int fd, uint32_t bufferId) { return ioctl(fd, DRM_IOCTL_MODE_RMFB, &bufferId); + + } drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) @@ -511,3 +513,19 @@ void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) drmFree(ptr->data); drmFree(ptr); } + +int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, + uint64_t value) +{ + struct drm_mode_output_set_property osp; + int ret; + + osp.output_id = output_id; + osp.prop_id = property_id; + osp.value = value; + + if (ret = ioctl(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp)) + return ret; + + return 0; +} diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 6fcf6a19..05b61bc8 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -223,3 +223,5 @@ extern void drmModeFreeProperty(drmModePropertyPtr ptr); extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id); extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); +extern int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, + uint64_t value); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 871f8994..e1b37c0b 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -33,6 +33,33 @@ #include "drmP.h" #include "drm_crtc.h" +struct drm_prop_enum_list { + int type; + char *name; +}; + +static struct drm_prop_enum_list drm_dpms_enum_list[] = +{ { DPMSModeOn, "On" }, + { DPMSModeStandby, "Standby" }, + { DPMSModeSuspend, "Suspend" }, + { DPMSModeOff, "Off" } +}; +static struct drm_prop_enum_list drm_conn_enum_list[] = +{ { ConnectorVGA, "VGA" }, + { ConnectorDVII, "DVI-I" }, + { ConnectorDVID, "DVI-D" }, + { ConnectorDVIA, "DVI-A" }, + { ConnectorComposite, "Composite" }, + { ConnectorSVIDEO, "SVIDEO" }, + { ConnectorLVDS, "LVDS" }, + { ConnectorComponent, "Component" }, + { Connector9PinDIN, "9-pin DIN" }, + { ConnectorDisplayPort, "DisplayPort" }, + { ConnectorHDMIA, "HDMI Type A" }, + { ConnectorHDMIB, "HDMI Type B" }, +}; + + /** * drm_idr_get - allocate a new identifier * @dev: DRM device @@ -709,6 +736,34 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_destroy); +static int drm_mode_create_standard_output_properties(struct drm_device *dev) +{ + int i; + + dev->mode_config.edid_property = + drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, + "EDID", 0); + + dev->mode_config.dpms_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM, "DPMS", 4); + + for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++) + drm_property_add_enum(dev->mode_config.dpms_property, i, drm_dpms_enum_list[i].type, drm_dpms_enum_list[i].name); + + dev->mode_config.connector_type_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, + "Connector Type", 10); + for (i = 0; i < ARRAY_SIZE(drm_conn_enum_list); i++) + drm_property_add_enum(dev->mode_config.connector_type_property, i, drm_conn_enum_list[i].type, drm_conn_enum_list[i].name); + + dev->mode_config.connector_num_property = + drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, + "Connector ID", 2); + dev->mode_config.connector_num_property->values[0] = 0; + dev->mode_config.connector_num_property->values[1] = 20; + return 0; +} + /** * drm_mode_config_init - initialize DRM mode_configuration structure * @dev: DRM device @@ -728,17 +783,8 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.property_list); INIT_LIST_HEAD(&dev->mode_config.property_blob_list); idr_init(&dev->mode_config.crtc_idr); - dev->mode_config.edid_property = drm_property_create(dev, - DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, - "EDID", 0); - - dev->mode_config.dpms_property = drm_property_create(dev, - DRM_MODE_PROP_ENUM, - "DPMS", 4); - drm_property_add_enum(dev->mode_config.dpms_property, 0, DPMSModeOn, "On"); - drm_property_add_enum(dev->mode_config.dpms_property, 1, DPMSModeStandby, "Standby"); - drm_property_add_enum(dev->mode_config.dpms_property, 2, DPMSModeSuspend, "Suspend"); - drm_property_add_enum(dev->mode_config.dpms_property, 3, DPMSModeOff, "Off"); + + drm_mode_create_standard_output_properties(dev); } EXPORT_SYMBOL(drm_mode_config_init); @@ -2160,15 +2206,16 @@ int drm_mode_output_update_edid_property(struct drm_output *output, unsigned cha EXPORT_SYMBOL(drm_mode_output_update_edid_property); int drm_mode_output_property_set_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) + void *data, struct drm_file *file_priv) { struct drm_mode_output_set_property *out_resp = data; + struct drm_property *property; struct drm_output *output; int ret = -EINVAL; int i; mutex_lock(&dev->mode_config.mutex); - output= idr_find(&dev->mode_config.crtc_idr, out_resp->output_id); + output = idr_find(&dev->mode_config.crtc_idr, out_resp->output_id); if (!output || (output->id != out_resp->output_id)) { goto out; } @@ -2182,8 +2229,35 @@ int drm_mode_output_property_set_ioctl(struct drm_device *dev, goto out; } + property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); + if (!property || (property->id != out_resp->prop_id)) { + goto out; + } + + if (property->flags & DRM_MODE_PROP_IMMUTABLE) + goto out; + + if (property->flags & DRM_MODE_PROP_RANGE) { + if (out_resp->value < property->values[0]) + goto out; + + if (out_resp->value > property->values[1]) + goto out; + } else { + int found = 0; + for (i = 0; i < property->num_values; i++) { + if (property->values[i] == out_resp->value) { + found = 1; + break; + } + } + if (!found) { + goto out; + } + } + if (output->funcs->set_property) - ret = output->funcs->set_property(output, out_resp->prop_id, out_resp->value); + ret = output->funcs->set_property(output, property, out_resp->value); out: mutex_unlock(&dev->mode_config.mutex); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index ad5ecc5d..6b6e1dbf 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -142,11 +142,26 @@ struct drm_display_mode { #define V_CLKDIV2 (1<<13) #define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ + #define DPMSModeOn 0 #define DPMSModeStandby 1 #define DPMSModeSuspend 2 #define DPMSModeOff 3 +#define ConnectorUnknown 0 +#define ConnectorVGA 1 +#define ConnectorDVII 2 +#define ConnectorDVID 3 +#define ConnectorDVIA 4 +#define ConnectorComposite 5 +#define ConnectorSVIDEO 6 +#define ConnectorLVDS 7 +#define ConnectorComponent 8 +#define Connector9PinDIN 9 +#define ConnectorDisplayPort 10 +#define ConnectorHDMIA 11 +#define ConnectorHDMIB 12 + enum drm_output_status { output_status_connected = 1, output_status_disconnected = 2, @@ -396,7 +411,8 @@ struct drm_output_funcs { enum drm_output_status (*detect)(struct drm_output *output); int (*get_modes)(struct drm_output *output); /* JJJ: type checking for properties via property value type */ - bool (*set_property)(struct drm_output *output, int prop, uint64_t val); + bool (*set_property)(struct drm_output *output, struct drm_property *property, + uint64_t val); void (*cleanup)(struct drm_output *output); }; @@ -504,6 +520,8 @@ struct drm_mode_config { struct list_head property_blob_list; struct drm_property *edid_property; struct drm_property *dpms_property; + struct drm_property *connector_type_property; + struct drm_property *connector_num_property; }; struct drm_output *drm_output_create(struct drm_device *dev, @@ -597,5 +615,7 @@ extern int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_output_property_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index f8665be7..98fb9ac8 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -125,6 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_property_set_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 2ab6a27b..722a62c8 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -204,6 +204,19 @@ static int intel_crt_get_modes(struct drm_output *output) return intel_ddc_get_modes(output); } +static bool intel_crt_set_property(struct drm_output *output, + struct drm_property *property, + uint64_t value) +{ + struct drm_device *dev = output->dev; + int i; + + if (property == dev->mode_config.dpms_property) { + intel_crt_dpms(output, (uint32_t)(value & 0xf)); + } + return true; +} + /* * Routines for controlling stuff on the analog port */ @@ -219,6 +232,7 @@ static const struct drm_output_funcs intel_crt_output_funcs = { .detect = intel_crt_detect, .get_modes = intel_crt_get_modes, .cleanup = intel_crt_destroy, + .set_property = intel_crt_set_property, }; void intel_crt_init(struct drm_device *dev) @@ -246,4 +260,5 @@ void intel_crt_init(struct drm_device *dev) output->interlace_allowed = 0; output->doublescan_allowed = 0; + drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA); } diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index e3e4b38a..94232b94 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -499,6 +499,7 @@ void intel_lvds_init(struct drm_device *dev) #endif out: + drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorLVDS); return; failed: diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 51fe43cb..0da57faa 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -950,6 +950,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) struct intel_output *intel_output; struct intel_sdvo_priv *sdvo_priv; struct intel_i2c_chan *i2cbus = NULL; + int connector_type; u8 ch[0x40]; int i; char name[DRM_OUTPUT_LEN]; @@ -1019,24 +1020,28 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; output->subpixel_order = SubPixelHorizontalRGB; name_prefix="RGB"; + connector_type = ConnectorVGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; output->subpixel_order = SubPixelHorizontalRGB; name_prefix="RGB"; + connector_type = ConnectorVGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; output->subpixel_order = SubPixelHorizontalRGB; name_prefix="TMDS"; + connector_type = ConnectorDVID; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; output->subpixel_order = SubPixelHorizontalRGB; name_prefix="TMDS"; + connector_type = ConnectorDVID; } else { @@ -1084,4 +1089,6 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); intel_output->ddc_bus = i2cbus; + + drm_output_attach_property(output, dev->mode_config.connector_type_property, connector_type); } diff --git a/shared-core/drm.h b/shared-core/drm.h index df43802f..f13e36c9 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1118,7 +1118,7 @@ struct drm_mode_mode_cmd { #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) -#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_set_output_property) +#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xA7, struct drm_mode_output_set_property) #define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_blob) #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 4a8c6a17..f1fe64df 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -3,10 +3,13 @@ #include #include #include +#include +#include #include "xf86drm.h" #include "xf86drmMode.h" +int dpms_prop_id = 0; const char* getConnectionText(drmModeConnection conn) { switch (conn) { @@ -72,7 +75,7 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) printf("\tflags: %i\n", props->flags); printf("\tvalues %d: ", props->count_values); for (j = 0; j < props->count_values; j++) - printf("%d ", props->values[j]); + printf("%lld ", props->values[j]); printf("\n\tenums %d: \n", props->count_enums); @@ -86,6 +89,9 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) } } else { + if (!strncmp(props->name, "DPMS", 4)) + dpms_prop_id = props->prop_id; + for (j = 0; j < props->count_enums; j++) { printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); if (output->prop_values[i] == props->enums[j].value) @@ -96,7 +102,7 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) if (props->count_enums && name) { printf("\toutput property name %s %s\n", props->name, name); } else { - printf("\toutput property id %s %i\n", props->name, output->prop_values[i]); + printf("\toutput property id %s %lli\n", props->name, output->prop_values[i]); } } @@ -109,7 +115,7 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) if (mode) printMode(mode); else - printf("\t\tmode: Invalid mode %i\n", output->modes[i]); + printf("\t\tmode: Invalid mode %p\n", &output->modes[i]); } return 0; @@ -123,7 +129,7 @@ int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) printf("\ty : %i\n", crtc->y); printf("\twidth : %i\n", crtc->width); printf("\theight : %i\n", crtc->height); - printf("\tmode : %i\n", crtc->mode); + printf("\tmode : %p\n", &crtc->mode); printf("\tnum outputs : %i\n", crtc->count_outputs); printf("\toutputs : %i\n", crtc->outputs); printf("\tnum possible : %i\n", crtc->count_possibles); @@ -314,6 +320,21 @@ err: return 1; } +int testDPMS(int fd, drmModeResPtr res) +{ + int output_id; + int i; + + for (i = 0; i < res->count_outputs; i++) { + output_id = res->outputs[i]; + /* turn output off */ + drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 3); + sleep(2); + drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 0); + } + return 1; + +} int main(int argc, char **argv) { @@ -343,6 +364,8 @@ int main(int argc, char **argv) testFrameBufferAdd(fd, res); + /* try dpms test */ + testDPMS(fd, res); drmModeFreeResources(res); printf("Ok\n"); -- cgit v1.2.3 From e239882b1e90cba0297118ec7dc432bea06b0bd0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 4 Dec 2007 15:36:36 +0100 Subject: Modesetting Hotplug --- linux-core/drmP.h | 2 + linux-core/drm_bo.c | 1 - linux-core/drm_crtc.c | 54 ++++++++++- linux-core/drm_crtc.h | 1 + linux-core/drm_drv.c | 8 +- linux-core/drm_mm.c | 15 +++ linux-core/i915_drv.c | 5 +- linux-core/intel_crt.c | 10 ++ linux-core/intel_drv.h | 5 + linux-core/intel_fb.c | 45 ++++++++- linux-core/intel_sdvo.c | 76 +++++++++++++++- shared-core/i915_drv.h | 2 + shared-core/i915_init.c | 40 ++++---- shared-core/i915_irq.c | 238 +++++++++++++++++++++++++++++++++++++++++++++--- 14 files changed, 453 insertions(+), 49 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4a0cabc3..5e674b2a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -669,6 +669,7 @@ struct drm_driver { /* FB routines, if present */ int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc); int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc); + int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); struct drm_fence_driver *fence_driver; struct drm_bo_driver *bo_driver; @@ -1210,6 +1211,7 @@ extern int drm_mm_clean(struct drm_mm *mm); extern unsigned long drm_mm_tail_space(struct drm_mm *mm); extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size); extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size); +extern void drm_mm_print(struct drm_mm *mm, const char *name); static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block) { diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7a123dad..068ccf00 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -569,7 +569,6 @@ void drm_putback_buffer_objects(struct drm_device *dev) } EXPORT_SYMBOL(drm_putback_buffer_objects); - /* * Note. The caller has to register (if applicable) * and deregister fence object usage. diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e1b37c0b..ac2f1d42 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -382,6 +382,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) drm_crtc_probe_single_output_modes(output, maxX, maxY); } } +EXPORT_SYMBOL(drm_crtc_probe_output_modes); /** * drm_crtc_set_mode - set a mode @@ -539,7 +540,8 @@ void drm_disable_unused_functions(struct drm_device *dev) crtc->funcs->dpms(crtc, DPMSModeOff); } } - +EXPORT_SYMBOL(drm_disable_unused_functions); + /** * drm_mode_probed_add - add a mode to the specified output's probed mode list * @output: output the new mode @@ -936,7 +938,7 @@ clone: } } } - +EXPORT_SYMBOL(drm_pick_crtcs); /** * drm_initial_config - setup a sane initial output configuration @@ -1122,6 +1124,54 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, return 0; } +/** + * drm_hotplug_stage_two + * @dev DRM device + * @output hotpluged output + * + * LOCKING. + * Caller must hold mode config lock, function might grap struct lock. + * + * Stage two of a hotplug. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output) +{ + int has_config = 0; + + if (output->crtc && output->crtc->desired_mode) { + DRM_DEBUG("drm thinks that output already has a config\n"); + has_config = 1; + } + + drm_crtc_probe_output_modes(dev, 2048, 2048); + + if (!has_config) + drm_pick_crtcs(dev); + + if (!output->crtc || !output->crtc->desired_mode) { + DRM_DEBUG("could not find a desired mode or crtc for output\n"); + return 1; + } + + /* We should realy check if there is a fb using this crtc */ + if (!has_config) + dev->driver->fb_probe(dev, output->crtc); + else { + dev->driver->fb_resize(dev, output->crtc); + + if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) + DRM_ERROR("failed to set mode after hotplug\n"); + } + + drm_disable_unused_functions(dev); + + return 0; +} +EXPORT_SYMBOL(drm_hotplug_stage_two); + /** * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo * @out: drm_mode_modeinfo struct to return to the user diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 6b6e1dbf..ce502062 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -577,6 +577,7 @@ extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); +extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output); extern int drm_output_attach_property(struct drm_output *output, struct drm_property *property, uint64_t init_val); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 0b9ce30a..ab02c659 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -181,6 +181,7 @@ int drm_lastclose(struct drm_device * dev) DRM_DEBUG("\n"); +/* return 0; */ /* * We can't do much about this function failing. */ @@ -195,8 +196,8 @@ int drm_lastclose(struct drm_device * dev) dev->unique_len = 0; } - if (dev->irq_enabled) - drm_irq_uninstall(dev); +/* if (dev->irq_enabled) + drm_irq_uninstall(dev); */ /* Free drawable information memory */ mutex_lock(&dev->struct_mutex); @@ -251,12 +252,13 @@ int drm_lastclose(struct drm_device * dev) drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS); } + /* list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { if (!(r_list->map->flags & _DRM_DRIVER)) { drm_rmmap_locked(dev, r_list->map); r_list = NULL; } - } + }*/ if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) { for (i = 0; i < dev->queue_count; i++) { diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 59110293..28726a65 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -294,3 +294,18 @@ void drm_mm_takedown(struct drm_mm * mm) } EXPORT_SYMBOL(drm_mm_takedown); + +void drm_mm_print(struct drm_mm *mm, const char *name) +{ + struct list_head *list; + const struct list_head *mm_stack = &mm->ml_entry; + struct drm_mm_node *entry; + + DRM_DEBUG("Memory usage for '%s'\n", name ? name : "unknown"); + list_for_each(list, mm_stack) { + entry = list_entry(list, struct drm_mm_node, ml_entry); + DRM_DEBUG("\t0x%08lx %li %s pages\n", entry->start, entry->size, + entry->free ? "free" : "used"); + } +} +EXPORT_SYMBOL(drm_mm_print); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index fb4149c4..598039dc 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -541,8 +541,8 @@ static struct drm_driver driver = { DRIVER_IRQ_VBL2, .load = i915_driver_load, .unload = i915_driver_unload, - .lastclose = i915_driver_lastclose, - .preclose = i915_driver_preclose, +/* .lastclose = i915_driver_lastclose, + .preclose = i915_driver_preclose, */ .suspend = i915_suspend, .resume = i915_resume, .device_is_agp = i915_driver_device_is_agp, @@ -557,6 +557,7 @@ static struct drm_driver driver = { .get_reg_ofs = drm_core_get_reg_ofs, .fb_probe = intelfb_probe, .fb_remove = intelfb_remove, + .fb_resize = intelfb_resize, .ioctls = i915_ioctls, .fops = { .owner = THIS_MODULE, diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 722a62c8..864b1a25 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -142,6 +142,7 @@ static bool intel_crt_detect_hotplug(struct drm_output *output) struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 temp; +#if 1 unsigned long timeout = jiffies + msecs_to_jiffies(1000); temp = I915_READ(PORT_HOTPLUG_EN); @@ -160,6 +161,15 @@ static bool intel_crt_detect_hotplug(struct drm_output *output) return true; return false; +#else + temp = I915_READ(PORT_HOTPLUG_STAT); + DRM_DEBUG("HST 0x%08x\n", temp); + + if (temp & (1 << 8) && temp & (1 << 9)) + return true; + + return false; +#endif } static bool intel_crt_detect_ddc(struct drm_output *output) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 7de4b924..06335b18 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -76,7 +76,12 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, extern void intel_wait_for_vblank(struct drm_device *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); +extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB); +extern int intel_sdvo_supports_hotplug(struct drm_output *output); +extern void intel_sdvo_set_hotplug(struct drm_output *output, int enable); + extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc); +extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 32c7dc31..b67c0fcc 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -489,6 +489,46 @@ static struct fb_ops intelfb_ops = { .fb_imageblit = cfb_imageblit, //intelfb_imageblit, }; +/** + * Curretly it is assumed that the old framebuffer is reused. + * + * LOCKING + * caller should hold the mode config lock. + * + */ +int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_display_mode *mode = crtc->desired_mode; + + fb = crtc->fb; + if (!fb) + return 1; + + info = fb->fbdev; + if (!info) + return 1; + + if (!mode) + return 1; + + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + + return 0; +} +EXPORT_SYMBOL(intelfb_resize); + int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) { struct fb_info *info; @@ -512,8 +552,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) } crtc->fb = fb; - fb->width = crtc->desired_mode->hdisplay; - fb->height = crtc->desired_mode->vdisplay; + /* To allow resizeing without swapping buffers */ + fb->width = 2048;/* crtc->desired_mode->hdisplay; */ + fb->height = 2048;/* crtc->desired_mode->vdisplay; */ fb->bits_per_pixel = 32; fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 0da57faa..d2d00e2a 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -60,7 +60,7 @@ struct intel_sdvo_priv { * SDVOB and SDVOC to work around apparent hardware issues (according to * comments in the BIOS). */ -static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) +void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -69,10 +69,12 @@ static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) u32 bval = val, cval = val; int i; - if (sdvo_priv->output_device == SDVOB) + if (sdvo_priv->output_device == SDVOB) { cval = I915_READ(SDVOC); - else - bval = I915_READ(SDVOB); + bval = bval | (1 << 26); + } else { + bval = I915_READ(SDVOB) | (1 << 26); + } /* * Write the registers twice for luck. Sometimes, * writing them only once doesn't appear to 'stick'. @@ -879,6 +881,72 @@ void intel_sdvo_dump(void) } +struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB) +{ + struct drm_output *output = 0; + struct intel_output *iout = 0; + struct intel_sdvo_priv *sdvo; + + /* find the sdvo output */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + iout = output->driver_private; + + if (iout->type != INTEL_OUTPUT_SDVO) + continue; + + sdvo = iout->dev_priv; + + if (sdvo->output_device == SDVOB && sdvoB) + return output; + + if (sdvo->output_device == SDVOC && !sdvoB) + return output; + + } + + return 0; +} + +int intel_sdvo_supports_hotplug(struct drm_output *output) +{ + u8 response[2]; + u8 status; + DRM_DEBUG("\n"); + + if (!output) + return 0; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); + status = intel_sdvo_read_response(output, &response, 2); + + if (response[0] !=0) + return 1; + + return 0; +} + +void intel_sdvo_set_hotplug(struct drm_output *output, int on) +{ + u8 response[2]; + u8 status; + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); + intel_sdvo_read_response(output, &response, 2); + + if (on) { + intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); + status = intel_sdvo_read_response(output, &response, 2); + + intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); + } else { + response[0] = 0; + response[1] = 0; + intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); + } + + intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); + intel_sdvo_read_response(output, &response, 2); +} static enum drm_output_status intel_sdvo_detect(struct drm_output *output) { diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index d9e86de9..45b7786a 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -135,6 +135,8 @@ struct drm_i915_private { uint32_t irq_enable_reg; int irq_enabled; + struct workqueue_struct *wq; + #ifdef I915_HAVE_FENCE uint32_t flush_sequence; uint32_t flush_flags; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 3b43c722..588cd17e 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -30,7 +30,7 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, u16 tmp = 0; unsigned long overhead; - bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + bridge_dev = pci_find_slot(0, PCI_DEVFN(0,0)); if (!bridge_dev) { DRM_ERROR("bridge device not found\n"); return -1; @@ -249,9 +249,20 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } DRM_DEBUG("Enabled hardware status page\n"); + dev_priv->wq = create_singlethread_workqueue("i915"); + if (dev_priv == 0) { + DRM_DEBUG("Error\n"); + } + + intel_modeset_init(dev); drm_initial_config(dev, false); + drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); + drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); + + drm_irq_install(dev); + return 0; } @@ -259,9 +270,15 @@ int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + I915_WRITE(LP_RING + RING_LEN, 0); + + intel_modeset_cleanup(dev); + +#if 0 if (dev_priv->ring.virtual_start) { drm_core_ioremapfree(&dev_priv->ring.map, dev); } +#endif if (dev_priv->status_page_dmah) { drm_pci_free(dev, dev_priv->status_page_dmah); @@ -278,10 +295,6 @@ int i915_driver_unload(struct drm_device *dev) I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); } - I915_WRITE(LP_RING + RING_LEN, 0); - - intel_modeset_cleanup(dev); - drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, dev_priv->ring.virtual_start); @@ -310,20 +323,3 @@ int i915_driver_unload(struct drm_device *dev) dev->dev_private = NULL; return 0; } - -void i915_driver_lastclose(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - i915_do_cleanup_pageflip(dev); - //i915_mem_takedown(&(dev_priv->agp_heap)); - i915_dma_cleanup(dev); -} - -void i915_driver_preclose(struct drm_device *dev, struct drm_file *filp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - //i915_mem_release(dev, filp, dev_priv->agp_heap); -} - diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4312eae2..4508d146 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -31,6 +31,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#include "intel_drv.h" + #define USER_INT_FLAG (1<<1) #define VSYNC_PIPEB_FLAG (1<<5) #define VSYNC_PIPEA_FLAG (1<<7) @@ -301,27 +303,174 @@ static void i915_vblank_tasklet(struct drm_device *dev) } } +static struct drm_device *hotplug_dev; +static int hotplug_cmd = 0; +static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; + +static void i915_hotplug_crt(struct drm_device *dev) +{ + struct drm_output *output; + struct intel_output *iout; + + mutex_lock(&dev->mode_config.mutex); + + /* find the crt output */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + iout = output->driver_private; + if (iout->type == INTEL_OUTPUT_ANALOG) + break; + else + iout = 0; + } + + if (iout == 0) + goto unlock; + + drm_hotplug_stage_two(dev, output); + +unlock: + mutex_unlock(&dev->mode_config.mutex); +} + +static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) +{ + struct drm_output *output = 0; + enum drm_output_status status; + + mutex_lock(&dev->mode_config.mutex); + + output = intel_sdvo_find(dev, sdvoB); + + if (!output) { + DRM_ERROR("could not find sdvo%s output\n", sdvoB ? "B" : "C"); + goto unlock; + } + + status = output->funcs->detect(output); + + if (status != output_status_connected) + DRM_DEBUG("disconnect or unkown we don't do anything then\n"); + else + drm_hotplug_stage_two(dev, output); + + /* wierd hw bug, sdvo stop sending interupts */ + intel_sdvo_set_hotplug(output, 1); + +unlock: + mutex_unlock(&dev->mode_config.mutex); +} + +static void i915_hotplug_work_func(struct work_struct *work) +{ + struct drm_device *dev = hotplug_dev; + int crt; + int sdvoB; + int sdvoC; + + spin_lock(&hotplug_lock); + crt = hotplug_cmd & 1; + sdvoB = hotplug_cmd & 4; + sdvoC = hotplug_cmd & 8; + hotplug_cmd = 0; + spin_unlock(&hotplug_lock); + + if (crt) + i915_hotplug_crt(dev); + + if (sdvoB) + i915_hotplug_sdvo(dev, 1); + + if (sdvoC) + i915_hotplug_sdvo(dev, 0); + +} + +static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) +{ + static DECLARE_WORK(hotplug, i915_hotplug_work_func); + struct drm_i915_private *dev_priv = dev->dev_private; + + hotplug_dev = dev; + + if (stat & (1 << 11)) { + DRM_DEBUG("CRT event\n"); + + if (stat & (1 << 9) && stat & (1 << 8)) { + spin_lock(&hotplug_lock); + hotplug_cmd |= 1; + spin_unlock(&hotplug_lock); + } else { + /* handle crt disconnects */ + } + } + + if (stat & (1 << 6)) { + DRM_DEBUG("sDVOB event\n"); + + spin_lock(&hotplug_lock); + hotplug_cmd |= 4; + spin_unlock(&hotplug_lock); + } + + if (stat & (1 << 7)) { + DRM_DEBUG("sDVOC event\n"); + + spin_lock(&hotplug_lock); + hotplug_cmd |= 8; + spin_unlock(&hotplug_lock); + } + + queue_work(dev_priv->wq, &hotplug); + + return 0; +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - u16 temp; + u32 temp = 0; + u32 temp2; u32 pipea_stats, pipeb_stats; pipea_stats = I915_READ(I915REG_PIPEASTAT); pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - temp = I915_READ16(I915REG_INT_IDENTITY_R); + /* On i8xx hw the IIR and IER are 16bit on i9xx its 32bit */ + if (IS_I9XX(dev)) { + temp = I915_READ(I915REG_INT_IDENTITY_R); + } else { + temp = I915_READ16(I915REG_INT_IDENTITY_R); + } + + temp2 = temp; temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG); +#if 0 + /* ugly despamification of pipeb event irq */ + if (temp & (0xFFFFFFF ^ ((1 << 5) | (1 << 7)))) { + DRM_DEBUG("IIR %08x\n", temp2); + DRM_DEBUG("MSK %08x\n", dev_priv->irq_enable_reg | USER_INT_FLAG); + DRM_DEBUG("M&I %08x\n", temp); + DRM_DEBUG("HOT %08x\n", I915_READ(PORT_HOTPLUG_STAT)); + } +#else #if 0 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); #endif +#endif + if (temp == 0) return IRQ_NONE; - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); - (void) I915_READ16(I915REG_INT_IDENTITY_R); + if (IS_I9XX(dev)) { + I915_WRITE(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ(I915REG_INT_IDENTITY_R); + } else { + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ16(I915REG_INT_IDENTITY_R); + } + DRM_READMEMORYBARRIER(); dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -362,6 +511,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_VBLANK_CLEAR); } + /* for now lest just ack it */ + if (temp & (1 << 17)) { + DRM_DEBUG("Hotplug event recived\n"); + + temp2 = I915_READ(PORT_HOTPLUG_STAT); + + i915_run_hotplug_tasklet(dev, temp2); + + I915_WRITE(PORT_HOTPLUG_STAT,temp2); + } + return IRQ_HANDLED; } @@ -536,6 +696,7 @@ int i915_irq_wait(struct drm_device *dev, void *data, void i915_enable_interrupt (struct drm_device *dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_output *o; dev_priv->irq_enable_reg = USER_INT_FLAG; @@ -544,7 +705,41 @@ void i915_enable_interrupt (struct drm_device *dev) if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + if (IS_I9XX(dev) && dev->mode_config.funcs) { + dev_priv->irq_enable_reg |= (1 << 17); + + /* Activate the CRT */ + I915_WRITE(PORT_HOTPLUG_EN, (1 << 9)); + + /* SDVOB */ + o = intel_sdvo_find(dev, 1); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + I915_WRITE(PORT_HOTPLUG_EN, (1 << 26)); + } + + /* SDVOC */ + o = intel_sdvo_find(dev, 0); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + I915_WRITE(PORT_HOTPLUG_EN, (1 << 25)); + } + + } + + if (IS_I9XX(dev)) { + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } else { + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } + + DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN)); + DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT)); + DRM_DEBUG("IER %08x\n",I915_READ(I915REG_INT_ENABLE_R)); + DRM_DEBUG("SDB %08x\n",I915_READ(SDVOB)); + + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + dev_priv->irq_enabled = 1; } @@ -749,8 +944,14 @@ void i915_driver_irq_preinstall(struct drm_device * dev) struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; I915_WRITE16(I915REG_HWSTAM, 0xeffe); - I915_WRITE16(I915REG_INT_MASK_R, 0x0); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + if (IS_I9XX(dev)) { + I915_WRITE(I915REG_INT_MASK_R, 0x0); + I915_WRITE(I915REG_INT_ENABLE_R, 0x0); + } else { + I915_WRITE16(I915REG_INT_MASK_R, 0x0); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + } + } void i915_driver_irq_postinstall(struct drm_device * dev) @@ -777,16 +978,27 @@ void i915_driver_irq_postinstall(struct drm_device * dev) void i915_driver_irq_uninstall(struct drm_device * dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - u16 temp; + u32 temp; if (!dev_priv) return; dev_priv->irq_enabled = 0; - I915_WRITE16(I915REG_HWSTAM, 0xffff); - I915_WRITE16(I915REG_INT_MASK_R, 0xffff); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); - temp = I915_READ16(I915REG_INT_IDENTITY_R); - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + + if(IS_I9XX(dev)) { + I915_WRITE(I915REG_HWSTAM, 0xffffffff); + I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); + I915_WRITE(I915REG_INT_ENABLE_R, 0x0); + + temp = I915_READ(I915REG_INT_IDENTITY_R); + I915_WRITE(I915REG_INT_IDENTITY_R, temp); + } else { + I915_WRITE16(I915REG_HWSTAM, 0xffff); + I915_WRITE16(I915REG_INT_MASK_R, 0xffff); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + + temp = I915_READ16(I915REG_INT_IDENTITY_R); + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + } } -- cgit v1.2.3 From bdbc34e297bd7e4cb036df6244dfb0d816eed36d Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 18 Dec 2007 02:09:48 +0100 Subject: Fix and cleanup of Hotplug --- linux-core/drm_crtc.c | 2 +- linux-core/intel_sdvo.c | 17 +++++++++++++++-- shared-core/i915_irq.c | 42 +++++++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ac2f1d42..4397b867 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1142,7 +1142,7 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output) int has_config = 0; if (output->crtc && output->crtc->desired_mode) { - DRM_DEBUG("drm thinks that output already has a config\n"); + DRM_DEBUG("drm thinks that the output already has a config\n"); has_config = 1; } diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index d2d00e2a..1d7d0b7d 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -53,6 +53,7 @@ struct intel_sdvo_priv { struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2; struct intel_sdvo_dtd save_output_dtd[16]; u32 save_SDVOX; + int hotplug_enabled; }; /** @@ -71,9 +72,14 @@ void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) if (sdvo_priv->output_device == SDVOB) { cval = I915_READ(SDVOC); - bval = bval | (1 << 26); + + if (sdvo_priv->hotplug_enabled) + bval = bval | (1 << 26); } else { - bval = I915_READ(SDVOB) | (1 << 26); + bval = I915_READ(SDVOB); + + if (sdvo_priv->hotplug_enabled) + cval = cval | (1 << 26); } /* * Write the registers twice for luck. Sometimes, @@ -927,6 +933,8 @@ int intel_sdvo_supports_hotplug(struct drm_output *output) void intel_sdvo_set_hotplug(struct drm_output *output, int on) { + struct intel_output *intel_output = output->driver_private; + struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u8 response[2]; u8 status; @@ -934,11 +942,15 @@ void intel_sdvo_set_hotplug(struct drm_output *output, int on) intel_sdvo_read_response(output, &response, 2); if (on) { + sdvo_priv->hotplug_enabled = 1; + intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); status = intel_sdvo_read_response(output, &response, 2); intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); } else { + sdvo_priv->hotplug_enabled = 0; + response[0] = 0; response[1] = 0; intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); @@ -1064,6 +1076,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) } sdvo_priv->output_device = output_device; + sdvo_priv->hotplug_enabled = 0; intel_output->i2c_bus = i2cbus; intel_output->dev_priv = sdvo_priv; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4508d146..ac5361f2 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -36,6 +36,7 @@ #define USER_INT_FLAG (1<<1) #define VSYNC_PIPEB_FLAG (1<<5) #define VSYNC_PIPEA_FLAG (1<<7) +#define HOTPLUG_FLAG (1 << 17) #define MAX_NOPID ((u32)~0) @@ -303,6 +304,10 @@ static void i915_vblank_tasklet(struct drm_device *dev) } } +#define HOTPLUG_CMD_CRT 1 +#define HOTPLUG_CMD_SDVOB 4 +#define HOTPLUG_CMD_SDVOC 8 + static struct drm_device *hotplug_dev; static int hotplug_cmd = 0; static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; @@ -359,7 +364,10 @@ static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) unlock: mutex_unlock(&dev->mode_config.mutex); } - +/* + * This code is called in a more safe envirmoent to handle the hotplugs. + * Add code here for hotplug love to userspace. + */ static void i915_hotplug_work_func(struct work_struct *work) { struct drm_device *dev = hotplug_dev; @@ -368,9 +376,9 @@ static void i915_hotplug_work_func(struct work_struct *work) int sdvoC; spin_lock(&hotplug_lock); - crt = hotplug_cmd & 1; - sdvoB = hotplug_cmd & 4; - sdvoC = hotplug_cmd & 8; + crt = hotplug_cmd & HOTPLUG_CMD_CRT; + sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; + sdvoC = hotplug_cmd & HOTPLUG_CMD_SDVOC; hotplug_cmd = 0; spin_unlock(&hotplug_lock); @@ -392,31 +400,31 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) hotplug_dev = dev; - if (stat & (1 << 11)) { + if (stat & CRT_HOTPLUG_INT_STATUS) { DRM_DEBUG("CRT event\n"); - if (stat & (1 << 9) && stat & (1 << 8)) { + if (stat & CRT_HOTPLUG_MONITOR_MASK) { spin_lock(&hotplug_lock); - hotplug_cmd |= 1; + hotplug_cmd |= HOTPLUG_CMD_CRT; spin_unlock(&hotplug_lock); } else { /* handle crt disconnects */ } } - if (stat & (1 << 6)) { + if (stat & SDVOB_HOTPLUG_INT_STATUS) { DRM_DEBUG("sDVOB event\n"); spin_lock(&hotplug_lock); - hotplug_cmd |= 4; + hotplug_cmd |= HOTPLUG_CMD_SDVOB; spin_unlock(&hotplug_lock); } - if (stat & (1 << 7)) { + if (stat & SDVOC_HOTPLUG_INT_STATUS) { DRM_DEBUG("sDVOC event\n"); spin_lock(&hotplug_lock); - hotplug_cmd |= 8; + hotplug_cmd |= HOTPLUG_CMD_SDVOC; spin_unlock(&hotplug_lock); } @@ -513,7 +521,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) /* for now lest just ack it */ if (temp & (1 << 17)) { - DRM_DEBUG("Hotplug event recived\n"); + DRM_DEBUG("Hotplug event received\n"); temp2 = I915_READ(PORT_HOTPLUG_STAT); @@ -705,24 +713,24 @@ void i915_enable_interrupt (struct drm_device *dev) if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; - if (IS_I9XX(dev) && dev->mode_config.funcs) { - dev_priv->irq_enable_reg |= (1 << 17); + if (IS_I9XX(dev) && dev->mode_config.num_output) { + dev_priv->irq_enable_reg |= HOTPLUG_FLAG; /* Activate the CRT */ - I915_WRITE(PORT_HOTPLUG_EN, (1 << 9)); + I915_WRITE(PORT_HOTPLUG_EN, CRT_HOTPLUG_INT_EN); /* SDVOB */ o = intel_sdvo_find(dev, 1); if (o && intel_sdvo_supports_hotplug(o)) { intel_sdvo_set_hotplug(o, 1); - I915_WRITE(PORT_HOTPLUG_EN, (1 << 26)); + I915_WRITE(PORT_HOTPLUG_EN, SDVOB_HOTPLUG_INT_EN); } /* SDVOC */ o = intel_sdvo_find(dev, 0); if (o && intel_sdvo_supports_hotplug(o)) { intel_sdvo_set_hotplug(o, 1); - I915_WRITE(PORT_HOTPLUG_EN, (1 << 25)); + I915_WRITE(PORT_HOTPLUG_EN, SDVOC_HOTPLUG_INT_EN); } } -- cgit v1.2.3 From ea915c77e169a50ca7dc557512212eafa93e2205 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 18 Dec 2007 02:52:09 +0100 Subject: Fixed build --- shared-core/i915_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 588cd17e..ebdcd5d3 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -30,7 +30,7 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, u16 tmp = 0; unsigned long overhead; - bridge_dev = pci_find_slot(0, PCI_DEVFN(0,0)); + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); if (!bridge_dev) { DRM_ERROR("bridge device not found\n"); return -1; -- cgit v1.2.3 From b13dc383df85d75cb1ea422f4d13efc2a4a8a732 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 18 Dec 2007 17:41:20 +1100 Subject: remove output names --- libdrm/xf86drmMode.c | 6 +++-- libdrm/xf86drmMode.h | 3 ++- linux-core/drm_bo.c | 2 +- linux-core/drm_crtc.c | 68 +++++++++++++++++++------------------------------ linux-core/drm_crtc.h | 12 +++++---- linux-core/drm_edid.c | 6 ++--- linux-core/intel_crt.c | 3 ++- linux-core/intel_lvds.c | 3 ++- linux-core/intel_sdvo.c | 31 +++++++++------------- shared-core/drm.h | 9 ++++++- shared-core/i915_init.c | 4 +-- tests/mode/modetest.c | 2 +- 12 files changed, 70 insertions(+), 79 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 726c55ab..0edb1d7d 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -328,6 +328,8 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) drmModeOutputPtr r = NULL; out.output = output_id; + out.output_type_id = 0; + out.output_type = 0; out.count_crtcs = 0; out.crtcs = 0; out.count_clones = 0; @@ -372,8 +374,8 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) r->props = drmAllocCpy(U642VOID(out.props_ptr), out.count_props, sizeof(uint32_t)); r->prop_values = drmAllocCpy(U642VOID(out.prop_values_ptr), out.count_props, sizeof(uint64_t)); r->modes = drmAllocCpy(U642VOID(out.modes_ptr), out.count_modes, sizeof(struct drm_mode_modeinfo)); - strncpy(r->name, out.name, DRM_OUTPUT_NAME_LEN); - r->name[DRM_OUTPUT_NAME_LEN-1] = 0; + r->output_type = out.output_type; + r->output_type_id = out.output_type_id; err_allocs: drmFree(U642VOID(out.prop_values_ptr)); diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 05b61bc8..e2dda8ac 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -125,7 +125,8 @@ typedef struct _drmModeOutput { unsigned int output_id; unsigned int crtc; /**< Crtc currently connected to */ - unsigned char name[DRM_OUTPUT_NAME_LEN]; + unsigned int output_type; + unsigned int output_type_id; drmModeConnection connection; uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ drmModeSubPixel subpixel; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7a123dad..c89d6608 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1650,7 +1650,7 @@ int drm_buffer_object_create(struct drm_device *dev, size += buffer_start & ~PAGE_MASK; num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; if (num_pages == 0) { - DRM_ERROR("Illegal buffer object size.\n"); + DRM_ERROR("Illegal buffer object size %d.\n", size); return -EINVAL; } diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e1b37c0b..9a840ea1 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -58,7 +58,22 @@ static struct drm_prop_enum_list drm_conn_enum_list[] = { ConnectorHDMIA, "HDMI Type A" }, { ConnectorHDMIB, "HDMI Type B" }, }; +static struct drm_prop_enum_list drm_output_enum_list[] = +{ { DRM_MODE_OUTPUT_NONE, "None" }, + { DRM_MODE_OUTPUT_DAC, "DAC" }, + { DRM_MODE_OUTPUT_TMDS, "TMDS" }, + { DRM_MODE_OUTPUT_LVDS, "LVDS" }, + { DRM_MODE_OUTPUT_TVDAC, "TV" }, +}; +char *drm_get_output_name(struct drm_output *output) +{ + static char buf[32]; + + snprintf(buf, 32, "%s-%d", drm_output_enum_list[output->output_type].name, + output->output_type_id); + return buf; +} /** * drm_idr_get - allocate a new identifier @@ -322,7 +337,7 @@ void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int output->status = (*output->funcs->detect)(output); if (output->status == output_status_disconnected) { - DRM_DEBUG("%s is disconnected\n", output->name); + DRM_DEBUG("%s is disconnected\n", drm_get_output_name(output)); /* TODO set EDID to NULL */ return; } @@ -347,7 +362,7 @@ void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int if (list_empty(&output->modes)) { struct drm_display_mode *stdmode; - DRM_DEBUG("No valid modes on %s\n", output->name); + DRM_DEBUG("No valid modes on %s\n", drm_get_output_name(output)); /* Should we do this here ??? * When no valid EDID modes are available we end up @@ -360,12 +375,12 @@ void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int &output->modes); DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", - output->name); + drm_get_output_name(output)); } drm_mode_sort(&output->modes); - DRM_DEBUG("Probed modes for %s\n", output->name); + DRM_DEBUG("Probed modes for %s\n", drm_get_output_name(output)); list_for_each_entry_safe(mode, t, &output->modes, head) { mode->vrefresh = drm_mode_vrefresh(mode); @@ -472,7 +487,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, if (output->crtc != crtc) continue; - DRM_INFO("%s: set mode %s %x\n", output->name, mode->name, mode->mode_id); + DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id); output->funcs->mode_set(output, mode, adjusted_mode); } @@ -591,7 +606,7 @@ EXPORT_SYMBOL(drm_mode_remove); */ struct drm_output *drm_output_create(struct drm_device *dev, const struct drm_output_funcs *funcs, - const char *name) + int output_type) { struct drm_output *output = NULL; @@ -602,9 +617,8 @@ struct drm_output *drm_output_create(struct drm_device *dev, output->dev = dev; output->funcs = funcs; output->id = drm_idr_get(dev, output); - if (name) - strncpy(output->name, name, DRM_OUTPUT_LEN); - output->name[DRM_OUTPUT_LEN - 1] = 0; + output->output_type = output_type; + output->output_type_id = 1; /* TODO */ output->subpixel_order = SubPixelUnknown; INIT_LIST_HEAD(&output->user_modes); INIT_LIST_HEAD(&output->probed_modes); @@ -663,35 +677,6 @@ void drm_output_destroy(struct drm_output *output) } EXPORT_SYMBOL(drm_output_destroy); -/** - * drm_output_rename - rename an output - * @output: output to rename - * @name: new user visible name - * - * LOCKING: - * None. - * - * Simply stuff a new name into @output's name field, based on @name. - * - * RETURNS: - * True if the name was changed, false otherwise. - */ -bool drm_output_rename(struct drm_output *output, const char *name) -{ - if (!name) - return false; - - strncpy(output->name, name, DRM_OUTPUT_LEN); - output->name[DRM_OUTPUT_LEN - 1] = 0; - - DRM_DEBUG("Changed name to %s\n", output->name); -// drm_output_set_monitor(output); -// if (drm_output_ignored(output)) -// return FALSE; - - return TRUE; -} -EXPORT_SYMBOL(drm_output_rename); /** * drm_mode_create - create a new display mode @@ -912,7 +897,7 @@ static void drm_pick_crtcs (struct drm_device *dev) list_for_each_entry(modes_equal, &output_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) { - printk("Cloning %s (0x%lx) to %s (0x%lx)\n",output->name,output->possible_clones,output_equal->name,output_equal->possible_clones); + printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones); assigned = 0; goto clone; } @@ -1408,9 +1393,8 @@ int drm_mode_getoutput(struct drm_device *dev, drm_crtc_probe_single_output_modes(output, dev->mode_config.max_width, dev->mode_config.max_height); } - strncpy(out_resp->name, output->name, DRM_OUTPUT_NAME_LEN); - out_resp->name[DRM_OUTPUT_NAME_LEN-1] = 0; - + out_resp->output_type = output->output_type; + out_resp->output_type_id = output->output_type_id; out_resp->mm_width = output->mm_width; out_resp->mm_height = output->mm_height; out_resp->subpixel = output->subpixel_order; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 6b6e1dbf..dbb41867 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -433,7 +433,6 @@ struct drm_output_funcs { * @subpixel_order: for this output * @mm_width: displayable width of output in mm * @mm_height: displayable height of output in mm - * @name: name of output (should be one of a few standard names) * @funcs: output control functions * @driver_private: private driver data * @@ -447,6 +446,9 @@ struct drm_output { struct list_head head; struct drm_crtc *crtc; int id; /* idr assigned */ + + int output_type; + int output_type_id; unsigned long possible_crtcs; unsigned long possible_clones; bool interlace_allowed; @@ -467,8 +469,7 @@ struct drm_output { enum subpixel_order subpixel_order; int mm_width, mm_height; struct drm_display_info *monitor_info; /* if any */ - char name[DRM_OUTPUT_LEN]; - const struct drm_output_funcs *funcs; + const struct drm_output_funcs *funcs; void *driver_private; struct list_head user_modes; @@ -526,9 +527,10 @@ struct drm_mode_config { struct drm_output *drm_output_create(struct drm_device *dev, const struct drm_output_funcs *funcs, - const char *name); + int type); + +extern char *drm_get_output_name(struct drm_output *output); extern void drm_output_destroy(struct drm_output *output); -extern bool drm_output_rename(struct drm_output *output, const char *name); extern void drm_fb_release(struct file *filp); extern struct edid *drm_get_edid(struct drm_output *output, diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 7068cef3..41aa8f5e 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -443,12 +443,12 @@ struct edid *drm_get_edid(struct drm_output *output, edid = (struct edid *)drm_ddc_read(adapter); if (!edid) { dev_warn(&output->dev->pdev->dev, "%s: no EDID data\n", - output->name); + drm_get_output_name(output)); return NULL; } if (!edid_valid(edid)) { dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", - output->name); + drm_get_output_name(output)); kfree(edid); return NULL; } @@ -474,7 +474,7 @@ int drm_add_edid_modes(struct drm_output *output, struct edid *edid) } if (!edid_valid(edid)) { dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", - output->name); + drm_get_output_name(output)); return 0; } num_modes += add_established_modes(output, edid); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 722a62c8..74e3dcd6 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -240,7 +240,8 @@ void intel_crt_init(struct drm_device *dev) struct drm_output *output; struct intel_output *intel_output; - output = drm_output_create(dev, &intel_crt_output_funcs, "VGA"); + output = drm_output_create(dev, &intel_crt_output_funcs, + DRM_MODE_OUTPUT_DAC); intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) { diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 94232b94..80f77af6 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -372,7 +372,8 @@ void intel_lvds_init(struct drm_device *dev) u32 lvds; int pipe; - output = drm_output_create(dev, &intel_lvds_output_funcs, "LVDS"); + output = drm_output_create(dev, &intel_lvds_output_funcs, + DRM_MODE_OUTPUT_LVDS); if (!output) return; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 0da57faa..7f55829b 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -953,12 +953,10 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) int connector_type; u8 ch[0x40]; int i; - char name[DRM_OUTPUT_LEN]; - char *name_prefix; - char *name_suffix; - + int output_type, output_id; - output = drm_output_create(dev, &intel_sdvo_output_funcs, NULL); + output = drm_output_create(dev, &intel_sdvo_output_funcs, + DRM_MODE_OUTPUT_NONE); if (!output) return; @@ -988,10 +986,10 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) sdvo_priv->i2c_bus = i2cbus; if (output_device == SDVOB) { - name_suffix = "-1"; + output_id = 1; sdvo_priv->i2c_bus->slave_addr = 0x38; } else { - name_suffix = "-2"; + output_id = 2; sdvo_priv->i2c_bus->slave_addr = 0x39; } @@ -1019,28 +1017,28 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="RGB"; + output_type = DRM_MODE_OUTPUT_DAC; connector_type = ConnectorVGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="RGB"; + output_type = DRM_MODE_OUTPUT_DAC; connector_type = ConnectorVGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="TMDS"; + output_type = DRM_MODE_OUTPUT_TMDS; connector_type = ConnectorDVID; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; output->subpixel_order = SubPixelHorizontalRGB; - name_prefix="TMDS"; + output_type = DRM_MODE_OUTPUT_TMDS; connector_type = ConnectorDVID; } else @@ -1054,14 +1052,9 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) drm_output_destroy(output); return; } - strcpy (name, name_prefix); - strcat (name, name_suffix); - if (!drm_output_rename(output, name)) - { - drm_output_destroy(output); - return; - } - + + output->output_type = output_type; + output->output_type_id = output_id; /* Set the input timing to the screen. Assume always input 0. */ intel_sdvo_set_target_input(output, true, false); diff --git a/shared-core/drm.h b/shared-core/drm.h index 9a8dc1d2..f8d44048 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -950,6 +950,12 @@ struct drm_mode_crtc { struct drm_mode_modeinfo mode; }; +#define DRM_MODE_OUTPUT_NONE 0 +#define DRM_MODE_OUTPUT_DAC 1 +#define DRM_MODE_OUTPUT_TMDS 2 +#define DRM_MODE_OUTPUT_LVDS 3 +#define DRM_MODE_OUTPUT_TVDAC 4 + struct drm_mode_get_output { uint64_t modes_ptr; @@ -960,7 +966,8 @@ struct drm_mode_get_output { int count_props; unsigned int output; /**< Id */ unsigned int crtc; /**< Id of crtc */ - unsigned char name[DRM_OUTPUT_NAME_LEN]; + unsigned int output_type; + unsigned int output_type_id; unsigned int connection; unsigned int mm_width, mm_height; /**< HxW in millimeters */ diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 3b43c722..e44cb930 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -188,8 +188,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT | - DRM_BO_HINT_DONT_FENCE, 0, 0x1, 0, + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0x1, 0, &dev_priv->ring_buffer); if (ret < 0) { DRM_ERROR("Unable to allocate or pin ring buffer\n"); diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index f1fe64df..bd8372dc 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -54,7 +54,7 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) drmModePropertyPtr props; unsigned char *name = NULL; - printf("Output: %s\n", output->name); + printf("Output: %d-%d\n", output->output_type, output->output_type_id); printf("\tid : %i\n", id); printf("\tcrtc id : %i\n", output->crtc); printf("\tconn : %s\n", getConnectionText(output->connection)); -- cgit v1.2.3 From 01f905c1779279811d4f0467da4bdf33ff786c86 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 18 Dec 2007 19:16:51 +1100 Subject: we should not be unlocking this here --- linux-core/drm_crtc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 9a840ea1..405b54b7 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -165,7 +165,6 @@ struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev) /* Limit to single framebuffer for now */ if (dev->mode_config.num_fb > 1) { - mutex_unlock(&dev->mode_config.mutex); DRM_ERROR("Attempt to add multiple framebuffers failed\n"); return NULL; } -- cgit v1.2.3 From a19e0efb0e03dbaad68e281b7e018663fb8c3589 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 18 Dec 2007 19:17:11 +1100 Subject: lockdep warned about a possible locking dependency --- linux-core/drm_fops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index cc09fc14..7efcb23f 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -472,8 +472,8 @@ int drm_release(struct inode *inode, struct file *filp) } mutex_unlock(&dev->ctxlist_mutex); - mutex_lock(&dev->struct_mutex); drm_fb_release(filp); + mutex_lock(&dev->struct_mutex); drm_object_release(filp); if (file_priv->remove_auth_on_close == 1) { struct drm_file *temp; -- cgit v1.2.3 From 6d03411e5faa124bac014ebacec470ffd7cf2ce4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 18 Dec 2007 19:18:05 +1100 Subject: HERE BEZ HACKZ.. magic variable to make shit work --- linux-core/drm_crtc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index dbb41867..d133e0e0 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -471,7 +471,7 @@ struct drm_output { struct drm_display_info *monitor_info; /* if any */ const struct drm_output_funcs *funcs; void *driver_private; - + uint32_t make_shit_work; struct list_head user_modes; struct drm_property_blob *edid_blob_ptr; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; -- cgit v1.2.3 From d8c94a84b7f8da5fdf32a0799eaac72a1fc3007d Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 19 Dec 2007 18:27:38 +0100 Subject: radeon_ms: add sarea & install header --- shared-core/Makefile.am | 1 + shared-core/radeon_ms_drm.h | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/shared-core/Makefile.am b/shared-core/Makefile.am index 7193e527..42e08e75 100644 --- a/shared-core/Makefile.am +++ b/shared-core/Makefile.am @@ -32,6 +32,7 @@ klibdrminclude_HEADERS = \ nouveau_drm.h \ r128_drm.h \ radeon_drm.h \ + radeon_ms_drm.h \ savage_drm.h \ sis_drm.h \ via_drm.h \ diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h index 842d5331..7186030c 100644 --- a/shared-core/radeon_ms_drm.h +++ b/shared-core/radeon_ms_drm.h @@ -57,4 +57,12 @@ struct drm_radeon_execbuffer { struct drm_fence_arg fence_arg; }; +#define RADEON_MS_MAX_SAREA_CLIPRECTS 16 + +struct drm_radeon_ms_sarea { + /* the cliprects */ + struct drm_clip_rect boxes[RADEON_MS_MAX_SAREA_CLIPRECTS]; + unsigned int nbox; +}; + #endif -- cgit v1.2.3 From 21b01cd4b54781cfab038016c2d644069d522787 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 20 Dec 2007 12:35:54 +0100 Subject: radeon_ms: update to follow lastest modesetting change --- shared-core/radeon_ms.h | 15 +-------------- shared-core/radeon_ms_dac.c | 4 ++-- shared-core/radeon_ms_family.c | 10 ++++------ shared-core/radeon_ms_i2c.c | 15 ++++++++++++--- shared-core/radeon_ms_output.c | 4 ++-- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index ee795f3a..d86c40b9 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -87,17 +87,6 @@ enum radeon_monitor_type { MT_STV = 5 }; -enum radeon_connector_type { - CONNECTOR_NONE, - CONNECTOR_PROPRIETARY, - CONNECTOR_VGA, - CONNECTOR_DVI_I, - CONNECTOR_DVI_D, - CONNECTOR_CTV, - CONNECTOR_STV, - CONNECTOR_UNSUPPORTED -}; - enum radeon_output_type { OUTPUT_NONE, OUTPUT_DAC1, @@ -131,7 +120,6 @@ struct radeon_ms_connector { int crtc; uint32_t i2c_reg; char outputs[RADEON_MAX_OUTPUTS]; - char name[32]; }; struct radeon_ms_output { @@ -459,8 +447,7 @@ int radeon_ms_wait_for_idle(struct drm_device *dev); /* radeon_ms_i2c.c */ void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c); struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, - const uint32_t reg, - const char *name); + const uint32_t reg, int type); /* radeon_ms_irq.c */ void radeon_ms_irq_emit(struct drm_device *dev); diff --git a/shared-core/radeon_ms_dac.c b/shared-core/radeon_ms_dac.c index 297623a0..2483eab8 100644 --- a/shared-core/radeon_ms_dac.c +++ b/shared-core/radeon_ms_dac.c @@ -369,8 +369,8 @@ int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, case CHIP_R420: case CHIP_R430: case CHIP_R480: - if (connector->type != CONNECTOR_CTV && - connector->type != CONNECTOR_STV) { + if (connector->type != ConnectorComposite && + connector->type != ConnectorSVIDEO) { state->dac_cntl2 |= DAC_CNTL2__DAC2_CLK_SEL; } } diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c index 779595d6..fcfec799 100644 --- a/shared-core/radeon_ms_family.c +++ b/shared-core/radeon_ms_family.c @@ -58,19 +58,17 @@ static struct radeon_ms_output radeon_ms_dac2 = { }; static struct radeon_ms_connector radeon_ms_vga = { - NULL, NULL, NULL, CONNECTOR_VGA, MT_NONE, 0, GPIO_DDC1, + NULL, NULL, NULL, ConnectorVGA, MT_NONE, 0, GPIO_DDC1, { 0, -1, -1, -1, -1, -1, -1, -1 - }, - "VGA" + } }; static struct radeon_ms_connector radeon_ms_dvi_i_2 = { - NULL, NULL, NULL, CONNECTOR_DVI_I, MT_NONE, 0, GPIO_DDC2, + NULL, NULL, NULL, ConnectorDVII, MT_NONE, 0, GPIO_DDC2, { 1, -1, -1, -1, -1, -1, -1, -1 - }, - "DVI-I" + } }; static struct radeon_ms_properties properties[] = { diff --git a/shared-core/radeon_ms_i2c.c b/shared-core/radeon_ms_i2c.c index 1801c496..f8730702 100644 --- a/shared-core/radeon_ms_i2c.c +++ b/shared-core/radeon_ms_i2c.c @@ -219,8 +219,7 @@ static void set_data(void *i2c_priv, int data) * */ struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, - const uint32_t reg, - const char *name) + const uint32_t reg, int type) { struct radeon_ms_i2c *i2c; int ret; @@ -233,7 +232,17 @@ struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, i2c->drm_dev = dev; i2c->reg = reg; - snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-%s", name); + switch (type) { + case ConnectorVGA: + snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-VGA"); + break; + case ConnectorDVII: + snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-DVII"); + break; + default: + snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-UNKNOWN"); + break; + } i2c->adapter.owner = THIS_MODULE; /* fixme need to take a look at what its needed for */ i2c->adapter.id = I2C_HW_B_RADEON; diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c index 35e5c376..a1ed29cb 100644 --- a/shared-core/radeon_ms_output.c +++ b/shared-core/radeon_ms_output.c @@ -249,14 +249,14 @@ int radeon_ms_connectors_from_properties(struct drm_device *dev) dev_priv->properties->connectors[i], sizeof(struct radeon_ms_connector)); connector->i2c = radeon_ms_i2c_create(dev, - connector->i2c_reg, connector->name); + connector->i2c_reg, connector->type); if (connector->i2c == NULL) { radeon_ms_connectors_destroy(dev); return -ENOMEM; } output = drm_output_create(dev, &radeon_ms_output_funcs, - connector->name); + connector->type); if (output == NULL) { radeon_ms_connectors_destroy(dev); return -EINVAL; -- cgit v1.2.3 From 219ba5cd9aff2dc79e414bbe2e9f90406f7543df Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 21 Dec 2007 18:38:55 +1000 Subject: s/TRUE/true --- linux-core/drm_crtc.c | 4 ++-- linux-core/intel_display.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fef2700a..bb89cb10 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -356,7 +356,7 @@ void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int } - drm_mode_prune_invalid(dev, &output->modes, TRUE); + drm_mode_prune_invalid(dev, &output->modes, true); if (list_empty(&output->modes)) { struct drm_display_mode *stdmode; @@ -510,7 +510,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, /* XXX free adjustedmode */ drm_mode_destroy(dev, adjusted_mode); - ret = TRUE; + ret = true; /* TODO */ // if (scrn->pScreen) // drm_crtc_set_screen_sub_pixel_order(dev); diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index a81cfe69..8a6ce440 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -461,7 +461,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc_load_lut(crtc); /* Give the overlay scaler a chance to enable if it's on this pipe */ - //intel_crtc_dpms_video(crtc, TRUE); TODO + //intel_crtc_dpms_video(crtc, true); TODO break; case DPMSModeOff: /* Give the overlay scaler a chance to disable if it's on this pipe */ @@ -699,19 +699,19 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, switch (intel_output->type) { case INTEL_OUTPUT_LVDS: - is_lvds = TRUE; + is_lvds = true; break; case INTEL_OUTPUT_SDVO: - is_sdvo = TRUE; + is_sdvo = true; break; case INTEL_OUTPUT_DVO: - is_dvo = TRUE; + is_dvo = true; break; case INTEL_OUTPUT_TVOUT: - is_tv = TRUE; + is_tv = true; break; case INTEL_OUTPUT_ANALOG: - is_crt = TRUE; + is_crt = true; break; } } -- cgit v1.2.3 From 10937cf20b6814e4cf68114fab4619fad94eafcb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 4 Jan 2008 16:12:24 +1100 Subject: drm: move drm_head to drm_minor and fix up users --- linux-core/drmP.h | 29 +++++++++++++---------- linux-core/drm_agpsupport.c | 2 +- linux-core/drm_bo.c | 14 +++++------ linux-core/drm_bo_lock.c | 4 ++-- linux-core/drm_crtc.c | 6 ++--- linux-core/drm_drv.c | 30 ++++++++++++------------ linux-core/drm_fence.c | 4 ++-- linux-core/drm_fops.c | 23 +++++++++--------- linux-core/drm_object.c | 16 ++++++------- linux-core/drm_proc.c | 4 ++-- linux-core/drm_stub.c | 53 +++++++++++++++++++++--------------------- linux-core/drm_sysfs.c | 6 ++--- linux-core/drm_vm.c | 20 ++++++++-------- linux-core/i810_dma.c | 4 ++-- linux-core/intel_display.c | 12 +++++----- shared-core/Makefile.am | 1 - shared-core/i915_dma.c | 6 ++--- shared-core/radeon_ms.h | 15 +++++++++++- shared-core/radeon_ms_dac.c | 4 ++-- shared-core/radeon_ms_drm.h | 8 ------- shared-core/radeon_ms_family.c | 10 ++++---- shared-core/radeon_ms_i2c.c | 15 +++--------- shared-core/radeon_ms_output.c | 4 ++-- 23 files changed, 146 insertions(+), 144 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5e674b2a..962ad4eb 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -412,13 +412,12 @@ enum drm_ref_type { struct drm_file { int authenticated; int master; - int minor; pid_t pid; uid_t uid; drm_magic_t magic; unsigned long ioctl_count; struct list_head lhead; - struct drm_head *head; + struct drm_minor *minor; int remove_auth_on_close; unsigned long lock_count; @@ -690,16 +689,19 @@ struct drm_driver { struct pci_driver pci_driver; }; +#define DRM_MINOR_UNASSIGNED 0 +#define DRM_MINOR_CONTROL 1 +#define DRM_MINOR_RENDER 2 /** - * DRM head structure. This structure represent a video head on a card - * that may contain multiple heads. Embed one per head of these in the - * private drm_device structure. + * DRM minor structure. This structure represents a drm minor number. */ -struct drm_head { +struct drm_minor { int minor; /**< Minor device number */ + int type; /**< Control or render */ + dev_t device; /**< Device number for mknod */ struct drm_device *dev; + /* for render nodes */ struct proc_dir_entry *dev_root; /**< proc directory entry */ - dev_t device; /**< Device number for mknod */ struct class_device *dev_class; }; @@ -830,7 +832,10 @@ struct drm_device { struct drm_driver *driver; drm_local_map_t *agp_buffer_map; unsigned int agp_buffer_token; - struct drm_head primary; /**< primary screen head */ + + /* minor number for control node */ + struct drm_minor control; + struct drm_minor primary; /**< primary screen head */ struct drm_fence_manager fm; struct drm_buffer_manager bm; @@ -1153,10 +1158,10 @@ extern void drm_agp_chipset_flush(struct drm_device *dev); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); extern int drm_put_dev(struct drm_device *dev); -extern int drm_put_head(struct drm_head * head); +extern int drm_put_head(struct drm_minor *minor); extern unsigned int drm_debug; /* 1 to enable debug output */ -extern unsigned int drm_cards_limit; -extern struct drm_head **drm_heads; +extern unsigned int drm_minors_limit; +extern struct drm_minor **drm_minors; extern struct class *drm_class; extern struct proc_dir_entry *drm_proc_root; @@ -1193,7 +1198,7 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); struct drm_sysfs_class; extern struct class *drm_sysfs_create(struct module *owner, char *name); extern void drm_sysfs_destroy(void); -extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head); +extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor); extern void drm_sysfs_device_remove(struct drm_device *dev); /* diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index e8bfaea4..0b321afd 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -130,7 +130,7 @@ EXPORT_SYMBOL(drm_agp_acquire); int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - return drm_agp_acquire((struct drm_device *) file_priv->head->dev); + return drm_agp_acquire((struct drm_device *) file_priv->minor->dev); } /** diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e4ec24e2..55f5d08a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1164,7 +1164,7 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep) { struct drm_buffer_object *bo; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int ret = 0; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; @@ -1236,7 +1236,7 @@ out: static int drm_buffer_object_unmap(struct drm_file *file_priv, uint32_t handle) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; struct drm_ref_object *ro; int ret = 0; @@ -1543,7 +1543,7 @@ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep, struct drm_buffer_object **bo_rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; int ret; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; @@ -1581,7 +1581,7 @@ EXPORT_SYMBOL(drm_bo_handle_validate); static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; mutex_lock(&dev->struct_mutex); @@ -1604,7 +1604,7 @@ static int drm_bo_handle_wait(struct drm_file *file_priv, uint32_t handle, uint32_t hint, struct drm_bo_info_rep *rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; int ret; @@ -1717,7 +1717,7 @@ EXPORT_SYMBOL(drm_buffer_object_create); static int drm_bo_add_user_object(struct drm_file *file_priv, struct drm_buffer_object *bo, int shareable) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -1757,7 +1757,7 @@ int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fil if (bo_type == drm_bo_type_user) req->mask &= ~DRM_BO_FLAG_SHAREABLE; - ret = drm_buffer_object_create(file_priv->head->dev, + ret = drm_buffer_object_create(file_priv->minor->dev, req->size, bo_type, req->mask, req->hint, req->page_alignment, req->buffer_start, &entry); diff --git a/linux-core/drm_bo_lock.c b/linux-core/drm_bo_lock.c index f967fb7c..2795384e 100644 --- a/linux-core/drm_bo_lock.c +++ b/linux-core/drm_bo_lock.c @@ -141,7 +141,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv) * while holding it. */ - dev = file_priv->head->dev; + dev = file_priv->minor->dev; mutex_lock(&dev->struct_mutex); ret = drm_add_user_object(file_priv, &lock->base, 0); lock->base.remove = &drm_bo_write_lock_remove; @@ -156,7 +156,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv) int drm_bo_write_unlock(struct drm_bo_lock *lock, struct drm_file *file_priv) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_ref_object *ro; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bb89cb10..dc8b1462 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -356,7 +356,7 @@ void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int } - drm_mode_prune_invalid(dev, &output->modes, true); + drm_mode_prune_invalid(dev, &output->modes, TRUE); if (list_empty(&output->modes)) { struct drm_display_mode *stdmode; @@ -510,7 +510,7 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, /* XXX free adjustedmode */ drm_mode_destroy(dev, adjusted_mode); - ret = true; + ret = TRUE; /* TODO */ // if (scrn->pScreen) // drm_crtc_set_screen_sub_pixel_order(dev); @@ -1781,7 +1781,7 @@ out: void drm_fb_release(struct file *filp) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_framebuffer *fb, *tfb; mutex_lock(&dev->mode_config.mutex); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index ab02c659..29fa18d8 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -432,19 +432,19 @@ void drm_exit(struct drm_driver *driver) { int i; struct drm_device *dev = NULL; - struct drm_head *head; + struct drm_minor *minor; DRM_DEBUG("\n"); if (drm_fb_loaded) { - for (i = 0; i < drm_cards_limit; i++) { - head = drm_heads[i]; - if (!head) + for (i = 0; i < drm_minors_limit; i++) { + minor = drm_minors[i]; + if (!minor) continue; - if (!head->dev) + if (!minor->dev) continue; - if (head->dev->driver != driver) + if (minor->dev->driver != driver) continue; - dev = head->dev; + dev = minor->dev; if (dev) { /* release the pci driver */ if (dev->pdev) @@ -495,10 +495,10 @@ static int __init drm_core_init(void) drm_init_memctl(avail_memctl_mem/2, avail_memctl_mem*3/4, si.mem_unit); ret = -ENOMEM; - drm_cards_limit = - (drm_cards_limit < DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1); - drm_heads = drm_calloc(drm_cards_limit, sizeof(*drm_heads), DRM_MEM_STUB); - if (!drm_heads) + drm_minors_limit = + (drm_minors_limit < DRM_MAX_MINOR + 1 ? drm_minors_limit : DRM_MAX_MINOR + 1); + drm_minors = drm_calloc(drm_minors_limit, sizeof(*drm_minors), DRM_MEM_STUB); + if (!drm_minors) goto err_p1; if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) @@ -528,7 +528,7 @@ err_p3: drm_sysfs_destroy(); err_p2: unregister_chrdev(DRM_MAJOR, "drm"); - drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); + drm_free(drm_minors, sizeof(*drm_minors) * drm_minors_limit, DRM_MEM_STUB); err_p1: return ret; } @@ -540,7 +540,7 @@ static void __exit drm_core_exit(void) unregister_chrdev(DRM_MAJOR, "drm"); - drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); + drm_free(drm_minors, sizeof(*drm_minors) * drm_minors_limit, DRM_MEM_STUB); } module_init(drm_core_init); @@ -600,7 +600,7 @@ EXPORT_SYMBOL(drm_ioctl); long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_ioctl_desc *ioctl; drm_ioctl_t *func; unsigned int nr = DRM_IOCTL_NR(cmd); @@ -612,7 +612,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++file_priv->ioctl_count; DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", - current->pid, cmd, nr, (long)old_encode_dev(file_priv->head->device), + current->pid, cmd, nr, (long)old_encode_dev(file_priv->minor->device), file_priv->authenticated); if ((nr >= DRM_CORE_IOCTL_COUNT) && diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 288b4db6..b2c4e9c9 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -516,7 +516,7 @@ static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class, int drm_fence_add_user_object(struct drm_file *priv, struct drm_fence_object *fence, int shareable) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -612,7 +612,7 @@ void drm_fence_manager_takedown(struct drm_device *dev) struct drm_fence_object *drm_lookup_fence_object(struct drm_file *priv, uint32_t handle) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_fence_object *fence; diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 7efcb23f..28aaeb1f 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -131,13 +131,13 @@ int drm_open(struct inode *inode, struct file *filp) int minor = iminor(inode); int retcode = 0; - if (!((minor >= 0) && (minor < drm_cards_limit))) + if (!((minor >= 0) && (minor < drm_minors_limit))) return -ENODEV; - if (!drm_heads[minor]) + if (!drm_minors[minor]) return -ENODEV; - if (!(dev = drm_heads[minor]->dev)) + if (!(dev = drm_minors[minor]->dev)) return -ENODEV; retcode = drm_open_helper(inode, filp, dev); @@ -182,13 +182,13 @@ int drm_stub_open(struct inode *inode, struct file *filp) DRM_DEBUG("\n"); - if (!((minor >= 0) && (minor < drm_cards_limit))) + if (!((minor >= 0) && (minor < drm_minors_limit))) return -ENODEV; - if (!drm_heads[minor]) + if (!drm_minors[minor]) return -ENODEV; - if (!(dev = drm_heads[minor]->dev)) + if (!(dev = drm_minors[minor]->dev)) return -ENODEV; old_fops = filp->f_op; @@ -254,8 +254,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->filp = filp; priv->uid = current->euid; priv->pid = current->pid; - priv->minor = minor; - priv->head = drm_heads[minor]; + priv->minor = drm_minors[minor]; priv->ioctl_count = 0; /* for compatibility root is always authenticated */ priv->authenticated = capable(CAP_SYS_ADMIN); @@ -321,11 +320,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp, int drm_fasync(int fd, struct file *filp, int on) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int retcode; DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, - (long)old_encode_dev(priv->head->device)); + (long)old_encode_dev(priv->minor->device)); retcode = fasync_helper(fd, filp, on, &dev->buf_async); if (retcode < 0) return retcode; @@ -375,7 +374,7 @@ static void drm_object_release(struct file *filp) int drm_release(struct inode *inode, struct file *filp) { struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int retcode = 0; lock_kernel(); @@ -390,7 +389,7 @@ int drm_release(struct inode *inode, struct file *filp) */ DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", - current->pid, (long)old_encode_dev(file_priv->head->device), + current->pid, (long)old_encode_dev(file_priv->minor->device), dev->open_count); if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c index 5ade6178..16ccdbcb 100644 --- a/linux-core/drm_object.c +++ b/linux-core/drm_object.c @@ -33,7 +33,7 @@ int drm_add_user_object(struct drm_file *priv, struct drm_user_object *item, int shareable) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; DRM_ASSERT_LOCKED(&dev->struct_mutex); @@ -58,7 +58,7 @@ EXPORT_SYMBOL(drm_add_user_object); struct drm_user_object *drm_lookup_user_object(struct drm_file *priv, uint32_t key) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_hash_item *hash; int ret; struct drm_user_object *item; @@ -85,7 +85,7 @@ EXPORT_SYMBOL(drm_lookup_user_object); static void drm_deref_user_object(struct drm_file *priv, struct drm_user_object *item) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; if (atomic_dec_and_test(&item->refcount)) { @@ -121,7 +121,7 @@ int drm_add_ref_object(struct drm_file *priv, struct drm_user_object *referenced struct drm_ref_object *item; struct drm_open_hash *ht = &priv->refd_object_hash[ref_action]; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); if (!referenced_object->shareable && priv != referenced_object->owner) { DRM_ERROR("Not allowed to reference this object\n"); return -EINVAL; @@ -178,7 +178,7 @@ struct drm_ref_object *drm_lookup_ref_object(struct drm_file *priv, struct drm_hash_item *hash; int ret; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); ret = drm_ht_find_item(&priv->refd_object_hash[ref_action], (unsigned long)referenced_object, &hash); if (ret) @@ -212,7 +212,7 @@ void drm_remove_ref_object(struct drm_file *priv, struct drm_ref_object *item) struct drm_open_hash *ht = &priv->refd_object_hash[item->unref_action]; enum drm_ref_type unref_action; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); unref_action = item->unref_action; if (atomic_dec_and_test(&item->refcount)) { ret = drm_ht_remove_item(ht, &item->hash); @@ -239,7 +239,7 @@ EXPORT_SYMBOL(drm_remove_ref_object); int drm_user_object_ref(struct drm_file *priv, uint32_t user_token, enum drm_object_type type, struct drm_user_object **object) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_hash_item *hash; int ret; @@ -269,7 +269,7 @@ out_err: int drm_user_object_unref(struct drm_file *priv, uint32_t user_token, enum drm_object_type type) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_ref_object *ro; int ret; diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 3012c5b0..8f26726c 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -90,7 +90,7 @@ static struct drm_proc_list { * "/proc/dri/%minor%/", and each entry in proc_list as * "/proc/dri/%minor%/%name%". */ -int drm_proc_init(struct drm_device * dev, int minor, +int drm_proc_init(struct drm_device *dev, int minor, struct proc_dir_entry *root, struct proc_dir_entry **dev_root) { struct proc_dir_entry *ent; @@ -535,7 +535,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset, list_for_each_entry(priv, &dev->filelist, lhead) { DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", priv->authenticated ? 'y' : 'n', - priv->minor, + priv->minor->minor, priv->pid, priv->uid, priv->magic, priv->ioctl_count); } diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index cc759d5c..433869e6 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -37,20 +37,20 @@ #include "drmP.h" #include "drm_core.h" -unsigned int drm_cards_limit = 16; /* Enough for one machine */ +unsigned int drm_minors_limit = 16; /* Enough for one machine */ unsigned int drm_debug = 0; /* 1 to enable debug output */ EXPORT_SYMBOL(drm_debug); MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); -MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards"); +MODULE_PARM_DESC(minors_limit, "Maximum number of graphics cards"); MODULE_PARM_DESC(debug, "Enable debug output"); -module_param_named(cards_limit, drm_cards_limit, int, 0444); +module_param_named(minors_limit, drm_minors_limit, int, 0444); module_param_named(debug, drm_debug, int, 0600); -struct drm_head **drm_heads; +struct drm_minor **drm_minors; struct class *drm_class; struct proc_dir_entry *drm_proc_root; @@ -160,48 +160,48 @@ error_out_unreg: * create the proc init entry via proc_init(). This routines assigns * minor numbers to secondary heads of multi-headed cards */ -static int drm_get_head(struct drm_device * dev, struct drm_head * head) +static int drm_get_head(struct drm_device * dev, struct drm_minor *minor) { - struct drm_head **heads = drm_heads; + struct drm_minor **minors = drm_minors; int ret; - int minor; + int index; DRM_DEBUG("\n"); - for (minor = 0; minor < drm_cards_limit; minor++, heads++) { - if (!*heads) { + for (index = 0; index < drm_minors_limit; index++, minors++) { + if (!*minors) { - *head = (struct drm_head) { + *minor = (struct drm_minor) { .dev = dev, - .device = MKDEV(DRM_MAJOR, minor), - .minor = minor, + .device = MKDEV(DRM_MAJOR, index), + .minor = index, }; if ((ret = - drm_proc_init(dev, minor, drm_proc_root, - &head->dev_root))) { + drm_proc_init(dev, index, drm_proc_root, + &minor->dev_root))) { printk(KERN_ERR "DRM: Failed to initialize /proc/dri.\n"); goto err_g1; } - ret = drm_sysfs_device_add(dev, head); + ret = drm_sysfs_device_add(dev, minor); if (ret) { printk(KERN_ERR "DRM: Error sysfs_device_add.\n"); goto err_g2; } - *heads = head; + *minors = minor; - DRM_DEBUG("new minor assigned %d\n", minor); + DRM_DEBUG("new minor assigned %d\n", index); return 0; } } DRM_ERROR("out of minors\n"); return -ENOMEM; err_g2: - drm_proc_cleanup(minor, drm_proc_root, head->dev_root); + drm_proc_cleanup(index, drm_proc_root, minor->dev_root); err_g1: - *head = (struct drm_head) { + *minor = (struct drm_minor) { .dev = NULL}; return ret; } @@ -309,17 +309,18 @@ int drm_put_dev(struct drm_device * dev) * last minor released. * */ -int drm_put_head(struct drm_head * head) +int drm_put_minor(struct drm_minor *minor) { - int minor = head->minor; + int index = minor->minor; - DRM_DEBUG("release secondary minor %d\n", minor); + DRM_DEBUG("release secondary minor %d\n", index); - drm_proc_cleanup(minor, drm_proc_root, head->dev_root); - drm_sysfs_device_remove(head->dev); + drm_proc_cleanup(index, drm_proc_root, minor->dev_root); + drm_sysfs_device_remove(minor->dev); - *head = (struct drm_head) {.dev = NULL}; + *minor = (struct drm_minor) {.type = DRM_MINOR_UNASSIGNED, + .dev = NULL}; - drm_heads[minor] = NULL; + drm_minors[index] = NULL; return 0; } diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 3aaac11b..1f2d763b 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -154,7 +154,7 @@ static void drm_sysfs_device_release(struct device *dev) * as the parent for the Linux device, and make sure it has a file containing * the driver we're using (for userspace compatibility). */ -int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) +int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor) { int err; int i, j; @@ -162,8 +162,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) dev->dev.parent = &dev->pdev->dev; dev->dev.class = drm_class; dev->dev.release = drm_sysfs_device_release; - dev->dev.devt = head->device; - snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor); + dev->dev.devt = minor->device; + snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", minor->minor); err = device_register(&dev->dev); if (err) { diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index f2681cc9..f439fa21 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -86,7 +86,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, unsigned long address) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_map *map = NULL; struct drm_map_list *r_list; struct drm_hash_item *hash; @@ -204,7 +204,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, static void drm_vm_shm_close(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *pt, *temp; struct drm_map *map; struct drm_map_list *r_list; @@ -286,7 +286,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_device_dma *dma = dev->dma; unsigned long offset; unsigned long page_nr; @@ -323,7 +323,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma, { struct drm_map *map = (struct drm_map *) vma->vm_private_data; struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_sg_mem *entry = dev->sg; unsigned long offset; unsigned long map_offset; @@ -419,7 +419,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { static void drm_vm_open_locked(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *vma_entry; DRM_DEBUG("0x%08lx,0x%08lx\n", @@ -437,7 +437,7 @@ static void drm_vm_open_locked(struct vm_area_struct *vma) static void drm_vm_open(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; mutex_lock(&dev->struct_mutex); drm_vm_open_locked(vma); @@ -455,7 +455,7 @@ static void drm_vm_open(struct vm_area_struct *vma) static void drm_vm_close(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *pt, *temp; DRM_DEBUG("0x%08lx,0x%08lx\n", @@ -491,7 +491,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) struct drm_device_dma *dma; unsigned long length = vma->vm_end - vma->vm_start; - dev = priv->head->dev; + dev = priv->minor->dev; dma = dev->dma; DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", vma->vm_start, vma->vm_end, vma->vm_pgoff); @@ -556,7 +556,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_map *map = NULL; unsigned long offset = 0; struct drm_hash_item *hash; @@ -677,7 +677,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) int drm_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index c085fbc9..64c7c0db 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -113,7 +113,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) drm_i810_buf_priv_t *buf_priv; lock_kernel(); - dev = priv->head->dev; + dev = priv->minor->dev; dev_priv = dev->dev_private; buf = dev_priv->mmap_buffer; buf_priv = buf->dev_private; @@ -141,7 +141,7 @@ static const struct file_operations i810_buffer_fops = { static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_private_t *dev_priv = dev->dev_private; const struct file_operations *old_fops; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 8a6ce440..a81cfe69 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -461,7 +461,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc_load_lut(crtc); /* Give the overlay scaler a chance to enable if it's on this pipe */ - //intel_crtc_dpms_video(crtc, true); TODO + //intel_crtc_dpms_video(crtc, TRUE); TODO break; case DPMSModeOff: /* Give the overlay scaler a chance to disable if it's on this pipe */ @@ -699,19 +699,19 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, switch (intel_output->type) { case INTEL_OUTPUT_LVDS: - is_lvds = true; + is_lvds = TRUE; break; case INTEL_OUTPUT_SDVO: - is_sdvo = true; + is_sdvo = TRUE; break; case INTEL_OUTPUT_DVO: - is_dvo = true; + is_dvo = TRUE; break; case INTEL_OUTPUT_TVOUT: - is_tv = true; + is_tv = TRUE; break; case INTEL_OUTPUT_ANALOG: - is_crt = true; + is_crt = TRUE; break; } } diff --git a/shared-core/Makefile.am b/shared-core/Makefile.am index 42e08e75..7193e527 100644 --- a/shared-core/Makefile.am +++ b/shared-core/Makefile.am @@ -32,7 +32,6 @@ klibdrminclude_HEADERS = \ nouveau_drm.h \ r128_drm.h \ radeon_drm.h \ - radeon_ms_drm.h \ savage_drm.h \ sis_drm.h \ via_drm.h \ diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 23e8b491..4c1a07ac 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -780,7 +780,7 @@ int i915_process_relocs(struct drm_file *file_priv, struct drm_i915_validate_buffer *buffers, uint32_t num_buffers) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *reloc_list_object; uint32_t cur_handle = *reloc_buf_handle; uint32_t *reloc_page; @@ -866,7 +866,7 @@ static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle, struct drm_i915_validate_buffer *buffers, uint32_t buf_count) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct i915_relocatee_info relocatee; int ret = 0; int b; @@ -926,7 +926,7 @@ int i915_validate_buffer_list(struct drm_file *file_priv, unsigned long next = 0; int ret = 0; unsigned buf_count = 0; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; uint32_t buf_reloc_handle, buf_handle; diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index d86c40b9..ee795f3a 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -87,6 +87,17 @@ enum radeon_monitor_type { MT_STV = 5 }; +enum radeon_connector_type { + CONNECTOR_NONE, + CONNECTOR_PROPRIETARY, + CONNECTOR_VGA, + CONNECTOR_DVI_I, + CONNECTOR_DVI_D, + CONNECTOR_CTV, + CONNECTOR_STV, + CONNECTOR_UNSUPPORTED +}; + enum radeon_output_type { OUTPUT_NONE, OUTPUT_DAC1, @@ -120,6 +131,7 @@ struct radeon_ms_connector { int crtc; uint32_t i2c_reg; char outputs[RADEON_MAX_OUTPUTS]; + char name[32]; }; struct radeon_ms_output { @@ -447,7 +459,8 @@ int radeon_ms_wait_for_idle(struct drm_device *dev); /* radeon_ms_i2c.c */ void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c); struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, - const uint32_t reg, int type); + const uint32_t reg, + const char *name); /* radeon_ms_irq.c */ void radeon_ms_irq_emit(struct drm_device *dev); diff --git a/shared-core/radeon_ms_dac.c b/shared-core/radeon_ms_dac.c index 2483eab8..297623a0 100644 --- a/shared-core/radeon_ms_dac.c +++ b/shared-core/radeon_ms_dac.c @@ -369,8 +369,8 @@ int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, case CHIP_R420: case CHIP_R430: case CHIP_R480: - if (connector->type != ConnectorComposite && - connector->type != ConnectorSVIDEO) { + if (connector->type != CONNECTOR_CTV && + connector->type != CONNECTOR_STV) { state->dac_cntl2 |= DAC_CNTL2__DAC2_CLK_SEL; } } diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h index 7186030c..842d5331 100644 --- a/shared-core/radeon_ms_drm.h +++ b/shared-core/radeon_ms_drm.h @@ -57,12 +57,4 @@ struct drm_radeon_execbuffer { struct drm_fence_arg fence_arg; }; -#define RADEON_MS_MAX_SAREA_CLIPRECTS 16 - -struct drm_radeon_ms_sarea { - /* the cliprects */ - struct drm_clip_rect boxes[RADEON_MS_MAX_SAREA_CLIPRECTS]; - unsigned int nbox; -}; - #endif diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c index fcfec799..779595d6 100644 --- a/shared-core/radeon_ms_family.c +++ b/shared-core/radeon_ms_family.c @@ -58,17 +58,19 @@ static struct radeon_ms_output radeon_ms_dac2 = { }; static struct radeon_ms_connector radeon_ms_vga = { - NULL, NULL, NULL, ConnectorVGA, MT_NONE, 0, GPIO_DDC1, + NULL, NULL, NULL, CONNECTOR_VGA, MT_NONE, 0, GPIO_DDC1, { 0, -1, -1, -1, -1, -1, -1, -1 - } + }, + "VGA" }; static struct radeon_ms_connector radeon_ms_dvi_i_2 = { - NULL, NULL, NULL, ConnectorDVII, MT_NONE, 0, GPIO_DDC2, + NULL, NULL, NULL, CONNECTOR_DVI_I, MT_NONE, 0, GPIO_DDC2, { 1, -1, -1, -1, -1, -1, -1, -1 - } + }, + "DVI-I" }; static struct radeon_ms_properties properties[] = { diff --git a/shared-core/radeon_ms_i2c.c b/shared-core/radeon_ms_i2c.c index f8730702..1801c496 100644 --- a/shared-core/radeon_ms_i2c.c +++ b/shared-core/radeon_ms_i2c.c @@ -219,7 +219,8 @@ static void set_data(void *i2c_priv, int data) * */ struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, - const uint32_t reg, int type) + const uint32_t reg, + const char *name) { struct radeon_ms_i2c *i2c; int ret; @@ -232,17 +233,7 @@ struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, i2c->drm_dev = dev; i2c->reg = reg; - switch (type) { - case ConnectorVGA: - snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-VGA"); - break; - case ConnectorDVII: - snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-DVII"); - break; - default: - snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-UNKNOWN"); - break; - } + snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-%s", name); i2c->adapter.owner = THIS_MODULE; /* fixme need to take a look at what its needed for */ i2c->adapter.id = I2C_HW_B_RADEON; diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c index a1ed29cb..35e5c376 100644 --- a/shared-core/radeon_ms_output.c +++ b/shared-core/radeon_ms_output.c @@ -249,14 +249,14 @@ int radeon_ms_connectors_from_properties(struct drm_device *dev) dev_priv->properties->connectors[i], sizeof(struct radeon_ms_connector)); connector->i2c = radeon_ms_i2c_create(dev, - connector->i2c_reg, connector->type); + connector->i2c_reg, connector->name); if (connector->i2c == NULL) { radeon_ms_connectors_destroy(dev); return -ENOMEM; } output = drm_output_create(dev, &radeon_ms_output_funcs, - connector->type); + connector->name); if (output == NULL) { radeon_ms_connectors_destroy(dev); return -EINVAL; -- cgit v1.2.3 From df9cfeff37d40722df4e8a785478ac41246ca51f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 4 Jan 2008 17:48:42 +1100 Subject: crtc: fixup allocation size --- linux-core/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index dc8b1462..b49fa697 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1952,7 +1952,7 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, { struct drm_property *property = NULL; - property = kzalloc(sizeof(struct drm_output), GFP_KERNEL); + property = kzalloc(sizeof(struct drm_property), GFP_KERNEL); if (!property) return NULL; -- cgit v1.2.3 From d3da253adbf471c9af9c68b2ff67cbf516856352 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 4 Jan 2008 17:49:40 +1100 Subject: drm: add initial support for a drm control device node --- linux-core/drmP.h | 8 ++++---- linux-core/drm_drv.c | 3 ++- linux-core/drm_stub.c | 44 ++++++++++++++++++++++++++--------------- linux-core/drm_sysfs.c | 53 +++++++++++++++++++++++++++++--------------------- 4 files changed, 65 insertions(+), 43 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 962ad4eb..5bc4887a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -699,6 +699,7 @@ struct drm_minor { int minor; /**< Minor device number */ int type; /**< Control or render */ dev_t device; /**< Device number for mknod */ + struct device kdev; /**< Linux device */ struct drm_device *dev; /* for render nodes */ struct proc_dir_entry *dev_root; /**< proc directory entry */ @@ -711,7 +712,6 @@ struct drm_minor { * may contain multiple heads. */ struct drm_device { - struct device dev; /**< Linux device */ char *unique; /**< Unique identifier: e.g., busid */ int unique_len; /**< Length of unique field */ char *devname; /**< For /proc/interrupts */ @@ -1158,7 +1158,7 @@ extern void drm_agp_chipset_flush(struct drm_device *dev); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); extern int drm_put_dev(struct drm_device *dev); -extern int drm_put_head(struct drm_minor *minor); +extern int drm_put_minor(struct drm_minor *minor); extern unsigned int drm_debug; /* 1 to enable debug output */ extern unsigned int drm_minors_limit; extern struct drm_minor **drm_minors; @@ -1198,8 +1198,8 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); struct drm_sysfs_class; extern struct class *drm_sysfs_create(struct module *owner, char *name); extern void drm_sysfs_destroy(void); -extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor); -extern void drm_sysfs_device_remove(struct drm_device *dev); +extern int drm_sysfs_device_add(struct drm_minor *minor); +extern void drm_sysfs_device_remove(struct drm_minor *minor); /* * Basic memory manager support (drm_mm.c) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 29fa18d8..58beec66 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -423,7 +423,8 @@ static void drm_cleanup(struct drm_device * dev) drm_mm_takedown(&dev->offset_manager); drm_ht_remove(&dev->object_hash); - drm_put_head(&dev->primary); + drm_put_minor(&dev->primary); + drm_put_minor(&dev->control); if (drm_put_dev(dev)) DRM_ERROR("Cannot unload module\n"); } diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 433869e6..cee00c5e 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -160,7 +160,7 @@ error_out_unreg: * create the proc init entry via proc_init(). This routines assigns * minor numbers to secondary heads of multi-headed cards */ -static int drm_get_head(struct drm_device * dev, struct drm_minor *minor) +static int drm_get_minor(struct drm_device *dev, struct drm_minor *minor, int type) { struct drm_minor **minors = drm_minors; int ret; @@ -172,19 +172,23 @@ static int drm_get_head(struct drm_device * dev, struct drm_minor *minor) if (!*minors) { *minor = (struct drm_minor) { + .type = type, .dev = dev, .device = MKDEV(DRM_MAJOR, index), .minor = index, }; - if ((ret = - drm_proc_init(dev, index, drm_proc_root, - &minor->dev_root))) { - printk(KERN_ERR - "DRM: Failed to initialize /proc/dri.\n"); - goto err_g1; - } - ret = drm_sysfs_device_add(dev, minor); + if (type == DRM_MINOR_RENDER) { + ret = drm_proc_init(dev, index, drm_proc_root, + &minor->dev_root); + if (ret) { + DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); + goto err_g1; + } + } else + minor->dev_root = NULL; + + ret = drm_sysfs_device_add(minor); if (ret) { printk(KERN_ERR "DRM: Error sysfs_device_add.\n"); @@ -199,7 +203,8 @@ static int drm_get_head(struct drm_device * dev, struct drm_minor *minor) DRM_ERROR("out of minors\n"); return -ENOMEM; err_g2: - drm_proc_cleanup(index, drm_proc_root, minor->dev_root); + if (minor->type == DRM_MINOR_RENDER) + drm_proc_cleanup(index, drm_proc_root, minor->dev_root); err_g1: *minor = (struct drm_minor) { .dev = NULL}; @@ -245,22 +250,28 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, printk(KERN_ERR "DRM: fill_in_dev failed\n"); goto err_g3; } - if ((ret = drm_get_head(dev, &dev->primary))) + + if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL))) goto err_g3; + if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_RENDER))) + goto err_g4; + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, dev->primary.minor); return 0; - err_g3: +err_g4: + drm_put_minor(&dev->control); +err_g3: if (!drm_fb_loaded) pci_disable_device(pdev); - err_g2: +err_g2: if (!drm_fb_loaded) pci_release_regions(pdev); - err_g1: +err_g1: if (!drm_fb_loaded) pci_set_drvdata(pdev, NULL); @@ -315,8 +326,9 @@ int drm_put_minor(struct drm_minor *minor) DRM_DEBUG("release secondary minor %d\n", index); - drm_proc_cleanup(index, drm_proc_root, minor->dev_root); - drm_sysfs_device_remove(minor->dev); + if (minor->type == DRM_MINOR_RENDER) + drm_proc_cleanup(index, drm_proc_root, minor->dev_root); + drm_sysfs_device_remove(minor); *minor = (struct drm_minor) {.type = DRM_MINOR_UNASSIGNED, .dev = NULL}; diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 1f2d763b..a56e9959 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -19,7 +19,7 @@ #include "drm_core.h" #include "drmP.h" -#define to_drm_device(d) container_of(d, struct drm_device, dev) +#define to_drm_minor(d) container_of(d, struct drm_minor, kdev) /** * drm_sysfs_suspend - DRM class suspend hook @@ -31,7 +31,8 @@ */ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) { - struct drm_device *drm_dev = to_drm_device(dev); + struct drm_minor *drm_minor = to_drm_minor(dev); + struct drm_device *drm_dev = drm_minor->dev; printk(KERN_ERR "%s\n", __FUNCTION__); @@ -50,7 +51,8 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) */ static int drm_sysfs_resume(struct device *dev) { - struct drm_device *drm_dev = to_drm_device(dev); + struct drm_minor *drm_minor = to_drm_minor(dev); + struct drm_device *drm_dev = drm_minor->dev; if (drm_dev->driver->resume) return drm_dev->driver->resume(drm_dev); @@ -122,10 +124,11 @@ void drm_sysfs_destroy(void) static ssize_t show_dri(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_device *dev = to_drm_device(device); - if (dev->driver->dri_library_name) - return dev->driver->dri_library_name(dev, buf); - return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); + struct drm_minor *drm_minor = to_drm_minor(device); + struct drm_device *drm_dev = drm_minor->dev; + if (drm_dev->driver->dri_library_name) + return drm_dev->driver->dri_library_name(drm_dev, buf); + return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name); } static struct device_attribute device_attrs[] = { @@ -154,25 +157,31 @@ static void drm_sysfs_device_release(struct device *dev) * as the parent for the Linux device, and make sure it has a file containing * the driver we're using (for userspace compatibility). */ -int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor) +int drm_sysfs_device_add(struct drm_minor *minor) { int err; int i, j; - - dev->dev.parent = &dev->pdev->dev; - dev->dev.class = drm_class; - dev->dev.release = drm_sysfs_device_release; - dev->dev.devt = minor->device; - snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", minor->minor); - - err = device_register(&dev->dev); + char *minor_str; + + minor->kdev.parent = &minor->dev->pdev->dev; + minor->kdev.class = drm_class; + minor->kdev.release = drm_sysfs_device_release; + minor->kdev.devt = minor->device; + if (minor->type == DRM_MINOR_CONTROL) + minor_str = "controlD%d"; + else + minor_str = "card%d"; + + snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->minor); + + err = device_register(&minor->kdev); if (err) { DRM_ERROR("device add failed: %d\n", err); goto err_out; } for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - err = device_create_file(&dev->dev, &device_attrs[i]); + err = device_create_file(&minor->kdev, &device_attrs[i]); if (err) goto err_out_files; } @@ -182,8 +191,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_minor *minor) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&dev->dev, &device_attrs[i]); - device_unregister(&dev->dev); + device_remove_file(&minor->kdev, &device_attrs[i]); + device_unregister(&minor->kdev); err_out: return err; @@ -196,11 +205,11 @@ err_out: * This call unregisters and cleans up a class device that was created with a * call to drm_sysfs_device_add() */ -void drm_sysfs_device_remove(struct drm_device *dev) +void drm_sysfs_device_remove(struct drm_minor *minor) { int i; for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(&dev->dev, &device_attrs[i]); - device_unregister(&dev->dev); + device_remove_file(&minor->kdev, &device_attrs[i]); + device_unregister(&minor->kdev); } -- cgit v1.2.3 From 135f51306b08f9863d77ac85b69989288c62f147 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Jan 2008 16:21:56 +1100 Subject: drm: only call suspend/resume on control node --- linux-core/drm_sysfs.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index a56e9959..114e355e 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -36,8 +36,9 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) printk(KERN_ERR "%s\n", __FUNCTION__); - if (drm_dev->driver->suspend) - return drm_dev->driver->suspend(drm_dev); + if (drm_minor->type == DRM_MINOR_CONTROL) + if (drm_dev->driver->suspend) + return drm_dev->driver->suspend(drm_dev); return 0; } @@ -54,8 +55,9 @@ static int drm_sysfs_resume(struct device *dev) struct drm_minor *drm_minor = to_drm_minor(dev); struct drm_device *drm_dev = drm_minor->dev; - if (drm_dev->driver->resume) - return drm_dev->driver->resume(drm_dev); + if (drm_minor->type == DRM_MINOR_CONTROL) + if (drm_dev->driver->resume) + return drm_dev->driver->resume(drm_dev); return 0; } @@ -168,7 +170,7 @@ int drm_sysfs_device_add(struct drm_minor *minor) minor->kdev.release = drm_sysfs_device_release; minor->kdev.devt = minor->device; if (minor->type == DRM_MINOR_CONTROL) - minor_str = "controlD%d"; + minor_str = "controlD%d"; else minor_str = "card%d"; -- cgit v1.2.3 From ebbc2e0a2e19f5e0fdc06af0951d7fc2cc9ddcbe Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Jan 2008 16:31:37 +1100 Subject: add control ioctls --- linux-core/drmP.h | 1 + linux-core/drm_drv.c | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5bc4887a..2f0791c0 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -302,6 +302,7 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, #define DRM_AUTH 0x1 #define DRM_MASTER 0x2 #define DRM_ROOT_ONLY 0x4 +#define DRM_CONTROL_ALLOW 0x8 // allow ioctl to operate on control node struct drm_ioctl_desc { unsigned int cmd; diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 58beec66..bba4d629 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -117,19 +117,19 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY), - - DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_property_set_ioctl, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_property_set_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY | DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -628,6 +628,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retcode = -EINVAL; goto err_i1; } + #if 0 /* * This check is disabled, because driver private ioctl->cmd @@ -658,7 +659,8 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retcode = -EINVAL; } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) || ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || - ((ioctl->flags & DRM_MASTER) && !file_priv->master)) { + ((ioctl->flags & DRM_MASTER) && !file_priv->master) || + ((!(ioctl->flags & DRM_CONTROL_ALLOW)) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ) { retcode = -EACCES; } else { retcode = func(dev, kdata, file_priv); -- cgit v1.2.3 From 8d6e3c208f8090ccc32ef3a38c58f2aca7f4be2a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Jan 2008 16:43:51 +1100 Subject: allow control getversion --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index bba4d629..4ecea67f 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -56,7 +56,7 @@ static int drm_version(struct drm_device *dev, void *data, /** Ioctl table */ static struct drm_ioctl_desc drm_ioctls[] = { - DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0), + DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), -- cgit v1.2.3 From 73bf5e867089b58b2c4baaa833d15a2b1fb268a4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Jan 2008 16:44:31 +1100 Subject: add internals for opening a control node --- libdrm/xf86drm.c | 21 ++++++++++++--------- libdrm/xf86drm.h | 1 + tests/dristat.c | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 4265c320..2d7d85c1 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -87,6 +87,9 @@ #define DRM_MSG_VERBOSITY 3 +#define DRM_NODE_CONTROL 0 +#define DRM_NODE_RENDER 1 + static drmServerInfoPtr drm_server_info; void drmSetServerInfo(drmServerInfoPtr info) @@ -264,7 +267,7 @@ static int drmMatchBusID(const char *id1, const char *id2) * special file node with the major and minor numbers specified by \p dev and * parent directory if necessary and was called by root. */ -static int drmOpenDevice(long dev, int minor) +static int drmOpenDevice(long dev, int minor, int type) { stat_t st; char buf[64]; @@ -274,7 +277,7 @@ static int drmOpenDevice(long dev, int minor) uid_t user = DRM_DEV_UID; gid_t group = DRM_DEV_GID, serv_group; - sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); + sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor); drmMsg("drmOpenDevice: node name is %s\n", buf); if (drm_server_info) { @@ -348,15 +351,15 @@ static int drmOpenDevice(long dev, int minor) * Calls drmOpenDevice() if \p create is set, otherwise assembles the device * name from \p minor and opens it. */ -static int drmOpenMinor(int minor, int create) +static int drmOpenMinor(int minor, int create, int type) { int fd; char buf[64]; if (create) - return drmOpenDevice(makedev(DRM_MAJOR, minor), minor); + return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); - sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); + sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor); if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd; return -errno; @@ -379,7 +382,7 @@ int drmAvailable(void) int retval = 0; int fd; - if ((fd = drmOpenMinor(0, 1)) < 0) { + if ((fd = drmOpenMinor(0, 1, DRM_NODE_RENDER)) < 0) { #ifdef __linux__ /* Try proc for backward Linux compatibility */ if (!access("/proc/dri/0", R_OK)) @@ -420,7 +423,7 @@ static int drmOpenByBusid(const char *busid) drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); for (i = 0; i < DRM_MAX_MINOR; i++) { - fd = drmOpenMinor(i, 1); + fd = drmOpenMinor(i, 1, DRM_NODE_RENDER); drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); if (fd >= 0) { sv.drm_di_major = 1; @@ -482,7 +485,7 @@ static int drmOpenByName(const char *name) * already in use. If it's in use it will have a busid assigned already. */ for (i = 0; i < DRM_MAX_MINOR; i++) { - if ((fd = drmOpenMinor(i, 1)) >= 0) { + if ((fd = drmOpenMinor(i, 1, DRM_NODE_RENDER)) >= 0) { if ((version = drmGetVersion(fd))) { if (!strcmp(version->name, name)) { drmFreeVersion(version); @@ -526,7 +529,7 @@ static int drmOpenByName(const char *name) if (*pt) { /* Found busid */ return drmOpenByBusid(++pt); } else { /* No busid */ - return drmOpenDevice(strtol(devstring, NULL, 0),i); + return drmOpenDevice(strtol(devstring, NULL, 0),i, DRM_NODE_RENDER); } } } diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 230f54ce..d6e98825 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -49,6 +49,7 @@ #define DRM_DIR_NAME "/dev/dri" #define DRM_DEV_NAME "%s/card%d" +#define DRM_CONTROL_DEV_NAME "%s/controlD%d" #define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */ #define DRM_ERR_NO_DEVICE (-1001) diff --git a/tests/dristat.c b/tests/dristat.c index 89853164..48c3b51b 100644 --- a/tests/dristat.c +++ b/tests/dristat.c @@ -263,7 +263,7 @@ int main(int argc, char **argv) for (i = 0; i < 16; i++) if (!minor || i == minor) { sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, i); - fd = drmOpenMinor(i, 1); + fd = drmOpenMinor(i, 1, DRM_NODE_RENDER); if (fd >= 0) { printf("%s\n", buf); if (mask & DRM_BUSID) getbusid(fd); -- cgit v1.2.3 From 87a32efcdde124df59656e00a402ba50a0ba1e45 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Jan 2008 18:11:04 +1100 Subject: add control node open --- libdrm/xf86drm.c | 4 ++++ libdrm/xf86drm.h | 1 + 2 files changed, 5 insertions(+) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 2d7d85c1..3cc54f12 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -579,6 +579,10 @@ int drmOpen(const char *name, const char *busid) return -1; } +int drmOpenControl(int minor) +{ + return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); +} /** * Free the version information returned by drmGetVersion(). diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index d6e98825..7b418604 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -509,6 +509,7 @@ do { register unsigned int __old __asm("o0"); \ /* General user-level programmer's API: unprivileged */ extern int drmAvailable(void); extern int drmOpen(const char *name, const char *busid); +extern int drmOpenControl(int minor); extern int drmClose(int fd); extern drmVersionPtr drmGetVersion(int fd); extern drmVersionPtr drmGetLibVersion(int fd); -- cgit v1.2.3 From e04d942ee8e74fce90e332446e740a100d782033 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Jan 2008 18:11:17 +1100 Subject: fixup crtcinfo on modes from userspace --- linux-core/drm_crtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index b49fa697..0b71b134 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1548,6 +1548,7 @@ int drm_mode_setcrtc(struct drm_device *dev, mode = drm_mode_create(dev); drm_crtc_convert_umode(mode, &crtc_req->mode); + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); } if (crtc_req->count_outputs == 0 && mode) { -- cgit v1.2.3 From 0a4df3372aec219298e3787f6f377941bc51bfcb Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 10 Jan 2008 05:03:13 +0100 Subject: Updated test mode and added modedemo --- tests/mode/Makefile | 11 +++-- tests/mode/modetest.c | 10 +++- tests/mode/test | 2 +- tests/modedemo/Makefile | 14 ++++++ tests/modedemo/demo.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/modedemo/test | 1 + 6 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 tests/modedemo/Makefile create mode 100644 tests/modedemo/demo.c create mode 100755 tests/modedemo/test diff --git a/tests/mode/Makefile b/tests/mode/Makefile index a3d3b49a..7a9c3c24 100644 --- a/tests/mode/Makefile +++ b/tests/mode/Makefile @@ -1,11 +1,14 @@ -all: modetest +all: app #CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ # -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ -modetest: modetest.c - @gcc $(CFLAGS) -o modetest -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c +app: modetest.c + @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c clean: - @rm -f modetest + @rm -f app + +run: app + @sudo ./test diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index bd8372dc..c1f291b2 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -278,7 +278,15 @@ int testFrameBufferAdd(int fd, drmModeResPtr res) printf("\tCreating BO\n"); /* TODO */ - ret = 1; + ret = drmBOCreate(fd, 800 * 600 * 4, 0, 0, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, &bo); + + printf("\tgot %i\n", ret); if (ret) goto err; diff --git a/tests/mode/test b/tests/mode/test index fa155f4e..f98e3708 100755 --- a/tests/mode/test +++ b/tests/mode/test @@ -1 +1 @@ -LD_PRELOAD=../../libdrm/.libs/libdrm.so ./modetest +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app diff --git a/tests/modedemo/Makefile b/tests/modedemo/Makefile new file mode 100644 index 00000000..467fb11a --- /dev/null +++ b/tests/modedemo/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: demo.c + @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c + +clean: + @rm -f app + +run: app + sudo ./test diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c new file mode 100644 index 00000000..ea71fd1d --- /dev/null +++ b/tests/modedemo/demo.c @@ -0,0 +1,119 @@ + +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" +static struct drm_mode_modeinfo mode = { + .name = "Test mode", + .clock = 25200, + .hdisplay = 640, + .hsync_start = 656, + .hsync_end = 752, + .htotal = 800, + .hskew = 0, + .vdisplay = 480, + .vsync_start = 490, + .vsync_end = 492, + .vtotal = 525, + .vscan = 0, + .vrefresh = 60000, /* vertical refresh * 1000 */ + .flags = 10, +}; + +drmModeFBPtr createFB(int fd, drmModeResPtr res); +int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out); +drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res); + +int main(int argc, char **argv) +{ + int fd; + const char *driver = "i915"; /* hardcoded for now */ + drmModeResPtr res; + drmModeFBPtr framebuffer; + int numOutputs; + drmModeOutputPtr out[8]; + drmModeCrtcPtr crtc; + + printf("Starting test\n"); + + fd = drmOpen(driver, NULL); + + if (fd < 0) { + printf("Failed to open the card fb\n"); + return 1; + } + + res = drmModeGetResources(fd); + if (res == 0) { + printf("Failed to get resources from card\n"); + drmClose(fd); + return 1; + } + + framebuffer = createFB(fd, res); + if (framebuffer == NULL) { + printf("Failed to create framebuffer\n"); + return 1; + } + + numOutputs = findConnectedOutputs(fd, res, out); + if (numOutputs < 1) { + printf("Failed to find connected outputs\n"); + return 1; + } + + crtc = findFreeCrtc(fd, res); + if (numOutputs < 1) { + printf("Couldn't find a free crtc\n"); + return 1; + } + + + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 0, &out[0]->output_id, 1, &mode); + sleep(2); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 500, &out[0]->output_id, 1, &mode); + sleep(2); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 500, 0, &out[0]->output_id, 1, &mode); + sleep(2); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 500, 500, &out[0]->output_id, 1, &mode); + + drmModeFreeResources(res); + printf("Ok\n"); + + return 0; +} + +drmModeFBPtr createFB(int fd, drmModeResPtr res) +{ + /* Haveing problems getting drmBOCreate to work with me. */ + return drmModeGetFB(fd, res->fbs[1]); +} + +int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out) +{ + int count = 0; + int i; + + drmModeOutputPtr output; + + for (i = 0; i < res->count_outputs; i++) { + output = drmModeGetOutput(fd, res->outputs[i]); + + if (!output || output->connection != DRM_MODE_CONNECTED) + continue; + + out[count++] = output; + } + + return count; +} + +drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res) +{ + return drmModeGetCrtc(fd, res->crtcs[0]); +} diff --git a/tests/modedemo/test b/tests/modedemo/test new file mode 100755 index 00000000..f98e3708 --- /dev/null +++ b/tests/modedemo/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app -- cgit v1.2.3 From 0b69c1d1d6a09d55d3367296dfdf23269f2721ea Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 11 Jan 2008 02:55:00 +0100 Subject: Added fixed misc framebuffer problems --- linux-core/drm_crtc.c | 53 ++++++++++++++++++++++++++++----------------------- tests/mode/modetest.c | 2 +- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 0b71b134..fdf4c70e 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -163,12 +163,6 @@ struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev) { struct drm_framebuffer *fb; - /* Limit to single framebuffer for now */ - if (dev->mode_config.num_fb > 1) { - DRM_ERROR("Attempt to add multiple framebuffers failed\n"); - return NULL; - } - fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); if (!fb) return NULL; @@ -771,7 +765,11 @@ void drm_mode_config_init(struct drm_device *dev) idr_init(&dev->mode_config.crtc_idr); drm_mode_create_standard_output_properties(dev); - + + /* Just to be sure */ + dev->mode_config.num_fb = 0; + dev->mode_config.num_output = 0; + dev->mode_config.num_crtc = 0; } EXPORT_SYMBOL(drm_mode_config_init); @@ -1013,6 +1011,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) } list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { + /* there should only be bo of kernel type left */ if (fb->bo->type != drm_bo_type_kernel) drm_framebuffer_destroy(fb); else @@ -1621,7 +1620,6 @@ int drm_mode_addfb(struct drm_device *dev, struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; struct drm_buffer_object *bo; - struct drm_crtc *crtc; int ret = 0; if ((config->min_width > r->width) || (r->width > config->max_width)) { @@ -1637,6 +1635,7 @@ int drm_mode_addfb(struct drm_device *dev, /* TODO check limits are okay */ ret = drm_get_buffer_object(dev, &bo, r->handle); if (ret || !bo) { + DRM_ERROR("BO handle not valid\n"); ret = -EINVAL; goto out; } @@ -1646,6 +1645,7 @@ int drm_mode_addfb(struct drm_device *dev, fb = drm_framebuffer_create(dev); if (!fb) { + DRM_ERROR("could not create framebuffer\n"); ret = -EINVAL; goto out; } @@ -1662,12 +1662,6 @@ int drm_mode_addfb(struct drm_device *dev, list_add(&fb->filp_head, &file_priv->fbs); - /* FIXME: bind the fb to the right crtc */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - crtc->fb = fb; - dev->driver->fb_probe(dev, crtc); - } - out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1694,8 +1688,10 @@ int drm_mode_rmfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_framebuffer *fb = 0; + struct drm_framebuffer *fbl = 0; uint32_t *id = data; int ret = 0; + int found = 0; mutex_lock(&dev->mode_config.mutex); fb = idr_find(&dev->mode_config.crtc_idr, *id); @@ -1706,15 +1702,24 @@ int drm_mode_rmfb(struct drm_device *dev, goto out; } - /* TODO check if we own the buffer */ + list_for_each_entry(fbl, &file_priv->fbs, filp_head) + if (fb == fbl) + found = 1; + + if (!found) { + DRM_ERROR("tried to remove a fb that we didn't own\n"); + ret = -EINVAL; + goto out; + } + /* TODO release all crtc connected to the framebuffer */ - /* bind the fb to the crtc for now */ /* TODO unhock the destructor from the buffer object */ - if (fb->bo->type != drm_bo_type_kernel) - drm_framebuffer_destroy(fb); - else - dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); + if (fb->bo->type == drm_bo_type_kernel) + DRM_ERROR("the bo type should not be of kernel type\n"); + + list_del(&fb->filp_head); + drm_framebuffer_destroy(fb); out: mutex_unlock(&dev->mode_config.mutex); @@ -1788,10 +1793,10 @@ void drm_fb_release(struct file *filp) mutex_lock(&dev->mode_config.mutex); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { list_del(&fb->filp_head); - if (fb->bo->type != drm_bo_type_kernel) - drm_framebuffer_destroy(fb); - else - dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); + if (fb->bo->type == drm_bo_type_kernel) + DRM_ERROR("the bo type should not be of kernel_type, the kernel will probably explode, why Dave\n"); + + drm_framebuffer_destroy(fb); } mutex_unlock(&dev->mode_config.mutex); } diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index c1f291b2..eeb4b258 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -291,7 +291,7 @@ int testFrameBufferAdd(int fd, drmModeResPtr res) goto err; printf("\tAdding FB\n"); - ret = drmModeAddFB(fd, 640, 480, 32, 8, 0, &bo, &fb); + ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, &bo, &fb); if (ret) goto err_bo; -- cgit v1.2.3 From 12a47cd136803883231c9763f2007216236ec3b2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 11 Jan 2008 04:23:32 +0100 Subject: Updated the modedemo test --- tests/modedemo/demo.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 7 deletions(-) diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index ea71fd1d..44ebacd3 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -8,6 +8,11 @@ #include "xf86drm.h" #include "xf86drmMode.h" + +/* setting this to 2024 gets the pitch wrong check it */ +#define SIZE_X 2048 +#define SIZE_Y 2048 + static struct drm_mode_modeinfo mode = { .name = "Test mode", .clock = 25200, @@ -28,6 +33,7 @@ static struct drm_mode_modeinfo mode = { drmModeFBPtr createFB(int fd, drmModeResPtr res); int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out); drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res); +void prettyColors(int fd, unsigned int handle); int main(int argc, char **argv) { @@ -73,14 +79,26 @@ int main(int argc, char **argv) return 1; } + prettyColors(fd, framebuffer->handle); + + printf("0 0\n"); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 0, &out[1]->output_id, 1, &mode); + sleep(2); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 0, &out[0]->output_id, 1, &mode); + printf("0 100\n"); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 100, &out[1]->output_id, 1, &mode); sleep(2); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 500, &out[0]->output_id, 1, &mode); + + printf("100 0\n"); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 0, &out[1]->output_id, 1, &mode); sleep(2); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 500, 0, &out[0]->output_id, 1, &mode); + + printf("100 100\n"); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 100, &out[1]->output_id, 1, &mode); sleep(2); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 500, 500, &out[0]->output_id, 1, &mode); + + /* turn the crtc off just in case */ + drmModeSetCrtc(fd, crtc->crtc_id, 0, 0, 0, 0, 0, 0); drmModeFreeResources(res); printf("Ok\n"); @@ -90,8 +108,40 @@ int main(int argc, char **argv) drmModeFBPtr createFB(int fd, drmModeResPtr res) { - /* Haveing problems getting drmBOCreate to work with me. */ - return drmModeGetFB(fd, res->fbs[1]); + drmModeFBPtr frame; + unsigned int fb = 0; + int ret = 0; + drmBO bo; + + ret = drmBOCreate(fd, SIZE_X * SIZE_Y * 4, 0, 0, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, &bo); + + if (ret) + goto err; + + ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, SIZE_X*4, &bo, &fb); + + if (ret) + goto err_bo; + + frame = drmModeGetFB(fd, fb); + + if (!frame) + goto err_bo; + + return frame; + +err_bo: + drmBOUnreference(fd, &bo); +err: + printf("Something went wrong when creating a fb, using one of the predefined ones\n"); + + return drmModeGetFB(fd, res->fbs[0]); } int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out) @@ -115,5 +165,37 @@ int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out) drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res) { - return drmModeGetCrtc(fd, res->crtcs[0]); + return drmModeGetCrtc(fd, res->crtcs[1]); +} + +void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr) +{ + int i, j; + + for (i = x; i < x + w; i++) + for(j = y; j < y + h; j++) + ptr[(i * SIZE_X) + j] = v; + +} + +void prettyColors(int fd, unsigned int handle) +{ + drmBO bo; + unsigned int *ptr; + int i, j; + + drmBOReference(fd, handle, &bo); + drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); + + for (i = 0; i < (SIZE_X*SIZE_Y); i++) + ptr[i] = 0xFFFFFFFF; + + for (i = 0; i < 8; i++) + draw(i*40, i*40, 40, 40, 0, ptr); + + + draw(200, 100, 40, 40, 0xff00ff, ptr); + draw(100, 200, 40, 40, 0xff00ff, ptr); + + drmBOUnmap(fd, &bo); } -- cgit v1.2.3 From f07942f74a08e4c65e3b5e5c46f543686ae30c2b Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 11 Jan 2008 17:13:48 +0100 Subject: Panning now works without modeset --- linux-core/drm_crtc.c | 14 +++++++++++++- linux-core/drm_crtc.h | 4 ++++ linux-core/intel_display.c | 1 + tests/modedemo/demo.c | 21 +++++++++++---------- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fdf4c70e..1e69eca3 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1048,6 +1048,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_crtc **save_crtcs, *new_crtc; bool save_enabled = crtc->enabled; bool changed = false; + bool flip_or_move = false; struct drm_output *output; int count = 0, ro; @@ -1055,11 +1056,13 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, if (!save_crtcs) return -ENOMEM; + /* We should be able to check here if the fb has the same properties + * and then just flip_or_move it */ if (crtc->fb != fb) changed = true; if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) - changed = true; + flip_or_move = true; if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) changed = true; @@ -1082,6 +1085,10 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, } } + /* mode_set_base is not a required function */ + if (flip_or_move && !crtc->funcs->mode_set_base) + changed = true; + if (changed) { crtc->fb = fb; crtc->enabled = (new_mode != NULL); @@ -1102,7 +1109,10 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, crtc->desired_mode = new_mode; } drm_disable_unused_functions(dev); + } else if (flip_or_move) { + crtc->funcs->mode_set_base(crtc, crtc_info->x, crtc_info->y); } + kfree(save_crtcs); return 0; } @@ -1564,6 +1574,7 @@ int drm_mode_setcrtc(struct drm_device *dev, if (crtc_req->count_outputs > 0) { u32 out_id; + /* Maybe we should check that count_outputs is a sensible value. */ output_set = kmalloc(crtc_req->count_outputs * sizeof(struct drm_output *), GFP_KERNEL); if (!output_set) { @@ -1589,6 +1600,7 @@ int drm_mode_setcrtc(struct drm_device *dev, } } + /* What happens to output_set, leak? */ ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb); out: diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 54e0c000..65c3704a 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -325,6 +325,10 @@ struct drm_crtc_funcs { /* Actually set the mode */ void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y); + + /* Move the crtc on the current fb to the given position *optional* */ + void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); + /* Set gamma on the CRTC */ void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b, int regno); diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index a81cfe69..e75d3c07 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1083,6 +1083,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .unlock = intel_crtc_unlock, .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, + .mode_set_base = intel_pipe_set_base, .gamma_set = intel_crtc_gamma_set, .prepare = intel_crtc_prepare, .commit = intel_crtc_commit, diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 44ebacd3..594d60db 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -9,9 +9,10 @@ #include "xf86drm.h" #include "xf86drmMode.h" -/* setting this to 2024 gets the pitch wrong check it */ #define SIZE_X 2048 #define SIZE_Y 2048 +/* Pitch needs to be power of two */ +#define PITCH 2048 static struct drm_mode_modeinfo mode = { .name = "Test mode", @@ -82,19 +83,19 @@ int main(int argc, char **argv) prettyColors(fd, framebuffer->handle); printf("0 0\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 0, &out[1]->output_id, 1, &mode); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 0, &out[0]->output_id, 1, &mode); sleep(2); printf("0 100\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 100, &out[1]->output_id, 1, &mode); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 100, &out[0]->output_id, 1, &mode); sleep(2); printf("100 0\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 0, &out[1]->output_id, 1, &mode); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 0, &out[0]->output_id, 1, &mode); sleep(2); printf("100 100\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 100, &out[1]->output_id, 1, &mode); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 100, &out[0]->output_id, 1, &mode); sleep(2); /* turn the crtc off just in case */ @@ -124,7 +125,7 @@ drmModeFBPtr createFB(int fd, drmModeResPtr res) if (ret) goto err; - ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, SIZE_X*4, &bo, &fb); + ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, &bo, &fb); if (ret) goto err_bo; @@ -165,7 +166,7 @@ int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out) drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res) { - return drmModeGetCrtc(fd, res->crtcs[1]); + return drmModeGetCrtc(fd, res->crtcs[0]); } void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr) @@ -174,7 +175,7 @@ void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsign for (i = x; i < x + w; i++) for(j = y; j < y + h; j++) - ptr[(i * SIZE_X) + j] = v; + ptr[(i * PITCH) + j] = v; } @@ -182,7 +183,7 @@ void prettyColors(int fd, unsigned int handle) { drmBO bo; unsigned int *ptr; - int i, j; + int i; drmBOReference(fd, handle, &bo); drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); @@ -191,7 +192,7 @@ void prettyColors(int fd, unsigned int handle) ptr[i] = 0xFFFFFFFF; for (i = 0; i < 8; i++) - draw(i*40, i*40, 40, 40, 0, ptr); + draw(i * 40, i * 40, 40, 40, 0, ptr); draw(200, 100, 40, 40, 0xff00ff, ptr); -- cgit v1.2.3 From e6fc47129ffe972bbee1c08fd822a8c171f21322 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 11 Jan 2008 17:33:00 +0100 Subject: Fix for X axis panning problem --- linux-core/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index e75d3c07..1498a51c 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -370,7 +370,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); Start = crtc->fb->offset; - Offset = y * crtc->fb->pitch + x; + Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); if (IS_I965G(dev)) { -- cgit v1.2.3 From f1f934c8c97d6664fb5e1920a41154c09cc7f293 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 15 Jan 2008 14:05:25 +0100 Subject: radeon_ms: add rom parsing & adapt code Add rom (only combios for now) parsing and use informations retrieve instead of hardcoded table. Shuffle code around a bit. --- linux-core/Makefile.kernel | 3 +- linux-core/radeon_ms_combios.c | 1 + linux-core/radeon_ms_combios.h | 1 + linux-core/radeon_ms_properties.c | 1 + linux-core/radeon_ms_properties.h | 1 + linux-core/radeon_ms_rom.c | 1 + linux-core/radeon_ms_rom.h | 1 + shared-core/radeon_ms.h | 44 ++--- shared-core/radeon_ms_combios.c | 396 +++++++++++++++++++++++++++++++++++++ shared-core/radeon_ms_combios.h | 385 ++++++++++++++++++++++++++++++++++++ shared-core/radeon_ms_crtc.c | 45 +++-- shared-core/radeon_ms_drm.c | 28 ++- shared-core/radeon_ms_family.c | 100 +--------- shared-core/radeon_ms_i2c.c | 63 +++++- shared-core/radeon_ms_output.c | 50 +++-- shared-core/radeon_ms_properties.c | 121 ++++++++++++ shared-core/radeon_ms_properties.h | 50 +++++ shared-core/radeon_ms_reg.h | 26 +++ shared-core/radeon_ms_rom.c | 91 +++++++++ shared-core/radeon_ms_rom.h | 51 +++++ 20 files changed, 1301 insertions(+), 158 deletions(-) create mode 120000 linux-core/radeon_ms_combios.c create mode 120000 linux-core/radeon_ms_combios.h create mode 120000 linux-core/radeon_ms_properties.c create mode 120000 linux-core/radeon_ms_properties.h create mode 120000 linux-core/radeon_ms_rom.c create mode 120000 linux-core/radeon_ms_rom.h create mode 100644 shared-core/radeon_ms_combios.c create mode 100644 shared-core/radeon_ms_combios.h create mode 100644 shared-core/radeon_ms_properties.c create mode 100644 shared-core/radeon_ms_properties.h create mode 100644 shared-core/radeon_ms_rom.c create mode 100644 shared-core/radeon_ms_rom.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 7ef504ad..b4fdcf6b 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -39,7 +39,8 @@ radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ radeon_ms_bus.o radeon_ms_fence.o \ radeon_ms_cp.o radeon_ms_cp_mc.o radeon_ms_i2c.o \ radeon_ms_output.o radeon_ms_crtc.o radeon_ms_fb.o \ - radeon_ms_exec.o radeon_ms_gpu.o radeon_ms_dac.o + radeon_ms_exec.o radeon_ms_gpu.o radeon_ms_dac.o \ + radeon_ms_properties.o radeon_ms_rom.o radeon_ms_combios.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/radeon_ms_combios.c b/linux-core/radeon_ms_combios.c new file mode 120000 index 00000000..d7b99958 --- /dev/null +++ b/linux-core/radeon_ms_combios.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_combios.c \ No newline at end of file diff --git a/linux-core/radeon_ms_combios.h b/linux-core/radeon_ms_combios.h new file mode 120000 index 00000000..5b19c708 --- /dev/null +++ b/linux-core/radeon_ms_combios.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_combios.h \ No newline at end of file diff --git a/linux-core/radeon_ms_properties.c b/linux-core/radeon_ms_properties.c new file mode 120000 index 00000000..e2e0dc0b --- /dev/null +++ b/linux-core/radeon_ms_properties.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_properties.c \ No newline at end of file diff --git a/linux-core/radeon_ms_properties.h b/linux-core/radeon_ms_properties.h new file mode 120000 index 00000000..59783e89 --- /dev/null +++ b/linux-core/radeon_ms_properties.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_properties.h \ No newline at end of file diff --git a/linux-core/radeon_ms_rom.c b/linux-core/radeon_ms_rom.c new file mode 120000 index 00000000..80f5f606 --- /dev/null +++ b/linux-core/radeon_ms_rom.c @@ -0,0 +1 @@ +../shared-core/radeon_ms_rom.c \ No newline at end of file diff --git a/linux-core/radeon_ms_rom.h b/linux-core/radeon_ms_rom.h new file mode 120000 index 00000000..f20e42be --- /dev/null +++ b/linux-core/radeon_ms_rom.h @@ -0,0 +1 @@ +../shared-core/radeon_ms_rom.h \ No newline at end of file diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index ee795f3a..a784882b 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -33,6 +33,8 @@ #include "radeon_ms_drv.h" #include "radeon_ms_reg.h" #include "radeon_ms_drm.h" +#include "radeon_ms_rom.h" +#include "radeon_ms_properties.h" #define DRIVER_AUTHOR "Jerome Glisse, Dave Airlie, Gareth Hughes, "\ "Keith Whitwell, others." @@ -43,10 +45,6 @@ #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 0 -#define RADEON_PAGE_SIZE 4096 -#define RADEON_MAX_CONNECTORS 8 -#define RADEON_MAX_OUTPUTS 8 - enum radeon_bus_type { RADEON_PCI = 0x10000, RADEON_AGP = 0x20000, @@ -154,20 +152,6 @@ struct radeon_ms_output { struct radeon_state *state); }; -struct radeon_ms_properties { - uint16_t subvendor; - uint16_t subdevice; - int16_t pll_reference_freq; - int32_t pll_min_pll_freq; - int32_t pll_max_pll_freq; - char pll_use_bios; - char pll_dummy_reads; - char pll_delay; - char pll_r300_errata; - struct radeon_ms_output *outputs[RADEON_MAX_OUTPUTS]; - struct radeon_ms_connector *connectors[RADEON_MAX_CONNECTORS]; -}; - struct radeon_state { /* memory */ uint32_t config_aper_0_base; @@ -310,7 +294,6 @@ struct drm_radeon_private { /* card family */ uint32_t usec_timeout; uint32_t family; - struct radeon_ms_properties *properties; struct radeon_ms_output *outputs[RADEON_MAX_OUTPUTS]; struct radeon_ms_connector *connectors[RADEON_MAX_CONNECTORS]; /* drm map (MMIO, FB) */ @@ -342,6 +325,9 @@ struct drm_radeon_private { uint8_t cp_ready; uint8_t bus_ready; uint8_t write_back; + /* abstract asic specific structures */ + struct radeon_ms_rom rom; + struct radeon_ms_properties properties; }; @@ -369,6 +355,11 @@ int radeon_ms_pcie_init(struct drm_device *dev); void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state); void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state); +/* radeon_ms_combios.c */ +int radeon_ms_combios_get_properties(struct drm_device *dev); +int radeon_ms_connectors_from_combios(struct drm_device *dev); +int radeon_ms_outputs_from_combios(struct drm_device *dev); + /* radeon_ms_compat.c */ long radeon_ms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); @@ -475,12 +466,21 @@ void radeon_ms_irq_uninstall(struct drm_device * dev); /* radeon_ms_output.c */ void radeon_ms_connectors_destroy(struct drm_device *dev); int radeon_ms_connectors_from_properties(struct drm_device *dev); +int radeon_ms_connectors_from_rom(struct drm_device *dev); void radeon_ms_outputs_destroy(struct drm_device *dev); int radeon_ms_outputs_from_properties(struct drm_device *dev); +int radeon_ms_outputs_from_rom(struct drm_device *dev); void radeon_ms_outputs_restore(struct drm_device *dev, struct radeon_state *state); void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state); +/* radeon_ms_properties.c */ +int radeon_ms_properties_init(struct drm_device *dev); + +/* radeon_ms_rom.c */ +int radeon_ms_rom_get_properties(struct drm_device *dev); +int radeon_ms_rom_init(struct drm_device *dev); + /* radeon_ms_state.c */ void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state); void radeon_ms_state_restore(struct drm_device *dev, @@ -545,7 +545,7 @@ static __inline__ void pll_index_errata(struct drm_radeon_private *dev_priv) /* This workaround is necessary on rv200 and RS200 or PLL * reads may return garbage (among others...) */ - if (dev_priv->properties->pll_dummy_reads) { + if (dev_priv->properties.pll_dummy_reads) { tmp = MMIO_R(CLOCK_CNTL_DATA); tmp = MMIO_R(CRTC_GEN_CNTL); } @@ -554,7 +554,7 @@ static __inline__ void pll_index_errata(struct drm_radeon_private *dev_priv) * CLOCK_CNTL_INDEX register access. If not, register reads afterward * may not be correct. */ - if (dev_priv->properties->pll_r300_errata) { + if (dev_priv->properties.pll_r300_errata) { tmp = save = MMIO_R(CLOCK_CNTL_INDEX); tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK; tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_WR_EN; @@ -569,7 +569,7 @@ static __inline__ void pll_data_errata(struct drm_radeon_private *dev_priv) /* This workarounds is necessary on RV100, RS100 and RS200 chips * or the chip could hang on a subsequent access */ - if (dev_priv->properties->pll_delay) { + if (dev_priv->properties.pll_delay) { /* we can't deal with posted writes here ... */ udelay(5000); } diff --git a/shared-core/radeon_ms_combios.c b/shared-core/radeon_ms_combios.c new file mode 100644 index 00000000..04a33699 --- /dev/null +++ b/shared-core/radeon_ms_combios.c @@ -0,0 +1,396 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jérôme Glisse + */ +#include "radeon_ms.h" + +extern struct radeon_ms_output radeon_ms_dac1; +extern struct radeon_ms_output radeon_ms_dac2; +extern const struct drm_output_funcs radeon_ms_output_funcs; + +static struct combios_connector_chip_info * +radeon_ms_combios_get_connector_chip_info(struct drm_device *dev, int chip_num) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_rom *rom = &dev_priv->rom; + struct combios_header *header; + struct combios_connector_table *connector_table; + struct combios_connector_chip_info *connector_chip_info; + uint32_t offset; + int numof_chips, i; + + if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) { + return NULL; + } + header = rom->rom.combios_header; + offset = header->usPointerToExtendedInitTable2; + if ((offset + sizeof(struct combios_connector_table)) > rom->rom_size) { + DRM_INFO("[radeon_ms] wrong COMBIOS connector offset\n"); + return NULL; + } + if (!offset) { + return NULL; + } + connector_table = (struct combios_connector_table *) + &rom->rom_image[offset]; + numof_chips = (connector_table->ucConnectorHeader & + BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK) >> + BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT; + DRM_INFO("[radeon_ms] COMBIOS number of chip: %d (table rev: %d)\n", + numof_chips, + (connector_table->ucConnectorHeader & + BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK) >> + BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT); + for (i = 0; i < numof_chips; i++) { + int chip; + + connector_chip_info = &connector_table->sChipConnectorInfo[i]; + chip = (connector_chip_info->ucChipHeader & + BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK) >> + BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT; + DRM_INFO("[radeon_ms] COMBIOS chip: %d (asked for: %d)\n", + chip, chip_num); + if (chip == chip_num) { + return connector_chip_info; + } + } + return NULL; +} + +static int radeon_combios_get_connector_infos(struct drm_device *dev, + int connector_info, + int *connector_type, + int *ddc_line, + int *tmds_type, + int *dac_type) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + *connector_type = (connector_info & BIOS_CONNECTOR_INFO__TYPE__MASK) >> + BIOS_CONNECTOR_INFO__TYPE__SHIFT; + *ddc_line = (connector_info & BIOS_CONNECTOR_INFO__DDC_LINE__MASK) >> + BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT; + *tmds_type = (connector_info & BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK) >> + BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT; + *dac_type = (connector_info & BIOS_CONNECTOR_INFO__DAC_TYPE__MASK) >> + BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT; + + /* most XPRESS chips seem to specify DDC_CRT2 for their + * VGA DDC port, however DDC never seems to work on that + * port. Some have reported success on DDC_MONID, so + * lets see what happens with that. + */ + if (dev_priv->family == CHIP_RS400 && + *connector_type == BIOS_CONNECTOR_TYPE__CRT && + *ddc_line == BIOS_DDC_LINE__CRT2) { + *ddc_line = BIOS_DDC_LINE__MONID01; + } + /* XPRESS desktop chips seem to have a proprietary + * connector listed for DVI-D, try and do the right + * thing here. + */ + if (dev_priv->family == CHIP_RS400 && + *connector_type == BIOS_CONNECTOR_TYPE__PROPRIETARY) { + DRM_INFO("[radeon_ms] COMBIOS Proprietary connector " + "found, assuming DVI-D\n"); + *dac_type = 2; + *tmds_type = BIOS_TMDS_TYPE__EXTERNAL; + *connector_type = BIOS_CONNECTOR_TYPE__DVI_D; + } + return 0; +} + +static int radeon_ms_combios_connector_add(struct drm_device *dev, + int connector_number, + int connector_type, + uint32_t i2c_reg) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_connector *connector = NULL; + struct drm_output *output = NULL; + + connector = drm_alloc(sizeof(struct radeon_ms_connector), + DRM_MEM_DRIVER); + if (connector == NULL) { + radeon_ms_connectors_destroy(dev); + return -ENOMEM; + } + memset(connector, 0, sizeof(struct radeon_ms_connector)); + connector->monitor_type = MT_NONE; + connector->type = connector_type; + connector->i2c_reg = i2c_reg; + + if (i2c_reg) { + connector->i2c = radeon_ms_i2c_create(dev, + connector->i2c_reg, + connector->type); + if (connector->i2c == NULL) { + radeon_ms_connectors_destroy(dev); + return -ENOMEM; + } + } else { + connector->i2c = NULL; + } + + output = drm_output_create(dev, &radeon_ms_output_funcs, + connector->type); + if (output == NULL) { + radeon_ms_connectors_destroy(dev); + return -EINVAL; + } + connector->output = output; + output->driver_private = connector; + output->possible_crtcs = 0x3; + dev_priv->connectors[connector_number] = connector; + return 0; +} + +int radeon_ms_combios_get_properties(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_rom *rom = &dev_priv->rom; + struct combios_pll_block *pll_block; + struct combios_header *header; + uint32_t offset; + + if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) { + return 0; + } + header = rom->rom.combios_header; + offset = header->usPointerToPllInfoBlock; + if ((offset + sizeof(struct combios_pll_block)) > rom->rom_size) { + DRM_INFO("[radeon_ms] wrong COMBIOS pll block offset\n"); + return 0; + } + if (!offset) { + return 0; + } + pll_block = (struct combios_pll_block *)&rom->rom_image[offset]; + dev_priv->properties.pll_reference_freq = pll_block->usDotClockRefFreq; + dev_priv->properties.pll_reference_div = pll_block->usDotClockRefDiv; + dev_priv->properties.pll_min_pll_freq = pll_block->ulDotClockMinFreq; + dev_priv->properties.pll_max_pll_freq = pll_block->ulDotClockMaxFreq; + dev_priv->properties.pll_reference_freq *= 10; + dev_priv->properties.pll_min_pll_freq *= 10; + dev_priv->properties.pll_max_pll_freq *= 10; + DRM_INFO("[radeon_ms] COMBIOS pll reference frequency : %d\n", + dev_priv->properties.pll_reference_freq); + DRM_INFO("[radeon_ms] COMBIOS pll reference divider : %d\n", + dev_priv->properties.pll_reference_div); + DRM_INFO("[radeon_ms] COMBIOS pll minimum frequency : %d\n", + dev_priv->properties.pll_min_pll_freq); + DRM_INFO("[radeon_ms] COMBIOS pll maximum frequency : %d\n", + dev_priv->properties.pll_max_pll_freq); + return 1; +} + +int radeon_ms_connectors_from_combios(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct combios_connector_chip_info *connector_chip_info; + int connector_type, ddc_line, tmds_type, dac_type; + int dac1, dac2, tmdsint, tmdsext; + int numof_connector, i, c = 0, added, j; + uint32_t i2c_reg; + int ret; + + dac1 = dac2 = tmdsint = tmdsext = -1; + connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1); + if (connector_chip_info == NULL) { + return -1; + } + numof_connector = (connector_chip_info->ucChipHeader & + BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >> + BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT; + DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n", + numof_connector); + for (i = 0; i < numof_connector; i++) { + int connector_info = connector_chip_info->sConnectorInfo[i]; + + ret = radeon_combios_get_connector_infos(dev, + connector_info, + &connector_type, + &ddc_line, + &tmds_type, + &dac_type); + + switch (ddc_line) { + case BIOS_DDC_LINE__MONID01: + i2c_reg = GPIO_MONID; + break; + case BIOS_DDC_LINE__DVI: + i2c_reg = GPIO_DVI_DDC; + break; + case BIOS_DDC_LINE__VGA: + i2c_reg = GPIO_DDC1; + break; + case BIOS_DDC_LINE__CRT2: + i2c_reg = GPIO_CRT2_DDC; + break; + case BIOS_DDC_LINE__GPIOPAD: + i2c_reg = VIPPAD_EN; + break; + case BIOS_DDC_LINE__ZV_LCDPAD: + i2c_reg = VIPPAD1_EN; + break; + default: + i2c_reg = 0; + break; + } + added = 0; + switch (connector_type) { + case BIOS_CONNECTOR_TYPE__CRT: + ret = radeon_ms_combios_connector_add(dev, c, + ConnectorVGA, + i2c_reg); + if (ret) { + return ret; + } + added = 1; + break; + case BIOS_CONNECTOR_TYPE__DVI_I: + ret = radeon_ms_combios_connector_add(dev, c, + ConnectorDVII, + i2c_reg); + if (ret) { + return ret; + } + added = 1; + break; + case BIOS_CONNECTOR_TYPE__DVI_D: + ret = radeon_ms_combios_connector_add(dev, c, + ConnectorDVID, + i2c_reg); + if (ret) { + return ret; + } + added = 1; + break; + default: + break; + } + if (added) { + j = 0; + /* find to which output this connector is associated + * by following same algo as in: + * radeon_ms_outputs_from_combios*/ + switch (dac_type) { + case BIOS_DAC_TYPE__CRT: + if (dac1 == -1) { + dac1 = c; + } + dev_priv->connectors[c]->outputs[j++] = dac1; + break; + case BIOS_DAC_TYPE__NON_CRT: + if (dac2 == -1) { + dac2 = c; + } + dev_priv->connectors[c]->outputs[j++] = dac2; + break; + } +#if 0 + switch (tmds_type) { + case BIOS_TMDS_TYPE__INTERNAL: + if (tmdsint == -1) { + tmdsint = c; + } + dev_priv->connectors[c]->outputs[j++] = tmdsint; + break; + case BIOS_TMDS_TYPE__EXTERNAL: + if (tmdsext == -1) { + tmdsext = c; + } + dev_priv->connectors[c]->outputs[j++] = tmdsext; + break; + } +#endif + c++; + } + } + return c; +} + +int radeon_ms_outputs_from_combios(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct combios_connector_chip_info *connector_chip_info; + int connector_type, ddc_line, tmds_type, dac_type; + int numof_connector, i, dac1_present, dac2_present, c = 0; + int ret; + + dac1_present = dac2_present = 0; + connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1); + if (connector_chip_info == NULL) { + return -1; + } + numof_connector = (connector_chip_info->ucChipHeader & + BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >> + BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT; + DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n", + numof_connector); + for (i = 0; i < numof_connector; i++) { + int connector_info = connector_chip_info->sConnectorInfo[i]; + + ret = radeon_combios_get_connector_infos(dev, + connector_info, + &connector_type, + &ddc_line, + &tmds_type, + &dac_type); + + if (!dac1_present && dac_type == BIOS_DAC_TYPE__CRT) { + dev_priv->outputs[c] = + drm_alloc(sizeof(struct radeon_ms_output), + DRM_MEM_DRIVER); + if (dev_priv->outputs[c] == NULL) { + radeon_ms_outputs_destroy(dev); + return -ENOMEM; + } + memcpy(dev_priv->outputs[c], &radeon_ms_dac1, + sizeof(struct radeon_ms_output)); + dev_priv->outputs[c]->dev = dev; + dev_priv->outputs[c]->initialize(dev_priv->outputs[c]); + dac1_present = 1; + c++; + } + if (!dac2_present && dac_type == BIOS_DAC_TYPE__NON_CRT) { + dev_priv->outputs[c] = + drm_alloc(sizeof(struct radeon_ms_output), + DRM_MEM_DRIVER); + if (dev_priv->outputs[c] == NULL) { + radeon_ms_outputs_destroy(dev); + return -ENOMEM; + } + memcpy(dev_priv->outputs[c], &radeon_ms_dac2, + sizeof(struct radeon_ms_output)); + dev_priv->outputs[c]->dev = dev; + dev_priv->outputs[c]->initialize(dev_priv->outputs[c]); + dac1_present = 1; + c++; + } + } + return c; +} diff --git a/shared-core/radeon_ms_combios.h b/shared-core/radeon_ms_combios.h new file mode 100644 index 00000000..fbceadf2 --- /dev/null +++ b/shared-core/radeon_ms_combios.h @@ -0,0 +1,385 @@ +/* + * Copyright 2006-2007 Advanced Micro Devices, Inc. + * Copyright 2007 Jérôme Glisse + * + * 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: + * Jérôme Glisse + */ +#ifndef __RADEON_MS_COMBIOS_H__ +#define __RADEON_MS_COMBIOS_H__ + +#pragma pack(1) + +#define ROM_HEADER 0x48 + +struct combios_header +{ + uint8_t ucTypeDefinition; + uint8_t ucExtFunctionCode; + uint8_t ucOemID1; + uint8_t ucOemID2; + uint8_t ucBiosMajorRev; + uint8_t ucBiosMinorRev; + uint16_t usStructureSize; + uint16_t usPointerToSmi; + uint16_t usPointerToPmid; + uint16_t usPointerToInitTable; + uint16_t usPointerToCrcChecksumBlock; + uint16_t usPointerToConfigFilename; + uint16_t usPointerToLogonMessage; + uint16_t usPointerToMiscInfo; + uint16_t usPciBusDevInitCode; + uint16_t usBiosRuntimeSegmentAddress; + uint16_t usIoBaseAddress; + uint16_t usSubsystemVendorID; + uint16_t usSubsystemID; + uint16_t usPostVendorID; + uint16_t usInt10Offset; + uint16_t usInt10Segment; + uint16_t usMonitorInfo; + uint16_t usPointerToConfigBlock; + uint16_t usPointerToDacDelayInfo; + uint16_t usPointerToCapDataStruct; + uint16_t usPointerToInternalCrtTables; + uint16_t usPointerToPllInfoBlock; + uint16_t usPointerToTVInfoTable; + uint16_t usPointerToDFPInfoTable; + uint16_t usPointerToHWConfigTable; + uint16_t usPointerToMMConfigTable; + uint32_t ulTVStdPatchTableSignature; + uint16_t usPointerToTVStdPatchTable; + uint16_t usPointerToPanelInfoTable; + uint16_t usPointerToAsicInfoTable; + uint16_t usPointerToAuroraInfoTable; + uint16_t usPointerToPllInitTable; + uint16_t usPointerToMemoryConfigTable; + uint16_t usPointerToSaveMaskTable; + uint16_t usPointerHardCodedEdid; + uint16_t usPointerToExtendedInitTable1; + uint16_t usPointerToExtendedInitTable2; + uint16_t usPointerToDynamicClkTable; + uint16_t usPointerToReservedMemoryTable; + uint16_t usPointerToBridgetInitTable; + uint16_t usPointerToExtTMDSInitTable; + uint16_t usPointerToMemClkInfoTable; + uint16_t usPointerToExtDACTable; + uint16_t usPointerToMiscInfoTable; +}; + +struct combios_pll_block +{ + /* Usually 6 */ + uint8_t ucPLLBiosVersion; + /* Size in bytes */ + uint8_t ucStructureSize; + /* Dot clock entry used for accelerated modes */ + uint8_t ucDotClockEntry; + /* Dot clock entry used for extended VGA modes */ + uint8_t ucDotClockEntryVga; + /* Offset into internal clock table used for by VGA parameter table */ + uint16_t usPointerToInternalClock; + /* Offset into actual programmed frequency table at POST */ + uint16_t usPointerToFreqTable; + /* XCLK setting, (memory clock in 10 KHz units) */ + uint16_t usXclkSetting; + /* MCLK setting, (engine clock in 10 KHz units) */ + uint16_t usMclkSetting; + /* Number of PLL information block to follow, currently value is 3 */ + uint8_t ucPllInfoBlockNumber; + /* Size of each PLL information block */ + uint8_t ucPllInfoBlockSize; + /* Reference frequency of the dot clock */ + uint16_t usDotClockRefFreq; + /* Reference Divider of the dot clock */ + uint16_t usDotClockRefDiv; + /* Min Frequency supported before post divider for the dot clock */ + uint32_t ulDotClockMinFreq; + /* Max Frequency can be supported for the dot clock */ + uint32_t ulDotClockMaxFreq; + /* Reference frequency of the MCLK, engine clock */ + uint16_t usMclkRefFreq; + /* Reference Divider of the MCLK, engine clock */ + uint16_t usMclkRefDiv; + /* Min Frequency supported before post divider for MCLK, engine clock */ + uint32_t ulMclkMinFreq; + /* Max Frequency can be supported for the MCLK, engine clock */ + uint32_t ulMclkMaxFreq; + /* Reference frequency of the XCLK, memory clock */ + uint16_t usXclkRefFreq; + /* Reference Divider of the XCLK, memory clock */ + uint16_t usXclkRefDiv; + /* Min Frequency supported before post divider for XCLK, memory clock */ + uint32_t ulXclkMinFreq; + /* Max Frequency can be supported for the XCLK, memory clock */ + uint32_t ulXclkMaxFreq; + + /*this is the PLL Information Table Extended structure version 10 */ + uint8_t ucNumberOfExtendedPllBlocks; + uint8_t ucSizePLLDefinition; + uint16_t ulCrystalFrequencyPixelClock_pll; + uint32_t ulMinInputPixelClockPLLFrequency; + uint32_t ulMaxInputPixelClockPLLFrequency; + uint32_t ulMinOutputPixelClockPLLFrequency; + uint32_t ulMaxOutputPixelClockPLLFrequency; + + /*version 11 */ + uint16_t ulCrystalFrequencyEngineClock_pll; + uint32_t ulMinInputFrequencyEngineClock_pll; + uint32_t ulMaxInputFrequencyEngineClock_pll; + uint32_t ulMinOutputFrequencyEngineClock_pll; + uint32_t ulMaxOutputFrequencyEngineClock_pll; + uint16_t ulCrystalFrequencyMemoryClock_pll; + uint32_t ulMinInputFrequencyMemoryClock_pll; + uint32_t ulMaxInputFrequencyMemoryClock_pll; + uint32_t ulMinOutputFrequencyMemoryClock_pll; + uint32_t ulMaxOutputFrequencyMemoryClock_pll; + uint32_t ulMaximumDACOutputFrequency; +}; + +#define MAX_NO_OF_LCD_RES_TIMING 25 + +struct panel_information_table +{ + uint8_t ucPanelIdentification; + uint8_t ucPanelIDString[24]; + uint16_t usHorizontalSize; + uint16_t usVerticalSize; + uint16_t usFlatPanelType; + uint8_t ucRedBitsPerPrimary; + uint8_t ucGreenBitsPerPrimary; + uint8_t ucBlueBitsPerPrimary; + uint8_t ucReservedBitsPerPrimary; + uint8_t ucPanelCaps; + uint8_t ucPowerSequenceDelayStepsInMS; + uint8_t ucSupportedRefreshRateExtended; + uint16_t usExtendedPanelInfoTable; + uint16_t usPtrToHalfFrameBufferInformationTable; + uint16_t usVccOntoBlOn; + uint16_t usOffDelay; + uint16_t usRefDiv; + uint8_t ucPostDiv; + uint16_t usFeedBackDiv; + uint8_t ucSpreadSpectrumType; + uint16_t usSpreadSpectrumPercentage; + uint8_t ucBackLightLevel; + uint8_t ucBiasLevel; + uint8_t ucPowerSequenceDelay; + uint32_t ulPanelData; + uint8_t ucPanelRefreshRateData; + uint16_t usSupportedRefreshRate; + uint16_t usModeTableOffset[MAX_NO_OF_LCD_RES_TIMING]; +}; + +struct extended_panel_info_table +{ + uint8_t ucExtendedPanelInfoTableVer; + uint8_t ucSSDelay; + uint8_t ucSSStepSizeIndex; +}; + +struct lcd_mode_table_center +{ + uint16_t usHorizontalRes; + uint16_t usVerticalRes; + uint8_t ucModeType; + uint16_t usOffset2ExpParamTable; + uint16_t usOffset2TvParamTable; + uint16_t usPixelClock; + uint16_t usPixelClockAdjustment; + uint16_t usFpPos; + uint8_t ucReserved; + uint8_t ucMiscBits; + uint16_t usCrtcHTotal; + uint16_t usCrtcHDisp; + uint16_t usCrtcHSyncStrt; + uint8_t ucCrtcHSyncWid; + uint16_t usCrtcVTotal; + uint16_t usCrtcVDisp; + uint16_t usCrtcVSyncStrt; + uint8_t ucOvrWidTop; +}; + +struct lcd_mode_table_exp +{ + uint16_t usPixelClock; + uint16_t usPixelClockAdjustment; + uint16_t usFpPos; + uint8_t ucReserved; + uint8_t ucMiscBits; + uint16_t usCrtcHTotal; + uint16_t usCrtcHDisp; + uint16_t usCrtcHSyncStrt; + uint8_t ucCrtcHSyncWid; + uint16_t usCrtcVTotal; + uint16_t usCrtcVDisp; + uint16_t usCrtcVSyncStrt; + uint8_t ucOvrWidTop; + uint16_t usHorizontalBlendRatio; + uint32_t ulVgaVertStretching; + uint16_t usCopVertStretching; + uint16_t usVgaExtVertStretching; +}; + +struct tmds_pll_cntl_block +{ + uint16_t usClockUpperRange; + uint32_t ulPllSetting; +}; + +#define MAX_PLL_CNTL_ENTRIES 8 + +struct combios_dfp_info_table +{ + uint8_t ucDFPInfoTableRev; + uint8_t ucDFPInfoTableSize; + uint16_t usOffsetDetailedTimingTable; + uint8_t ucReserved; + uint8_t ucNumberOfClockRanges; + uint16_t usMaxPixelClock; + uint32_t ulInitValueTmdsPllCntl; + uint32_t ulFinalValueTmdsPllCntl; + struct tmds_pll_cntl_block sTmdsPllCntlBlock[MAX_PLL_CNTL_ENTRIES]; +}; + +struct combios_exttmds_table_header +{ + uint8_t ucTableRev; + uint16_t usTableSize; + uint8_t ucNoBlocks; +}; + +struct combios_exttmds_block_header +{ + uint16_t usMaxFreq; + uint8_t ucI2CSlaveAddr; + uint8_t ucI2CLine; + uint8_t ucConnectorId; + uint8_t ucFlags; +}; + +/* Connector table - applicable from Piglet and later ASICs + byte 0 (embedded revision) + [7:4] = number of chips (valid number 1 - 15) + [3:0] = revision number of table (valid number 1 - 15) + + byte 1 (Chip info) + [7:4] = chip number, max. 15 (valid number 1 - 15) + [3:0] = number of connectors for that chip, (valid number 1 - 15) + (number of connectors = number of 'Connector info' entries + for that chip) + + byte 2,3 (Connector info) + [15:12] - connector type + = 0 - no connector + = 1 - proprietary + = 2 - CRT + = 3 - DVI-I + = 4 - DVI-D + = 5-15 - reserved for future expansion + [11:8] - DDC line pair used for that connector + = 0 - no DDC + = 1 - MONID 0/1 + = 2 - DVI_DDC + = 3 - VGA_DDC + = 4 - CRT2_DDC + = 5-15 - reserved for future expansion + [5] - bit indicating presence of multiplexer for TV,CRT2 + [7:6] - reserved for future expansion + [4] - TMDS type + = 0 - internal TMDS + = 1 - external TMDS + [3:1] - reserved for future expansion + [0] - DAC associated with that connector + = 0 - CRT DAC + = 1 - non-CRT DAC (e.g. TV DAC, external DAC ..) + + byte 4,5,6... - byte 4,5 can be another "Connector info" word + describing another connector + - or byte 5 is a "Chip info" byte for anther chip, + then start with byte 5,6 to describe connectors + for that chip + - or byte 5 = 0 if all connectors for all chips on + board have been described, no more connector left + to describe. +*/ +#define BIOS_CONNECTOR_INFO__TYPE__MASK 0xF000 +#define BIOS_CONNECTOR_INFO__TYPE__SHIFT 0x0000000C +#define BIOS_CONNECTOR_TYPE__NONE 0x00000000 +#define BIOS_CONNECTOR_TYPE__PROPRIETARY 0x00000001 +#define BIOS_CONNECTOR_TYPE__CRT 0x00000002 +#define BIOS_CONNECTOR_TYPE__DVI_I 0x00000003 +#define BIOS_CONNECTOR_TYPE__DVI_D 0x00000004 + +#define BIOS_CONNECTOR_INFO__DDC_LINE__MASK 0x0F00 +#define BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT 0x00000008 +#define BIOS_DDC_LINE__NONE 0x00000000 +#define BIOS_DDC_LINE__MONID01 0x00000001 +#define BIOS_DDC_LINE__DVI 0x00000002 +#define BIOS_DDC_LINE__VGA 0x00000003 +#define BIOS_DDC_LINE__CRT2 0x00000004 +#define BIOS_DDC_LINE__GPIOPAD 0x00000005 +#define BIOS_DDC_LINE__ZV_LCDPAD 0x00000006 + +#define BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK 0x0010 +#define BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT 0x00000004 +#define BIOS_TMDS_TYPE__INTERNAL 0x00000000 +#define BIOS_TMDS_TYPE__EXTERNAL 0x00000001 + +#define BIOS_CONNECTOR_INFO__DAC_TYPE__MASK 0x0001 +#define BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT 0x00000000 +#define BIOS_DAC_TYPE__CRT 0x00000000 +#define BIOS_DAC_TYPE__NON_CRT 0x00000001 + +#define BIOS_CONNECTOR_INFO__MUX_MASK 0x00000020 +#define BIOS_CONNECTOR_INFO__MUX_SHIFT 0x00000005 + +#define BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK 0xF0 +#define BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT 0x00000004 + +#define BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK 0x0F +#define BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT 0x00000000 + +#define BIOS_CHIPINFO__MAX_NUMBER_OF_CONNECTORS 0x00000010 + +struct combios_connector_chip_info +{ + uint8_t ucChipHeader; + uint16_t sConnectorInfo[BIOS_CHIPINFO__MAX_NUMBER_OF_CONNECTORS]; +}; + +#define BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK 0xF0 +#define BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT 0x00000004 + +#define BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK 0x0F +#define BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT 0x00000000 + +struct combios_connector_table +{ + uint8_t ucConnectorHeader; + struct combios_connector_chip_info sChipConnectorInfo[0x10]; +}; + +#pragma pack() + +int combios_parse(unsigned char *rom, struct combios_header *header); + +#endif diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c index fe89e5e4..0da5a5a4 100644 --- a/shared-core/radeon_ms_crtc.c +++ b/shared-core/radeon_ms_crtc.c @@ -380,23 +380,26 @@ static void radeon_ms_crtc_mode_prepare(struct drm_crtc *crtc) } /* compute PLL registers values for requested video mode */ -static int radeon_pll1_constraint(int clock, int rdiv, +static int radeon_pll1_constraint(struct drm_device *dev, + int clock, int rdiv, int fdiv, int pdiv, int rfrq, int pfrq) { - int dfrq; - - if (rdiv < 2 || fdiv < 4) { - return 0; - } - dfrq = rfrq / rdiv; - if (dfrq < 2000 || dfrq > 3300) { - return 0; - } - if (pfrq < 125000 || pfrq > 250000) { - return 0; - } - return 1; + struct drm_radeon_private *dev_priv = dev->dev_private; + int dfrq; + + if (rdiv < 2 || fdiv < 4) { + return 0; + } + dfrq = rfrq / rdiv; + if (dfrq < 2000 || dfrq > 3300) { + return 0; + } + if (pfrq < dev_priv->properties.pll_min_pll_freq || + pfrq > dev_priv->properties.pll_max_pll_freq) { + return 0; + } + return 1; } static void radeon_pll1_compute(struct drm_crtc *crtc, @@ -424,7 +427,7 @@ static void radeon_pll1_compute(struct drm_crtc *crtc, struct drm_radeon_private *dev_priv = crtc->dev->dev_private; struct radeon_state *state = &dev_priv->driver_state; int clock = mode->clock; - int rfrq = dev_priv->properties->pll_reference_freq; + int rfrq = dev_priv->properties.pll_reference_freq; int pdiv = 1; int pdiv_id = 0; int rdiv_best = 2; @@ -441,11 +444,11 @@ static void radeon_pll1_compute(struct drm_crtc *crtc, int diff_cpfrq = 350000; /* clamp frequency into pll [min; max] frequency range */ - if (clock > dev_priv->properties->pll_max_pll_freq) { - clock = dev_priv->properties->pll_max_pll_freq; + if (clock > dev_priv->properties.pll_max_pll_freq) { + clock = dev_priv->properties.pll_max_pll_freq; } - if ((clock * 12) < dev_priv->properties->pll_min_pll_freq) { - clock = dev_priv->properties->pll_min_pll_freq / 12; + if ((clock * 12) < dev_priv->properties.pll_min_pll_freq) { + clock = dev_priv->properties.pll_min_pll_freq / 12; } /* maximize pll_ref_div while staying in boundary and minimizing @@ -457,8 +460,8 @@ static void radeon_pll1_compute(struct drm_crtc *crtc, tfrq = clock * post_div->divider; for (fdiv = 1023; fdiv >= 4; fdiv--) { rdiv = (fdiv * rfrq) / tfrq; - if (radeon_pll1_constraint(clock, rdiv, fdiv, - pdiv, rfrq, tfrq)) { + if (radeon_pll1_constraint(crtc->dev, clock, rdiv, + fdiv, pdiv, rfrq, tfrq)) { pfrq = (fdiv * rfrq) / rdiv; diff_cpfrq = pfrq - tfrq; if ((diff_cpfrq >= 0 && diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index 8d0481e1..91ca4a32 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -203,15 +203,35 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) radeon_ms_driver_unload(dev); return ret; } - ret = radeon_ms_outputs_from_properties(dev); - if (ret != 0) { + ret = radeon_ms_outputs_from_rom(dev); + if (ret < 0) { radeon_ms_driver_unload(dev); return ret; + } else if (!ret) { + ret = radeon_ms_outputs_from_properties(dev); + if (ret < 0) { + radeon_ms_driver_unload(dev); + return ret; + } else if (ret == 0) { + DRM_INFO("[radeon_ms] no outputs !\n"); + } + } else { + DRM_INFO("[radeon_ms] added %d outputs from rom.\n", ret); } - ret = radeon_ms_connectors_from_properties(dev); - if (ret != 0) { + ret = radeon_ms_connectors_from_rom(dev); + if (ret < 0) { radeon_ms_driver_unload(dev); return ret; + } else if (!ret) { + ret = radeon_ms_connectors_from_properties(dev); + if (ret < 0) { + radeon_ms_driver_unload(dev); + return ret; + } else if (!ret) { + DRM_INFO("[radeon_ms] no connectors !\n"); + } + } else { + DRM_INFO("[radeon_ms] added %d connectors from rom.\n", ret); } radeon_ms_outputs_save(dev, &dev_priv->load_state); drm_initial_config(dev, false); diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c index 779595d6..b70dca20 100644 --- a/shared-core/radeon_ms_family.c +++ b/shared-core/radeon_ms_family.c @@ -29,87 +29,6 @@ #include "drm.h" #include "radeon_ms.h" -static struct radeon_ms_output radeon_ms_dac1 = { - OUTPUT_DAC1, - NULL, - NULL, - radeon_ms_dac1_initialize, - radeon_ms_dac1_detect, - radeon_ms_dac1_dpms, - radeon_ms_dac1_get_modes, - radeon_ms_dac1_mode_fixup, - radeon_ms_dac1_mode_set, - radeon_ms_dac1_restore, - radeon_ms_dac1_save -}; - -static struct radeon_ms_output radeon_ms_dac2 = { - OUTPUT_DAC2, - NULL, - NULL, - radeon_ms_dac2_initialize, - radeon_ms_dac2_detect, - radeon_ms_dac2_dpms, - radeon_ms_dac2_get_modes, - radeon_ms_dac2_mode_fixup, - radeon_ms_dac2_mode_set, - radeon_ms_dac2_restore, - radeon_ms_dac2_save -}; - -static struct radeon_ms_connector radeon_ms_vga = { - NULL, NULL, NULL, CONNECTOR_VGA, MT_NONE, 0, GPIO_DDC1, - { - 0, -1, -1, -1, -1, -1, -1, -1 - }, - "VGA" -}; - -static struct radeon_ms_connector radeon_ms_dvi_i_2 = { - NULL, NULL, NULL, CONNECTOR_DVI_I, MT_NONE, 0, GPIO_DDC2, - { - 1, -1, -1, -1, -1, -1, -1, -1 - }, - "DVI-I" -}; - -static struct radeon_ms_properties properties[] = { - /* default only one VGA connector */ - { - 0, 0, 27000, 25000, 200000, 1, 1, 1, 1, - { - &radeon_ms_dac1, NULL, NULL, NULL, NULL, NULL, NULL, - NULL - }, - { - &radeon_ms_vga, NULL, NULL, NULL, NULL, NULL, NULL, - NULL - } - }, - { - 0x1043, 0x176, 27000, 25000, 200000, 1, 1, 1, 1, - { - &radeon_ms_dac1, &radeon_ms_dac2, NULL, NULL, NULL, - NULL, NULL, NULL - }, - { - &radeon_ms_vga, &radeon_ms_dvi_i_2, NULL, NULL, NULL, - NULL, NULL, NULL - } - }, - { - 0x1002, 0x4150, 27000, 25000, 200000, 1, 1, 1, 1, - { - &radeon_ms_dac1, &radeon_ms_dac2, NULL, NULL, NULL, - NULL, NULL, NULL - }, - { - &radeon_ms_vga, &radeon_ms_dvi_i_2, NULL, NULL, NULL, - NULL, NULL, NULL - } - }, -}; - extern const uint32_t radeon_cp_microcode[]; extern const uint32_t r200_cp_microcode[]; extern const uint32_t r300_cp_microcode[]; @@ -159,7 +78,7 @@ static void r300_flush_cache(struct drm_device *dev) int radeon_ms_family_init(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; - int i; + int ret; dev_priv->microcode = radeon_cp_microcode; dev_priv->irq_emit = radeon_ms_irq_emit; @@ -213,17 +132,10 @@ int radeon_ms_family_init(struct drm_device *dev) DRM_ERROR("Unknown radeon bus type, aborting\n"); return -EINVAL; } - dev_priv->properties = NULL; - for (i = 1; i < sizeof(properties)/sizeof(properties[0]); i++) { - if (dev->pdev->subsystem_vendor == properties[i].subvendor && - dev->pdev->subsystem_device == properties[i].subdevice) { - DRM_INFO("[radeon_ms] found properties for 0x%04X:0x%04X\n", - properties[i].subvendor, properties[i].subdevice); - dev_priv->properties = &properties[i]; - } - } - if (dev_priv->properties == NULL) { - dev_priv->properties = &properties[0]; + ret = radeon_ms_rom_init(dev); + if (ret) { + return ret; } - return 0; + ret = radeon_ms_properties_init(dev); + return ret; } diff --git a/shared-core/radeon_ms_i2c.c b/shared-core/radeon_ms_i2c.c index 1801c496..f4468c1e 100644 --- a/shared-core/radeon_ms_i2c.c +++ b/shared-core/radeon_ms_i2c.c @@ -66,6 +66,22 @@ static int get_clock(void *data) v = 0; } break; + case GPIO_MONID: + v = MMIO_R(GPIO_MONID); + if ((GPIO_MONID__GPIO_MONID_1_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_CRT2_DDC: + v = MMIO_R(GPIO_CRT2_DDC); + if ((GPIO_CRT2_DDC__CRT2_DDC_CLK_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; default: v = 0; break; @@ -112,6 +128,22 @@ static int get_data(void *data) v = 0; } break; + case GPIO_MONID: + v = MMIO_R(GPIO_MONID); + if ((GPIO_MONID__GPIO_MONID_0_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; + case GPIO_CRT2_DDC: + v = MMIO_R(GPIO_CRT2_DDC); + if ((GPIO_CRT2_DDC__CRT2_DDC_DATA_INPUT & v)) { + v = 1; + } else { + v = 0; + } + break; default: v = 0; break; @@ -157,6 +189,18 @@ static void set_clock(void *i2c_priv, int clock) v |= GPIO_DDC2__DDC2_CLK_OUT_EN; } break; + case GPIO_MONID: + v &= ~GPIO_MONID__GPIO_MONID_1_OUT_EN; + if (!clock) { + v |= GPIO_MONID__GPIO_MONID_1_OUT_EN; + } + break; + case GPIO_CRT2_DDC: + v &= ~GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN; + if (!clock) { + v |= GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN; + } + break; default: return; } @@ -201,6 +245,18 @@ static void set_data(void *i2c_priv, int data) v |= GPIO_DDC2__DDC2_DATA_OUT_EN; } break; + case GPIO_MONID: + v &= ~GPIO_MONID__GPIO_MONID_0_OUT_EN; + if (!data) { + v |= GPIO_MONID__GPIO_MONID_0_OUT_EN; + } + break; + case GPIO_CRT2_DDC: + v &= ~GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN; + if (!data) { + v |= GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN; + } + break; default: return; } @@ -251,11 +307,12 @@ struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, ret = i2c_bit_add_bus(&i2c->adapter); if(ret) { - DRM_INFO("[radeon_ms] failed to register I2C '%s' bus\n", - i2c->adapter.name); + DRM_INFO("[radeon_ms] failed to register I2C '%s' bus (0x%X)\n", + i2c->adapter.name, reg); goto out_free; } - DRM_INFO("[radeon_ms] registered I2C '%s' bus\n", i2c->adapter.name); + DRM_INFO("[radeon_ms] registered I2C '%s' bus (0x%X)\n", + i2c->adapter.name, reg); return i2c; out_free: diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c index 35e5c376..18806324 100644 --- a/shared-core/radeon_ms_output.c +++ b/shared-core/radeon_ms_output.c @@ -189,7 +189,7 @@ static void radeon_ms_output_cleanup(struct drm_output *output) output->driver_private = NULL; } -static const struct drm_output_funcs radeon_ms_output_funcs = { +const struct drm_output_funcs radeon_ms_output_funcs = { .dpms = radeon_ms_output_dpms, .save = NULL, .restore = NULL, @@ -233,11 +233,11 @@ int radeon_ms_connectors_from_properties(struct drm_device *dev) struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_ms_connector *connector = NULL; struct drm_output *output = NULL; - int i = 0; + int i = 0, c = 0; radeon_ms_connectors_destroy(dev); for (i = 0; i < RADEON_MAX_CONNECTORS; i++) { - if (dev_priv->properties->connectors[i]) { + if (dev_priv->properties.connectors[i]) { connector = drm_alloc(sizeof(struct radeon_ms_connector), DRM_MEM_DRIVER); @@ -245,11 +245,11 @@ int radeon_ms_connectors_from_properties(struct drm_device *dev) radeon_ms_connectors_destroy(dev); return -ENOMEM; } - memcpy(connector, - dev_priv->properties->connectors[i], - sizeof(struct radeon_ms_connector)); - connector->i2c = radeon_ms_i2c_create(dev, - connector->i2c_reg, connector->name); + memcpy(connector, dev_priv->properties.connectors[i], + sizeof(struct radeon_ms_connector)); + connector->i2c = + radeon_ms_i2c_create(dev, connector->i2c_reg, + connector->name); if (connector->i2c == NULL) { radeon_ms_connectors_destroy(dev); return -ENOMEM; @@ -264,9 +264,20 @@ int radeon_ms_connectors_from_properties(struct drm_device *dev) connector->output = output; output->driver_private = connector; output->possible_crtcs = 0x3; - dev_priv->connectors[i] = connector; + dev_priv->connectors[c++] = connector; } } + return c; +} + +int radeon_ms_connectors_from_rom(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (dev_priv->rom.type) { + case ROM_COMBIOS: + return radeon_ms_connectors_from_combios(dev); + } return 0; } @@ -289,24 +300,37 @@ int radeon_ms_outputs_from_properties(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; int i = 0; + int c = 0; radeon_ms_outputs_destroy(dev); for (i = 0; i < RADEON_MAX_OUTPUTS; i++) { - if (dev_priv->properties->outputs[i]) { + if (dev_priv->properties.outputs[i]) { dev_priv->outputs[i] = drm_alloc(sizeof(struct radeon_ms_output), - DRM_MEM_DRIVER); + DRM_MEM_DRIVER); if (dev_priv->outputs[i] == NULL) { radeon_ms_outputs_destroy(dev); return -ENOMEM; } memcpy(dev_priv->outputs[i], - dev_priv->properties->outputs[i], - sizeof(struct radeon_ms_output)); + dev_priv->properties.outputs[i], + sizeof(struct radeon_ms_output)); dev_priv->outputs[i]->dev = dev; dev_priv->outputs[i]->initialize(dev_priv->outputs[i]); + c++; } } + return c; +} + +int radeon_ms_outputs_from_rom(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (dev_priv->rom.type) { + case ROM_COMBIOS: + return radeon_ms_outputs_from_combios(dev); + } return 0; } diff --git a/shared-core/radeon_ms_properties.c b/shared-core/radeon_ms_properties.c new file mode 100644 index 00000000..393f496f --- /dev/null +++ b/shared-core/radeon_ms_properties.c @@ -0,0 +1,121 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#include "drmP.h" +#include "drm.h" +#include "radeon_ms.h" + +struct radeon_ms_output radeon_ms_dac1 = { + OUTPUT_DAC1, + NULL, + NULL, + radeon_ms_dac1_initialize, + radeon_ms_dac1_detect, + radeon_ms_dac1_dpms, + radeon_ms_dac1_get_modes, + radeon_ms_dac1_mode_fixup, + radeon_ms_dac1_mode_set, + radeon_ms_dac1_restore, + radeon_ms_dac1_save +}; + +struct radeon_ms_output radeon_ms_dac2 = { + OUTPUT_DAC2, + NULL, + NULL, + radeon_ms_dac2_initialize, + radeon_ms_dac2_detect, + radeon_ms_dac2_dpms, + radeon_ms_dac2_get_modes, + radeon_ms_dac2_mode_fixup, + radeon_ms_dac2_mode_set, + radeon_ms_dac2_restore, + radeon_ms_dac2_save +}; + +struct radeon_ms_connector radeon_ms_vga = { + NULL, NULL, NULL, ConnectorVGA, MT_NONE, 0, GPIO_DDC1, + { + 0, -1, -1, -1, -1, -1, -1, -1 + } +}; + +struct radeon_ms_connector radeon_ms_dvi_i_2 = { + NULL, NULL, NULL, ConnectorDVII, MT_NONE, 0, GPIO_DDC2, + { + 1, -1, -1, -1, -1, -1, -1, -1 + } +}; + +struct radeon_ms_properties properties[] = { + /* default only one VGA connector */ + { + 0, 0, 27000, 12, 25000, 200000, 1, 1, 1, 1, + { + &radeon_ms_dac1, NULL, NULL, NULL, NULL, NULL, NULL, + NULL + }, + { + &radeon_ms_vga, NULL, NULL, NULL, NULL, NULL, NULL, + NULL + } + } +}; + +int radeon_ms_properties_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i, ret; + + for (i = 1; i < sizeof(properties)/sizeof(properties[0]); i++) { + if (dev->pdev->subsystem_vendor == properties[i].subvendor && + dev->pdev->subsystem_device == properties[i].subdevice) { + DRM_INFO("[radeon_ms] found properties for " + "0x%04X:0x%04X\n", properties[i].subvendor, + properties[i].subdevice); + memcpy(&dev_priv->properties, &properties[i], + sizeof(struct radeon_ms_properties)); + } + } + if (dev_priv->properties.subvendor == 0) { + ret = radeon_ms_rom_get_properties(dev); + if (ret < 0) { + return ret; + } + if (!ret) { + memcpy(&dev_priv->properties, &properties[0], + sizeof(struct radeon_ms_properties)); + } else { + dev_priv->properties.pll_dummy_reads = 1; + dev_priv->properties.pll_delay = 1; + dev_priv->properties.pll_r300_errata = 1; + } + dev_priv->properties.subvendor = dev->pdev->subsystem_vendor; + dev_priv->properties.subdevice = dev->pdev->subsystem_device; + } + return 0; +} diff --git a/shared-core/radeon_ms_properties.h b/shared-core/radeon_ms_properties.h new file mode 100644 index 00000000..a02a84d5 --- /dev/null +++ b/shared-core/radeon_ms_properties.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#ifndef __RADEON_MS_PROPERTIES_H__ +#define __RADEON_MS_PROPERTIES_H__ + +#define RADEON_PAGE_SIZE 4096 +#define RADEON_MAX_CONNECTORS 8 +#define RADEON_MAX_OUTPUTS 8 + +struct radeon_ms_properties { + uint16_t subvendor; + uint16_t subdevice; + int16_t pll_reference_freq; + int16_t pll_reference_div; + int32_t pll_min_pll_freq; + int32_t pll_max_pll_freq; + char pll_use_bios; + char pll_dummy_reads; + char pll_delay; + char pll_r300_errata; + struct radeon_ms_output *outputs[RADEON_MAX_OUTPUTS]; + struct radeon_ms_connector *connectors[RADEON_MAX_CONNECTORS]; +}; + +#endif diff --git a/shared-core/radeon_ms_reg.h b/shared-core/radeon_ms_reg.h index d450280c..56963c63 100644 --- a/shared-core/radeon_ms_reg.h +++ b/shared-core/radeon_ms_reg.h @@ -827,6 +827,32 @@ #define GPIO_DDC2__SW_CAN_USE_DVI_I2C 0x00100000 #define GPIO_DDC2__SW_DONE_USING_DVI_I2C 0x00200000 #define GPIO_DDC2__HW_USING_DVI_I2C 0x00400000 +#define GPIO_DVI_DDC 0x00000064 +#define GPIO_DVI_DDC__DVI_DDC_DATA_OUTPUT 0x00000001 +#define GPIO_DVI_DDC__DVI_DCC_DATA_OUTPUT 0x00000001 +#define GPIO_DVI_DDC__DVI_DDC_CLK_OUTPUT 0x00000002 +#define GPIO_DVI_DDC__DVI_DDC_DATA_INPUT 0x00000100 +#define GPIO_DVI_DDC__DVI_DDC_CLK_INPUT 0x00000200 +#define GPIO_DVI_DDC__DVI_DDC_DATA_OUT_EN 0x00010000 +#define GPIO_DVI_DDC__DVI_DDC_CLK_OUT_EN 0x00020000 +#define GPIO_DVI_DDC__SW_WANTS_TO_USE_DVI_I2C 0x00100000 +#define GPIO_DVI_DDC__SW_CAN_USE_DVI_I2C 0x00100000 +#define GPIO_DVI_DDC__SW_DONE_USING_DVI_I2C 0x00200000 +#define GPIO_DVI_DDC__HW_USING_DVI_I2C 0x00400000 +#define GPIO_MONID 0x00000068 +#define GPIO_MONID__GPIO_MONID_0_OUTPUT 0x00000001 +#define GPIO_MONID__GPIO_MONID_1_OUTPUT 0x00000002 +#define GPIO_MONID__GPIO_MONID_0_INPUT 0x00000100 +#define GPIO_MONID__GPIO_MONID_1_INPUT 0x00000200 +#define GPIO_MONID__GPIO_MONID_0_OUT_EN 0x00010000 +#define GPIO_MONID__GPIO_MONID_1_OUT_EN 0x00020000 +#define GPIO_CRT2_DDC 0x0000006C +#define GPIO_CRT2_DDC__CRT2_DDC_DATA_OUTPUT 0x00000001 +#define GPIO_CRT2_DDC__CRT2_DDC_CLK_OUTPUT 0x00000002 +#define GPIO_CRT2_DDC__CRT2_DDC_DATA_INPUT 0x00000100 +#define GPIO_CRT2_DDC__CRT2_DDC_CLK_INPUT 0x00000200 +#define GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN 0x00010000 +#define GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN 0x00020000 #define CLOCK_CNTL_INDEX 0x00000008 #define CLOCK_CNTL_INDEX__PLL_ADDR__MASK 0x0000001F #define CLOCK_CNTL_INDEX__PLL_ADDR__SHIFT 0 diff --git a/shared-core/radeon_ms_rom.c b/shared-core/radeon_ms_rom.c new file mode 100644 index 00000000..5054a390 --- /dev/null +++ b/shared-core/radeon_ms_rom.c @@ -0,0 +1,91 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#include "radeon_ms.h" + +int radeon_ms_rom_get_properties(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (dev_priv->rom.type) { + case ROM_COMBIOS: + return radeon_ms_combios_get_properties(dev); + } + return 0; +} + +int radeon_ms_rom_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_ms_rom *rom = &dev_priv->rom; + void *rom_mapped; + char atomstr[5] = {0, 0, 0, 0, 0}; + uint16_t *offset; + + dev_priv->rom.type = ROM_UNKNOWN; + /* copy rom if any */ + rom_mapped = pci_map_rom_copy(dev->pdev, &rom->rom_size); + if (rom->rom_size) { + rom->rom_image = drm_alloc(rom->rom_size, DRM_MEM_DRIVER); + if (rom->rom_image == NULL) { + return -1; + } + memcpy(rom->rom_image, rom_mapped, rom->rom_size); + DRM_INFO("[radeon_ms] ROM %d bytes copied\n", rom->rom_size); + } else { + DRM_INFO("[radeon_ms] no ROM\n"); + return 0; + } + pci_unmap_rom(dev->pdev, rom_mapped); + + if (rom->rom_image[0] != 0x55 || rom->rom_image[1] != 0xaa) { + DRM_INFO("[radeon_ms] no ROM\n"); + DRM_INFO("[radeon_ms] ROM signature 0x55 0xaa missing\n"); + return 0; + } + offset = (uint16_t *)&rom->rom_image[ROM_HEADER]; + memcpy(atomstr, &rom->rom_image[*offset + 4], 4); + if (!strcpy(atomstr, "ATOM") || !strcpy(atomstr, "MOTA")) { + DRM_INFO("[radeon_ms] ATOMBIOS ROM detected\n"); + return 0; + } else { + struct combios_header **header; + + header = &rom->rom.combios_header; + if ((*offset + sizeof(struct combios_header)) > rom->rom_size) { + DRM_INFO("[radeon_ms] wrong COMBIOS header offset\n"); + return -1; + } + dev_priv->rom.type = ROM_COMBIOS; + *header = (struct combios_header *)&rom->rom_image[*offset]; + DRM_INFO("[radeon_ms] COMBIOS type : %d\n", + (*header)->ucTypeDefinition); + DRM_INFO("[radeon_ms] COMBIOS OEM ID: %02x %02x\n", + (*header)->ucOemID1, (*header)->ucOemID2); + } + return 0; +} diff --git a/shared-core/radeon_ms_rom.h b/shared-core/radeon_ms_rom.h new file mode 100644 index 00000000..36a54cbb --- /dev/null +++ b/shared-core/radeon_ms_rom.h @@ -0,0 +1,51 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + * Authors: + * Jerome Glisse + */ +#ifndef __RADEON_MS_ROM_H__ +#define __RADEON_MS_ROM_H__ + +#include "radeon_ms_combios.h" + +enum radeon_rom_type { + ROM_COMBIOS, + ROM_ATOMBIOS, + ROM_UNKNOWN +}; + +union radeon_ms_rom_type { + struct combios_header *combios_header; +}; + +struct radeon_ms_rom { + uint8_t type; + size_t rom_size; + uint8_t *rom_image; + union radeon_ms_rom_type rom; +}; + +#endif + -- cgit v1.2.3 From 20a8e2d30e99a3248e6f02f792a29d20ec9f2ce5 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 15 Jan 2008 14:30:40 +0100 Subject: radeon_ms: cope with lastest drm modesetting change --- shared-core/radeon_ms_combios.c | 17 ++++++++++++++++- shared-core/radeon_ms_output.c | 4 ++-- shared-core/radeon_ms_properties.c | 6 ++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/shared-core/radeon_ms_combios.c b/shared-core/radeon_ms_combios.c index 04a33699..ecd4bd06 100644 --- a/shared-core/radeon_ms_combios.c +++ b/shared-core/radeon_ms_combios.c @@ -143,10 +143,25 @@ static int radeon_ms_combios_connector_add(struct drm_device *dev, connector->type = connector_type; connector->i2c_reg = i2c_reg; + switch (connector->type) { + case ConnectorVGA: + sprintf(connector->name, "VGA"); + break; + case ConnectorDVII: + sprintf(connector->name, "DVI-I"); + break; + case ConnectorDVID: + sprintf(connector->name, "DVI-D"); + break; + default: + sprintf(connector->name, "UNKNOWN-CONNECTOR"); + break; + } + if (i2c_reg) { connector->i2c = radeon_ms_i2c_create(dev, connector->i2c_reg, - connector->type); + connector->name); if (connector->i2c == NULL) { radeon_ms_connectors_destroy(dev); return -ENOMEM; diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c index 18806324..bc174371 100644 --- a/shared-core/radeon_ms_output.c +++ b/shared-core/radeon_ms_output.c @@ -255,8 +255,8 @@ int radeon_ms_connectors_from_properties(struct drm_device *dev) return -ENOMEM; } output = drm_output_create(dev, - &radeon_ms_output_funcs, - connector->name); + &radeon_ms_output_funcs, + connector->type); if (output == NULL) { radeon_ms_connectors_destroy(dev); return -EINVAL; diff --git a/shared-core/radeon_ms_properties.c b/shared-core/radeon_ms_properties.c index 393f496f..2bd45dcd 100644 --- a/shared-core/radeon_ms_properties.c +++ b/shared-core/radeon_ms_properties.c @@ -61,14 +61,16 @@ struct radeon_ms_connector radeon_ms_vga = { NULL, NULL, NULL, ConnectorVGA, MT_NONE, 0, GPIO_DDC1, { 0, -1, -1, -1, -1, -1, -1, -1 - } + }, + "VGA" }; struct radeon_ms_connector radeon_ms_dvi_i_2 = { NULL, NULL, NULL, ConnectorDVII, MT_NONE, 0, GPIO_DDC2, { 1, -1, -1, -1, -1, -1, -1, -1 - } + }, + "DVI-I" }; struct radeon_ms_properties properties[] = { -- cgit v1.2.3 From 6ba979ea467ef6ff76c32ee63ee9a6d4073ec672 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 15 Jan 2008 16:01:39 +0100 Subject: radeon_ms: use radeon connector type insted of drm --- shared-core/radeon_ms_combios.c | 12 ++++++------ shared-core/radeon_ms_dac.c | 2 +- shared-core/radeon_ms_properties.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/shared-core/radeon_ms_combios.c b/shared-core/radeon_ms_combios.c index ecd4bd06..65609af9 100644 --- a/shared-core/radeon_ms_combios.c +++ b/shared-core/radeon_ms_combios.c @@ -144,13 +144,13 @@ static int radeon_ms_combios_connector_add(struct drm_device *dev, connector->i2c_reg = i2c_reg; switch (connector->type) { - case ConnectorVGA: + case CONNECTOR_VGA: sprintf(connector->name, "VGA"); break; - case ConnectorDVII: + case CONNECTOR_DVI_I: sprintf(connector->name, "DVI-I"); break; - case ConnectorDVID: + case CONNECTOR_DVI_D: sprintf(connector->name, "DVI-D"); break; default: @@ -279,7 +279,7 @@ int radeon_ms_connectors_from_combios(struct drm_device *dev) switch (connector_type) { case BIOS_CONNECTOR_TYPE__CRT: ret = radeon_ms_combios_connector_add(dev, c, - ConnectorVGA, + CONNECTOR_VGA, i2c_reg); if (ret) { return ret; @@ -288,7 +288,7 @@ int radeon_ms_connectors_from_combios(struct drm_device *dev) break; case BIOS_CONNECTOR_TYPE__DVI_I: ret = radeon_ms_combios_connector_add(dev, c, - ConnectorDVII, + CONNECTOR_DVI_I, i2c_reg); if (ret) { return ret; @@ -297,7 +297,7 @@ int radeon_ms_connectors_from_combios(struct drm_device *dev) break; case BIOS_CONNECTOR_TYPE__DVI_D: ret = radeon_ms_combios_connector_add(dev, c, - ConnectorDVID, + CONNECTOR_DVI_D, i2c_reg); if (ret) { return ret; diff --git a/shared-core/radeon_ms_dac.c b/shared-core/radeon_ms_dac.c index 297623a0..e6312942 100644 --- a/shared-core/radeon_ms_dac.c +++ b/shared-core/radeon_ms_dac.c @@ -370,7 +370,7 @@ int radeon_ms_dac2_mode_set(struct radeon_ms_output *output, case CHIP_R430: case CHIP_R480: if (connector->type != CONNECTOR_CTV && - connector->type != CONNECTOR_STV) { + connector->type != CONNECTOR_STV) { state->dac_cntl2 |= DAC_CNTL2__DAC2_CLK_SEL; } } diff --git a/shared-core/radeon_ms_properties.c b/shared-core/radeon_ms_properties.c index 2bd45dcd..baf2a7f2 100644 --- a/shared-core/radeon_ms_properties.c +++ b/shared-core/radeon_ms_properties.c @@ -58,7 +58,7 @@ struct radeon_ms_output radeon_ms_dac2 = { }; struct radeon_ms_connector radeon_ms_vga = { - NULL, NULL, NULL, ConnectorVGA, MT_NONE, 0, GPIO_DDC1, + NULL, NULL, NULL, CONNECTOR_VGA, MT_NONE, 0, GPIO_DDC1, { 0, -1, -1, -1, -1, -1, -1, -1 }, @@ -66,7 +66,7 @@ struct radeon_ms_connector radeon_ms_vga = { }; struct radeon_ms_connector radeon_ms_dvi_i_2 = { - NULL, NULL, NULL, ConnectorDVII, MT_NONE, 0, GPIO_DDC2, + NULL, NULL, NULL, CONNECTOR_DVI_I, MT_NONE, 0, GPIO_DDC2, { 1, -1, -1, -1, -1, -1, -1, -1 }, -- cgit v1.2.3 From fb9ea12438de95a6ac085879e079055eaea3daf8 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 18 Jan 2008 15:00:31 +0100 Subject: Made radeon_ms not always compile --- linux-core/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/linux-core/Makefile b/linux-core/Makefile index 76ed3e39..2f33e5df 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -287,7 +287,7 @@ CONFIG_DRM_MACH64 := n CONFIG_DRM_NV := n CONFIG_DRM_NOUVEAU := n CONFIG_DRM_XGI := n -CONFIG_DRM_RADEON_MS := m +CONFIG_DRM_RADEON_MS := n # Enable module builds for the modules requested/supported. @@ -327,6 +327,9 @@ endif ifneq (,$(findstring xgi,$(DRM_MODULES))) CONFIG_DRM_XGI := m endif +ifneq (,$(findstring radeon_ms,$(DRM_MODULES))) +CONFIG_DRM_RADEON_MS := m +endif # These require AGP support -- cgit v1.2.3 From fa7b779c91cbac16ec699efab4ee150412d4ba74 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 25 Jan 2008 16:32:09 +1000 Subject: don't reinit ring if already initialised --- shared-core/i915_dma.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 66d1b13d..68505dca 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -110,27 +110,29 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) dev_priv->sarea_priv = (drm_i915_sarea_t *) ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); - dev_priv->ring.Start = init->ring_start; - dev_priv->ring.End = init->ring_end; - dev_priv->ring.Size = init->ring_size; - dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - - dev_priv->ring.map.offset = init->ring_start; - dev_priv->ring.map.size = init->ring_size; - dev_priv->ring.map.type = 0; - dev_priv->ring.map.flags = 0; - dev_priv->ring.map.mtrr = 0; - - drm_core_ioremap(&dev_priv->ring.map, dev); - - if (dev_priv->ring.map.handle == NULL) { - i915_dma_cleanup(dev); - DRM_ERROR("can not ioremap virtual address for" - " ring buffer\n"); - return -ENOMEM; + if (!dev_priv->ring.Size) { + dev_priv->ring.Start = init->ring_start; + dev_priv->ring.End = init->ring_end; + dev_priv->ring.Size = init->ring_size; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + dev_priv->ring.map.offset = init->ring_start; + dev_priv->ring.map.size = init->ring_size; + dev_priv->ring.map.type = 0; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; + + drm_core_ioremap(&dev_priv->ring.map, dev); + + if (dev_priv->ring.map.handle == NULL) { + i915_dma_cleanup(dev); + DRM_ERROR("can not ioremap virtual address for" + " ring buffer\n"); + return -ENOMEM; + } + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; } - dev_priv->ring.virtual_start = dev_priv->ring.map.handle; dev_priv->cpp = init->cpp; dev_priv->sarea_priv->pf_current_page = 0; -- cgit v1.2.3 From 98361cf28c62530e34758b27aa1eea805269e0e5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 25 Jan 2008 16:34:05 +1000 Subject: if irq already enabled well just keep trucking --- linux-core/drm_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 367d2dd8..c75f20b2 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -183,7 +183,7 @@ int drm_irq_install(struct drm_device * dev) if (dev->irq_enabled) { mutex_unlock(&dev->struct_mutex); - return -EBUSY; + return 0; } dev->irq_enabled = 1; mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From a2254c5a9670a3e865f0eb5acd46e905c9b146ce Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 28 Jan 2008 03:12:29 +0100 Subject: Added cursor support --- libdrm/xf86drmMode.c | 28 +++++++++ libdrm/xf86drmMode.h | 13 ++++ linux-core/drm_crtc.c | 57 +++++++++++++++++ linux-core/drm_crtc.h | 22 +++++++ linux-core/drm_drv.c | 1 + linux-core/intel_display.c | 108 ++++++++++++++++++++++++++++++++ linux-core/intel_drv.h | 1 + linux-core/intel_fb.c | 26 +++++--- shared-core/drm.h | 28 +++++++++ shared-core/i915_drv.h | 1 + shared-core/i915_init.c | 5 ++ tests/modedemo/demo.c | 47 +++++++++++++- tests/modefb/Makefile | 14 +++++ tests/modefb/demo.c | 150 +++++++++++++++++++++++++++++++++++++++++++++ tests/modefb/test | 1 + 15 files changed, 494 insertions(+), 8 deletions(-) create mode 100644 tests/modefb/Makefile create mode 100644 tests/modefb/demo.c create mode 100755 tests/modefb/test diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 0edb1d7d..86572872 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -317,6 +317,34 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); } +/* + * Cursor manipulation + */ + +int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height) +{ + struct drm_mode_cursor arg; + + arg.flags = DRM_MODE_CURSOR_BO; + arg.crtc = crtcId; + arg.width = width; + arg.height = height; + arg.handle = bo->handle; + + return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); +} + +int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) +{ + struct drm_mode_cursor arg; + + arg.flags = DRM_MODE_CURSOR_MOVE; + arg.crtc = crtcId; + arg.x = x; + arg.y = y; + + return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); +} /* * Output manipulation diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index e2dda8ac..f5b3337c 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -197,6 +197,19 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *outputs, int count, struct drm_mode_modeinfo *mode); +/* + * Cursor functions + */ + +/** + * Set the cursor on crtc + */ +int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height); + +/** + * Move the cursor on crtc + */ +int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y); /* * Output manipulation diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1e69eca3..18fa02ce 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1608,6 +1608,63 @@ out: return ret; } +int drm_mode_cursor_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_cursor *req = data; + struct drm_crtc *crtc; + struct drm_buffer_object *bo = NULL; /* must be set */ + int ret = 0; + + DRM_DEBUG("\n"); + + if (!req->flags) { + DRM_ERROR("no operation set\n"); + return -EINVAL; + } + + mutex_lock(&dev->mode_config.mutex); + crtc = idr_find(&dev->mode_config.crtc_idr, req->crtc); + if (!crtc || (crtc->id != req->crtc)) { + DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc); + ret = -EINVAL; + goto out; + } + + if (req->flags & DRM_MODE_CURSOR_BO) { + /* Turn of the cursor if handle is 0 */ + if (req->handle) + ret = drm_get_buffer_object(dev, &bo, req->handle); + + if (ret) { + DRM_ERROR("invalid buffer id\n"); + ret = -EINVAL; + goto out; + } + + if (crtc->funcs->cursor_set) { + ret = crtc->funcs->cursor_set(crtc, bo, req->width, req->height); + } else { + DRM_ERROR("crtc does not support cursor\n"); + ret = -EFAULT; + goto out; + } + } + + if (req->flags & DRM_MODE_CURSOR_MOVE) { + if (crtc->funcs->cursor_move) { + ret = crtc->funcs->cursor_move(crtc, req->x, req->y); + } else { + DRM_ERROR("crtc does not support cursor\n"); + ret = -EFAULT; + goto out; + } + } +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + /** * drm_mode_addfb - add an FB to the graphics configuration * @inode: inode from the ioctl diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 65c3704a..8f6a8938 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -329,6 +329,11 @@ struct drm_crtc_funcs { /* Move the crtc on the current fb to the given position *optional* */ void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); + /* cursor controls */ + int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo, + uint32_t width, uint32_t height); + int (*cursor_move)(struct drm_crtc *crtc, int x, int y); + /* Set gamma on the CRTC */ void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b, int regno); @@ -482,6 +487,21 @@ struct drm_output { uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; }; +/** + * struct drm_mode_set + * + * Represents a single crtc the outputs that it drives with what mode + * and from which framebuffer it scans out from. + */ +struct drm_mode_set +{ + struct drm_framebuffer *fb; + struct drm_crtc *crtc; + + struct drm_output **outputs; + size_t num_outputs; +}; + /** * struct drm_mode_config_funcs - configure CRTCs for a given screen layout * @resize: adjust CRTCs as necessary for the proposed layout @@ -603,6 +623,8 @@ extern int drm_mode_getoutput(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_cursor_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); extern int drm_mode_addfb(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_rmfb(struct drm_device *dev, diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index ab047ca3..b0b44c90 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -125,6 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 1498a51c..88cf653c 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -402,6 +402,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) } } + + /** * Sets the power management mode of the pipe and plane. * @@ -956,6 +958,108 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } } +#define CURSOR_A_CONTROL 0x70080 +#define CURSOR_A_BASE 0x70084 +#define CURSOR_A_POSITION 0x70088 + +#define CURSOR_B_CONTROL 0x700C0 +#define CURSOR_B_BASE 0x700C4 +#define CURSOR_B_POSITION 0x700C8 + +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_64_32B_AX 0x07 +#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) +#define MCURSOR_GAMMA_ENABLE (1 << 26) + +#define CURSOR_POS_MASK 0x007FF +#define CURSOR_POS_SIGN 0x8000 +#define CURSOR_X_SHIFT 0 +#define CURSOR_Y_SHIFT 16 + +static int intel_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_buffer_object *bo, + uint32_t width, uint32_t height) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL; + uint32_t temp; + size_t adder; + + DRM_DEBUG("\n"); + + /* if we want to turn of the cursor ignore width and height */ + if (!bo) { + DRM_DEBUG("cursor off\n"); + /* turn of the cursor */ + temp = 0; + temp |= CURSOR_MODE_DISABLE; + + I915_WRITE(control, temp); + return 0; + } + + /* Currently we only support 64x64 cursors */ + if (width != 64 || height != 64) { + DRM_ERROR("we currently only support 64x64 cursors\n"); + return -EINVAL; + } + + if ((bo->mem.flags & DRM_BO_MASK_MEM) != DRM_BO_FLAG_MEM_VRAM) { + DRM_ERROR("buffer needs to be in VRAM\n"); + return -ENOMEM; + } + + if (bo->mem.size < width * height * 4) { + DRM_ERROR("buffer is to small\n"); + return -ENOMEM; + } + + adder = dev_priv->stolen_base + bo->offset; + intel_crtc->cursor_adder = adder; + temp = 0; + /* set the pipe for the cursor */ + temp |= (pipe << 28); + temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + + DRM_DEBUG("cusror base %x\n", adder); + + I915_WRITE((pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL, temp); + I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder); + + return 0; +} + +static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = crtc->driver_private; + int pipe = intel_crtc->pipe; + uint32_t temp = 0; + uint32_t adder; + + if (x < 0) { + temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); + x = -x; + } + if (y < 0) { + temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); + y = -y; + } + + temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); + temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); + + adder = intel_crtc->cursor_adder; + I915_WRITE((pipe == 0) ? CURSOR_A_POSITION : CURSOR_B_POSITION, temp); + I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder); + + return 0; +} + /** Sets the color ramps on behalf of RandR */ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) @@ -1084,6 +1188,8 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, + .cursor_set = intel_crtc_cursor_set, + .cursor_move = intel_crtc_cursor_move, .gamma_set = intel_crtc_gamma_set, .prepare = intel_crtc_prepare, .commit = intel_crtc_commit, @@ -1113,6 +1219,8 @@ void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->lut_b[i] = i; } + intel_crtc->cursor_adder = 0; + crtc->driver_private = intel_crtc; } diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 06335b18..25c3a978 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -55,6 +55,7 @@ struct intel_output { struct intel_crtc { int pipe; + uint32_t cursor_adder; u8 lut_r[256], lut_g[256], lut_b[256]; }; diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index b67c0fcc..bb42bc69 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -49,7 +49,7 @@ struct intelfb_par { struct drm_crtc *crtc; struct drm_display_mode *fb_mode; }; - +/* static int var_to_refresh(const struct fb_var_screeninfo *var) { @@ -59,7 +59,7 @@ var_to_refresh(const struct fb_var_screeninfo *var) var->vsync_len; return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; -} +}*/ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, @@ -106,10 +106,10 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_device *dev = par->dev; + /*struct drm_device *dev = par->dev;*/ struct drm_framebuffer *fb = par->crtc->fb; - struct drm_output *output; - int depth, found = 0; + /*struct drm_output *output;*/ + int depth/*, found = 0*/; if (!var->pixclock) return -EINVAL; @@ -254,6 +254,8 @@ static int intelfb_set_par(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; int found = 0; + DRM_DEBUG("\n"); + switch (var->bits_per_pixel) { case 16: fb->depth = (var->green.length == 6) ? 16 : 15; @@ -321,9 +323,19 @@ static int intelfb_set_par(struct fb_info *info) } if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) - if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) + if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) return -EINVAL; + } else if (par->crtc->x != var->xoffset || par->crtc->x != var->xoffset) { + if (!par->crtc->funcs->mode_set_base) { + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) + return -EINVAL; + } else { + par->crtc->funcs->mode_set_base(par->crtc, var->xoffset, var->yoffset); + par->crtc->x = var->xoffset; + par->crtc->y = var->yoffset; + } + } } return 0; } diff --git a/shared-core/drm.h b/shared-core/drm.h index 7aea3033..209a8db0 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1084,6 +1084,33 @@ struct drm_mode_mode_cmd { struct drm_mode_modeinfo mode; }; +#define DRM_MODE_CURSOR_BO 0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 + +/* + * depending on the value in flags diffrent members are used. + * + * CURSOR_BO uses + * crtc + * width + * height + * handle - if 0 turns the cursor of + * + * CURSOR_MOVE uses + * crtc + * x + * y + */ +struct drm_mode_cursor { + unsigned int flags; + unsigned int crtc; + int x; + int y; + uint32_t width; + uint32_t height; + unsigned int handle; +}; + /** * \name Ioctls Definitions */ @@ -1190,6 +1217,7 @@ struct drm_mode_mode_cmd { #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property) +#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xAC, struct drm_mode_cursor) /*@}*/ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 49e23ac3..ea89bc4c 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -147,6 +147,7 @@ struct drm_i915_private { void *agp_iomap; unsigned int max_validate_buffers; struct mutex cmdbuf_mutex; + size_t stolen_base; #endif DRM_SPINTYPE swaps_lock; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 3b271b17..792c40bb 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -131,6 +131,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->types[8] = _DRM_STAT_SECONDARY; dev->types[9] = _DRM_STAT_DMA; + if (IS_I9XX(dev)) { + pci_read_config_dword(dev->pdev, 0x5C, &dev_priv->stolen_base); + DRM_DEBUG("stolen base %p\n", (void*)dev_priv->stolen_base); + } + if (IS_I9XX(dev)) { dev_priv->mmiobase = drm_get_resource_start(dev, 0); dev_priv->mmiolen = drm_get_resource_len(dev, 0); diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 594d60db..1efeb272 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -34,7 +34,9 @@ static struct drm_mode_modeinfo mode = { drmModeFBPtr createFB(int fd, drmModeResPtr res); int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out); drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res); +void testCursor(int fd, uint32_t crtc); void prettyColors(int fd, unsigned int handle); +void prettyCursor(int fd, unsigned int handle); int main(int argc, char **argv) { @@ -98,6 +100,11 @@ int main(int argc, char **argv) drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 100, &out[0]->output_id, 1, &mode); sleep(2); + printf("0 0\n"); + drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 1, 1, &out[0]->output_id, 1, &mode); + + testCursor(fd, crtc->crtc_id); + /* turn the crtc off just in case */ drmModeSetCrtc(fd, crtc->crtc_id, 0, 0, 0, 0, 0, 0); @@ -166,7 +173,7 @@ int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out) drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res) { - return drmModeGetCrtc(fd, res->crtcs[0]); + return drmModeGetCrtc(fd, res->crtcs[1]); } void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr) @@ -200,3 +207,41 @@ void prettyColors(int fd, unsigned int handle) drmBOUnmap(fd, &bo); } + +void testCursor(int fd, uint32_t crtc) +{ + drmBO bo; + int ret; + ret = drmBOCreate(fd, 64 * 64 * 4, 0, 0, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, &bo); + + prettyCursor(fd, bo.handle); + + printf("set cursor\n"); + drmModeSetCursor(fd, crtc, &bo, 64, 64); + printf("move cursor 0, 0\n"); + drmModeMoveCursor(fd, crtc, 0, 0); + sleep(2); + printf("move cursor 40, 40\n"); + drmModeMoveCursor(fd, crtc, 40, 40); + sleep(2); +} + +void prettyCursor(int fd, unsigned int handle) +{ + drmBO bo; + unsigned int *ptr; + int i; + + drmBOReference(fd, handle, &bo); + drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); + + for (i = 0; i < (64 * 64); i++) + ptr[i] = 0xFFFF00FF; + + drmBOUnmap(fd, &bo); +} diff --git a/tests/modefb/Makefile b/tests/modefb/Makefile new file mode 100644 index 00000000..84c6c86a --- /dev/null +++ b/tests/modefb/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: demo.c + @gcc $(CFLAGS) -o app -Wall demo.c + +clean: + @rm -f app + +run: app + sudo ./test diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c new file mode 100644 index 00000000..0dbf01c7 --- /dev/null +++ b/tests/modefb/demo.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include "linux/fb.h" +#include "sys/ioctl.h" + + +void setMode(struct fb_var_screeninfo *var); +void pan(int fd, struct fb_var_screeninfo *var, int x, int y); +void cursor(int fd); + +int main(int argc, char **argv) +{ + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + const char* name = "/dev/fb0"; + + int fd = open(name, O_RDONLY); + + if (fd == -1) { + printf("open %s : %s\n", name, strerror(errno)); + return 1; + } + + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); + + if (ioctl(fd, FBIOGET_VSCREENINFO, &var)) + printf("var %s\n", strerror(errno)); + if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)) + printf("fix %s\n", strerror(errno)); + + setMode(&var); + printf("pan: 0, 0\n"); + pan(fd, &var, 0, 0); + sleep(2); + printf("pan: 100, 0\n"); + pan(fd, &var, 100, 0); + sleep(2); + printf("pan: 0, 100\n"); + pan(fd, &var, 0, 100); + sleep(2); + printf("pan: 100, 100\n"); + pan(fd, &var, 100, 100); + sleep(2); + printf("pan: 0, 0\n"); + pan(fd, &var, 0, 0); + sleep(2); + + printf("cursor\n"); + cursor(fd); + return 0; +} + +void pan(int fd, struct fb_var_screeninfo *var, int x, int y) +{ + var->xoffset = x; + var->yoffset = y; + + var->activate = FB_ACTIVATE_NOW; + + if (ioctl(fd, FBIOPUT_VSCREENINFO, var)) + printf("pan error: %s\n", strerror(errno)); +} + +/* + * Currently isn't supported in the driver + */ +void cursor(int fd) +{ + struct fb_cursor cur; + void *data = malloc(64 * 64 * 4); + memset(&cur, 0, sizeof(cur)); + + cur.set = FB_CUR_SETIMAGE | FB_CUR_SETPOS | FB_CUR_SETSIZE; + cur.enable = 1; + cur.image.dx = 1; + cur.image.dy = 1; + cur.image.width = 2; + cur.image.height = 2; + cur.image.depth = 32; + cur.image.data = data; + + if (ioctl(fd, FBIO_CURSOR, &cur)) + printf("cursor error: %s\n", strerror(errno)); + + sleep(2); + + memset(&cur, 0, sizeof(cur)); + cur.set = FB_CUR_SETPOS; + cur.enable = 0; + cur.image.dx = 100; + cur.image.dy = 100; + + if (ioctl(fd, FBIO_CURSOR, &cur)) + printf("cursor error: %s\n", strerror(errno)); + + free(data); +} + +struct drm_mode +{ + int clock; + int hdisplay; + int hsync_start; + int hsync_end; + int htotal; + int hskew; + int vdisplay; + int vsync_start; + int vsync_end; + int vtotal; + int vscan; + int vrefresh; + int flags; +}; + +struct drm_mode mode = +{ + .clock = 25200, + .hdisplay = 640, + .hsync_start = 656, + .hsync_end = 752, + .htotal = 800, + .hskew = 0, + .vdisplay = 480, + .vsync_start = 490, + .vsync_end = 492, + .vtotal = 525, + .vscan = 0, + .vrefresh = 60000, /* vertical refresh * 1000 */ + .flags = 10, +}; + +void setMode(struct fb_var_screeninfo *var) { + var->activate = FB_ACTIVATE_NOW; + var->xres = mode.hdisplay; + var->right_margin = mode.hsync_start - mode.hdisplay; + var->hsync_len = mode.hsync_end - mode.hsync_start; + var->left_margin = mode.htotal - mode.hsync_end; + var->yres = mode.vdisplay; + var->lower_margin = mode.vsync_start - mode.vdisplay; + var->vsync_len = mode.vsync_end - mode.vsync_start; + var->upper_margin = mode.vtotal - mode.vsync_end; + var->pixclock = 10000000 / mode.htotal * 1000 / mode.vtotal * 100; + /* avoid overflow */ + var->pixclock = var->pixclock * 1000 / mode.vrefresh; +} diff --git a/tests/modefb/test b/tests/modefb/test new file mode 100755 index 00000000..f98e3708 --- /dev/null +++ b/tests/modefb/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app -- cgit v1.2.3 From b9b6f9234dd9e702a7d58978cbd88dc297b2b51a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 28 Jan 2008 22:06:09 +0100 Subject: Misc panning fixes for intel_fb --- linux-core/intel_fb.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index bb42bc69..59df1976 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -326,7 +326,7 @@ static int intelfb_set_par(struct fb_info *info) if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) return -EINVAL; - } else if (par->crtc->x != var->xoffset || par->crtc->x != var->xoffset) { + } else if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) { if (!par->crtc->funcs->mode_set_base) { if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) return -EINVAL; @@ -485,6 +485,31 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) ADVANCE_LP_RING(); } #endif +static int intelfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct intelfb_par *par = info->par; + struct drm_crtc *crtc = par->crtc; + struct drm_framebuffer *fb = crtc->fb; + + DRM_DEBUG("\n"); + + if (!crtc->funcs->mode_set_base) { + DRM_ERROR("panning not supported\n"); + return -EFAULT; + } + + /* TODO add check size and pos*/ + + crtc->funcs->mode_set_base(crtc, var->xoffset, var->yoffset); + + par->crtc->x = var->xoffset; + par->crtc->y = var->yoffset; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + return 0; +} static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, @@ -499,6 +524,7 @@ static struct fb_ops intelfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, //intelfb_copyarea, .fb_imageblit = cfb_imageblit, //intelfb_imageblit, + .fb_pan_display = intelfb_pan_display, }; /** @@ -606,8 +632,8 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.type_aux = 0; - info->fix.xpanstep = 8; - info->fix.ypanstep = 1; + info->fix.xpanstep = 1; /* doing it in hw */ + info->fix.ypanstep = 1; /* doing it in hw */ info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_I830; info->fix.type_aux = 0; -- cgit v1.2.3 From 841ef9eb8da8058d6495e9f8e1b14af2709dfaa1 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 30 Jan 2008 15:47:26 +0100 Subject: ModeFB demo now display cursor --- libdrm/xf86drmMode.c | 5 +++- tests/modedemo/demo.c | 1 + tests/modefb/Makefile | 2 +- tests/modefb/demo.c | 82 +++++++++++++++++++++++++++++++++------------------ 4 files changed, 60 insertions(+), 30 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 86572872..681ad417 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -329,7 +329,10 @@ int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_ arg.crtc = crtcId; arg.width = width; arg.height = height; - arg.handle = bo->handle; + if (bo) + arg.handle = bo->handle; + else + arg.handle = 0; return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); } diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 1efeb272..b399aec1 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -244,4 +244,5 @@ void prettyCursor(int fd, unsigned int handle) ptr[i] = 0xFFFF00FF; drmBOUnmap(fd, &bo); + drmBOUnreference(fd, &bo); } diff --git a/tests/modefb/Makefile b/tests/modefb/Makefile index 84c6c86a..467fb11a 100644 --- a/tests/modefb/Makefile +++ b/tests/modefb/Makefile @@ -5,7 +5,7 @@ all: app # -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ app: demo.c - @gcc $(CFLAGS) -o app -Wall demo.c + @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c clean: @rm -f app diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c index 0dbf01c7..9af369c2 100644 --- a/tests/modefb/demo.c +++ b/tests/modefb/demo.c @@ -5,25 +5,37 @@ #include #include "linux/fb.h" #include "sys/ioctl.h" +#include "xf86drm.h" +#include "xf86drmMode.h" - +void pretty(int fd); void setMode(struct fb_var_screeninfo *var); void pan(int fd, struct fb_var_screeninfo *var, int x, int y); -void cursor(int fd); +void cursor(int fd, int drmfd); +void prettyCursor(int fd, unsigned int handle, unsigned int color); + +extern void sleep(int); int main(int argc, char **argv) { struct fb_var_screeninfo var; struct fb_fix_screeninfo fix; + const char* driver = "i915"; const char* name = "/dev/fb0"; int fd = open(name, O_RDONLY); + int drmfd = drmOpen(driver, NULL); if (fd == -1) { printf("open %s : %s\n", name, strerror(errno)); return 1; } + if (drmfd < 0) { + printf("drmOpen failed\n"); + return 1; + } + memset(&var, 0, sizeof(struct fb_var_screeninfo)); memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); @@ -50,7 +62,7 @@ int main(int argc, char **argv) sleep(2); printf("cursor\n"); - cursor(fd); + cursor(fd, drmfd); return 0; } @@ -66,38 +78,52 @@ void pan(int fd, struct fb_var_screeninfo *var, int x, int y) } /* - * Currently isn't supported in the driver + * Cursor support removed from the fb kernel interface + * using drm instead. */ -void cursor(int fd) +void cursor(int fd, int drmfd) { - struct fb_cursor cur; - void *data = malloc(64 * 64 * 4); - memset(&cur, 0, sizeof(cur)); - - cur.set = FB_CUR_SETIMAGE | FB_CUR_SETPOS | FB_CUR_SETSIZE; - cur.enable = 1; - cur.image.dx = 1; - cur.image.dy = 1; - cur.image.width = 2; - cur.image.height = 2; - cur.image.depth = 32; - cur.image.data = data; - - if (ioctl(fd, FBIO_CURSOR, &cur)) - printf("cursor error: %s\n", strerror(errno)); + drmModeResPtr res = drmModeGetResources(drmfd); + uint32_t crtc = res->crtcs[1]; /* select crtc here */ + drmBO bo; + int ret; + ret = drmBOCreate(drmfd, 64 * 64 * 4, 0, 0, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, &bo); + + if (ret) { + printf("failed to create buffer: %s\n", strerror(ret)); + return; + } + prettyCursor(drmfd, bo.handle, 0xFFFF00FF); + drmModeSetCursor(drmfd, crtc, &bo, 64, 64); + drmModeMoveCursor(drmfd, crtc, 0, 0); + sleep(2); + drmModeMoveCursor(drmfd, crtc, 40, 40); + prettyCursor(drmfd, bo.handle, 0xFFFF0000); sleep(2); + drmModeSetCursor(drmfd, crtc, 0, 0, 0); + drmBOUnreference(drmfd, &bo); +} + +void prettyCursor(int drmfd, unsigned int handle, unsigned int color) +{ + drmBO bo; + unsigned int *ptr; + int i; - memset(&cur, 0, sizeof(cur)); - cur.set = FB_CUR_SETPOS; - cur.enable = 0; - cur.image.dx = 100; - cur.image.dy = 100; + drmBOReference(drmfd, handle, &bo); + drmBOMap(drmfd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); - if (ioctl(fd, FBIO_CURSOR, &cur)) - printf("cursor error: %s\n", strerror(errno)); + for (i = 0; i < (64 * 64); i++) + ptr[i] = color; - free(data); + drmBOUnmap(drmfd, &bo); + drmBOUnreference(drmfd, &bo); } struct drm_mode -- cgit v1.2.3 From abed0995585050d5fd179958d01f14f7e430e795 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 30 Jan 2008 16:16:10 +0100 Subject: Fix for cursor off --- linux-core/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 88cf653c..5b7a510b 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -985,6 +985,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = crtc->driver_private; int pipe = intel_crtc->pipe; uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL; + uint32_t base = (pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE; uint32_t temp; size_t adder; @@ -998,6 +999,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, temp |= CURSOR_MODE_DISABLE; I915_WRITE(control, temp); + I915_WRITE(base, 0); return 0; } @@ -1026,8 +1028,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, DRM_DEBUG("cusror base %x\n", adder); - I915_WRITE((pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL, temp); - I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder); + I915_WRITE(control, temp); + I915_WRITE(base, adder); return 0; } -- cgit v1.2.3 From d8bbd02a6086ebe302859cec22c503d32ed77dc6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 4 Feb 2008 20:51:59 +0100 Subject: Modedemo now uses two crtc and output pairs --- tests/modedemo/demo.c | 345 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 261 insertions(+), 84 deletions(-) diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index b399aec1..de31e7a6 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -14,6 +14,60 @@ /* Pitch needs to be power of two */ #define PITCH 2048 +/* old functions to be replaced */ +drmModeFBPtr createFB(int fd, drmModeResPtr res); +void testCursor(int fd, uint32_t crtc); +void prettyColors(int fd, unsigned int handle); +void prettyCursor(int fd, unsigned int handle); + +/* structs for the demo_driver */ + +struct demo_driver; + +struct demo_screen +{ + /* drm stuff */ + drmBO buffer; + drmModeFBPtr fb; + drmModeCrtcPtr crtc; + drmModeOutputPtr output; + + struct drm_mode_modeinfo *mode; + + /* virtual buffer */ + uint32_t virt_x; + uint32_t virt_y; + uint32_t pitch; + + /* parent */ + struct demo_driver *driver; +}; + +#define DEMO_MAX_SCREENS 4 +#define MAX_FIND_OUTPUTS 8 + +struct demo_driver +{ + /* drm stuff */ + int fd; + drmModeResPtr res; + + /* screens */ + size_t numScreens; + struct demo_screen screens[DEMO_MAX_SCREENS]; +}; + +struct demo_driver* demoCreateDriver(const char *name); +void demoUpdateRes(struct demo_driver *driver); +int demoCreateScreens(struct demo_driver *driver); +void demoTakeDownScreen(struct demo_screen *screen); +int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out); +drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output); +void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y); +/* yet to be implemented */ +void demoMouseActivate(struct demo_screen *screen); +void demoMouseMove(struct demo_screen *screen, uint16_t x, uint16_t y); + static struct drm_mode_modeinfo mode = { .name = "Test mode", .clock = 25200, @@ -31,87 +85,232 @@ static struct drm_mode_modeinfo mode = { .flags = 10, }; -drmModeFBPtr createFB(int fd, drmModeResPtr res); -int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out); -drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res); -void testCursor(int fd, uint32_t crtc); -void prettyColors(int fd, unsigned int handle); -void prettyCursor(int fd, unsigned int handle); - int main(int argc, char **argv) { - int fd; - const char *driver = "i915"; /* hardcoded for now */ - drmModeResPtr res; - drmModeFBPtr framebuffer; - int numOutputs; - drmModeOutputPtr out[8]; - drmModeCrtcPtr crtc; + const char *driver_name = "i915"; /* hardcoded for now */ + struct demo_driver *driver; + int num; + int i; - printf("Starting test\n"); + printf("starting demo\n"); - fd = drmOpen(driver, NULL); + driver = demoCreateDriver(driver_name); - if (fd < 0) { - printf("Failed to open the card fb\n"); + if (!driver) { + printf("failed to create driver\n"); return 1; } - res = drmModeGetResources(fd); - if (res == 0) { - printf("Failed to get resources from card\n"); - drmClose(fd); + num = demoCreateScreens(driver); + if (num < 1) { + printf("no screens attached or an error occured\n"); return 1; } + printf("created %i screens\n", num); - framebuffer = createFB(fd, res); - if (framebuffer == NULL) { - printf("Failed to create framebuffer\n"); - return 1; + for (i = 0; i < num; i++) { + prettyColors(driver->fd, driver->screens[i].fb->handle); } + sleep(1); - numOutputs = findConnectedOutputs(fd, res, out); - if (numOutputs < 1) { - printf("Failed to find connected outputs\n"); - return 1; + for (i = 0; i < num; i++) { + printf("%i: 100 0\n", i); + demoPanScreen(&driver->screens[i], 100, 0); + sleep(1); + + printf("%i: 0 100\n", i); + demoPanScreen(&driver->screens[i], 0, 100); + sleep(1); + + printf("%i: 100 100\n", i); + demoPanScreen(&driver->screens[i], 100, 100); + sleep(1); + + printf("%i: 0 0\n", i); + demoPanScreen(&driver->screens[i], 0, 1); + sleep(1); + testCursor(driver->fd, driver->screens[i].crtc->crtc_id); } - crtc = findFreeCrtc(fd, res); - if (numOutputs < 1) { - printf("Couldn't find a free crtc\n"); - return 1; + sleep(2); + printf("ok\n"); + return 0; +} + +int demoCreateScreens(struct demo_driver *driver) +{ + drmModeOutputPtr out[MAX_FIND_OUTPUTS]; + int num; + int num_screens = 0; + struct demo_screen *screen; + int ret = 0; + int i; + + num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS); + if (num < 0) + return 0; + + printf("found %i connected outputs\n", num); + + for (i = 0; i < num; i++) { + screen = &driver->screens[i]; + + screen->crtc = demoFindFreeCrtc(driver, out[i]); + if (!screen->crtc) { + printf("found no free crtc for output\n"); + drmModeFreeOutput(out[i]); + continue; + } + + screen->fb = createFB(driver->fd, driver->res); + if (!screen->fb) { + drmModeFreeOutput(out[i]); + drmModeFreeCrtc(screen->crtc); + screen->crtc = 0; + printf("could not create framebuffer\n"); + continue; + } + + screen->virt_x = SIZE_X; + screen->virt_y = SIZE_Y; + screen->pitch = PITCH; + + screen->output = out[i]; + screen->mode = &mode; + screen->driver = driver; + + ret = drmModeSetCrtc( + driver->fd, + screen->crtc->crtc_id, + screen->fb->buffer_id, + 0, 0, + &screen->output->output_id, 1, + screen->mode); + + if (ret) { + printf("failed to set mode\n"); + demoTakeDownScreen(screen); + } else { + num_screens++; + } + + demoUpdateRes(driver); } - prettyColors(fd, framebuffer->handle); + return num_screens; +} - printf("0 0\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 0, &out[0]->output_id, 1, &mode); - sleep(2); +void demoTakeDownScreen(struct demo_screen *screen) +{ + /* TODO Unrefence the BO */ + /* TODO Destroy FB */ + /* TODO take down the mode */ - printf("0 100\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 0, 100, &out[0]->output_id, 1, &mode); - sleep(2); + drmModeFreeOutput(screen->output); + drmModeFreeCrtc(screen->crtc); +} - printf("100 0\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 0, &out[0]->output_id, 1, &mode); - sleep(2); +drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output) +{ + drmModeCrtcPtr crtc; + int i, j, used = 0; + drmModeResPtr res = driver->res; - printf("100 100\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 100, 100, &out[0]->output_id, 1, &mode); - sleep(2); - printf("0 0\n"); - drmModeSetCrtc(fd, crtc->crtc_id, framebuffer->buffer_id, 1, 1, &out[0]->output_id, 1, &mode); + for (i = 0; i < res->count_crtcs; i++) { + used = 0; + for (j = 0; j < DEMO_MAX_SCREENS; j++) { + crtc = driver->screens[j].crtc; - testCursor(fd, crtc->crtc_id); + if (crtc && crtc->crtc_id == res->crtcs[i]) + used = 1; + } - /* turn the crtc off just in case */ - drmModeSetCrtc(fd, crtc->crtc_id, 0, 0, 0, 0, 0, 0); + if (!used) { + crtc = drmModeGetCrtc(driver->fd, res->crtcs[i]); + break; + } else { + crtc = 0; + } + } - drmModeFreeResources(res); - printf("Ok\n"); + return crtc; +} - return 0; +struct demo_driver* demoCreateDriver(const char *name) +{ + struct demo_driver* driver = malloc(sizeof(struct demo_driver)); + + memset(driver, 0, sizeof(struct demo_driver)); + + driver->fd = drmOpen(name, NULL); + + if (driver->fd < 0) { + printf("Failed to open the card fb\n"); + goto err_driver; + } + + demoUpdateRes(driver); + if (!driver->res) { + printf("could not retrive resources\n"); + goto err_res; + } + + return driver; + +err_res: + drmClose(driver->fd); +err_driver: + free(driver); + return NULL; +} + +void demoUpdateRes(struct demo_driver *driver) +{ + if (driver->res) + drmModeFreeResources(driver->res); + + driver->res = drmModeGetResources(driver->fd); + + if (!driver->res) + printf("failed to get resources from kernel\n"); +} + +int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out) +{ + int count = 0; + int i; + int fd = driver->fd; + drmModeResPtr res = driver->res; + + drmModeOutputPtr output; + + for (i = 0; i < res->count_outputs && count < max_out; i++) { + output = drmModeGetOutput(fd, res->outputs[i]); + + if (!output) + continue; + + if (output->connection != DRM_MODE_CONNECTED) { + drmModeFreeOutput(output); + continue; + } + + out[count++] = output; + } + + return count; +} + +void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y) +{ + drmModeSetCrtc( + screen->driver->fd, + screen->crtc->crtc_id, + screen->fb->buffer_id, + x, y, + &screen->output->output_id, 1, + screen->mode); } drmModeFBPtr createFB(int fd, drmModeResPtr res) @@ -147,33 +346,7 @@ drmModeFBPtr createFB(int fd, drmModeResPtr res) err_bo: drmBOUnreference(fd, &bo); err: - printf("Something went wrong when creating a fb, using one of the predefined ones\n"); - - return drmModeGetFB(fd, res->fbs[0]); -} - -int findConnectedOutputs(int fd, drmModeResPtr res, drmModeOutputPtr *out) -{ - int count = 0; - int i; - - drmModeOutputPtr output; - - for (i = 0; i < res->count_outputs; i++) { - output = drmModeGetOutput(fd, res->outputs[i]); - - if (!output || output->connection != DRM_MODE_CONNECTED) - continue; - - out[count++] = output; - } - - return count; -} - -drmModeCrtcPtr findFreeCrtc(int fd, drmModeResPtr res) -{ - return drmModeGetCrtc(fd, res->crtcs[1]); + return 0; } void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr) @@ -225,10 +398,14 @@ void testCursor(int fd, uint32_t crtc) drmModeSetCursor(fd, crtc, &bo, 64, 64); printf("move cursor 0, 0\n"); drmModeMoveCursor(fd, crtc, 0, 0); - sleep(2); + sleep(1); printf("move cursor 40, 40\n"); drmModeMoveCursor(fd, crtc, 40, 40); - sleep(2); + sleep(1); + printf("move cursor 100, 100\n"); + drmModeMoveCursor(fd, crtc, 100, 100); + sleep(1); + drmModeSetCursor(fd, crtc, NULL, 0, 0); } void prettyCursor(int fd, unsigned int handle) -- cgit v1.2.3 From 709aa4629321533bfa30c72c4e33f229c895358a Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 09:28:32 +0000 Subject: Remove duplicate --- linux-core/drm_compat.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 3f3abc9a..c3a70486 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -331,8 +331,4 @@ void idr_remove_all(struct idr *idp); void *idr_replace(struct idr *idp, void *ptr, int id); #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) -typedef _Bool bool; -#endif - #endif -- cgit v1.2.3 From c9772f8c037667ed3586337f90904e7978f8ab14 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 09:28:51 +0000 Subject: consistency --- linux-core/drm_crtc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 8f6a8938..63324ca1 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -259,7 +259,7 @@ struct drm_property_blob { struct drm_property_enum { uint64_t value; struct list_head head; - unsigned char name[DRM_PROP_NAME_LEN]; + char name[DRM_PROP_NAME_LEN]; }; struct drm_property { -- cgit v1.2.3 From 7cc825f5946659ad586fd4aa4fd867a1373f3373 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 10:10:36 +0000 Subject: Add missing round_jiffies_relative() for older kernels --- linux-core/ati_pcigart.c | 3 ++- linux-core/drm_compat.c | 35 +++++++++++++++++++++++++++++++++++ linux-core/drm_compat.h | 4 ++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index c669067b..97a5dfb2 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -274,7 +274,8 @@ static int ati_pcigart_needs_unbind_cache_adjust(struct drm_ttm_backend *backend static int ati_pcigart_populate(struct drm_ttm_backend *backend, unsigned long num_pages, - struct page **pages) + struct page **pages, + struct page *dummy_page) { ati_pcigart_ttm_backend_t *atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index a745a7d9..cd4ff7df 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -729,3 +729,38 @@ void *idr_replace(struct idr *idp, void *ptr, int id) } EXPORT_SYMBOL(idr_replace); #endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +static __inline__ unsigned long __round_jiffies(unsigned long j, int cpu) +{ + int rem; + unsigned long original = j; + + j += cpu * 3; + + rem = j % HZ; + + if (rem < HZ/4) /* round down */ + j = j - rem; + else /* round up */ + j = j - rem + HZ; + + /* now that we have rounded, subtract the extra skew again */ + j -= cpu * 3; + + if (j <= jiffies) /* rounding ate our timeout entirely; */ + return original; + return j; +} + +static __inline__ unsigned long __round_jiffies_relative(unsigned long j, int cpu) +{ + return __round_jiffies(j + jiffies, cpu) - jiffies; +} + +unsigned long round_jiffies_relative(unsigned long j) +{ + return __round_jiffies_relative(j, raw_smp_processor_id()); +} +EXPORT_SYMBOL(round_jiffies_relative); +#endif diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index c3a70486..92dcbc21 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -331,4 +331,8 @@ void idr_remove_all(struct idr *idp); void *idr_replace(struct idr *idp, void *ptr, int id); #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +extern unsigned long round_jiffies_relative(unsigned long j); +#endif + #endif -- cgit v1.2.3 From f2c706e24782940582b75d5286f9bbf2fe37f0cd Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 10:11:01 +0000 Subject: Fix function declaration --- linux-core/drm_crtc.c | 2 +- linux-core/drm_crtc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 18fa02ce..03e5ffe9 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2299,7 +2299,7 @@ done: return ret; } -int drm_mode_output_update_edid_property(struct drm_output *output, unsigned char *edid) +int drm_mode_output_update_edid_property(struct drm_output *output, struct edid *edid) { struct drm_device *dev = output->dev; int ret = 0; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 63324ca1..3b22e886 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -592,7 +592,7 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); extern void drm_mode_output_list_update(struct drm_output *output); -extern int drm_mode_output_update_edid_property(struct drm_output *output, unsigned char *edid); +extern int drm_mode_output_update_edid_property(struct drm_output *output, struct edid *edid); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, -- cgit v1.2.3 From 5e81a40f3b531ef95f84581a40b5a5badd9ee986 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 10:11:24 +0000 Subject: build fix for older kernels --- linux-core/i915_buffer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 54aa75ad..ba586888 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -270,10 +270,12 @@ static inline void clflush(volatile void *__p) static inline void drm_cache_flush_addr(void *virt) { +#ifdef cpu_has_clflush int i; for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) clflush(virt+i); +#endif } static inline void drm_cache_flush_page(struct page *p) @@ -291,6 +293,9 @@ void i915_flush_ttm(struct drm_ttm *ttm) DRM_MEMORYBARRIER(); #ifdef CONFIG_X86_32 +#ifndef cpu_has_clflush +#define cpu_has_clflush 0 +#endif /* Hopefully nobody has built an x86-64 processor without clflush */ if (!cpu_has_clflush) { wbinvd(); -- cgit v1.2.3 From de0084590bc34c2c23cb3d7a754f3e98059f4cf2 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 10:11:46 +0000 Subject: fix some warnings --- linux-core/intel_crt.c | 5 ++--- linux-core/intel_fb.c | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 4be71cba..a9fb50a3 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -219,11 +219,10 @@ static bool intel_crt_set_property(struct drm_output *output, uint64_t value) { struct drm_device *dev = output->dev; - int i; - if (property == dev->mode_config.dpms_property) { + if (property == dev->mode_config.dpms_property) intel_crt_dpms(output, (uint32_t)(value & 0xf)); - } + return true; } diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 59df1976..6df243b0 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -490,7 +490,6 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; struct drm_crtc *crtc = par->crtc; - struct drm_framebuffer *fb = crtc->fb; DRM_DEBUG("\n"); -- cgit v1.2.3 From 53937a189f8dbe2dd82fb97c0e88454d29a6c7cd Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 10:12:21 +0000 Subject: build fix for older kernels --- shared-core/i915_irq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9b391b75..836a8c46 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -476,7 +476,11 @@ unlock: * This code is called in a more safe envirmoent to handle the hotplugs. * Add code here for hotplug love to userspace. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +static void i915_hotplug_work_func(void *work) +#else static void i915_hotplug_work_func(struct work_struct *work) +#endif { struct drm_device *dev = hotplug_dev; int crt; @@ -503,7 +507,11 @@ static void i915_hotplug_work_func(struct work_struct *work) static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + static DECLARE_WORK(hotplug, i915_hotplug_work_func, NULL); +#else static DECLARE_WORK(hotplug, i915_hotplug_work_func); +#endif struct drm_i915_private *dev_priv = dev->dev_private; hotplug_dev = dev; -- cgit v1.2.3 From 7af1bb874d9b8b1b8760ad200cee587c41c23434 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 15:12:46 +0000 Subject: DRM_CONTROL_ALLOW logic was reversed --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index b0b44c90..927225f1 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -666,7 +666,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) || ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || ((ioctl->flags & DRM_MASTER) && !file_priv->master) || - ((!(ioctl->flags & DRM_CONTROL_ALLOW)) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ) { + ((ioctl->flags & DRM_CONTROL_ALLOW) && !(file_priv->minor->type == DRM_MINOR_CONTROL)) ) { retcode = -EACCES; } else { retcode = func(dev, kdata, file_priv); -- cgit v1.2.3 From 5997e10ca75ac87fd54b3bc0035938e1a9ad7929 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 15:15:13 +0000 Subject: consistency --- libdrm/xf86drmMode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index f5b3337c..e878c40a 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -78,7 +78,7 @@ typedef struct _drmModePropertyBlob { typedef struct _drmModeProperty { unsigned int prop_id; unsigned int flags; - unsigned char name[DRM_PROP_NAME_LEN]; + char name[DRM_PROP_NAME_LEN]; int count_values; uint64_t *values; // store the blob lengths int count_enums; -- cgit v1.2.3 From 936e32b08c05c9658cc51cd8fe118e0342733a79 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 15:18:05 +0000 Subject: make modefb/modedemo match each others test output. --- tests/mode/modetest.c | 5 ++-- tests/modedemo/demo.c | 23 +++++++------- tests/modefb/demo.c | 83 +++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 82 insertions(+), 29 deletions(-) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index eeb4b258..ab0cdc9c 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -347,15 +347,14 @@ int testDPMS(int fd, drmModeResPtr res) int main(int argc, char **argv) { int fd; - const char *driver = "i915"; /* hardcoded for now */ drmModeResPtr res; printf("Starting test\n"); - fd = drmOpen(driver, NULL); + fd = drmOpenControl(0); if (fd < 0) { - printf("Failed to open the card fb\n"); + printf("Failed to open the card fb (%d)\n",fd); return 1; } diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index de31e7a6..48a4f1f1 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -18,7 +18,7 @@ drmModeFBPtr createFB(int fd, drmModeResPtr res); void testCursor(int fd, uint32_t crtc); void prettyColors(int fd, unsigned int handle); -void prettyCursor(int fd, unsigned int handle); +void prettyCursor(int fd, unsigned int handle, unsigned int color); /* structs for the demo_driver */ @@ -57,7 +57,7 @@ struct demo_driver struct demo_screen screens[DEMO_MAX_SCREENS]; }; -struct demo_driver* demoCreateDriver(const char *name); +struct demo_driver* demoCreateDriver(void); void demoUpdateRes(struct demo_driver *driver); int demoCreateScreens(struct demo_driver *driver); void demoTakeDownScreen(struct demo_screen *screen); @@ -87,14 +87,13 @@ static struct drm_mode_modeinfo mode = { int main(int argc, char **argv) { - const char *driver_name = "i915"; /* hardcoded for now */ struct demo_driver *driver; int num; int i; printf("starting demo\n"); - driver = demoCreateDriver(driver_name); + driver = demoCreateDriver(); if (!driver) { printf("failed to create driver\n"); @@ -237,13 +236,13 @@ drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr out return crtc; } -struct demo_driver* demoCreateDriver(const char *name) +struct demo_driver* demoCreateDriver(void) { struct demo_driver* driver = malloc(sizeof(struct demo_driver)); memset(driver, 0, sizeof(struct demo_driver)); - driver->fd = drmOpen(name, NULL); + driver->fd = drmOpenControl(0); if (driver->fd < 0) { printf("Failed to open the card fb\n"); @@ -328,8 +327,10 @@ drmModeFBPtr createFB(int fd, drmModeResPtr res) DRM_BO_FLAG_NO_EVICT, DRM_BO_HINT_DONT_FENCE, &bo); - if (ret) + if (ret) { + printf("failed to create framebuffer (ret %d)\n",ret); goto err; + } ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, &bo, &fb); @@ -392,13 +393,13 @@ void testCursor(int fd, uint32_t crtc) DRM_BO_FLAG_NO_EVICT, DRM_BO_HINT_DONT_FENCE, &bo); - prettyCursor(fd, bo.handle); - + prettyCursor(fd, bo.handle, 0xFFFF00FF); printf("set cursor\n"); drmModeSetCursor(fd, crtc, &bo, 64, 64); printf("move cursor 0, 0\n"); drmModeMoveCursor(fd, crtc, 0, 0); sleep(1); + prettyCursor(fd, bo.handle, 0xFFFF0000); printf("move cursor 40, 40\n"); drmModeMoveCursor(fd, crtc, 40, 40); sleep(1); @@ -408,7 +409,7 @@ void testCursor(int fd, uint32_t crtc) drmModeSetCursor(fd, crtc, NULL, 0, 0); } -void prettyCursor(int fd, unsigned int handle) +void prettyCursor(int fd, unsigned int handle, unsigned int color) { drmBO bo; unsigned int *ptr; @@ -418,7 +419,7 @@ void prettyCursor(int fd, unsigned int handle) drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr); for (i = 0; i < (64 * 64); i++) - ptr[i] = 0xFFFF00FF; + ptr[i] = color; drmBOUnmap(fd, &bo); drmBOUnreference(fd, &bo); diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c index 9af369c2..f80753cf 100644 --- a/tests/modefb/demo.c +++ b/tests/modefb/demo.c @@ -4,6 +4,7 @@ #include #include #include "linux/fb.h" +#include #include "sys/ioctl.h" #include "xf86drm.h" #include "xf86drmMode.h" @@ -12,19 +13,20 @@ void pretty(int fd); void setMode(struct fb_var_screeninfo *var); void pan(int fd, struct fb_var_screeninfo *var, int x, int y); void cursor(int fd, int drmfd); +void prettyColors(int fd); void prettyCursor(int fd, unsigned int handle, unsigned int color); extern void sleep(int); +struct fb_var_screeninfo var; +struct fb_fix_screeninfo fix; + int main(int argc, char **argv) { - struct fb_var_screeninfo var; - struct fb_fix_screeninfo fix; - const char* driver = "i915"; - const char* name = "/dev/fb0"; - - int fd = open(name, O_RDONLY); - int drmfd = drmOpen(driver, NULL); + const char* name = "/dev/fb1"; + int i; + int fd = open(name, O_RDWR); + int drmfd = drmOpenControl(0); if (fd == -1) { printf("open %s : %s\n", name, strerror(errno)); @@ -32,7 +34,7 @@ int main(int argc, char **argv) } if (drmfd < 0) { - printf("drmOpen failed\n"); + printf("drmOpenControl failed\n"); return 1; } @@ -45,6 +47,15 @@ int main(int argc, char **argv) printf("fix %s\n", strerror(errno)); setMode(&var); + + if (ioctl(fd, FBIOPUT_VSCREENINFO, &var)) + printf("var %s\n", strerror(errno)); + + for (i = 0; i < 1; i++) { + prettyColors(fd); + } + sleep(1); + printf("pan: 0, 0\n"); pan(fd, &var, 0, 0); sleep(2); @@ -71,12 +82,51 @@ void pan(int fd, struct fb_var_screeninfo *var, int x, int y) var->xoffset = x; var->yoffset = y; - var->activate = FB_ACTIVATE_NOW; - - if (ioctl(fd, FBIOPUT_VSCREENINFO, var)) + if (ioctl(fd, FBIOPAN_DISPLAY, var)) printf("pan error: %s\n", strerror(errno)); } +void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr) +{ + int i, j; + + for (i = x; i < x + w; i++) + for(j = y; j < y + h; j++) + ptr[(i * var.xres_virtual) + j] = v; +} + +void prettyColors(int fd) +{ + unsigned int *ptr, *newptr; + int i,w,h; + int size = var.xres * var.yres * var.bits_per_pixel; + + ptr = (unsigned int *)mmap(NULL, size, + PROT_READ|PROT_WRITE, MAP_SHARED, fd, + 0); + if (ptr < 0) { + printf("FAILED MMAP %d\n",errno); + exit(1); + } + + newptr = ptr; + for (h = 0; h < var.yres; h++) { + for (w = 0; w < var.xres; w++) { + newptr[w] = 0xFFFFFFFF; + } + newptr += var.xres_virtual; + } + + for (i = 0; i < 8; i++) + draw(i * 40, i * 40, 40, 40, 0, ptr); + + + draw(200, 100, 40, 40, 0xff00ff, ptr); + draw(100, 200, 40, 40, 0xff00ff, ptr); + + munmap(ptr, size); +} + /* * Cursor support removed from the fb kernel interface * using drm instead. @@ -102,11 +152,13 @@ void cursor(int fd, int drmfd) prettyCursor(drmfd, bo.handle, 0xFFFF00FF); drmModeSetCursor(drmfd, crtc, &bo, 64, 64); drmModeMoveCursor(drmfd, crtc, 0, 0); - sleep(2); - drmModeMoveCursor(drmfd, crtc, 40, 40); + sleep(1); prettyCursor(drmfd, bo.handle, 0xFFFF0000); - sleep(2); - drmModeSetCursor(drmfd, crtc, 0, 0, 0); + drmModeMoveCursor(drmfd, crtc, 40, 40); + sleep(1); + drmModeMoveCursor(drmfd, crtc, 100, 100); + sleep(1); + drmModeSetCursor(drmfd, crtc, NULL, 0, 0); drmBOUnreference(drmfd, &bo); } @@ -173,4 +225,5 @@ void setMode(struct fb_var_screeninfo *var) { var->pixclock = 10000000 / mode.htotal * 1000 / mode.vtotal * 100; /* avoid overflow */ var->pixclock = var->pixclock * 1000 / mode.vrefresh; + var->bits_per_pixel = 32; } -- cgit v1.2.3 From 127cb1ff9a7bbb7af73cc418a7adc30d68c454d2 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 15:24:29 +0000 Subject: tweak it --- tests/modefb/demo.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c index f80753cf..ef2b6585 100644 --- a/tests/modefb/demo.c +++ b/tests/modefb/demo.c @@ -97,8 +97,8 @@ void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsign void prettyColors(int fd) { - unsigned int *ptr, *newptr; - int i,w,h; + unsigned int *ptr; + int i; int size = var.xres * var.yres * var.bits_per_pixel; ptr = (unsigned int *)mmap(NULL, size, @@ -109,13 +109,7 @@ void prettyColors(int fd) exit(1); } - newptr = ptr; - for (h = 0; h < var.yres; h++) { - for (w = 0; w < var.xres; w++) { - newptr[w] = 0xFFFFFFFF; - } - newptr += var.xres_virtual; - } + memset(ptr, 0xFF, size); for (i = 0; i < 8; i++) draw(i * 40, i * 40, 40, 40, 0, ptr); -- cgit v1.2.3 From 516c7a7b28ebf4bba797eaa718450b51aa772c6e Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 5 Feb 2008 15:30:28 +0000 Subject: update app to cycle through 4 fbdev's --- tests/modefb/demo.c | 102 +++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c index ef2b6585..7fa3b93f 100644 --- a/tests/modefb/demo.c +++ b/tests/modefb/demo.c @@ -23,57 +23,63 @@ struct fb_fix_screeninfo fix; int main(int argc, char **argv) { - const char* name = "/dev/fb1"; - int i; - int fd = open(name, O_RDWR); + char name[100]; + int i,d; + int fd; int drmfd = drmOpenControl(0); - if (fd == -1) { - printf("open %s : %s\n", name, strerror(errno)); - return 1; - } - - if (drmfd < 0) { - printf("drmOpenControl failed\n"); - return 1; + /* try four devices */ + for (d = 0; d < 4; d++) { + snprintf(name, 100, "/dev/fb%d", d); + fd = open(name, O_RDWR); + + if (fd == -1) { + printf("open %s : %s\n", name, strerror(errno)); + return 1; + } + + if (drmfd < 0) { + printf("drmOpenControl failed\n"); + return 1; + } + + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); + + if (ioctl(fd, FBIOGET_VSCREENINFO, &var)) + printf("var %s\n", strerror(errno)); + if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)) + printf("fix %s\n", strerror(errno)); + + setMode(&var); + + if (ioctl(fd, FBIOPUT_VSCREENINFO, &var)) + printf("var %s\n", strerror(errno)); + + for (i = 0; i < 1; i++) { + prettyColors(fd); + } + sleep(1); + + printf("pan: 0, 0\n"); + pan(fd, &var, 0, 0); + sleep(2); + printf("pan: 100, 0\n"); + pan(fd, &var, 100, 0); + sleep(2); + printf("pan: 0, 100\n"); + pan(fd, &var, 0, 100); + sleep(2); + printf("pan: 100, 100\n"); + pan(fd, &var, 100, 100); + sleep(2); + printf("pan: 0, 0\n"); + pan(fd, &var, 0, 0); + sleep(2); + + printf("cursor (may show up on wrong CRTC - fixme)\n"); + cursor(fd, drmfd); } - - memset(&var, 0, sizeof(struct fb_var_screeninfo)); - memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); - - if (ioctl(fd, FBIOGET_VSCREENINFO, &var)) - printf("var %s\n", strerror(errno)); - if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)) - printf("fix %s\n", strerror(errno)); - - setMode(&var); - - if (ioctl(fd, FBIOPUT_VSCREENINFO, &var)) - printf("var %s\n", strerror(errno)); - - for (i = 0; i < 1; i++) { - prettyColors(fd); - } - sleep(1); - - printf("pan: 0, 0\n"); - pan(fd, &var, 0, 0); - sleep(2); - printf("pan: 100, 0\n"); - pan(fd, &var, 100, 0); - sleep(2); - printf("pan: 0, 100\n"); - pan(fd, &var, 0, 100); - sleep(2); - printf("pan: 100, 100\n"); - pan(fd, &var, 100, 100); - sleep(2); - printf("pan: 0, 0\n"); - pan(fd, &var, 0, 0); - sleep(2); - - printf("cursor\n"); - cursor(fd, drmfd); return 0; } -- cgit v1.2.3 From 87d5f9cb2d2812c1da726e38965f0eb78c2b8dfa Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 7 Feb 2008 19:22:38 +0100 Subject: Small update to modedemo --- tests/modedemo/demo.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 48a4f1f1..0882fc91 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -201,12 +201,30 @@ int demoCreateScreens(struct demo_driver *driver) void demoTakeDownScreen(struct demo_screen *screen) { - /* TODO Unrefence the BO */ - /* TODO Destroy FB */ - /* TODO take down the mode */ + int fd = screen->driver->fd; + drmBO bo; + + if (screen->crtc) + drmModeSetCrtc(fd, screen->crtc->crtc_id, 0, 0, 0, 0, 0, 0); + + if (screen->fb) + drmModeRmFB(fd, screen->fb->buffer_id); + + /* maybe we should keep a pointer to the bo on the screen */ + if (screen->fb && !drmBOReference(fd, screen->fb->handle, &bo)) { + drmBOUnreference(fd, &bo); + drmBOUnreference(fd, &bo); + } else { + printf("bo error\n"); + } drmModeFreeOutput(screen->output); drmModeFreeCrtc(screen->crtc); + drmModeFreeFB(screen->fb); + + screen->output = NULL; + screen->crtc = NULL; + screen->fb = NULL; } drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output) -- cgit v1.2.3 From 34b76e0fac579e4afd269ebd3cbcbdd0416ec944 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 7 Feb 2008 19:23:27 +0100 Subject: Added hotplug ioctl --- shared-core/drm.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shared-core/drm.h b/shared-core/drm.h index 209a8db0..0d7cfd25 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1111,6 +1111,13 @@ struct drm_mode_cursor { unsigned int handle; }; +/* + * oh so ugly hotplug + */ +struct drm_mode_hotplug { + uint32_t counter; +}; + /** * \name Ioctls Definitions */ @@ -1218,6 +1225,7 @@ struct drm_mode_cursor { #define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property) #define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xAC, struct drm_mode_cursor) +#define DRM_IOCTL_MODE_HOTPLUG DRM_IOWR(0xAD, struct drm_mode_hotplug) /*@}*/ -- cgit v1.2.3 From 0618ac8a07d834e469cb96818a1dfee6f50662b8 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 7 Feb 2008 19:24:58 +0100 Subject: Added kernel part of hotplug ioctl --- linux-core/drm_crtc.c | 28 ++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 8 +++++++- linux-core/drm_drv.c | 2 +- shared-core/i915_irq.c | 19 +++++++++++++------ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 03e5ffe9..55390a82 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -770,6 +770,7 @@ void drm_mode_config_init(struct drm_device *dev) dev->mode_config.num_fb = 0; dev->mode_config.num_output = 0; dev->mode_config.num_crtc = 0; + dev->mode_config.hotplug_counter = 0; } EXPORT_SYMBOL(drm_mode_config_init); @@ -1130,10 +1131,18 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, * RETURNS: * Zero on success, errno on failure. */ -int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output) +int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, + bool connected) { int has_config = 0; + /* We might want to do something more here */ + if (!connected) { + DRM_DEBUG("not connected\n"); + dev->mode_config.hotplug_counter++; + return 0; + } + if (output->crtc && output->crtc->desired_mode) { DRM_DEBUG("drm thinks that the output already has a config\n"); has_config = 1; @@ -1146,7 +1155,7 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output) if (!output->crtc || !output->crtc->desired_mode) { DRM_DEBUG("could not find a desired mode or crtc for output\n"); - return 1; + goto out_err; } /* We should realy check if there is a fb using this crtc */ @@ -1161,10 +1170,25 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output) drm_disable_unused_functions(dev); + dev->mode_config.hotplug_counter++; return 0; + +out_err: + dev->mode_config.hotplug_counter++; + return 1; } EXPORT_SYMBOL(drm_hotplug_stage_two); +int drm_mode_hotplug_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_hotplug *arg = data; + + arg->counter = dev->mode_config.hotplug_counter; + + return 0; +} + /** * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo * @out: drm_mode_modeinfo struct to return to the user diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 3b22e886..db5fd34c 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -547,6 +547,9 @@ struct drm_mode_config { struct drm_property *dpms_property; struct drm_property *connector_type_property; struct drm_property *connector_num_property; + + /* hotplug */ + uint32_t hotplug_counter; }; struct drm_output *drm_output_create(struct drm_device *dev, @@ -603,7 +606,7 @@ extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); -extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output); +extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected); extern int drm_output_attach_property(struct drm_output *output, struct drm_property *property, uint64_t init_val); @@ -646,5 +649,8 @@ extern int drm_mode_getblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_output_property_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_hotplug_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); + #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 927225f1..5077f067 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -135,7 +135,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY | DRM_CONTROL_ALLOW), - + DRM_IOCTL_DEF(DRM_IOCTL_MODE_HOTPLUG, drm_mode_hotplug_ioctl, DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 836a8c46..5f6fa56d 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -413,6 +413,7 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) } #define HOTPLUG_CMD_CRT 1 +#define HOTPLUG_CMD_CRT_DIS 2 #define HOTPLUG_CMD_SDVOB 4 #define HOTPLUG_CMD_SDVOC 8 @@ -420,7 +421,7 @@ static struct drm_device *hotplug_dev; static int hotplug_cmd = 0; static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; -static void i915_hotplug_crt(struct drm_device *dev) +static void i915_hotplug_crt(struct drm_device *dev, bool connected) { struct drm_output *output; struct intel_output *iout; @@ -439,7 +440,7 @@ static void i915_hotplug_crt(struct drm_device *dev) if (iout == 0) goto unlock; - drm_hotplug_stage_two(dev, output); + drm_hotplug_stage_two(dev, output, connected); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -462,9 +463,9 @@ static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) status = output->funcs->detect(output); if (status != output_status_connected) - DRM_DEBUG("disconnect or unkown we don't do anything then\n"); + drm_hotplug_stage_two(dev, output, false); else - drm_hotplug_stage_two(dev, output); + drm_hotplug_stage_two(dev, output, true); /* wierd hw bug, sdvo stop sending interupts */ intel_sdvo_set_hotplug(output, 1); @@ -484,18 +485,22 @@ static void i915_hotplug_work_func(struct work_struct *work) { struct drm_device *dev = hotplug_dev; int crt; + int crtDis; int sdvoB; int sdvoC; spin_lock(&hotplug_lock); crt = hotplug_cmd & HOTPLUG_CMD_CRT; + crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS; sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; sdvoC = hotplug_cmd & HOTPLUG_CMD_SDVOC; hotplug_cmd = 0; spin_unlock(&hotplug_lock); if (crt) - i915_hotplug_crt(dev); + i915_hotplug_crt(dev, true); + if (crtDis) + i915_hotplug_crt(dev, false); if (sdvoB) i915_hotplug_sdvo(dev, 1); @@ -524,7 +529,9 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) hotplug_cmd |= HOTPLUG_CMD_CRT; spin_unlock(&hotplug_lock); } else { - /* handle crt disconnects */ + spin_lock(&hotplug_lock); + hotplug_cmd |= HOTPLUG_CMD_CRT_DIS; + spin_unlock(&hotplug_lock); } } -- cgit v1.2.3 From c8b45e9362aa16fed08540996af6d0b1e2e730d0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 7 Feb 2008 19:25:52 +0100 Subject: Added userspace part of hotplug ioctl and demo --- libdrm/xf86drmMode.c | 9 +++ libdrm/xf86drmMode.h | 4 ++ tests/modehotplug/Makefile | 14 ++++ tests/modehotplug/demo.c | 157 +++++++++++++++++++++++++++++++++++++++++++++ tests/modehotplug/test | 1 + 5 files changed, 185 insertions(+) create mode 100644 tests/modehotplug/Makefile create mode 100644 tests/modehotplug/demo.c create mode 100755 tests/modehotplug/test diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 681ad417..52fef81b 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -191,6 +191,15 @@ err_allocs: return r; } +uint32_t drmModeGetHotplug(int fd) +{ + struct drm_mode_hotplug arg; + arg.counter = 0; + + ioctl(fd, DRM_IOCTL_MODE_HOTPLUG, &arg); + return arg.counter; +} + int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id) { diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index e878c40a..7cc3ceca 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -159,6 +159,10 @@ extern void drmModeFreeOutput( drmModeOutputPtr ptr ); */ extern drmModeResPtr drmModeGetResources(int fd); +/** + * Retrives the hotplug counter + */ +extern uint32_t drmModeGetHotplug(int fd); /* * FrameBuffer manipulation. diff --git a/tests/modehotplug/Makefile b/tests/modehotplug/Makefile new file mode 100644 index 00000000..467fb11a --- /dev/null +++ b/tests/modehotplug/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: demo.c + @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c + +clean: + @rm -f app + +run: app + sudo ./test diff --git a/tests/modehotplug/demo.c b/tests/modehotplug/demo.c new file mode 100644 index 00000000..4ef2e386 --- /dev/null +++ b/tests/modehotplug/demo.c @@ -0,0 +1,157 @@ + +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +/* structs for the demo_driver */ + +#define DEMO_MAX_OUTPUTS 8 + +struct demo_driver +{ + /* drm stuff */ + int fd; + drmModeResPtr res; + uint32_t counter; + + drmModeOutputPtr outputs[DEMO_MAX_OUTPUTS]; +}; + +struct demo_driver* demoCreateDriver(void); +void demoUpdateRes(struct demo_driver *driver); + +void demoPopulateOutputs(struct demo_driver *driver); +void demoHotplug(struct demo_driver *driver); + +const char* demoGetStatus(drmModeOutputPtr out); + +int main(int argc, char **argv) +{ + struct demo_driver *driver; + uint32_t temp; + int i; + + printf("starting demo\n"); + + driver = demoCreateDriver(); + + if (!driver) { + printf("failed to create driver\n"); + return 1; + } + + driver->counter = drmModeGetHotplug(driver->fd); + demoPopulateOutputs(driver); + while (driver->counter != (temp = drmModeGetHotplug(driver->fd))) { + demoPopulateOutputs(driver); + driver->counter = temp; + } + + for (i = 0; i < driver->res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) { + printf("Output %u is %s\n", + driver->outputs[i]->output_id, + demoGetStatus(driver->outputs[i])); + } + + while(1) { + usleep(100000); + temp = drmModeGetHotplug(driver->fd); + if (temp == driver->counter) + continue; + + demoHotplug(driver); + driver->counter = temp; + } + + return 0; +} + +const char* demoGetStatus(drmModeOutputPtr output) +{ + switch (output->connection) { + case DRM_MODE_CONNECTED: + return "connected"; + case DRM_MODE_DISCONNECTED: + return "disconnected"; + default: + return "unknown"; + } +} + +void demoHotplug(struct demo_driver *driver) +{ + drmModeResPtr res = driver->res; + int i; + drmModeOutputPtr temp, current; + + for (i = 0; i < res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) { + temp = drmModeGetOutput(driver->fd, res->outputs[i]); + current = driver->outputs[i]; + + if (temp->connection != current->connection) { + printf("Output %u became %s was %s\n", + temp->output_id, + demoGetStatus(temp), + demoGetStatus(current)); + } + + drmModeFreeOutput(current); + driver->outputs[i] = temp; + } +} + +void demoPopulateOutputs(struct demo_driver *driver) +{ + drmModeResPtr res = driver->res; + int i; + + for (i = 0; i < res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) { + drmModeFreeOutput(driver->outputs[i]); + driver->outputs[i] = drmModeGetOutput(driver->fd, res->outputs[i]); + } +} + +struct demo_driver* demoCreateDriver(void) +{ + struct demo_driver* driver = malloc(sizeof(struct demo_driver)); + + memset(driver, 0, sizeof(struct demo_driver)); + + driver->fd = drmOpen("i915", NULL); + + if (driver->fd < 0) { + printf("Failed to open the card fb\n"); + goto err_driver; + } + + demoUpdateRes(driver); + if (!driver->res) { + printf("could not retrive resources\n"); + goto err_res; + } + + return driver; + +err_res: + drmClose(driver->fd); +err_driver: + free(driver); + return NULL; +} + +void demoUpdateRes(struct demo_driver *driver) +{ + if (driver->res) + drmModeFreeResources(driver->res); + + driver->res = drmModeGetResources(driver->fd); + + if (!driver->res) + printf("failed to get resources from kernel\n"); +} diff --git a/tests/modehotplug/test b/tests/modehotplug/test new file mode 100755 index 00000000..f98e3708 --- /dev/null +++ b/tests/modehotplug/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app -- cgit v1.2.3 From 2ceafcccb77723a464abd51d07e664933e117b6e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 7 Feb 2008 19:32:20 +0100 Subject: Wrong open call --- tests/modehotplug/demo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/modehotplug/demo.c b/tests/modehotplug/demo.c index 4ef2e386..1518e84c 100644 --- a/tests/modehotplug/demo.c +++ b/tests/modehotplug/demo.c @@ -123,7 +123,7 @@ struct demo_driver* demoCreateDriver(void) memset(driver, 0, sizeof(struct demo_driver)); - driver->fd = drmOpen("i915", NULL); + driver->fd = drmOpenControl(0); if (driver->fd < 0) { printf("Failed to open the card fb\n"); -- cgit v1.2.3 From fe83c068612dd1abef8cf6d224b6b0330604a8f1 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 7 Feb 2008 21:13:36 +0000 Subject: Revert "DRM_CONTROL_ALLOW logic was reversed" This reverts commit 7af1bb874d9b8b1b8760ad200cee587c41c23434. --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5077f067..7177f171 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -666,7 +666,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) || ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || ((ioctl->flags & DRM_MASTER) && !file_priv->master) || - ((ioctl->flags & DRM_CONTROL_ALLOW) && !(file_priv->minor->type == DRM_MINOR_CONTROL)) ) { + ((!(ioctl->flags & DRM_CONTROL_ALLOW)) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ) { retcode = -EACCES; } else { retcode = func(dev, kdata, file_priv); -- cgit v1.2.3 From f51dc37d75b0b1b8e5636f8f2c201e29986517ea Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 7 Feb 2008 22:21:50 +0000 Subject: After the previous revert fix libdrm to start at minor 1 and fixup the demos --- libdrm/xf86drm.c | 29 +++++++++++++---------------- tests/mode/modetest.c | 2 +- tests/modedemo/demo.c | 39 +++++++++++++++++++++++++++++++++------ tests/modefb/demo.c | 2 +- 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 39a849c6..8849f8bc 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -355,7 +355,7 @@ static int drmOpenMinor(int minor, int create, int type) { int fd; char buf[64]; - + if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); @@ -421,8 +421,15 @@ static int drmOpenByBusid(const char *busid) const char *buf; drmSetVersion sv; + /* + * Open the first minor number that matches the driver name and isn't + * already in use. If it's in use it will have a busid assigned already. + * + * start at 1, as 0 is the control node, and we should use drmOpenControl + * for that. + */ drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); - for (i = 0; i < DRM_MAX_MINOR; i++) { + for (i = 1; i < DRM_MAX_MINOR; i++) { fd = drmOpenMinor(i, 1, DRM_NODE_RENDER); drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); if (fd >= 0) { @@ -467,24 +474,14 @@ static int drmOpenByName(const char *name) drmVersionPtr version; char * id; - if (!drmAvailable()) { - if (!drm_server_info) { - return -1; - } - else { - /* try to load the kernel module now */ - if (!drm_server_info->load_module(name)) { - drmMsg("[drm] failed to load kernel module \"%s\"\n", name); - return -1; - } - } - } - /* * Open the first minor number that matches the driver name and isn't * already in use. If it's in use it will have a busid assigned already. + * + * start at 1, as 0 is the control node, and we should use drmOpenControl + * for that. */ - for (i = 0; i < DRM_MAX_MINOR; i++) { + for (i = 1; i < DRM_MAX_MINOR; i++) { if ((fd = drmOpenMinor(i, 1, DRM_NODE_RENDER)) >= 0) { if ((version = drmGetVersion(fd))) { if (!strcmp(version->name, name)) { diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index ab0cdc9c..caa3d970 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -351,7 +351,7 @@ int main(int argc, char **argv) printf("Starting test\n"); - fd = drmOpenControl(0); + fd = drmOpen("i915", NULL); if (fd < 0) { printf("Failed to open the card fb (%d)\n",fd); diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 0882fc91..6b6997ad 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -1,11 +1,16 @@ - +#define CLEAN_FBDEV #include #include #include #include #include #include - +#ifdef CLEAN_FBDEV +#include +#include +#include +#include +#endif #include "xf86drm.h" #include "xf86drmMode.h" @@ -20,6 +25,11 @@ void testCursor(int fd, uint32_t crtc); void prettyColors(int fd, unsigned int handle); void prettyCursor(int fd, unsigned int handle, unsigned int color); +#ifdef CLEAN_FBDEV +struct fb_var_screeninfo var; +struct fb_fix_screeninfo fix; +#endif + /* structs for the demo_driver */ struct demo_driver; @@ -90,6 +100,19 @@ int main(int argc, char **argv) struct demo_driver *driver; int num; int i; +#ifdef CLEAN_FBDEV + int fbdev_fd; + + fbdev_fd = open("/dev/fb0", O_RDWR); + + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); + + if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &var)) + printf("var %s\n", strerror(errno)); + if (ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fix)) + printf("fix %s\n", strerror(errno)); +#endif printf("starting demo\n"); @@ -131,9 +154,13 @@ int main(int argc, char **argv) testCursor(driver->fd, driver->screens[i].crtc->crtc_id); } - sleep(2); - printf("ok\n"); - return 0; +#ifdef CLEAN_FBDEV + if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &var)) + printf("var %s\n", strerror(errno)); +#endif + + printf("ok\n"); + return 0; } int demoCreateScreens(struct demo_driver *driver) @@ -260,7 +287,7 @@ struct demo_driver* demoCreateDriver(void) memset(driver, 0, sizeof(struct demo_driver)); - driver->fd = drmOpenControl(0); + driver->fd = drmOpen("i915", NULL); if (driver->fd < 0) { printf("Failed to open the card fb\n"); diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c index 7fa3b93f..4d81e511 100644 --- a/tests/modefb/demo.c +++ b/tests/modefb/demo.c @@ -26,7 +26,7 @@ int main(int argc, char **argv) char name[100]; int i,d; int fd; - int drmfd = drmOpenControl(0); + int drmfd = drmOpen("i915", NULL); /* try four devices */ for (d = 0; d < 4; d++) { -- cgit v1.2.3 From db2a1a223b94a5da9c5483b7963660c70052f025 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 7 Feb 2008 23:32:59 +0100 Subject: Added you can now clone displays in modedemo --- tests/modedemo/demo.c | 119 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 14 deletions(-) diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 6b6997ad..9eef9022 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -1,4 +1,16 @@ +/* + * Some defines to define the behavior of the program + */ + #define CLEAN_FBDEV +#undef DEMO_CLONE + +#define SIZE_X 2048 +#define SIZE_Y 2048 +/* Pitch needs to be power of two */ +#define PITCH 2048 + + #include #include #include @@ -14,11 +26,6 @@ #include "xf86drm.h" #include "xf86drmMode.h" -#define SIZE_X 2048 -#define SIZE_Y 2048 -/* Pitch needs to be power of two */ -#define PITCH 2048 - /* old functions to be replaced */ drmModeFBPtr createFB(int fd, drmModeResPtr res); void testCursor(int fd, uint32_t crtc); @@ -40,7 +47,10 @@ struct demo_screen drmBO buffer; drmModeFBPtr fb; drmModeCrtcPtr crtc; - drmModeOutputPtr output; + + size_t num_outputs; + uint32_t outputs_id[8]; + drmModeOutputPtr outputs[8]; struct drm_mode_modeinfo *mode; @@ -70,6 +80,7 @@ struct demo_driver struct demo_driver* demoCreateDriver(void); void demoUpdateRes(struct demo_driver *driver); int demoCreateScreens(struct demo_driver *driver); +int demoCreateScreenCloned(struct demo_driver *driver); void demoTakeDownScreen(struct demo_screen *screen); int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out); drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output); @@ -123,7 +134,12 @@ int main(int argc, char **argv) return 1; } +#ifndef DEMO_CLONE num = demoCreateScreens(driver); +#else + num = demoCreateScreenCloned(driver); +#endif + if (num < 1) { printf("no screens attached or an error occured\n"); return 1; @@ -154,13 +170,19 @@ int main(int argc, char **argv) testCursor(driver->fd, driver->screens[i].crtc->crtc_id); } + sleep(2); + printf("taking down screens\n"); + for (i = 0; i < num; i++) { + demoTakeDownScreen(&driver->screens[i]); + } + #ifdef CLEAN_FBDEV if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &var)) printf("var %s\n", strerror(errno)); #endif - printf("ok\n"); - return 0; + printf("ok\n"); + return 0; } int demoCreateScreens(struct demo_driver *driver) @@ -201,7 +223,10 @@ int demoCreateScreens(struct demo_driver *driver) screen->virt_y = SIZE_Y; screen->pitch = PITCH; - screen->output = out[i]; + screen->outputs[0] = out[i]; + screen->outputs_id[0] = out[i]->output_id; + screen->num_outputs = 1; + screen->mode = &mode; screen->driver = driver; @@ -210,7 +235,7 @@ int demoCreateScreens(struct demo_driver *driver) screen->crtc->crtc_id, screen->fb->buffer_id, 0, 0, - &screen->output->output_id, 1, + screen->outputs_id, screen->num_outputs, screen->mode); if (ret) { @@ -226,9 +251,73 @@ int demoCreateScreens(struct demo_driver *driver) return num_screens; } +int demoCreateScreenCloned(struct demo_driver *driver) +{ + drmModeOutputPtr out[MAX_FIND_OUTPUTS]; + int num; + struct demo_screen *screen; + int ret = 0; + int i; + + num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS); + if (num < 0) + return 0; + + printf("found %i connected outputs\n", num); + + screen = &driver->screens[0]; + + screen->fb = createFB(driver->fd, driver->res); + if (!screen->fb) { + printf("could not create framebuffer\n"); + return 0; + } + + screen->mode = &mode; + screen->driver = driver; + + screen->virt_x = SIZE_X; + screen->virt_y = SIZE_Y; + screen->pitch = PITCH; + + screen->num_outputs = 0; + for (i = 0; i < num; i++) { + screen->crtc = demoFindFreeCrtc(driver, out[i]); + if (!screen->crtc) { + printf("found no free crtc for output\n"); + drmModeFreeOutput(out[i]); + continue; + } + + screen->outputs[screen->num_outputs] = out[i]; + screen->outputs_id[screen->num_outputs] = out[i]->output_id; + screen->num_outputs++; + printf("%u, %u\n", out[i]->output_id, screen->num_outputs); + } + + ret = drmModeSetCrtc( + driver->fd, + screen->crtc->crtc_id, + screen->fb->buffer_id, + 0, 0, + screen->outputs_id, screen->num_outputs, + screen->mode); + + if (ret) { + printf("failed to set mode\n"); + demoTakeDownScreen(screen); + return 0; + } + + demoUpdateRes(driver); + + return 1; +} + void demoTakeDownScreen(struct demo_screen *screen) { int fd = screen->driver->fd; + int i; drmBO bo; if (screen->crtc) @@ -245,11 +334,14 @@ void demoTakeDownScreen(struct demo_screen *screen) printf("bo error\n"); } - drmModeFreeOutput(screen->output); + for (i = 0; i < screen->num_outputs; i++) { + drmModeFreeOutput(screen->outputs[i]); + screen->outputs[i] = NULL; + } + drmModeFreeCrtc(screen->crtc); drmModeFreeFB(screen->fb); - screen->output = NULL; screen->crtc = NULL; screen->fb = NULL; } @@ -260,7 +352,6 @@ drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr out int i, j, used = 0; drmModeResPtr res = driver->res; - for (i = 0; i < res->count_crtcs; i++) { used = 0; for (j = 0; j < DEMO_MAX_SCREENS; j++) { @@ -353,7 +444,7 @@ void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y) screen->crtc->crtc_id, screen->fb->buffer_id, x, y, - &screen->output->output_id, 1, + screen->outputs_id, screen->num_outputs, screen->mode); } -- cgit v1.2.3 From 04257f1a5a28550dc430d8051bb58fd0ac34e77d Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sat, 9 Feb 2008 18:23:35 +0100 Subject: radeon_ms: bring radeon_ms up to date with lastest changes --- shared-core/radeon_ms.h | 2 +- shared-core/radeon_ms_bus.c | 11 +++++++++-- shared-core/radeon_ms_irq.c | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index 66533837..903de97d 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -457,7 +457,7 @@ struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev, void radeon_ms_irq_emit(struct drm_device *dev); irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS); void radeon_ms_irq_preinstall(struct drm_device * dev); -void radeon_ms_irq_postinstall(struct drm_device * dev); +int radeon_ms_irq_postinstall(struct drm_device * dev); int radeon_ms_irq_init(struct drm_device *dev); void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state); void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state); diff --git a/shared-core/radeon_ms_bus.c b/shared-core/radeon_ms_bus.c index d50c9fb8..ed8fb211 100644 --- a/shared-core/radeon_ms_bus.c +++ b/shared-core/radeon_ms_bus.c @@ -46,6 +46,7 @@ struct radeon_pcie_gart { struct radeon_pcie *pcie; unsigned long page_first; struct page **pages; + struct page *dummy_read_page; unsigned long num_pages; int populated; int bound; @@ -57,7 +58,8 @@ static void pcie_ttm_clear(struct drm_ttm_backend *backend); static void pcie_ttm_destroy(struct drm_ttm_backend *backend); static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend); static int pcie_ttm_populate(struct drm_ttm_backend *backend, - unsigned long num_pages, struct page **pages); + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page); static int pcie_ttm_unbind(struct drm_ttm_backend *backend); static struct drm_ttm_backend_func radeon_pcie_gart_ttm_backend = @@ -130,6 +132,10 @@ static int pcie_ttm_bind(struct drm_ttm_backend *backend, for (i = 0, page = page_first; i < pcie_gart->num_pages; i++, page++) { struct page *cur_page = pcie_gart->pages[i]; + + if (!page) { + cur_page = pcie_gart->dummy_read_page; + } /* write value */ page_base = page_to_phys(cur_page); pcie_gart_set_page_base(pcie_gart->pcie, page, page_base); @@ -173,7 +179,8 @@ static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend) } static int pcie_ttm_populate(struct drm_ttm_backend *backend, - unsigned long num_pages, struct page **pages) + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page) { struct radeon_pcie_gart *pcie_gart; diff --git a/shared-core/radeon_ms_irq.c b/shared-core/radeon_ms_irq.c index 24182c75..2f94118f 100644 --- a/shared-core/radeon_ms_irq.c +++ b/shared-core/radeon_ms_irq.c @@ -115,9 +115,10 @@ void radeon_ms_irq_preinstall(struct drm_device * dev) radeon_ack_irqs(dev_priv, mask); } -void radeon_ms_irq_postinstall(struct drm_device * dev) +int radeon_ms_irq_postinstall(struct drm_device * dev) { radeon_ms_irq_enable(dev); + return 0; } int radeon_ms_irq_init(struct drm_device *dev) -- cgit v1.2.3 From f276c845bde4c712aa383540a2dd2055ecc00031 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Feb 2008 12:12:52 +1000 Subject: drm: re-write minor number allocation to use an idr. Fixup the minor number allocation scheme to use an idr and move the control nodes up higher. --- linux-core/drmP.h | 13 +++-- linux-core/drm_drv.c | 50 ++++++++--------- linux-core/drm_fops.c | 30 +++++------ linux-core/drm_proc.c | 2 +- linux-core/drm_stub.c | 143 ++++++++++++++++++++++++++++++++----------------- linux-core/drm_sysfs.c | 4 +- 6 files changed, 141 insertions(+), 101 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1c815c5f..afc16f5f 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -733,11 +733,12 @@ struct drm_driver { #define DRM_MINOR_UNASSIGNED 0 #define DRM_MINOR_CONTROL 1 #define DRM_MINOR_RENDER 2 +#define DRM_MINOR_GPGPU 3 /* this node is restricted to operations that don't require a master */ /** * DRM minor structure. This structure represents a drm minor number. */ struct drm_minor { - int minor; /**< Minor device number */ + int index; /**< Minor device number */ int type; /**< Control or render */ dev_t device; /**< Device number for mknod */ struct device kdev; /**< Linux device */ @@ -882,8 +883,8 @@ struct drm_device { unsigned int agp_buffer_token; /* minor number for control node */ - struct drm_minor control; - struct drm_minor primary; /**< primary screen head */ + struct drm_minor *control; + struct drm_minor *primary; /**< primary screen head */ struct drm_fence_manager fm; struct drm_buffer_manager bm; @@ -1214,13 +1215,15 @@ extern void drm_agp_chipset_flush(struct drm_device *dev); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); extern int drm_put_dev(struct drm_device *dev); -extern int drm_put_minor(struct drm_minor *minor); +extern int drm_put_minor(struct drm_minor **minor); extern unsigned int drm_debug; /* 1 to enable debug output */ extern unsigned int drm_minors_limit; -extern struct drm_minor **drm_minors; + extern struct class *drm_class; extern struct proc_dir_entry *drm_proc_root; +extern struct idr drm_minors_idr; + extern drm_local_map_t *drm_getsarea(struct drm_device *dev); /* Proc support (drm_proc.h) */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 7177f171..e9955239 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -435,30 +435,29 @@ static void drm_cleanup(struct drm_device * dev) DRM_ERROR("Cannot unload module\n"); } -void drm_exit(struct drm_driver *driver) +int drm_minors_cleanup(int id, void *ptr, void *data) { - int i; - struct drm_device *dev = NULL; - struct drm_minor *minor; + struct drm_minor *minor = ptr; + struct drm_device *dev; + struct drm_driver *driver = data; + if (id < 127 || id > 192) + return 0; + + dev = minor->dev; + if (minor->dev->driver != driver) + return 0; + + if (dev) + pci_dev_put(dev->pdev); + drm_cleanup(dev); + return 1; +} +void drm_exit(struct drm_driver *driver) +{ DRM_DEBUG("\n"); if (drm_fb_loaded) { - for (i = 0; i < drm_minors_limit; i++) { - minor = drm_minors[i]; - if (!minor) - continue; - if (!minor->dev) - continue; - if (minor->dev->driver != driver) - continue; - dev = minor->dev; - if (dev) { - /* release the pci driver */ - if (dev->pdev) - pci_dev_put(dev->pdev); - drm_cleanup(dev); - } - } + idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver); } else pci_unregister_driver(&driver->pci_driver); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) @@ -481,6 +480,7 @@ static int __init drm_core_init(void) unsigned long avail_memctl_mem; unsigned long max_memctl_mem; + idr_init(&drm_minors_idr); si_meminfo(&si); /* @@ -502,11 +502,6 @@ static int __init drm_core_init(void) drm_init_memctl(avail_memctl_mem/2, avail_memctl_mem*3/4, si.mem_unit); ret = -ENOMEM; - drm_minors_limit = - (drm_minors_limit < DRM_MAX_MINOR + 1 ? drm_minors_limit : DRM_MAX_MINOR + 1); - drm_minors = drm_calloc(drm_minors_limit, sizeof(*drm_minors), DRM_MEM_STUB); - if (!drm_minors) - goto err_p1; if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) goto err_p1; @@ -535,7 +530,8 @@ err_p3: drm_sysfs_destroy(); err_p2: unregister_chrdev(DRM_MAJOR, "drm"); - drm_free(drm_minors, sizeof(*drm_minors) * drm_minors_limit, DRM_MEM_STUB); + + idr_destroy(&drm_minors_idr); err_p1: return ret; } @@ -547,7 +543,7 @@ static void __exit drm_core_exit(void) unregister_chrdev(DRM_MAJOR, "drm"); - drm_free(drm_minors, sizeof(*drm_minors) * drm_minors_limit, DRM_MEM_STUB); + idr_destroy(&drm_minors_idr); } module_init(drm_core_init); diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 28aaeb1f..344d90e1 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -128,16 +128,15 @@ static int drm_setup(struct drm_device * dev) int drm_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; - int minor = iminor(inode); + int minor_id = iminor(inode); + struct drm_minor *minor; int retcode = 0; - if (!((minor >= 0) && (minor < drm_minors_limit))) + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) return -ENODEV; - if (!drm_minors[minor]) - return -ENODEV; - - if (!(dev = drm_minors[minor]->dev)) + if (!(dev = minor->dev)) return -ENODEV; retcode = drm_open_helper(inode, filp, dev); @@ -176,19 +175,18 @@ EXPORT_SYMBOL(drm_open); int drm_stub_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; - int minor = iminor(inode); + struct drm_minor *minor; + int minor_id = iminor(inode); int err = -ENODEV; const struct file_operations *old_fops; DRM_DEBUG("\n"); - if (!((minor >= 0) && (minor < drm_minors_limit))) + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) return -ENODEV; - - if (!drm_minors[minor]) - return -ENODEV; - - if (!(dev = drm_minors[minor]->dev)) + + if (!(dev = minor->dev)) return -ENODEV; old_fops = filp->f_op; @@ -233,7 +231,7 @@ static int drm_cpu_valid(void) static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev) { - int minor = iminor(inode); + int minor_id = iminor(inode); struct drm_file *priv; int ret; int i, j; @@ -243,7 +241,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, if (!drm_cpu_valid()) return -EINVAL; - DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); + DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor_id); priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); if (!priv) @@ -254,7 +252,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->filp = filp; priv->uid = current->euid; priv->pid = current->pid; - priv->minor = drm_minors[minor]; + priv->minor = idr_find(&drm_minors_idr, minor_id); priv->ioctl_count = 0; /* for compatibility root is always authenticated */ priv->authenticated = capable(CAP_SYS_ADMIN); diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 8f26726c..b28d8238 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -535,7 +535,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset, list_for_each_entry(priv, &dev->filelist, lhead) { DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", priv->authenticated ? 'y' : 'n', - priv->minor->minor, + priv->minor->index, priv->pid, priv->uid, priv->magic, priv->ioctl_count); } diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index cee00c5e..5a39afb3 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -50,10 +50,47 @@ MODULE_PARM_DESC(debug, "Enable debug output"); module_param_named(minors_limit, drm_minors_limit, int, 0444); module_param_named(debug, drm_debug, int, 0600); -struct drm_minor **drm_minors; +struct idr drm_minors_idr; + struct class *drm_class; struct proc_dir_entry *drm_proc_root; +static int drm_minor_get_id(struct drm_device *dev, int type) +{ + int new_id; + int ret; + int base = 0, limit = 127; + + if (type == DRM_MINOR_CONTROL) { + base += 128; + limit = base + 64; + } else if (type == DRM_MINOR_GPGPU) { + base += 192; + limit = base + 64; + } + +again: + if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { + DRM_ERROR("Out of memory expanding drawable idr\n"); + return -ENOMEM; + } + mutex_lock(&dev->struct_mutex); + ret = idr_get_new_above(&drm_minors_idr, NULL, + base, &new_id); + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) { + goto again; + } else if (ret) { + return ret; + } + + if (new_id >= limit) { + idr_remove(&drm_minors_idr, new_id); + return -EINVAL; + } + return new_id; +} + static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) @@ -160,54 +197,61 @@ error_out_unreg: * create the proc init entry via proc_init(). This routines assigns * minor numbers to secondary heads of multi-headed cards */ -static int drm_get_minor(struct drm_device *dev, struct drm_minor *minor, int type) +static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) { - struct drm_minor **minors = drm_minors; + struct drm_minor *new_minor; int ret; - int index; + int minor_id; DRM_DEBUG("\n"); - for (index = 0; index < drm_minors_limit; index++, minors++) { - if (!*minors) { - - *minor = (struct drm_minor) { - .type = type, - .dev = dev, - .device = MKDEV(DRM_MAJOR, index), - .minor = index, - }; - - if (type == DRM_MINOR_RENDER) { - ret = drm_proc_init(dev, index, drm_proc_root, - &minor->dev_root); - if (ret) { - DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); - goto err_g1; - } - } else - minor->dev_root = NULL; - - ret = drm_sysfs_device_add(minor); - if (ret) { - printk(KERN_ERR - "DRM: Error sysfs_device_add.\n"); - goto err_g2; - } - *minors = minor; - - DRM_DEBUG("new minor assigned %d\n", index); - return 0; + minor_id = drm_minor_get_id(dev, type); + if (minor_id < 0) + return minor_id; + + new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); + if (!new_minor) { + ret = -ENOMEM; + goto err_idr; + } + + new_minor->type = type; + new_minor->device = MKDEV(DRM_MAJOR, minor_id); + new_minor->dev = dev; + new_minor->index = minor_id; + + idr_replace(&drm_minors_idr, new_minor, minor_id); + + if (type == DRM_MINOR_RENDER) { + ret = drm_proc_init(dev, minor_id, drm_proc_root, + &new_minor->dev_root); + if (ret) { + DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); + goto err_mem; } + } else + new_minor->dev_root = NULL; + + ret = drm_sysfs_device_add(new_minor); + if (ret) { + printk(KERN_ERR + "DRM: Error sysfs_device_add.\n"); + goto err_g2; } - DRM_ERROR("out of minors\n"); - return -ENOMEM; + *minor = new_minor; + + DRM_DEBUG("new minor assigned %d\n", minor_id); + return 0; + + err_g2: - if (minor->type == DRM_MINOR_RENDER) - drm_proc_cleanup(index, drm_proc_root, minor->dev_root); -err_g1: - *minor = (struct drm_minor) { - .dev = NULL}; + if (new_minor->type == DRM_MINOR_RENDER) + drm_proc_cleanup(minor_id, drm_proc_root, new_minor->dev_root); +err_mem: + kfree(new_minor); +err_idr: + idr_remove(&drm_minors_idr, minor_id); + *minor = NULL; return ret; } @@ -259,7 +303,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, - driver->date, dev->primary.minor); + driver->date, dev->primary->index); return 0; @@ -320,19 +364,18 @@ int drm_put_dev(struct drm_device * dev) * last minor released. * */ -int drm_put_minor(struct drm_minor *minor) +int drm_put_minor(struct drm_minor **minor_p) { - int index = minor->minor; - - DRM_DEBUG("release secondary minor %d\n", index); + struct drm_minor *minor = *minor_p; + DRM_DEBUG("release secondary minor %d\n", minor->index); if (minor->type == DRM_MINOR_RENDER) - drm_proc_cleanup(index, drm_proc_root, minor->dev_root); + drm_proc_cleanup(minor->index, drm_proc_root, minor->dev_root); drm_sysfs_device_remove(minor); - *minor = (struct drm_minor) {.type = DRM_MINOR_UNASSIGNED, - .dev = NULL}; + idr_remove(&drm_minors_idr, minor->index); - drm_minors[index] = NULL; + kfree(minor); + *minor_p = NULL; return 0; } diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 114e355e..cd03da8a 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -170,11 +170,11 @@ int drm_sysfs_device_add(struct drm_minor *minor) minor->kdev.release = drm_sysfs_device_release; minor->kdev.devt = minor->device; if (minor->type == DRM_MINOR_CONTROL) - minor_str = "controlD%d"; + minor_str = "controlD%d"; else minor_str = "card%d"; - snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->minor); + snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); err = device_register(&minor->kdev); if (err) { -- cgit v1.2.3 From db85ed25afc616acfaadb21facf6066354f9d490 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Feb 2008 12:20:02 +1000 Subject: Revert "After the previous revert fix libdrm to start at minor 1" This reverts commit f51dc37d75b0b1b8e5636f8f2c201e29986517ea. Conflicts: tests/modedemo/demo.c --- libdrm/xf86drm.c | 29 ++++++++++++++++------------- tests/mode/modetest.c | 2 +- tests/modedemo/demo.c | 28 ++-------------------------- tests/modefb/demo.c | 2 +- 4 files changed, 20 insertions(+), 41 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 8849f8bc..39a849c6 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -355,7 +355,7 @@ static int drmOpenMinor(int minor, int create, int type) { int fd; char buf[64]; - + if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); @@ -421,15 +421,8 @@ static int drmOpenByBusid(const char *busid) const char *buf; drmSetVersion sv; - /* - * Open the first minor number that matches the driver name and isn't - * already in use. If it's in use it will have a busid assigned already. - * - * start at 1, as 0 is the control node, and we should use drmOpenControl - * for that. - */ drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); - for (i = 1; i < DRM_MAX_MINOR; i++) { + for (i = 0; i < DRM_MAX_MINOR; i++) { fd = drmOpenMinor(i, 1, DRM_NODE_RENDER); drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); if (fd >= 0) { @@ -474,14 +467,24 @@ static int drmOpenByName(const char *name) drmVersionPtr version; char * id; + if (!drmAvailable()) { + if (!drm_server_info) { + return -1; + } + else { + /* try to load the kernel module now */ + if (!drm_server_info->load_module(name)) { + drmMsg("[drm] failed to load kernel module \"%s\"\n", name); + return -1; + } + } + } + /* * Open the first minor number that matches the driver name and isn't * already in use. If it's in use it will have a busid assigned already. - * - * start at 1, as 0 is the control node, and we should use drmOpenControl - * for that. */ - for (i = 1; i < DRM_MAX_MINOR; i++) { + for (i = 0; i < DRM_MAX_MINOR; i++) { if ((fd = drmOpenMinor(i, 1, DRM_NODE_RENDER)) >= 0) { if ((version = drmGetVersion(fd))) { if (!strcmp(version->name, name)) { diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index caa3d970..ab0cdc9c 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -351,7 +351,7 @@ int main(int argc, char **argv) printf("Starting test\n"); - fd = drmOpen("i915", NULL); + fd = drmOpenControl(0); if (fd < 0) { printf("Failed to open the card fb (%d)\n",fd); diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 9eef9022..474f04a5 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -10,19 +10,13 @@ /* Pitch needs to be power of two */ #define PITCH 2048 - #include #include #include #include #include #include -#ifdef CLEAN_FBDEV -#include -#include -#include -#include -#endif + #include "xf86drm.h" #include "xf86drmMode.h" @@ -32,11 +26,6 @@ void testCursor(int fd, uint32_t crtc); void prettyColors(int fd, unsigned int handle); void prettyCursor(int fd, unsigned int handle, unsigned int color); -#ifdef CLEAN_FBDEV -struct fb_var_screeninfo var; -struct fb_fix_screeninfo fix; -#endif - /* structs for the demo_driver */ struct demo_driver; @@ -111,19 +100,6 @@ int main(int argc, char **argv) struct demo_driver *driver; int num; int i; -#ifdef CLEAN_FBDEV - int fbdev_fd; - - fbdev_fd = open("/dev/fb0", O_RDWR); - - memset(&var, 0, sizeof(struct fb_var_screeninfo)); - memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); - - if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &var)) - printf("var %s\n", strerror(errno)); - if (ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fix)) - printf("fix %s\n", strerror(errno)); -#endif printf("starting demo\n"); @@ -378,7 +354,7 @@ struct demo_driver* demoCreateDriver(void) memset(driver, 0, sizeof(struct demo_driver)); - driver->fd = drmOpen("i915", NULL); + driver->fd = drmOpenControl(0); if (driver->fd < 0) { printf("Failed to open the card fb\n"); diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c index 4d81e511..7fa3b93f 100644 --- a/tests/modefb/demo.c +++ b/tests/modefb/demo.c @@ -26,7 +26,7 @@ int main(int argc, char **argv) char name[100]; int i,d; int fd; - int drmfd = drmOpen("i915", NULL); + int drmfd = drmOpenControl(0); /* try four devices */ for (d = 0; d < 4; d++) { -- cgit v1.2.3 From 0fbee62ec14d08714dbc558dd20cc00b9a79c042 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Feb 2008 15:19:42 +1000 Subject: major port of multi-master ideas into modesetting --- linux-core/drmP.h | 59 +++++++++++++++++++++++++++----------- linux-core/drm_auth.c | 28 ++++++++++--------- linux-core/drm_bufs.c | 12 ++++---- linux-core/drm_context.c | 2 +- linux-core/drm_drv.c | 26 +++-------------- linux-core/drm_fops.c | 67 +++++++++++++++++++++++++++++--------------- linux-core/drm_ioctl.c | 46 ++++++++++++++++-------------- linux-core/drm_irq.c | 6 ++-- linux-core/drm_lock.c | 40 +++++++++++++------------- linux-core/drm_proc.c | 5 ++-- linux-core/drm_stub.c | 70 ++++++++++++++++++++++++++++++++++++++-------- linux-core/i915_drv.c | 2 ++ linux-core/intel_display.c | 31 ++++++++++++-------- linux-core/via_fence.c | 4 +-- 14 files changed, 246 insertions(+), 152 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index afc16f5f..d01bf09d 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -262,11 +262,11 @@ struct drm_file; */ #define LOCK_TEST_WITH_RETURN( dev, file_priv ) \ do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.file_priv != file_priv ) { \ + if ( !_DRM_LOCK_IS_HELD( dev->primary->master->lock.hw_lock->lock ) || \ + dev->primary->master->lock.file_priv != file_priv ) { \ DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ - __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\ - dev->lock.file_priv, file_priv ); \ + __FUNCTION__, _DRM_LOCK_IS_HELD( dev->primary->master->lock.hw_lock->lock ),\ + dev->primary->master->lock.file_priv, file_priv ); \ return -EINVAL; \ } \ } while (0) @@ -410,7 +410,6 @@ enum drm_ref_type { /** File private data */ struct drm_file { int authenticated; - int master; pid_t pid; uid_t uid; drm_magic_t magic; @@ -431,6 +430,7 @@ struct drm_file { struct drm_open_hash refd_object_hash[_DRM_NO_REF_TYPES]; struct file *filp; + struct drm_master *master; /* this private has a master associated with it */ void *driver_priv; struct list_head fbs; @@ -568,6 +568,8 @@ struct drm_map_list { struct drm_map *map; /**< mapping */ uint64_t user_token; struct drm_mm_node *file_offset_node; + struct drm_master *master; /** if this map is associated with a specific + master */ }; typedef struct drm_map drm_local_map_t; @@ -607,6 +609,27 @@ struct drm_ati_pcigart_info { #include "drm_objects.h" +/* per-master structure */ +struct drm_master { + + struct drm_device *dev; + + char *unique; /**< Unique identifier: e.g., busid */ + int unique_len; /**< Length of unique field */ + + int blocked; /**< Blocked due to VC switch? */ + + /** \name Authentication */ + /*@{ */ + struct drm_open_hash magiclist; + struct list_head magicfree; + /*@} */ + + struct drm_lock_data lock; /**< Information on hardware lock */ + + void *driver_priv; /**< Private structure for driver to use */ +}; + /** * DRM driver structure. This structure represent the common code for * a family of cards. There will one drm_device for each card present @@ -711,6 +734,10 @@ struct drm_driver { int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc); int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); + /* Master routines */ + int (*master_create)(struct drm_device *dev, struct drm_master *master); + void (*master_destroy)(struct drm_device *dev, struct drm_master *master); + struct drm_fence_driver *fence_driver; struct drm_bo_driver *bo_driver; @@ -746,6 +773,9 @@ struct drm_minor { /* for render nodes */ struct proc_dir_entry *dev_root; /**< proc directory entry */ struct class_device *dev_class; + + /* for control nodes - a pointer to the current master for this control node */ + struct drm_master *master; }; @@ -754,13 +784,9 @@ struct drm_minor { * may contain multiple heads. */ struct drm_device { - char *unique; /**< Unique identifier: e.g., busid */ - int unique_len; /**< Length of unique field */ char *devname; /**< For /proc/interrupts */ int if_version; /**< Highest interface version set */ - int blocked; /**< Blocked due to VC switch? */ - /** \name Locks */ /*@{ */ spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ @@ -783,12 +809,6 @@ struct drm_device { atomic_t counts[15]; /*@} */ - /** \name Authentication */ - /*@{ */ - struct list_head filelist; - struct drm_open_hash magiclist; - struct list_head magicfree; - /*@} */ /** \name Memory management */ /*@{ */ @@ -809,7 +829,9 @@ struct drm_device { struct idr ctx_idr; struct list_head vmalist; /**< List of vmas (for debugging) */ - struct drm_lock_data lock; /**< Information on hardware lock */ + + struct list_head filelist; +// struct drm_master *master; /*@} */ /** \name DMA queues (contexts) */ @@ -821,6 +843,7 @@ struct drm_device { struct drm_device_dma *dma; /**< Optional pointer for DMA support */ /*@} */ + /** \name Context support */ /*@{ */ int irq; /**< Interrupt used by board */ @@ -884,7 +907,7 @@ struct drm_device { /* minor number for control node */ struct drm_minor *control; - struct drm_minor *primary; /**< primary screen head */ + struct drm_minor *primary; /**< render type primary screen head */ struct drm_fence_manager fm; struct drm_buffer_manager bm; @@ -1212,6 +1235,8 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); extern struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev); extern void drm_agp_chipset_flush(struct drm_device *dev); /* Stub support (drm_stub.h) */ +extern struct drm_master *drm_get_master(struct drm_device *dev); +extern void drm_put_master(struct drm_master *master); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); extern int drm_put_dev(struct drm_device *dev); diff --git a/linux-core/drm_auth.c b/linux-core/drm_auth.c index c904a91d..8e85a761 100644 --- a/linux-core/drm_auth.c +++ b/linux-core/drm_auth.c @@ -45,14 +45,15 @@ * the one with matching magic number, while holding the drm_device::struct_mutex * lock. */ -static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic) +static struct drm_file *drm_find_file(struct drm_master *master , drm_magic_t magic) { struct drm_file *retval = NULL; struct drm_magic_entry *pt; struct drm_hash_item *hash; + struct drm_device *dev = master->dev; mutex_lock(&dev->struct_mutex); - if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { + if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); retval = pt->priv; } @@ -71,11 +72,11 @@ static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic * associated the magic number hash key in drm_device::magiclist, while holding * the drm_device::struct_mutex lock. */ -static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, +static int drm_add_magic(struct drm_master *master, struct drm_file * priv, drm_magic_t magic) { struct drm_magic_entry *entry; - + struct drm_device *dev = master->dev; DRM_DEBUG("%d\n", magic); entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); @@ -85,8 +86,8 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, entry->priv = priv; entry->hash_item.key = (unsigned long)magic; mutex_lock(&dev->struct_mutex); - drm_ht_insert_item(&dev->magiclist, &entry->hash_item); - list_add_tail(&entry->head, &dev->magicfree); + drm_ht_insert_item(&master->magiclist, &entry->hash_item); + list_add_tail(&entry->head, &master->magicfree); mutex_unlock(&dev->struct_mutex); return 0; @@ -101,20 +102,21 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, * Searches and unlinks the entry in drm_device::magiclist with the magic * number hash key, while holding the drm_device::struct_mutex lock. */ -static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic) +static int drm_remove_magic(struct drm_master *master, drm_magic_t magic) { struct drm_magic_entry *pt; struct drm_hash_item *hash; + struct drm_device *dev = master->dev; DRM_DEBUG("%d\n", magic); mutex_lock(&dev->struct_mutex); - if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { + if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { mutex_unlock(&dev->struct_mutex); return -EINVAL; } pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); - drm_ht_remove_item(&dev->magiclist, hash); + drm_ht_remove_item(&master->magiclist, hash); list_del(&pt->head); mutex_unlock(&dev->struct_mutex); @@ -152,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) ++sequence; /* reserve 0 */ auth->magic = sequence++; spin_unlock(&lock); - } while (drm_find_file(dev, auth->magic)); + } while (drm_find_file(dev->primary->master, auth->magic)); file_priv->magic = auth->magic; - drm_add_magic(dev, file_priv, auth->magic); + drm_add_magic(dev->primary->master, file_priv, auth->magic); } DRM_DEBUG("%u\n", auth->magic); @@ -180,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data, struct drm_file *file; DRM_DEBUG("%u\n", auth->magic); - if ((file = drm_find_file(dev, auth->magic))) { + if ((file = drm_find_file(dev->primary->master, auth->magic))) { file->authenticated = 1; - drm_remove_magic(dev, auth->magic); + drm_remove_magic(dev->primary->master, auth->magic); return 0; } return -EINVAL; diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 967e9a2d..3e1767c0 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -52,7 +52,7 @@ struct drm_map_list *drm_find_matching_map(struct drm_device *dev, drm_local_map { struct drm_map_list *entry; list_for_each_entry(entry, &dev->maplist, head) { - if (entry->map && map->type == entry->map->type && + if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) && ((entry->map->offset == map->offset) || ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) { return entry; @@ -209,12 +209,12 @@ static int drm_addmap_core(struct drm_device *dev, unsigned int offset, map->offset = (unsigned long)map->handle; if (map->flags & _DRM_CONTAINS_LOCK) { /* Prevent a 2nd X Server from creating a 2nd lock */ - if (dev->lock.hw_lock != NULL) { + if (dev->primary->master->lock.hw_lock != NULL) { vfree(map->handle); drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EBUSY; } - dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ + dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle; /* Pointer to lock */ } break; case _DRM_AGP: { @@ -412,9 +412,9 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) break; case _DRM_SHM: vfree(map->handle); - dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ - dev->lock.file_priv = NULL; - wake_up_interruptible(&dev->lock.lock_queue); + dev->sigdata.lock = dev->primary->master->lock.hw_lock = NULL; /* SHM removed */ + dev->primary->master->lock.file_priv = NULL; + wake_up_interruptible(&dev->primary->master->lock.lock_queue); break; case _DRM_AGP: case _DRM_SCATTER_GATHER: diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index 83ad291e..63a38253 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -262,7 +262,7 @@ static int drm_context_switch_complete(struct drm_device *dev, int new) dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ dev->last_switch = jiffies; - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(dev->primary->master->lock.hw_lock->lock)) { DRM_ERROR("Lock isn't held after context switch\n"); } diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index e9955239..4f5b364e 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -180,8 +180,6 @@ static struct drm_ioctl_desc drm_ioctls[] = { */ int drm_lastclose(struct drm_device * dev) { - struct drm_magic_entry *pt, *next; - struct drm_map_list *r_list, *list_t; struct drm_vma_entry *vma, *vma_temp; int i; @@ -196,11 +194,6 @@ int drm_lastclose(struct drm_device * dev) dev->driver->lastclose(dev); DRM_DEBUG("driver lastclose completed\n"); - if (dev->unique) { - drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); - dev->unique = NULL; - dev->unique_len = 0; - } /* if (dev->irq_enabled) drm_irq_uninstall(dev); */ @@ -211,22 +204,11 @@ int drm_lastclose(struct drm_device * dev) drm_drawable_free_all(dev); del_timer(&dev->timer); - if (dev->unique) { - drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); - dev->unique = NULL; - dev->unique_len = 0; - } - - if (dev->magicfree.next) { - list_for_each_entry_safe(pt, next, &dev->magicfree, head) { - list_del(&pt->head); - drm_ht_remove_item(&dev->magiclist, &pt->hash_item); - drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); - } - drm_ht_remove(&dev->magiclist); + if (dev->primary->master) { + drm_put_master(dev->primary->master); + dev->primary->master = NULL; } - - + /* Clear AGP information */ if (drm_core_has_AGP(dev) && dev->agp) { struct drm_agp_mem *entry, *tempe; diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 344d90e1..c699e967 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -54,8 +54,6 @@ static int drm_setup(struct drm_device * dev) return ret; } - dev->magicfree.next = NULL; - /* prebuild the SAREA */ sareapage = max(SAREA_MAX, PAGE_SIZE); i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); @@ -76,11 +74,8 @@ static int drm_setup(struct drm_device * dev) for (i = 0; i < ARRAY_SIZE(dev->counts); i++) atomic_set(&dev->counts[i], 0); - drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); - INIT_LIST_HEAD(&dev->magicfree); - dev->sigdata.lock = NULL; - init_waitqueue_head(&dev->lock.lock_queue); + dev->queue_count = 0; dev->queue_reserved = 0; dev->queue_slots = 0; @@ -282,8 +277,26 @@ static int drm_open_helper(struct inode *inode, struct file *filp, } mutex_lock(&dev->struct_mutex); - if (list_empty(&dev->filelist)) - priv->master = 1; + + /* if there is no current master make this fd it */ + if (!dev->primary->master) { + priv->master = drm_get_master(dev); + if (!priv->master) { + ret = -ENOMEM; + goto out_free; + } + dev->primary->master = priv->master; + + if (dev->driver->master_create) { + ret = dev->driver->master_create(dev, dev->primary->master); + if (ret) { + drm_put_master(dev->primary->master); + dev->primary->master = priv->master = NULL; + goto out_free; + } + } + } else + priv->master = NULL; list_add(&priv->lhead, &dev->filelist); mutex_unlock(&dev->struct_mutex); @@ -390,23 +403,23 @@ int drm_release(struct inode *inode, struct file *filp) current->pid, (long)old_encode_dev(file_priv->minor->device), dev->open_count); - if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { + if (dev->driver->reclaim_buffers_locked && dev->primary->master->lock.hw_lock) { if (drm_i_have_hw_lock(dev, file_priv)) { dev->driver->reclaim_buffers_locked(dev, file_priv); } else { unsigned long _end=jiffies + 3*DRM_HZ; int locked = 0; - drm_idlelock_take(&dev->lock); + drm_idlelock_take(&dev->primary->master->lock); /* * Wait for a while. */ do{ - spin_lock(&dev->lock.spinlock); - locked = dev->lock.idle_has_lock; - spin_unlock(&dev->lock.spinlock); + spin_lock(&dev->primary->master->lock.spinlock); + locked = dev->primary->master->lock.idle_has_lock; + spin_unlock(&dev->primary->master->lock.spinlock); if (locked) break; schedule(); @@ -419,24 +432,24 @@ int drm_release(struct inode *inode, struct file *filp) } dev->driver->reclaim_buffers_locked(dev, file_priv); - drm_idlelock_release(&dev->lock); + drm_idlelock_release(&dev->primary->master->lock); } } - if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { + if (dev->driver->reclaim_buffers_idlelocked && dev->primary->master->lock.hw_lock) { - drm_idlelock_take(&dev->lock); + drm_idlelock_take(&dev->primary->master->lock); dev->driver->reclaim_buffers_idlelocked(dev, file_priv); - drm_idlelock_release(&dev->lock); + drm_idlelock_release(&dev->primary->master->lock); } if (drm_i_have_hw_lock(dev, file_priv)) { DRM_DEBUG("File %p released, freeing lock for context %d\n", - filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + filp, _DRM_LOCKING_CONTEXT(dev->primary->master->lock.hw_lock->lock)); - drm_lock_free(&dev->lock, - _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + drm_lock_free(&dev->primary->master->lock, + _DRM_LOCKING_CONTEXT(dev->primary->master->lock.hw_lock->lock)); } @@ -479,6 +492,14 @@ int drm_release(struct inode *inode, struct file *filp) temp->authenticated = 0; } list_del(&file_priv->lhead); + + if (file_priv->master) { + if (file_priv->master == dev->primary->master) + dev->primary->master = NULL; + drm_put_master(file_priv->master); + file_priv->master = NULL; + } + mutex_unlock(&dev->struct_mutex); if (dev->driver->postclose) @@ -492,9 +513,9 @@ int drm_release(struct inode *inode, struct file *filp) atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); spin_lock(&dev->count_lock); if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count) || dev->blocked) { - DRM_ERROR("Device busy: %d %d\n", - atomic_read(&dev->ioctl_count), dev->blocked); + if (atomic_read(&dev->ioctl_count)) { + DRM_ERROR("Device busy: %d\n", + atomic_read(&dev->ioctl_count)); spin_unlock(&dev->count_lock); unlock_kernel(); return -EBUSY; diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c index 3df163db..c15923ef 100644 --- a/linux-core/drm_ioctl.c +++ b/linux-core/drm_ioctl.c @@ -53,12 +53,13 @@ int drm_getunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; + struct drm_master *master = dev->primary->master; - if (u->unique_len >= dev->unique_len) { - if (copy_to_user(u->unique, dev->unique, dev->unique_len)) + if (u->unique_len >= master->unique_len) { + if (copy_to_user(u->unique, master->unique, master->unique_len)) return -EFAULT; } - u->unique_len = dev->unique_len; + u->unique_len = master->unique_len; return 0; } @@ -81,36 +82,37 @@ int drm_setunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; + struct drm_master *master = dev->primary->master; int domain, bus, slot, func, ret; - if (dev->unique_len || dev->unique) + if (master->unique_len || master->unique) return -EBUSY; if (!u->unique_len || u->unique_len > 1024) return -EINVAL; - dev->unique_len = u->unique_len; - dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); - if (!dev->unique) + master->unique_len = u->unique_len; + master->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); + if (!master->unique) return -ENOMEM; - if (copy_from_user(dev->unique, u->unique, dev->unique_len)) + if (copy_from_user(master->unique, u->unique, master->unique_len)) return -EFAULT; - dev->unique[dev->unique_len] = '\0'; + master->unique[master->unique_len] = '\0'; dev->devname = drm_alloc(strlen(dev->driver->pci_driver.name) + - strlen(dev->unique) + 2, DRM_MEM_DRIVER); + strlen(master->unique) + 2, DRM_MEM_DRIVER); if (!dev->devname) return -ENOMEM; sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, - dev->unique); + master->unique); /* Return error if the busid submitted doesn't match the device's actual * busid. */ - ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func); + ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); if (ret != 3) return -EINVAL; domain = bus >> 8; @@ -127,31 +129,33 @@ int drm_setunique(struct drm_device *dev, void *data, static int drm_set_busid(struct drm_device * dev) { + struct drm_master *master = dev->primary->master; int len; - if (dev->unique != NULL) + + if (master->unique != NULL) return -EBUSY; - dev->unique_len = 40; - dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); - if (dev->unique == NULL) + master->unique_len = 40; + master->unique = drm_alloc(master->unique_len + 1, DRM_MEM_DRIVER); + if (master->unique == NULL) return -ENOMEM; - len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", + len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d", drm_get_pci_domain(dev), dev->pdev->bus->number, PCI_SLOT(dev->pdev->devfn), PCI_FUNC(dev->pdev->devfn)); - if (len > dev->unique_len) + if (len > master->unique_len) DRM_ERROR("buffer overflow"); dev->devname = - drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + + drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len + 2, DRM_MEM_DRIVER); if (dev->devname == NULL) return -ENOMEM; sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, - dev->unique); + master->unique); return 0; } @@ -275,7 +279,7 @@ int drm_getstats(struct drm_device *dev, void *data, for (i = 0; i < dev->counters; i++) { if (dev->types[i] == _DRM_STAT_LOCK) stats->data[i].value = - (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0); + (dev->primary->master->lock.hw_lock ? dev->primary->master->lock.hw_lock->lock : 0); else stats->data[i].value = atomic_read(&dev->counts[i]); stats->data[i].type = dev->types[i]; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index c75f20b2..d88269a4 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -636,18 +636,18 @@ static void drm_locked_tasklet_func(unsigned long data) spin_lock_irqsave(&dev->tasklet_lock, irqflags); if (!dev->locked_tasklet_func || - !drm_lock_take(&dev->lock, + !drm_lock_take(&dev->primary->master->lock, DRM_KERNEL_CONTEXT)) { spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); return; } - dev->lock.lock_time = jiffies; + dev->primary->master->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); dev->locked_tasklet_func(dev); - drm_lock_free(&dev->lock, + drm_lock_free(&dev->primary->master->lock, DRM_KERNEL_CONTEXT); dev->locked_tasklet_func = NULL; diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index b8e4a5d9..7404856e 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) { DECLARE_WAITQUEUE(entry, current); struct drm_lock *lock = data; + struct drm_master *master = dev->primary->master; int ret = 0; ++file_priv->lock_count; @@ -64,26 +65,26 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", lock->context, current->pid, - dev->lock.hw_lock->lock, lock->flags); + master->lock.hw_lock->lock, lock->flags); if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) if (lock->context < 0) return -EINVAL; - add_wait_queue(&dev->lock.lock_queue, &entry); - spin_lock(&dev->lock.spinlock); - dev->lock.user_waiters++; - spin_unlock(&dev->lock.spinlock); + add_wait_queue(&master->lock.lock_queue, &entry); + spin_lock(&master->lock.spinlock); + master->lock.user_waiters++; + spin_unlock(&master->lock.spinlock); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); - if (!dev->lock.hw_lock) { + if (!master->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; break; } - if (drm_lock_take(&dev->lock, lock->context)) { - dev->lock.file_priv = file_priv; - dev->lock.lock_time = jiffies; + if (drm_lock_take(&master->lock, lock->context)) { + master->lock.file_priv = file_priv; + master->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); break; /* Got lock */ } @@ -95,11 +96,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) break; } } - spin_lock(&dev->lock.spinlock); - dev->lock.user_waiters--; - spin_unlock(&dev->lock.spinlock); + spin_lock(&master->lock.spinlock); + master->lock.user_waiters--; + spin_unlock(&master->lock.spinlock); __set_current_state(TASK_RUNNING); - remove_wait_queue(&dev->lock.lock_queue, &entry); + remove_wait_queue(&master->lock.lock_queue, &entry); DRM_DEBUG("%d %s\n", lock->context, ret ? "interrupted" : "has lock"); @@ -111,7 +112,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) sigaddset(&dev->sigmask, SIGTTIN); sigaddset(&dev->sigmask, SIGTTOU); dev->sigdata.context = lock->context; - dev->sigdata.lock = dev->lock.hw_lock; + dev->sigdata.lock = master->lock.hw_lock; block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY)) @@ -149,6 +150,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_lock *lock = data; + struct drm_master *master = dev->primary->master; unsigned long irqflags; if (lock->context == DRM_KERNEL_CONTEXT) { @@ -175,7 +177,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) if (dev->driver->kernel_context_switch_unlock) dev->driver->kernel_context_switch_unlock(dev); else { - if (drm_lock_free(&dev->lock,lock->context)) { + if (drm_lock_free(&master->lock,lock->context)) { /* FIXME: Should really bail out here. */ } } @@ -384,10 +386,10 @@ EXPORT_SYMBOL(drm_idlelock_release); int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) { - - return (file_priv->lock_count && dev->lock.hw_lock && - _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.file_priv == file_priv); + struct drm_master *master = dev->primary->master; + return (file_priv->lock_count && master->lock.hw_lock && + _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && + master->lock.file_priv == file_priv); } EXPORT_SYMBOL(drm_i_have_hw_lock); diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index b28d8238..12c08c86 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -166,6 +166,7 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { struct drm_device *dev = (struct drm_device *) data; + struct drm_master *master = dev->primary->master; int len = 0; if (offset > DRM_PROC_LIMIT) { @@ -176,10 +177,10 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, *start = &buf[offset]; *eof = 0; - if (dev->unique) { + if (master->unique) { DRM_PROC_PRINT("%s %s %s\n", dev->driver->pci_driver.name, - pci_name(dev->pdev), dev->unique); + pci_name(dev->pdev), master->unique); } else { DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, pci_name(dev->pdev)); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 5a39afb3..66a7b8b5 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -91,13 +91,63 @@ again: return new_id; } +struct drm_master *drm_get_master(struct drm_device *dev) +{ + struct drm_master *master; + + master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER); + if (!master) + return NULL; + +// INIT_LIST_HEAD(&master->filelist); + spin_lock_init(&master->lock.spinlock); + init_waitqueue_head(&master->lock.lock_queue); + drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); + INIT_LIST_HEAD(&master->magicfree); + master->dev = dev; + + return master; +} + +void drm_put_master(struct drm_master *master) +{ + struct drm_magic_entry *pt, *next; + struct drm_device *dev = master->dev; + + if (dev->driver->master_destroy) + dev->driver->master_destroy(dev, master); + + if (master->unique) { + drm_free(master->unique, strlen(master->unique) + 1, DRM_MEM_DRIVER); + master->unique = NULL; + master->unique_len = 0; + } + + list_for_each_entry_safe(pt, next, &master->magicfree, head) { + list_del(&pt->head); + drm_ht_remove_item(&master->magiclist, &pt->hash_item); + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + } + + drm_ht_remove(&master->magiclist); + + if (master->lock.hw_lock) { + if (dev->sigdata.lock == master->lock.hw_lock) + dev->sigdata.lock = NULL; + master->lock.hw_lock = NULL; /* SHM removed */ + master->lock.file_priv = NULL; + wake_up_interruptible(&master->lock.lock_queue); + } + + drm_free(master, sizeof(*master), DRM_MEM_DRIVER); +} + static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) { int retcode; - INIT_LIST_HEAD(&dev->filelist); INIT_LIST_HEAD(&dev->ctxlist); INIT_LIST_HEAD(&dev->vmalist); INIT_LIST_HEAD(&dev->maplist); @@ -105,7 +155,7 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); spin_lock_init(&dev->tasklet_lock); - spin_lock_init(&dev->lock.spinlock); +// spin_lock_init(&dev->lock.spinlock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); @@ -168,10 +218,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, } } - if (dev->driver->load) - if ((retcode = dev->driver->load(dev, ent->driver_data))) - goto error_out_unreg; - retcode = drm_ctxbitmap_init(dev); if (retcode) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); @@ -301,12 +347,17 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_RENDER))) goto err_g4; + if (dev->driver->load) + if ((ret = dev->driver->load(dev, ent->driver_data))) + goto err_g5; + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, dev->primary->index); return 0; - +err_g5: + drm_put_minor(&dev->primary); err_g4: drm_put_minor(&dev->control); err_g3: @@ -340,11 +391,6 @@ int drm_put_dev(struct drm_device * dev) { DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name); - if (dev->unique) { - drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); - dev->unique = NULL; - dev->unique_len = 0; - } if (dev->devname) { drm_free(dev->devname, strlen(dev->devname) + 1, DRM_MEM_DRIVER); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 629a39be..1f841642 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -558,6 +558,8 @@ static struct drm_driver driver = { .fb_probe = intelfb_probe, .fb_remove = intelfb_remove, .fb_resize = intelfb_resize, + .master_create = i915_master_create, + .master_destroy = i915_master_destroy, .ioctls = i915_ioctls, .fops = { .owner = THIS_MODULE, diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 5b7a510b..db3aee83 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -363,6 +363,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = crtc->driver_private; int pipe = intel_crtc->pipe; unsigned long Start, Offset; @@ -384,17 +385,21 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) } - if (!dev_priv->sarea_priv) + if (!dev->primary->master) + return; + + master_priv = dev->primary->master->driver_priv; + if (!master_priv->sarea_priv) return; switch (pipe) { case 0: - dev_priv->sarea_priv->planeA_x = x; - dev_priv->sarea_priv->planeA_y = y; + master_priv->sarea_priv->planeA_x = x; + master_priv->sarea_priv->planeA_y = y; break; case 1: - dev_priv->sarea_priv->planeB_x = x; - dev_priv->sarea_priv->planeB_y = y; + master_priv->sarea_priv->planeB_x = x; + master_priv->sarea_priv->planeB_y = y; break; default: DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); @@ -413,6 +418,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; + struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = crtc->driver_private; int pipe = intel_crtc->pipe; @@ -506,21 +512,24 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) udelay(150); break; } - - if (!dev_priv->sarea_priv) + if (!dev->primary->master) + return; + + master_priv = dev->primary->master->driver_priv; + if (!master_priv->sarea_priv) return; enabled = crtc->enabled && mode != DPMSModeOff; switch (pipe) { case 0: - dev_priv->sarea_priv->planeA_w = enabled ? crtc->mode.hdisplay : 0; - dev_priv->sarea_priv->planeA_h = enabled ? crtc->mode.vdisplay : 0; + master_priv->sarea_priv->planeA_w = enabled ? crtc->mode.hdisplay : 0; + master_priv->sarea_priv->planeA_h = enabled ? crtc->mode.vdisplay : 0; break; case 1: - dev_priv->sarea_priv->planeB_w = enabled ? crtc->mode.hdisplay : 0; - dev_priv->sarea_priv->planeB_h = enabled ? crtc->mode.vdisplay : 0; + master_priv->sarea_priv->planeB_w = enabled ? crtc->mode.hdisplay : 0; + master_priv->sarea_priv->planeB_h = enabled ? crtc->mode.vdisplay : 0; break; default: DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); diff --git a/linux-core/via_fence.c b/linux-core/via_fence.c index 9af1bf3b..b853df5c 100644 --- a/linux-core/via_fence.c +++ b/linux-core/via_fence.c @@ -69,7 +69,7 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) if (!dev_priv->have_idlelock) { - drm_idlelock_take(&dev->lock); + drm_idlelock_take(&dev->primary->master->lock); dev_priv->have_idlelock = 1; } @@ -95,7 +95,7 @@ static uint32_t via_perform_flush(struct drm_device *dev, uint32_t class) if (signaled_flush_types) { pending_flush_types &= ~signaled_flush_types; if (!pending_flush_types && dev_priv->have_idlelock) { - drm_idlelock_release(&dev->lock); + drm_idlelock_release(&dev->primary->master->lock); dev_priv->have_idlelock = 0; } drm_fence_handler(dev, 0, dev_priv->emit_0_sequence, -- cgit v1.2.3 From a4fc1d7ac6be8d2648acda463723d56c68e4122e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Feb 2008 16:30:15 +1000 Subject: start moving over to proper hierarchy wrt master accesses --- linux-core/drmP.h | 34 +++++++++++++----------- linux-core/drm_auth.c | 14 +++++----- linux-core/drm_context.c | 7 ++--- linux-core/drm_fops.c | 64 ++++++++++++++++++++------------------------ linux-core/drm_ioctl.c | 12 ++++----- linux-core/drm_lock.c | 6 ++--- linux-core/drm_proc.c | 69 +++++++++++++++++++++++++++++------------------- linux-core/drm_stub.c | 18 ++++++++----- 8 files changed, 120 insertions(+), 104 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index d01bf09d..81417f1d 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -262,11 +262,11 @@ struct drm_file; */ #define LOCK_TEST_WITH_RETURN( dev, file_priv ) \ do { \ - if ( !_DRM_LOCK_IS_HELD( dev->primary->master->lock.hw_lock->lock ) || \ - dev->primary->master->lock.file_priv != file_priv ) { \ + if ( !_DRM_LOCK_IS_HELD( file_priv->master->lock.hw_lock->lock ) || \ + file_priv->master->lock.file_priv != file_priv ) { \ DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ - __FUNCTION__, _DRM_LOCK_IS_HELD( dev->primary->master->lock.hw_lock->lock ),\ - dev->primary->master->lock.file_priv, file_priv ); \ + __FUNCTION__, _DRM_LOCK_IS_HELD( file_priv->master->lock.hw_lock->lock ),\ + file_priv->master->lock.file_priv, file_priv ); \ return -EINVAL; \ } \ } while (0) @@ -430,9 +430,11 @@ struct drm_file { struct drm_open_hash refd_object_hash[_DRM_NO_REF_TYPES]; struct file *filp; - struct drm_master *master; /* this private has a master associated with it */ void *driver_priv; + int is_master; /* this file private is a master for a minor */ + struct drm_master *master; /* master this node is currently associated with + N.B. not always minor->master */ struct list_head fbs; }; @@ -612,7 +614,8 @@ struct drm_ati_pcigart_info { /* per-master structure */ struct drm_master { - struct drm_device *dev; + struct list_head head; /**< each minor contains a list of masters */ + struct drm_minor *minor; /**< link back to minor we are a master for */ char *unique; /**< Unique identifier: e.g., busid */ int unique_len; /**< Length of unique field */ @@ -775,7 +778,10 @@ struct drm_minor { struct class_device *dev_class; /* for control nodes - a pointer to the current master for this control node */ - struct drm_master *master; + struct drm_master *master; /* currently active master for this node */ + struct list_head master_list; + + /* possibly needs a list of configured modesetting pieces */ }; @@ -831,7 +837,7 @@ struct drm_device { struct list_head vmalist; /**< List of vmas (for debugging) */ struct list_head filelist; -// struct drm_master *master; + /*@} */ /** \name DMA queues (contexts) */ @@ -1235,7 +1241,7 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); extern struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev); extern void drm_agp_chipset_flush(struct drm_device *dev); /* Stub support (drm_stub.h) */ -extern struct drm_master *drm_get_master(struct drm_device *dev); +extern struct drm_master *drm_get_master(struct drm_minor *minor); extern void drm_put_master(struct drm_master *master); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); @@ -1252,13 +1258,9 @@ extern struct idr drm_minors_idr; extern drm_local_map_t *drm_getsarea(struct drm_device *dev); /* Proc support (drm_proc.h) */ -extern int drm_proc_init(struct drm_device *dev, - int minor, - struct proc_dir_entry *root, - struct proc_dir_entry **dev_root); -extern int drm_proc_cleanup(int minor, - struct proc_dir_entry *root, - struct proc_dir_entry *dev_root); +int drm_proc_init(struct drm_minor *minor, int minor_id, + struct proc_dir_entry *root); +int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root); /* Scatter Gather Support (drm_scatter.h) */ extern void drm_sg_cleanup(struct drm_sg_mem * entry); diff --git a/linux-core/drm_auth.c b/linux-core/drm_auth.c index 8e85a761..20c8a634 100644 --- a/linux-core/drm_auth.c +++ b/linux-core/drm_auth.c @@ -50,7 +50,7 @@ static struct drm_file *drm_find_file(struct drm_master *master , drm_magic_t ma struct drm_file *retval = NULL; struct drm_magic_entry *pt; struct drm_hash_item *hash; - struct drm_device *dev = master->dev; + struct drm_device *dev = master->minor->dev; mutex_lock(&dev->struct_mutex); if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { @@ -76,7 +76,7 @@ static int drm_add_magic(struct drm_master *master, struct drm_file * priv, drm_magic_t magic) { struct drm_magic_entry *entry; - struct drm_device *dev = master->dev; + struct drm_device *dev = master->minor->dev; DRM_DEBUG("%d\n", magic); entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); @@ -106,7 +106,7 @@ static int drm_remove_magic(struct drm_master *master, drm_magic_t magic) { struct drm_magic_entry *pt; struct drm_hash_item *hash; - struct drm_device *dev = master->dev; + struct drm_device *dev = master->minor->dev; DRM_DEBUG("%d\n", magic); @@ -154,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) ++sequence; /* reserve 0 */ auth->magic = sequence++; spin_unlock(&lock); - } while (drm_find_file(dev->primary->master, auth->magic)); + } while (drm_find_file(file_priv->master, auth->magic)); file_priv->magic = auth->magic; - drm_add_magic(dev->primary->master, file_priv, auth->magic); + drm_add_magic(file_priv->master, file_priv, auth->magic); } DRM_DEBUG("%u\n", auth->magic); @@ -182,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data, struct drm_file *file; DRM_DEBUG("%u\n", auth->magic); - if ((file = drm_find_file(dev->primary->master, auth->magic))) { + if ((file = drm_find_file(file_priv->master, auth->magic))) { file->authenticated = 1; - drm_remove_magic(dev->primary->master, auth->magic); + drm_remove_magic(file_priv->master, auth->magic); return 0; } return -EINVAL; diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index 63a38253..febee9f7 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -257,12 +257,13 @@ static int drm_context_switch(struct drm_device *dev, int old, int new) * hardware lock is held, clears the drm_device::context_flag and wakes up * drm_device::context_wait. */ -static int drm_context_switch_complete(struct drm_device *dev, int new) +static int drm_context_switch_complete(struct drm_device *dev, + struct drm_file *file_priv, int new) { dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ dev->last_switch = jiffies; - if (!_DRM_LOCK_IS_HELD(dev->primary->master->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) { DRM_ERROR("Lock isn't held after context switch\n"); } @@ -421,7 +422,7 @@ int drm_newctx(struct drm_device *dev, void *data, struct drm_ctx *ctx = data; DRM_DEBUG("%d\n", ctx->handle); - drm_context_switch_complete(dev, ctx->handle); + drm_context_switch_complete(dev, file_priv, ctx->handle); return 0; } diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index c699e967..6ac09fb9 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -43,10 +43,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp, static int drm_setup(struct drm_device * dev) { - drm_local_map_t *map; int i; int ret; - int sareapage; if (dev->driver->firstopen) { ret = dev->driver->firstopen(dev); @@ -54,12 +52,6 @@ static int drm_setup(struct drm_device * dev) return ret; } - /* prebuild the SAREA */ - sareapage = max(SAREA_MAX, PAGE_SIZE); - i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); - if (i != 0) - return i; - atomic_set(&dev->ioctl_count, 0); atomic_set(&dev->vma_count, 0); dev->buf_use = 0; @@ -279,25 +271,27 @@ static int drm_open_helper(struct inode *inode, struct file *filp, mutex_lock(&dev->struct_mutex); /* if there is no current master make this fd it */ - if (!dev->primary->master) { - priv->master = drm_get_master(dev); - if (!priv->master) { + if (!priv->minor->master) { + priv->minor->master = drm_get_master(priv->minor); + if (!priv->minor->master) { ret = -ENOMEM; goto out_free; } - dev->primary->master = priv->master; + + priv->is_master = 1; + priv->master = priv->minor->master; if (dev->driver->master_create) { - ret = dev->driver->master_create(dev, dev->primary->master); + ret = dev->driver->master_create(dev, priv->master); if (ret) { - drm_put_master(dev->primary->master); - dev->primary->master = priv->master = NULL; + drm_put_master(priv->minor->master); + priv->minor->master = priv->master = NULL; goto out_free; } } - } else - priv->master = NULL; - + } + else + priv->master = priv->minor->master; list_add(&priv->lhead, &dev->filelist); mutex_unlock(&dev->struct_mutex); @@ -403,23 +397,23 @@ int drm_release(struct inode *inode, struct file *filp) current->pid, (long)old_encode_dev(file_priv->minor->device), dev->open_count); - if (dev->driver->reclaim_buffers_locked && dev->primary->master->lock.hw_lock) { + if (dev->driver->reclaim_buffers_locked && file_priv->master->lock.hw_lock) { if (drm_i_have_hw_lock(dev, file_priv)) { dev->driver->reclaim_buffers_locked(dev, file_priv); } else { unsigned long _end=jiffies + 3*DRM_HZ; int locked = 0; - drm_idlelock_take(&dev->primary->master->lock); + drm_idlelock_take(&file_priv->master->lock); /* * Wait for a while. */ do{ - spin_lock(&dev->primary->master->lock.spinlock); - locked = dev->primary->master->lock.idle_has_lock; - spin_unlock(&dev->primary->master->lock.spinlock); + spin_lock(&file_priv->master->lock.spinlock); + locked = file_priv->master->lock.idle_has_lock; + spin_unlock(&file_priv->master->lock.spinlock); if (locked) break; schedule(); @@ -432,24 +426,24 @@ int drm_release(struct inode *inode, struct file *filp) } dev->driver->reclaim_buffers_locked(dev, file_priv); - drm_idlelock_release(&dev->primary->master->lock); + drm_idlelock_release(&file_priv->master->lock); } } - if (dev->driver->reclaim_buffers_idlelocked && dev->primary->master->lock.hw_lock) { + if (dev->driver->reclaim_buffers_idlelocked && file_priv->master->lock.hw_lock) { - drm_idlelock_take(&dev->primary->master->lock); + drm_idlelock_take(&file_priv->master->lock); dev->driver->reclaim_buffers_idlelocked(dev, file_priv); - drm_idlelock_release(&dev->primary->master->lock); + drm_idlelock_release(&file_priv->master->lock); } if (drm_i_have_hw_lock(dev, file_priv)) { DRM_DEBUG("File %p released, freeing lock for context %d\n", - filp, _DRM_LOCKING_CONTEXT(dev->primary->master->lock.hw_lock->lock)); + filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); - drm_lock_free(&dev->primary->master->lock, - _DRM_LOCKING_CONTEXT(dev->primary->master->lock.hw_lock->lock)); + drm_lock_free(&file_priv->master->lock, + _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); } @@ -493,13 +487,13 @@ int drm_release(struct inode *inode, struct file *filp) } list_del(&file_priv->lhead); - if (file_priv->master) { - if (file_priv->master == dev->primary->master) - dev->primary->master = NULL; - drm_put_master(file_priv->master); - file_priv->master = NULL; + if (file_priv->is_master) { + drm_put_master(file_priv->minor->master); + file_priv->minor->master = NULL; } + file_priv->master = NULL; + mutex_unlock(&dev->struct_mutex); if (dev->driver->postclose) diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c index c15923ef..e35126a3 100644 --- a/linux-core/drm_ioctl.c +++ b/linux-core/drm_ioctl.c @@ -53,7 +53,7 @@ int drm_getunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; - struct drm_master *master = dev->primary->master; + struct drm_master *master = file_priv->master; if (u->unique_len >= master->unique_len) { if (copy_to_user(u->unique, master->unique, master->unique_len)) @@ -82,7 +82,7 @@ int drm_setunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; - struct drm_master *master = dev->primary->master; + struct drm_master *master = file_priv->master; int domain, bus, slot, func, ret; if (master->unique_len || master->unique) @@ -127,9 +127,9 @@ int drm_setunique(struct drm_device *dev, void *data, return 0; } -static int drm_set_busid(struct drm_device * dev) +static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) { - struct drm_master *master = dev->primary->master; + struct drm_master *master = file_priv->master; int len; if (master->unique != NULL) @@ -279,7 +279,7 @@ int drm_getstats(struct drm_device *dev, void *data, for (i = 0; i < dev->counters; i++) { if (dev->types[i] == _DRM_STAT_LOCK) stats->data[i].value = - (dev->primary->master->lock.hw_lock ? dev->primary->master->lock.hw_lock->lock : 0); + (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0); else stats->data[i].value = atomic_read(&dev->counts[i]); stats->data[i].type = dev->types[i]; @@ -321,7 +321,7 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri /* * Version 1.1 includes tying of DRM to specific device */ - drm_set_busid(dev); + drm_set_busid(dev, file_priv); } } diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 7404856e..08e063d8 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -52,7 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) { DECLARE_WAITQUEUE(entry, current); struct drm_lock *lock = data; - struct drm_master *master = dev->primary->master; + struct drm_master *master = file_priv->master; int ret = 0; ++file_priv->lock_count; @@ -150,7 +150,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_lock *lock = data; - struct drm_master *master = dev->primary->master; + struct drm_master *master = file_priv->master; unsigned long irqflags; if (lock->context == DRM_KERNEL_CONTEXT) { @@ -386,7 +386,7 @@ EXPORT_SYMBOL(drm_idlelock_release); int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) { - struct drm_master *master = dev->primary->master; + struct drm_master *master = file_priv->master; return (file_priv->lock_count && master->lock.hw_lock && _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && master->lock.file_priv == file_priv); diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 12c08c86..2ccf6d99 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -90,34 +90,35 @@ static struct drm_proc_list { * "/proc/dri/%minor%/", and each entry in proc_list as * "/proc/dri/%minor%/%name%". */ -int drm_proc_init(struct drm_device *dev, int minor, - struct proc_dir_entry *root, struct proc_dir_entry **dev_root) +int drm_proc_init(struct drm_minor *minor, int minor_id, + struct proc_dir_entry *root) { struct proc_dir_entry *ent; int i, j; char name[64]; - sprintf(name, "%d", minor); - *dev_root = proc_mkdir(name, root); - if (!*dev_root) { + sprintf(name, "%d", minor_id); + minor->dev_root = proc_mkdir(name, root); + if (!minor->dev_root) { DRM_ERROR("Cannot create /proc/dri/%s\n", name); return -1; } for (i = 0; i < DRM_PROC_ENTRIES; i++) { ent = create_proc_entry(drm_proc_list[i].name, - S_IFREG | S_IRUGO, *dev_root); + S_IFREG | S_IRUGO, minor->dev_root); if (!ent) { DRM_ERROR("Cannot create /proc/dri/%s/%s\n", name, drm_proc_list[i].name); for (j = 0; j < i; j++) remove_proc_entry(drm_proc_list[i].name, - *dev_root); + minor->dev_root); remove_proc_entry(name, root); + minor->dev_root = NULL; return -1; } ent->read_proc = drm_proc_list[i].f; - ent->data = dev; + ent->data = minor; } return 0; } @@ -132,18 +133,17 @@ int drm_proc_init(struct drm_device *dev, int minor, * * Remove all proc entries created by proc_init(). */ -int drm_proc_cleanup(int minor, struct proc_dir_entry *root, - struct proc_dir_entry *dev_root) +int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) { int i; char name[64]; - if (!root || !dev_root) + if (!root || !minor->dev_root) return 0; for (i = 0; i < DRM_PROC_ENTRIES; i++) - remove_proc_entry(drm_proc_list[i].name, dev_root); - sprintf(name, "%d", minor); + remove_proc_entry(drm_proc_list[i].name, minor->dev_root); + sprintf(name, "%d", minor->index); remove_proc_entry(name, root); return 0; @@ -165,8 +165,9 @@ int drm_proc_cleanup(int minor, struct proc_dir_entry *root, static int drm_name_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; - struct drm_master *master = dev->primary->master; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_master *master = minor->master; + struct drm_device *dev = minor->dev; int len = 0; if (offset > DRM_PROC_LIMIT) { @@ -208,7 +209,9 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, static int drm__vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_master *master = minor->master; + struct drm_device *dev = minor->dev; int len = 0; struct drm_map *map; struct drm_map_list *r_list; @@ -265,7 +268,9 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, static int drm_vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_master *master = minor->master; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -288,7 +293,8 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request, static int drm__queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; int i; struct drm_queue *q; @@ -338,7 +344,8 @@ static int drm__queues_info(char *buf, char **start, off_t offset, static int drm_queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -361,7 +368,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request, static int drm__bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_device_dma *dma = dev->dma; int i; @@ -410,7 +418,8 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request, static int drm_bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -433,7 +442,8 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, static int drm__objects_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_buffer_manager *bm = &dev->bm; struct drm_fence_manager *fm = &dev->fm; @@ -497,7 +507,8 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request, static int drm_objects_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -520,7 +531,8 @@ static int drm_objects_info(char *buf, char **start, off_t offset, int request, static int drm__clients_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_file *priv; @@ -553,7 +565,8 @@ static int drm__clients_info(char *buf, char **start, off_t offset, static int drm_clients_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -567,7 +580,8 @@ static int drm_clients_info(char *buf, char **start, off_t offset, static int drm__vma_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_vma_entry *pt; struct vm_area_struct *vma; @@ -626,7 +640,8 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, static int drm_vma_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 66a7b8b5..ebb8fb97 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -91,7 +91,7 @@ again: return new_id; } -struct drm_master *drm_get_master(struct drm_device *dev) +struct drm_master *drm_get_master(struct drm_minor *minor) { struct drm_master *master; @@ -104,7 +104,9 @@ struct drm_master *drm_get_master(struct drm_device *dev) init_waitqueue_head(&master->lock.lock_queue); drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); INIT_LIST_HEAD(&master->magicfree); - master->dev = dev; + master->minor = minor; + + list_add_tail(&master->head, &minor->master_list); return master; } @@ -112,7 +114,9 @@ struct drm_master *drm_get_master(struct drm_device *dev) void drm_put_master(struct drm_master *master) { struct drm_magic_entry *pt, *next; - struct drm_device *dev = master->dev; + struct drm_device *dev = master->minor->dev; + + list_del(&master->head); if (dev->driver->master_destroy) dev->driver->master_destroy(dev, master); @@ -265,12 +269,12 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t new_minor->device = MKDEV(DRM_MAJOR, minor_id); new_minor->dev = dev; new_minor->index = minor_id; + INIT_LIST_HEAD(&new_minor->master_list); idr_replace(&drm_minors_idr, new_minor, minor_id); if (type == DRM_MINOR_RENDER) { - ret = drm_proc_init(dev, minor_id, drm_proc_root, - &new_minor->dev_root); + ret = drm_proc_init(new_minor, minor_id, drm_proc_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); goto err_mem; @@ -292,7 +296,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t err_g2: if (new_minor->type == DRM_MINOR_RENDER) - drm_proc_cleanup(minor_id, drm_proc_root, new_minor->dev_root); + drm_proc_cleanup(new_minor, drm_proc_root); err_mem: kfree(new_minor); err_idr: @@ -416,7 +420,7 @@ int drm_put_minor(struct drm_minor **minor_p) DRM_DEBUG("release secondary minor %d\n", minor->index); if (minor->type == DRM_MINOR_RENDER) - drm_proc_cleanup(minor->index, drm_proc_root, minor->dev_root); + drm_proc_cleanup(minor, drm_proc_root); drm_sysfs_device_remove(minor); idr_remove(&drm_minors_idr, minor->index); -- cgit v1.2.3 From 8bf8cd63bb4631b57ceb27058f81d767a94edc74 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Feb 2008 07:37:34 +1000 Subject: missing bits --- shared-core/i915_dma.c | 71 ++++++++++++++++++++-------------------------- shared-core/i915_drv.h | 11 +++++-- shared-core/i915_init.c | 58 +++++++++++++++++++++++++------------ shared-core/i915_irq.c | 40 ++++++++++++++++++++------ shared-core/i915_mem.c | 3 +- shared-core/radeon_state.c | 2 +- 6 files changed, 114 insertions(+), 71 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 68505dca..0a3d82a0 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -88,14 +88,7 @@ int i915_dma_cleanup(struct drm_device * dev) static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) { struct drm_i915_private *dev_priv = dev->dev_private; - - dev_priv->sarea = drm_getsarea(dev); - if (!dev_priv->sarea) { - DRM_ERROR("can not find sarea!\n"); - i915_dma_cleanup(dev); - return -EINVAL; - } - + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); if (!dev_priv->mmio_map) { i915_dma_cleanup(dev); @@ -107,9 +100,6 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; #endif - dev_priv->sarea_priv = (drm_i915_sarea_t *) - ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); - if (!dev_priv->ring.Size) { dev_priv->ring.Start = init->ring_start; dev_priv->ring.End = init->ring_end; @@ -135,7 +125,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) dev_priv->cpp = init->cpp; - dev_priv->sarea_priv->pf_current_page = 0; + master_priv->sarea_priv->pf_current_page = 0; /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. @@ -182,11 +172,6 @@ static int i915_dma_resume(struct drm_device * dev) DRM_DEBUG("\n"); - if (!dev_priv->sarea) { - DRM_ERROR("can not find sarea!\n"); - return -EINVAL; - } - if (!dev_priv->mmio_map) { DRM_ERROR("can not find mmio map!\n"); return -EINVAL; @@ -400,6 +385,7 @@ static int i915_emit_box(struct drm_device * dev, void i915_emit_breadcrumb(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; RING_LOCALS; if (++dev_priv->counter > BREADCRUMB_MASK) { @@ -407,7 +393,7 @@ void i915_emit_breadcrumb(struct drm_device *dev) DRM_DEBUG("Breadcrumb counter wrapped around\n"); } - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; + master_priv->sarea_priv->last_enqueue = dev_priv->counter; BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); @@ -534,37 +520,38 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; u32 num_pages, current_page, next_page, dspbase; int shift = 2 * plane, x, y; RING_LOCALS; /* Calculate display base offset */ - num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; - current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3; + num_pages = master_priv->sarea_priv->third_handle ? 3 : 2; + current_page = (master_priv->sarea_priv->pf_current_page >> shift) & 0x3; next_page = (current_page + 1) % num_pages; switch (next_page) { default: case 0: - dspbase = dev_priv->sarea_priv->front_offset; + dspbase = master_priv->sarea_priv->front_offset; break; case 1: - dspbase = dev_priv->sarea_priv->back_offset; + dspbase = master_priv->sarea_priv->back_offset; break; case 2: - dspbase = dev_priv->sarea_priv->third_offset; + dspbase = master_priv->sarea_priv->third_offset; break; } if (plane == 0) { - x = dev_priv->sarea_priv->planeA_x; - y = dev_priv->sarea_priv->planeA_y; + x = master_priv->sarea_priv->planeA_x; + y = master_priv->sarea_priv->planeA_y; } else { - x = dev_priv->sarea_priv->planeB_x; - y = dev_priv->sarea_priv->planeB_y; + x = master_priv->sarea_priv->planeB_x; + y = master_priv->sarea_priv->planeB_y; } - dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp; + dspbase += (y * master_priv->sarea_priv->pitch + x) * dev_priv->cpp; DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page, dspbase); @@ -575,21 +562,22 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) MI_WAIT_FOR_PLANE_A_FLIP))); OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) | (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A)); - OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp); + OUT_RING(master_priv->sarea_priv->pitch * dev_priv->cpp); OUT_RING(dspbase); ADVANCE_LP_RING(); - dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); - dev_priv->sarea_priv->pf_current_page |= next_page << shift; + master_priv->sarea_priv->pf_current_page &= ~(0x3 << shift); + master_priv->sarea_priv->pf_current_page |= next_page << shift; } void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int i; DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n", - planes, dev_priv->sarea_priv->pf_current_page); + planes, master_priv->sarea_priv->pf_current_page); i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH); @@ -625,8 +613,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) - dev_priv->sarea_priv; + master_priv->sarea_priv; drm_i915_batchbuffer_t *batch = data; int ret; @@ -655,8 +644,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; struct drm_i915_sarea *sarea_priv = (struct drm_i915_sarea *) - dev_priv->sarea_priv; + master_priv->sarea_priv; struct drm_i915_cmdbuffer *cmdbuf = data; int ret; @@ -1011,8 +1001,9 @@ static int i915_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) - dev_priv->sarea_priv; + master_priv->sarea_priv; struct drm_i915_execbuffer *exec_buf = data; struct drm_i915_batchbuffer *batch = &exec_buf->batch; struct drm_fence_arg *fence_arg = &exec_buf->fence_arg; @@ -1116,15 +1107,15 @@ out_free: int i915_do_cleanup_pageflip(struct drm_device * dev) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int i, planes, num_pages; DRM_DEBUG("\n"); - num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2; + num_pages = master_priv->sarea_priv->third_handle ? 3 : 2; for (i = 0, planes = 0; i < 2; i++) { - if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { - dev_priv->sarea_priv->pf_current_page = - (dev_priv->sarea_priv->pf_current_page & + if (master_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) { + master_priv->sarea_priv->pf_current_page = + (master_priv->sarea_priv->pf_current_page & ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i)); planes |= 1 << i; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index ea89bc4c..19fec0fc 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -97,17 +97,22 @@ struct drm_i915_vbl_swap { unsigned int plane; unsigned int sequence; int flip; + struct drm_minor *minor; }; +struct drm_i915_master_private { + drm_local_map_t *sarea; + struct drm_i915_sarea *sarea_priv; +}; + struct drm_i915_private { struct drm_buffer_object *ring_buffer; - drm_local_map_t *sarea; + drm_local_map_t *mmio_map; unsigned long mmiobase; unsigned long mmiolen; - struct drm_i915_sarea *sarea_priv; struct drm_i915_ring_buffer ring; struct drm_dma_handle *status_page_dmah; @@ -249,6 +254,8 @@ enum intel_chip_family { extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; +extern int i915_master_create(struct drm_device *dev, struct drm_master *master); +extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); /* i915_dma.c */ extern void i915_kernel_lost_context(struct drm_device * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 792c40bb..c2d8964e 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -113,7 +113,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv; unsigned long agp_size, prealloc_size; - unsigned long sareapage; int size, ret; dev_priv = drm_alloc(sizeof(struct drm_i915_private), DRM_MEM_DRIVER); @@ -160,20 +159,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return ret; } - /* prebuild the SAREA */ - sareapage = max(SAREA_MAX, PAGE_SIZE); - ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, - &dev_priv->sarea); - if (ret) { - DRM_ERROR("SAREA setup failed\n"); - return ret; - } - - init_waitqueue_head(&dev->lock.lock_queue); - - /* FIXME: assume sarea_priv is right after SAREA */ - dev_priv->sarea_priv = dev_priv->sarea->handle + sizeof(struct drm_sarea); - /* * Initialize the memory manager for local and AGP space */ @@ -216,7 +201,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start, dev_priv->ring.virtual_start, dev_priv->ring.Size); - dev_priv->sarea_priv->pf_current_page = 0; + // memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); @@ -319,12 +304,49 @@ int i915_driver_unload(struct drm_device *dev) drm_bo_driver_finish(dev); - DRM_DEBUG("%p, %p\n", dev_priv->mmio_map, dev_priv->sarea); + DRM_DEBUG("%p\n", dev_priv->mmio_map); drm_rmmap(dev, dev_priv->mmio_map); - drm_rmmap(dev, dev_priv->sarea); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; return 0; } + +int i915_master_create(struct drm_device *dev, struct drm_master *master) +{ + struct drm_i915_master_private *master_priv; + unsigned long sareapage; + int ret; + + master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + if (!master_priv) + return -ENOMEM; + + /* prebuild the SAREA */ + sareapage = max(SAREA_MAX, PAGE_SIZE); + ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, + &master_priv->sarea); + if (ret) { + DRM_ERROR("SAREA setup failed\n"); + return ret; + } + master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea); + master_priv->sarea_priv->pf_current_page = 0; + + master->driver_priv = master_priv; + return 0; +} + +void i915_master_destroy(struct drm_device *dev, struct drm_master *master) +{ + struct drm_i915_master_private *master_priv = master->driver_priv; + + if (!master_priv) + return; + + drm_rmmap(dev, master_priv->sarea); + drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + + master->driver_priv = NULL; +} diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 5f6fa56d..dad6ef86 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -107,8 +107,8 @@ static void i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, int plane) { - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - struct drm_i915_sarea *sarea_priv = dev_priv->sarea_priv; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv; u16 x1, y1, x2, y2; int pf_planes = 1 << plane; @@ -153,18 +153,18 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, static void i915_vblank_tasklet(struct drm_device *dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; struct list_head *list, *tmp, hits, *hit; int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; unsigned counter[2]; struct drm_drawable_info *drw; - struct drm_i915_sarea *sarea_priv = dev_priv->sarea_priv; + struct drm_i915_sarea *sarea_priv; u32 cpp = dev_priv->cpp, offsets[3]; u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB) : XY_SRC_COPY_BLT_CMD; - u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | - (cpp << 23) | (1 << 24); + u32 pitchropcpp; RING_LOCALS; counter[0] = drm_vblank_count(dev, 0); @@ -192,6 +192,12 @@ static void i915_vblank_tasklet(struct drm_device *dev) if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) continue; + master_priv = vbl_swap->minor->master->driver_priv; + sarea_priv = master_priv->sarea_priv; + + pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | + (cpp << 23) | (1 << 24); + list_del(list); dev_priv->swaps_pending--; drm_vblank_put(dev, pipe); @@ -306,7 +312,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) top = upper[plane]; bottom = lower[plane]; - front = (dev_priv->sarea_priv->pf_current_page >> + front = (master_priv->sarea_priv->pf_current_page >> (2 * plane)) & 0x3; back = (front + 1) % num_pages; @@ -559,6 +565,7 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; + struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; u32 temp = 0; u32 temp2; @@ -627,7 +634,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); - dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + } if (temp & USER_INT_FLAG) { DRM_WAKEUP(&dev_priv->irq_queue); @@ -699,6 +709,7 @@ void i915_user_irq_off(struct drm_i915_private *dev_priv) static int i915_wait_irq(struct drm_device * dev, int irq_nr) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_master_private *master_priv; int ret = 0; DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, @@ -716,8 +727,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); } + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + } - dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); return ret; } @@ -904,6 +919,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv; struct drm_i915_vblank_swap *swap = data; struct drm_i915_vbl_swap *vbl_swap; unsigned int pipe, seqtype, curseq, plane; @@ -916,7 +932,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data, return -EINVAL; } - if (dev_priv->sarea_priv->rotation) { + if (!dev->primary->master) + return -EINVAL; + + master_priv = dev->primary->master->driver_priv; + + if (master_priv->sarea_priv->rotation) { DRM_DEBUG("Rotation not supported\n"); return -EINVAL; } @@ -1037,6 +1058,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, vbl_swap->plane = plane; vbl_swap->sequence = swap->sequence; vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); + vbl_swap->minor = file_priv->minor; if (vbl_swap->flip) swap->sequence++; diff --git a/shared-core/i915_mem.c b/shared-core/i915_mem.c index f24547c7..15d63dec 100644 --- a/shared-core/i915_mem.c +++ b/shared-core/i915_mem.c @@ -46,7 +46,8 @@ static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_sarea *sarea_priv = dev_priv->sarea_priv; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv; struct drm_tex_region *list; unsigned shift, nr; unsigned start; diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 6f2e05b3..289fddc7 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3057,7 +3057,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil */ case RADEON_PARAM_SAREA_HANDLE: /* The lock is the first dword in the sarea. */ - value = (long)dev->lock.hw_lock; + value = (long)dev->primary->master->lock.hw_lock; break; #endif case RADEON_PARAM_GART_TEX_HANDLE: -- cgit v1.2.3 From f2f8ace3e1342d83096bf392922130d39cd86ec2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 15 Feb 2008 09:57:30 +1000 Subject: remove drm_minors_limit --- linux-core/drmP.h | 1 - linux-core/drm_stub.c | 3 --- 2 files changed, 4 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 81417f1d..697dc9a1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1248,7 +1248,6 @@ extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, extern int drm_put_dev(struct drm_device *dev); extern int drm_put_minor(struct drm_minor **minor); extern unsigned int drm_debug; /* 1 to enable debug output */ -extern unsigned int drm_minors_limit; extern struct class *drm_class; extern struct proc_dir_entry *drm_proc_root; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index ebb8fb97..d3992584 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -37,17 +37,14 @@ #include "drmP.h" #include "drm_core.h" -unsigned int drm_minors_limit = 16; /* Enough for one machine */ unsigned int drm_debug = 0; /* 1 to enable debug output */ EXPORT_SYMBOL(drm_debug); MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); -MODULE_PARM_DESC(minors_limit, "Maximum number of graphics cards"); MODULE_PARM_DESC(debug, "Enable debug output"); -module_param_named(minors_limit, drm_minors_limit, int, 0444); module_param_named(debug, drm_debug, int, 0600); struct idr drm_minors_idr; -- cgit v1.2.3 From 75b01cf996f2efdd72c5280238460443d5d1fbc7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 15 Feb 2008 10:04:28 +1000 Subject: switch naming to new proposed scheme --- linux-core/drmP.h | 4 ++-- linux-core/drm_proc.c | 2 -- linux-core/drm_stub.c | 18 +++++++++--------- linux-core/drm_sysfs.c | 2 ++ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 697dc9a1..ab17ba0e 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -762,8 +762,8 @@ struct drm_driver { #define DRM_MINOR_UNASSIGNED 0 #define DRM_MINOR_CONTROL 1 -#define DRM_MINOR_RENDER 2 -#define DRM_MINOR_GPGPU 3 /* this node is restricted to operations that don't require a master */ +#define DRM_MINOR_LEGACY 2 +#define DRM_MINOR_RENDER 3 /** * DRM minor structure. This structure represents a drm minor number. */ diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 2ccf6d99..e10501f2 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -210,7 +210,6 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { struct drm_minor *minor = (struct drm_minor *) data; - struct drm_master *master = minor->master; struct drm_device *dev = minor->dev; int len = 0; struct drm_map *map; @@ -269,7 +268,6 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { struct drm_minor *minor = (struct drm_minor *) data; - struct drm_master *master = minor->master; struct drm_device *dev = minor->dev; int ret; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index d3992584..801dab09 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -56,14 +56,14 @@ static int drm_minor_get_id(struct drm_device *dev, int type) { int new_id; int ret; - int base = 0, limit = 127; + int base = 0, limit = 63; if (type == DRM_MINOR_CONTROL) { + base += 64; + limit = base + 127; + } else if (type == DRM_MINOR_RENDER) { base += 128; - limit = base + 64; - } else if (type == DRM_MINOR_GPGPU) { - base += 192; - limit = base + 64; + limit = base + 255; } again: @@ -270,7 +270,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t idr_replace(&drm_minors_idr, new_minor, minor_id); - if (type == DRM_MINOR_RENDER) { + if (type == DRM_MINOR_LEGACY) { ret = drm_proc_init(new_minor, minor_id, drm_proc_root); if (ret) { DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); @@ -292,7 +292,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t err_g2: - if (new_minor->type == DRM_MINOR_RENDER) + if (new_minor->type == DRM_MINOR_LEGACY) drm_proc_cleanup(new_minor, drm_proc_root); err_mem: kfree(new_minor); @@ -345,7 +345,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL))) goto err_g3; - if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_RENDER))) + if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) goto err_g4; if (dev->driver->load) @@ -416,7 +416,7 @@ int drm_put_minor(struct drm_minor **minor_p) struct drm_minor *minor = *minor_p; DRM_DEBUG("release secondary minor %d\n", minor->index); - if (minor->type == DRM_MINOR_RENDER) + if (minor->type == DRM_MINOR_LEGACY) drm_proc_cleanup(minor, drm_proc_root); drm_sysfs_device_remove(minor); diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index cd03da8a..f03e5d4e 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -171,6 +171,8 @@ int drm_sysfs_device_add(struct drm_minor *minor) minor->kdev.devt = minor->device; if (minor->type == DRM_MINOR_CONTROL) minor_str = "controlD%d"; + else if (minor->type == DRM_MINOR_RENDER) + minor_str = "renderD%d"; else minor_str = "card%d"; -- cgit v1.2.3 From 222092a1a810b67b014ad6881f0c028ec6563329 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 15 Feb 2008 16:15:04 +1000 Subject: various fixes from trying to get userspace started --- linux-core/drm_bufs.c | 1 + linux-core/drm_crtc.c | 8 +++++++- linux-core/drm_fops.c | 25 ++++++++++++++++--------- linux-core/drm_stub.c | 1 + 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 3e1767c0..031f8ba0 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -318,6 +318,7 @@ static int drm_addmap_core(struct drm_device *dev, unsigned int offset, list->user_token = list->hash.key << PAGE_SHIFT; mutex_unlock(&dev->struct_mutex); + list->master = dev->primary->master; *maplist = list; return 0; } diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 55390a82..3a0dd9c8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1094,7 +1094,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, crtc->fb = fb; crtc->enabled = (new_mode != NULL); if (new_mode != NULL) { - DRM_DEBUG("attempting to set mode from userspace\n"); + DRM_DEBUG("attempting to set mode from userspace %p\n", crtc->fb); drm_mode_debug_printmodeline(dev, new_mode); if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x, crtc_info->y)) { @@ -1577,7 +1577,13 @@ int drm_mode_setcrtc(struct drm_device *dev, ret = -EINVAL; goto out; } + DRM_DEBUG("found fb %p for id %d\n", fb, crtc_req->fb_id); + } else { + DRM_DEBUG("Unknown FB ID %d\n", crtc_req->fb_id); + ret = -EINVAL; + goto out; } + mode = drm_mode_create(dev); drm_crtc_convert_umode(mode, &crtc_req->mode); diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 6ac09fb9..5a74f424 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -268,9 +268,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp, goto out_free; } - mutex_lock(&dev->struct_mutex); /* if there is no current master make this fd it */ + mutex_lock(&dev->struct_mutex); if (!priv->minor->master) { priv->minor->master = drm_get_master(priv->minor); if (!priv->minor->master) { @@ -281,17 +281,22 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->is_master = 1; priv->master = priv->minor->master; + mutex_unlock(&dev->struct_mutex); if (dev->driver->master_create) { ret = dev->driver->master_create(dev, priv->master); if (ret) { drm_put_master(priv->minor->master); priv->minor->master = priv->master = NULL; + mutex_unlock(&dev->struct_mutex); goto out_free; } } - } - else + } else { priv->master = priv->minor->master; + mutex_unlock(&dev->struct_mutex); + } + + mutex_lock(&dev->struct_mutex); list_add(&priv->lhead, &dev->filelist); mutex_unlock(&dev->struct_mutex); @@ -477,6 +482,14 @@ int drm_release(struct inode *inode, struct file *filp) mutex_unlock(&dev->ctxlist_mutex); drm_fb_release(filp); + + file_priv->master = NULL; + + if (file_priv->is_master) { + drm_put_master(file_priv->minor->master); + file_priv->minor->master = NULL; + } + mutex_lock(&dev->struct_mutex); drm_object_release(filp); if (file_priv->remove_auth_on_close == 1) { @@ -487,12 +500,6 @@ int drm_release(struct inode *inode, struct file *filp) } list_del(&file_priv->lhead); - if (file_priv->is_master) { - drm_put_master(file_priv->minor->master); - file_priv->minor->master = NULL; - } - - file_priv->master = NULL; mutex_unlock(&dev->struct_mutex); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 801dab09..334c8f03 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -152,6 +152,7 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, INIT_LIST_HEAD(&dev->ctxlist); INIT_LIST_HEAD(&dev->vmalist); INIT_LIST_HEAD(&dev->maplist); + INIT_LIST_HEAD(&dev->filelist); spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); -- cgit v1.2.3 From 088b38382962a9dccca59a53af2444a1fe8bc18f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 15 Feb 2008 16:42:44 +1000 Subject: fb: fixup the offset by getting it from the right place --- linux-core/drm_crtc.c | 1 - linux-core/intel_display.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 3a0dd9c8..aceb31b4 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1754,7 +1754,6 @@ int drm_mode_addfb(struct drm_device *dev, fb->pitch = r->pitch; fb->bits_per_pixel = r->bpp; fb->depth = r->depth; - fb->offset = bo->offset; fb->bo = bo; r->buffer_id = fb->id; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index db3aee83..6a9d9808 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -370,7 +370,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); - Start = crtc->fb->offset; + Start = crtc->fb->bo->offset; Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); @@ -814,6 +814,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, else dspcntr |= DISPPLANE_16BPP; break; + case 24: case 32: dspcntr |= DISPPLANE_32BPP_NO_ALPHA; break; -- cgit v1.2.3 From 2b1c9cd696049d23845870329d2b61a5873f7b13 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 15 Feb 2008 16:13:21 -0800 Subject: i915: initial (and untested) TV out support Ported from xf86-video-intel. Still need to tie in TV modes somehow, though preferably w/o using the properties mechanism. --- linux-core/Makefile.kernel | 2 +- linux-core/drm_crtc.c | 48 +- linux-core/drm_crtc.h | 13 +- linux-core/intel_drv.h | 3 +- linux-core/intel_tv.c | 1763 ++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_drv.h | 573 ++++++++++++++ 6 files changed, 2392 insertions(+), 10 deletions(-) create mode 100644 linux-core/intel_tv.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index b4fdcf6b..8f6f01ac 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -22,7 +22,7 @@ i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \ intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o \ - i915_compat.o + intel_tv.o i915_compat.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o nouveau_notifier.o nouveau_swmthd.o \ nouveau_sgdma.o nouveau_dma.o nouveau_buffer.o nouveau_fence.o \ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index aceb31b4..6b8cb9c7 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -38,6 +38,9 @@ struct drm_prop_enum_list { char *name; }; +/* + * Global properties + */ static struct drm_prop_enum_list drm_dpms_enum_list[] = { { DPMSModeOn, "On" }, { DPMSModeStandby, "Standby" }, @@ -720,6 +723,9 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) { int i; + /* + * Standard properties (apply to all outputs) + */ dev->mode_config.edid_property = drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, "EDID", 0); @@ -741,6 +747,39 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) "Connector ID", 2); dev->mode_config.connector_num_property->values[0] = 0; dev->mode_config.connector_num_property->values[1] = 20; + + /* + * TV specific properties + */ + dev->mode_config.tv_left_margin_property = + drm_property_create(dev, DRM_MODE_PROP_RANGE | + DRM_MODE_PROP_IMMUTABLE, + "left margin", 2); + dev->mode_config.tv_left_margin_property->values[0] = 0; + dev->mode_config.tv_left_margin_property->values[1] = 100; + + dev->mode_config.tv_right_margin_property = + drm_property_create(dev, DRM_MODE_PROP_RANGE | + DRM_MODE_PROP_IMMUTABLE, + "right margin", 2); + dev->mode_config.tv_right_margin_property->values[0] = 0; + dev->mode_config.tv_right_margin_property->values[1] = 100; + + dev->mode_config.tv_top_margin_property = + drm_property_create(dev, DRM_MODE_PROP_RANGE | + DRM_MODE_PROP_IMMUTABLE, + "top margin", 2); + dev->mode_config.tv_top_margin_property->values[0] = 0; + dev->mode_config.tv_top_margin_property->values[1] = 100; + + dev->mode_config.tv_bottom_margin_property = + drm_property_create(dev, DRM_MODE_PROP_RANGE | + DRM_MODE_PROP_IMMUTABLE, + "bottom margin", 2); + dev->mode_config.tv_bottom_margin_property->values[0] = 0; + dev->mode_config.tv_bottom_margin_property->values[1] = 100; + + return 0; } @@ -1094,7 +1133,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, crtc->fb = fb; crtc->enabled = (new_mode != NULL); if (new_mode != NULL) { - DRM_DEBUG("attempting to set mode from userspace %p\n", crtc->fb); + DRM_DEBUG("attempting to set mode from userspace\n"); drm_mode_debug_printmodeline(dev, new_mode); if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x, crtc_info->y)) { @@ -1577,13 +1616,7 @@ int drm_mode_setcrtc(struct drm_device *dev, ret = -EINVAL; goto out; } - DRM_DEBUG("found fb %p for id %d\n", fb, crtc_req->fb_id); - } else { - DRM_DEBUG("Unknown FB ID %d\n", crtc_req->fb_id); - ret = -EINVAL; - goto out; } - mode = drm_mode_create(dev); drm_crtc_convert_umode(mode, &crtc_req->mode); @@ -1754,6 +1787,7 @@ int drm_mode_addfb(struct drm_device *dev, fb->pitch = r->pitch; fb->bits_per_pixel = r->bpp; fb->depth = r->depth; + fb->offset = bo->offset; fb->bo = bo; r->buffer_id = fb->id; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index db5fd34c..43ef95ed 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -548,6 +548,13 @@ struct drm_mode_config { struct drm_property *connector_type_property; struct drm_property *connector_num_property; + /* TV properties */ + struct drm_property *tv_mode_property; + struct drm_property *tv_left_margin_property; + struct drm_property *tv_right_margin_property; + struct drm_property *tv_top_margin_property; + struct drm_property *tv_bottom_margin_property; + /* hotplug */ uint32_t hotplug_counter; }; @@ -595,7 +602,11 @@ extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); extern void drm_mode_output_list_update(struct drm_output *output); -extern int drm_mode_output_update_edid_property(struct drm_output *output, struct edid *edid); +extern int drm_mode_output_update_edid_property(struct drm_output *output, + struct edid *edid); +extern int drm_output_property_set_value(struct drm_output *output, + struct drm_property *property, + uint64_t value); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 25c3a978..72ba01da 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -49,12 +49,13 @@ struct intel_output { int type; struct intel_i2c_chan *i2c_bus; /* for control functions */ struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ - bool load_detect_tmp; + bool load_detect_temp; void *dev_priv; }; struct intel_crtc { int pipe; + int plane; uint32_t cursor_adder; u8 lut_r[256], lut_g[256], lut_b[256]; }; diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c new file mode 100644 index 00000000..0edbdbac --- /dev/null +++ b/linux-core/intel_tv.c @@ -0,0 +1,1763 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +/** @file + * Integrated TV-out support for the 915GM and 945GM. + */ + +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "drm_edid.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" + +enum tv_type { + TV_TYPE_NONE, + TV_TYPE_UNKNOWN, + TV_TYPE_COMPOSITE, + TV_TYPE_SVIDEO, + TV_TYPE_COMPONENT +}; + +enum tv_margin { + TV_MARGIN_LEFT, TV_MARGIN_TOP, + TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM +}; + +/** Private structure for the integrated TV support */ +struct intel_tv_priv { + int type; + char *tv_format; + int margin[4]; + u32 save_TV_H_CTL_1; + u32 save_TV_H_CTL_2; + u32 save_TV_H_CTL_3; + u32 save_TV_V_CTL_1; + u32 save_TV_V_CTL_2; + u32 save_TV_V_CTL_3; + u32 save_TV_V_CTL_4; + u32 save_TV_V_CTL_5; + u32 save_TV_V_CTL_6; + u32 save_TV_V_CTL_7; + u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3; + + u32 save_TV_CSC_Y; + u32 save_TV_CSC_Y2; + u32 save_TV_CSC_U; + u32 save_TV_CSC_U2; + u32 save_TV_CSC_V; + u32 save_TV_CSC_V2; + u32 save_TV_CLR_KNOBS; + u32 save_TV_CLR_LEVEL; + u32 save_TV_WIN_POS; + u32 save_TV_WIN_SIZE; + u32 save_TV_FILTER_CTL_1; + u32 save_TV_FILTER_CTL_2; + u32 save_TV_FILTER_CTL_3; + + u32 save_TV_H_LUMA[60]; + u32 save_TV_H_CHROMA[60]; + u32 save_TV_V_LUMA[43]; + u32 save_TV_V_CHROMA[43]; + + u32 save_TV_DAC; + u32 save_TV_CTL; +}; + +struct video_levels { + int blank, black, burst; +}; + +struct color_conversion { + u16 ry, gy, by, ay; + u16 ru, gu, bu, au; + u16 rv, gv, bv, av; +}; + +static const u32 filter_table[] = { + 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, + 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, + 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, + 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, + 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, + 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, + 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, + 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, + 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, + 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, + 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, + 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, + 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, + 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, + 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, + 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, + 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, + 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, + 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, + 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, + 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, + 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, + 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, + 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, + 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, + 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, + 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, + 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, + 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, + 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, + 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0, + 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, + 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, + 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, + 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, + 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, + 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, + 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, + 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, + 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, + 0x28003100, 0x28002F00, 0x00003100, 0x36403000, + 0x2D002CC0, 0x30003640, 0x2D0036C0, + 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, + 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, + 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, + 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, + 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, + 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, + 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, + 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, + 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, + 0x28003100, 0x28002F00, 0x00003100, +}; + +/* + * Color conversion values have 3 separate fixed point formats: + * + * 10 bit fields (ay, au) + * 1.9 fixed point (b.bbbbbbbbb) + * 11 bit fields (ry, by, ru, gu, gv) + * exp.mantissa (ee.mmmmmmmmm) + * ee = 00 = 10^-1 (0.mmmmmmmmm) + * ee = 01 = 10^-2 (0.0mmmmmmmmm) + * ee = 10 = 10^-3 (0.00mmmmmmmmm) + * ee = 11 = 10^-4 (0.000mmmmmmmmm) + * 12 bit fields (gy, rv, bu) + * exp.mantissa (eee.mmmmmmmmm) + * eee = 000 = 10^-1 (0.mmmmmmmmm) + * eee = 001 = 10^-2 (0.0mmmmmmmmm) + * eee = 010 = 10^-3 (0.00mmmmmmmmm) + * eee = 011 = 10^-4 (0.000mmmmmmmmm) + * eee = 100 = reserved + * eee = 101 = reserved + * eee = 110 = reserved + * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation) + * + * Saturation and contrast are 8 bits, with their own representation: + * 8 bit field (saturation, contrast) + * exp.mantissa (ee.mmmmmm) + * ee = 00 = 10^-1 (0.mmmmmm) + * ee = 01 = 10^0 (m.mmmmm) + * ee = 10 = 10^1 (mm.mmmm) + * ee = 11 = 10^2 (mmm.mmm) + * + * Simple conversion function: + * + * static u32 + * float_to_csc_11(float f) + * { + * u32 exp; + * u32 mant; + * u32 ret; + * + * if (f < 0) + * f = -f; + * + * if (f >= 1) { + * exp = 0x7; + * mant = 1 << 8; + * } else { + * for (exp = 0; exp < 3 && f < 0.5; exp++) + * f *= 2.0; + * mant = (f * (1 << 9) + 0.5); + * if (mant >= (1 << 9)) + * mant = (1 << 9) - 1; + * } + * ret = (exp << 9) | mant; + * return ret; + * } + */ + +/* + * Behold, magic numbers! If we plant them they might grow a big + * s-video cable to the sky... or something. + * + * Pre-converted to appropriate hex value. + */ + +/* + * PAL & NTSC values for composite & s-video connections + */ +static const struct color_conversion ntsc_m_csc_composite = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, + .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, + .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, +}; + +static const struct video_levels ntsc_m_levels_composite = { + .blank = 225, .black = 267, .burst = 113, +}; + +static const struct color_conversion ntsc_m_csc_svideo = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, + .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, + .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, +}; + +static const struct video_levels ntsc_m_levels_svideo = { + .blank = 266, .black = 316, .burst = 133, +}; + +static const struct color_conversion ntsc_j_csc_composite = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119, + .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00, + .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00, +}; + +static const struct video_levels ntsc_j_levels_composite = { + .blank = 225, .black = 225, .burst = 113, +}; + +static const struct color_conversion ntsc_j_csc_svideo = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c, + .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00, + .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00, +}; + +static const struct video_levels ntsc_j_levels_svideo = { + .blank = 266, .black = 266, .burst = 133, +}; + +static const struct color_conversion pal_csc_composite = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113, + .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00, + .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00, +}; + +static const struct video_levels pal_levels_composite = { + .blank = 237, .black = 237, .burst = 118, +}; + +static const struct color_conversion pal_csc_svideo = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145, + .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00, + .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00, +}; + +static const struct video_levels pal_levels_svideo = { + .blank = 280, .black = 280, .burst = 139, +}; + +static const struct color_conversion pal_m_csc_composite = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, + .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, + .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, +}; + +static const struct video_levels pal_m_levels_composite = { + .blank = 225, .black = 267, .burst = 113, +}; + +static const struct color_conversion pal_m_csc_svideo = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, + .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, + .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, +}; + +static const struct video_levels pal_m_levels_svideo = { + .blank = 266, .black = 316, .burst = 133, +}; + +static const struct color_conversion pal_n_csc_composite = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, + .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, + .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, +}; + +static const struct video_levels pal_n_levels_composite = { + .blank = 225, .black = 267, .burst = 118, +}; + +static const struct color_conversion pal_n_csc_svideo = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, + .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, + .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, +}; + +static const struct video_levels pal_n_levels_svideo = { + .blank = 266, .black = 316, .burst = 139, +}; + +/* + * Component connections + */ +static const struct color_conversion sdtv_csc_yprpb = { + .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146, + .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00, + .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00, +}; + +static const struct color_conversion sdtv_csc_rgb = { + .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, + .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, + .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, +}; + +static const struct color_conversion hdtv_csc_yprpb = { + .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146, + .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00, + .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00, +}; + +static const struct color_conversion hdtv_csc_rgb = { + .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, + .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, + .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, +}; + +static const struct video_levels component_levels = { + .blank = 279, .black = 279, .burst = 0, +}; + + +struct tv_mode { + char *name; + int clock; + int refresh; /* in millihertz (for precision) */ + u32 oversample; + int hsync_end, hblank_start, hblank_end, htotal; + bool progressive, trilevel_sync, component_only; + int vsync_start_f1, vsync_start_f2, vsync_len; + bool veq_ena; + int veq_start_f1, veq_start_f2, veq_len; + int vi_end_f1, vi_end_f2, nbr_end; + bool burst_ena; + int hburst_start, hburst_len; + int vburst_start_f1, vburst_end_f1; + int vburst_start_f2, vburst_end_f2; + int vburst_start_f3, vburst_end_f3; + int vburst_start_f4, vburst_end_f4; + /* + * subcarrier programming + */ + int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc; + u32 sc_reset; + bool pal_burst; + /* + * blank/black levels + */ + const struct video_levels *composite_levels, *svideo_levels; + const struct color_conversion *composite_color, *svideo_color; + const u32 *filter_table; + int max_srcw; +}; + + +/* + * Sub carrier DDA + * + * I think this works as follows: + * + * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096 + * + * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value + * + * So, + * dda1_ideal = subcarrier/pixel * 4096 + * dda1_inc = floor (dda1_ideal) + * dda2 = dda1_ideal - dda1_inc + * + * then pick a ratio for dda2 that gives the closest approximation. If + * you can't get close enough, you can play with dda3 as well. This + * seems likely to happen when dda2 is small as the jumps would be larger + * + * To invert this, + * + * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size) + * + * The constants below were all computed using a 107.520MHz clock + */ + +/** + * Register programming values for TV modes. + * + * These values account for -1s required. + */ + +const static struct tv_mode tv_modes[] = { + { + .name = "NTSC-M", + .clock = 107520, + .refresh = 29970, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ + + .hsync_end = 64, .hblank_end = 124, + .hblank_start = 836, .htotal = 857, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 20, .vi_end_f2 = 21, + .nbr_end = 240, + + .burst_ena = TRUE, + .hburst_start = 72, .hburst_len = 34, + .vburst_start_f1 = 9, .vburst_end_f1 = 240, + .vburst_start_f2 = 10, .vburst_end_f2 = 240, + .vburst_start_f3 = 9, .vburst_end_f3 = 240, + .vburst_start_f4 = 10, .vburst_end_f4 = 240, + + /* desired 3.5800000 actual 3.5800000 clock 107.52 */ + .dda1_inc = 136, + .dda2_inc = 7624, .dda2_size = 20013, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_4, + .pal_burst = FALSE, + + .composite_levels = &ntsc_m_levels_composite, + .composite_color = &ntsc_m_csc_composite, + .svideo_levels = &ntsc_m_levels_svideo, + .svideo_color = &ntsc_m_csc_svideo, + + .filter_table = filter_table, + }, + { + .name = "NTSC-443", + .clock = 107520, + .refresh = 29970, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */ + .hsync_end = 64, .hblank_end = 124, + .hblank_start = 836, .htotal = 857, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 20, .vi_end_f2 = 21, + .nbr_end = 240, + + .burst_ena = 8, + .hburst_start = 72, .hburst_len = 34, + .vburst_start_f1 = 9, .vburst_end_f1 = 240, + .vburst_start_f2 = 10, .vburst_end_f2 = 240, + .vburst_start_f3 = 9, .vburst_end_f3 = 240, + .vburst_start_f4 = 10, .vburst_end_f4 = 240, + + /* desired 4.4336180 actual 4.4336180 clock 107.52 */ + .dda1_inc = 168, + .dda2_inc = 18557, .dda2_size = 20625, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_8, + .pal_burst = TRUE, + + .composite_levels = &ntsc_m_levels_composite, + .composite_color = &ntsc_m_csc_composite, + .svideo_levels = &ntsc_m_levels_svideo, + .svideo_color = &ntsc_m_csc_svideo, + + .filter_table = filter_table, + }, + { + .name = "NTSC-J", + .clock = 107520, + .refresh = 29970, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + + /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ + .hsync_end = 64, .hblank_end = 124, + .hblank_start = 836, .htotal = 857, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 20, .vi_end_f2 = 21, + .nbr_end = 240, + + .burst_ena = TRUE, + .hburst_start = 72, .hburst_len = 34, + .vburst_start_f1 = 9, .vburst_end_f1 = 240, + .vburst_start_f2 = 10, .vburst_end_f2 = 240, + .vburst_start_f3 = 9, .vburst_end_f3 = 240, + .vburst_start_f4 = 10, .vburst_end_f4 = 240, + + /* desired 3.5800000 actual 3.5800000 clock 107.52 */ + .dda1_inc = 136, + .dda2_inc = 7624, .dda2_size = 20013, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_4, + .pal_burst = FALSE, + + .composite_levels = &ntsc_j_levels_composite, + .composite_color = &ntsc_j_csc_composite, + .svideo_levels = &ntsc_j_levels_svideo, + .svideo_color = &ntsc_j_csc_svideo, + + .filter_table = filter_table, + }, + { + .name = "PAL-M", + .clock = 107520, + .refresh = 29970, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + + /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ + .hsync_end = 64, .hblank_end = 124, + .hblank_start = 836, .htotal = 857, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 20, .vi_end_f2 = 21, + .nbr_end = 240, + + .burst_ena = TRUE, + .hburst_start = 72, .hburst_len = 34, + .vburst_start_f1 = 9, .vburst_end_f1 = 240, + .vburst_start_f2 = 10, .vburst_end_f2 = 240, + .vburst_start_f3 = 9, .vburst_end_f3 = 240, + .vburst_start_f4 = 10, .vburst_end_f4 = 240, + + /* desired 3.5800000 actual 3.5800000 clock 107.52 */ + .dda1_inc = 136, + .dda2_inc = 7624, .dda2_size = 20013, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_4, + .pal_burst = FALSE, + + .composite_levels = &pal_m_levels_composite, + .composite_color = &pal_m_csc_composite, + .svideo_levels = &pal_m_levels_svideo, + .svideo_color = &pal_m_csc_svideo, + + .filter_table = filter_table, + }, + { + /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ + .name = "PAL-N", + .clock = 107520, + .refresh = 25000, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + + .hsync_end = 64, .hblank_end = 128, + .hblank_start = 844, .htotal = 863, + + .progressive = FALSE, .trilevel_sync = FALSE, + + + .vsync_start_f1 = 6, .vsync_start_f2 = 7, + .vsync_len = 6, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 18, + + .vi_end_f1 = 24, .vi_end_f2 = 25, + .nbr_end = 286, + + .burst_ena = TRUE, + .hburst_start = 73, .hburst_len = 34, + .vburst_start_f1 = 8, .vburst_end_f1 = 285, + .vburst_start_f2 = 8, .vburst_end_f2 = 286, + .vburst_start_f3 = 9, .vburst_end_f3 = 286, + .vburst_start_f4 = 9, .vburst_end_f4 = 285, + + + /* desired 4.4336180 actual 4.4336180 clock 107.52 */ + .dda1_inc = 168, + .dda2_inc = 18557, .dda2_size = 20625, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_8, + .pal_burst = TRUE, + + .composite_levels = &pal_n_levels_composite, + .composite_color = &pal_n_csc_composite, + .svideo_levels = &pal_n_levels_svideo, + .svideo_color = &pal_n_csc_svideo, + + .filter_table = filter_table, + }, + { + /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ + .name = "PAL", + .clock = 107520, + .refresh = 25000, + .oversample = TV_OVERSAMPLE_8X, + .component_only = 0, + + .hsync_end = 64, .hblank_end = 128, + .hblank_start = 844, .htotal = 863, + + .progressive = FALSE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 5, .vsync_start_f2 = 6, + .vsync_len = 5, + + .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_start_f2 = 1, .veq_len = 15, + + .vi_end_f1 = 24, .vi_end_f2 = 25, + .nbr_end = 286, + + .burst_ena = TRUE, + .hburst_start = 73, .hburst_len = 32, + .vburst_start_f1 = 8, .vburst_end_f1 = 285, + .vburst_start_f2 = 8, .vburst_end_f2 = 286, + .vburst_start_f3 = 9, .vburst_end_f3 = 286, + .vburst_start_f4 = 9, .vburst_end_f4 = 285, + + /* desired 4.4336180 actual 4.4336180 clock 107.52 */ + .dda1_inc = 168, + .dda2_inc = 18557, .dda2_size = 20625, + .dda3_inc = 0, .dda3_size = 0, + .sc_reset = TV_SC_RESET_EVERY_8, + .pal_burst = TRUE, + + .composite_levels = &pal_levels_composite, + .composite_color = &pal_csc_composite, + .svideo_levels = &pal_levels_svideo, + .svideo_color = &pal_csc_svideo, + + .filter_table = filter_table, + }, + { + .name = "480p@59.94Hz", + .clock = 107520, + .refresh = 59940, + .oversample = TV_OVERSAMPLE_4X, + .component_only = 1, + + .hsync_end = 64, .hblank_end = 122, + .hblank_start = 842, .htotal = 857, + + .progressive = TRUE,.trilevel_sync = FALSE, + + .vsync_start_f1 = 12, .vsync_start_f2 = 12, + .vsync_len = 12, + + .veq_ena = FALSE, + + .vi_end_f1 = 44, .vi_end_f2 = 44, + .nbr_end = 496, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "480p@60Hz", + .clock = 107520, + .refresh = 60000, + .oversample = TV_OVERSAMPLE_4X, + .component_only = 1, + + .hsync_end = 64, .hblank_end = 122, + .hblank_start = 842, .htotal = 856, + + .progressive = TRUE,.trilevel_sync = FALSE, + + .vsync_start_f1 = 12, .vsync_start_f2 = 12, + .vsync_len = 12, + + .veq_ena = FALSE, + + .vi_end_f1 = 44, .vi_end_f2 = 44, + .nbr_end = 496, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "576p", + .clock = 107520, + .refresh = 50000, + .oversample = TV_OVERSAMPLE_4X, + .component_only = 1, + + .hsync_end = 64, .hblank_end = 139, + .hblank_start = 859, .htotal = 863, + + .progressive = TRUE, .trilevel_sync = FALSE, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = FALSE, + + .vi_end_f1 = 48, .vi_end_f2 = 48, + .nbr_end = 575, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "720p@60Hz", + .clock = 148800, + .refresh = 60000, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 80, .hblank_end = 300, + .hblank_start = 1580, .htotal = 1649, + + .progressive = TRUE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = FALSE, + + .vi_end_f1 = 29, .vi_end_f2 = 29, + .nbr_end = 719, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "720p@59.94Hz", + .clock = 148800, + .refresh = 59940, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 80, .hblank_end = 300, + .hblank_start = 1580, .htotal = 1651, + + .progressive = TRUE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = FALSE, + + .vi_end_f1 = 29, .vi_end_f2 = 29, + .nbr_end = 719, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "720p@50Hz", + .clock = 148800, + .refresh = 50000, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 80, .hblank_end = 300, + .hblank_start = 1580, .htotal = 1979, + + .progressive = TRUE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 10, .vsync_start_f2 = 10, + .vsync_len = 10, + + .veq_ena = FALSE, + + .vi_end_f1 = 29, .vi_end_f2 = 29, + .nbr_end = 719, + + .burst_ena = FALSE, + + .filter_table = filter_table, + .max_srcw = 800 + }, + { + .name = "1080i@50Hz", + .clock = 148800, + .refresh = 25000, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 88, .hblank_end = 235, + .hblank_start = 2155, .htotal = 2639, + + .progressive = FALSE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 4, .vsync_start_f2 = 5, + .vsync_len = 10, + + .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_start_f2 = 4, .veq_len = 10, + + + .vi_end_f1 = 21, .vi_end_f2 = 22, + .nbr_end = 539, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "1080i@60Hz", + .clock = 148800, + .refresh = 30000, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 88, .hblank_end = 235, + .hblank_start = 2155, .htotal = 2199, + + .progressive = FALSE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 4, .vsync_start_f2 = 5, + .vsync_len = 10, + + .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_start_f2 = 4, .veq_len = 10, + + + .vi_end_f1 = 21, .vi_end_f2 = 22, + .nbr_end = 539, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, + { + .name = "1080i@59.94Hz", + .clock = 148800, + .refresh = 29970, + .oversample = TV_OVERSAMPLE_2X, + .component_only = 1, + + .hsync_end = 88, .hblank_end = 235, + .hblank_start = 2155, .htotal = 2200, + + .progressive = FALSE, .trilevel_sync = TRUE, + + .vsync_start_f1 = 4, .vsync_start_f2 = 5, + .vsync_len = 10, + + .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_start_f2 = 4, .veq_len = 10, + + + .vi_end_f1 = 21, .vi_end_f2 = 22, + .nbr_end = 539, + + .burst_ena = FALSE, + + .filter_table = filter_table, + }, +}; + +#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0]) + +static void +intel_tv_dpms(struct drm_output *output, int mode) +{ + struct drm_device *dev = output->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + switch(mode) { + case DPMSModeOn: + I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE); + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); + break; + } +} + +static void +intel_tv_save(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; + int i; + + tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1); + tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2); + tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3); + tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1); + tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2); + tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3); + tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4); + tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5); + tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6); + tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7); + tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1); + tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2); + tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3); + + tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y); + tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2); + tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U); + tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2); + tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V); + tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2); + tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS); + tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL); + tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS); + tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE); + tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1); + tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2); + tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3); + + for (i = 0; i < 60; i++) + tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2)); + for (i = 0; i < 60; i++) + tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2)); + for (i = 0; i < 43; i++) + tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2)); + for (i = 0; i < 43; i++) + tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2)); + + tv_priv->save_TV_DAC = I915_READ(TV_DAC); + tv_priv->save_TV_CTL = I915_READ(TV_CTL); +} + +static void +intel_tv_restore(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; + struct drm_crtc *crtc = output->crtc; + struct intel_crtc *intel_crtc; + int i; + + /* FIXME: No CRTC? */ + if (!crtc) + return; + + intel_crtc = crtc->driver_private; + I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1); + I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2); + I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3); + I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1); + I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2); + I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3); + I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4); + I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5); + I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6); + I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7); + I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1); + I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2); + I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3); + + I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y); + I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2); + I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U); + I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2); + I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V); + I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2); + I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS); + I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL); + + { + int pipeconf_reg = (intel_crtc->pipe == 0) ? + PIPEACONF : PIPEBCONF; + int dspcntr_reg = (intel_crtc->plane == 0) ? + DSPACNTR : DSPBCNTR; + int pipeconf = I915_READ(pipeconf_reg); + int dspcntr = I915_READ(dspcntr_reg); + int dspbase_reg = (intel_crtc->plane == 0) ? + DSPABASE : DSPBBASE; + /* Pipe must be off here */ + I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + + if (!IS_I9XX(dev)) { + /* Wait for vblank for the disable to take effect */ + intel_wait_for_vblank(dev); + } + + I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); + /* Wait for vblank for the disable to take effect. */ + intel_wait_for_vblank(dev); + + /* Filter ctl must be set before TV_WIN_SIZE */ + I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1); + I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2); + I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3); + I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS); + I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE); + I915_WRITE(pipeconf_reg, pipeconf); + I915_WRITE(dspcntr_reg, dspcntr); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + } + + for (i = 0; i < 60; i++) + I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]); + for (i = 0; i < 60; i++) + I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]); + for (i = 0; i < 43; i++) + I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]); + for (i = 0; i < 43; i++) + I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]); + + I915_WRITE(TV_DAC, tv_priv->save_TV_DAC); + I915_WRITE(TV_CTL, tv_priv->save_TV_CTL); +} + +static const struct tv_mode * +intel_tv_mode_lookup (char *tv_format) +{ + int i; + + for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) { + const struct tv_mode *tv_mode = &tv_modes[i]; + + if (!strcmp(tv_format, tv_mode->name)) + return tv_mode; + } + return NULL; +} + +static const struct tv_mode * +intel_tv_mode_find (struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; + + return intel_tv_mode_lookup(tv_priv->tv_format); +} + +static enum drm_mode_status +intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode) +{ + const struct tv_mode *tv_mode = intel_tv_mode_find(output); + + /* Ensure TV refresh is close to desired refresh */ + if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1) + return MODE_OK; + return MODE_CLOCK_RANGE; +} + + +static bool +intel_tv_mode_fixup(struct drm_output *output, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = output->dev; + struct drm_mode_config *drm_config = &dev->mode_config; + const struct tv_mode *tv_mode = intel_tv_mode_find (output); + struct drm_output *other_output; + + if (!tv_mode) + return FALSE; + + /* FIXME: lock output list */ + list_for_each_entry(other_output, &drm_config->output_list, head) { + if (other_output != output && + other_output->crtc == output->crtc) + return FALSE; + } + + adjusted_mode->clock = tv_mode->clock; + return TRUE; +} + +static void +intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = output->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = output->crtc; + struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; + const struct tv_mode *tv_mode = intel_tv_mode_find(output); + u32 tv_ctl; + u32 hctl1, hctl2, hctl3; + u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; + u32 scctl1, scctl2, scctl3; + int i, j; + const struct video_levels *video_levels; + const struct color_conversion *color_conversion; + bool burst_ena; + + if (!tv_mode) + return; /* can't happen (mode_prepare prevents this) */ + + tv_ctl = 0; + + switch (tv_priv->type) { + default: + case TV_TYPE_UNKNOWN: + case TV_TYPE_COMPOSITE: + tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; + video_levels = tv_mode->composite_levels; + color_conversion = tv_mode->composite_color; + burst_ena = tv_mode->burst_ena; + break; + case TV_TYPE_COMPONENT: + tv_ctl |= TV_ENC_OUTPUT_COMPONENT; + video_levels = &component_levels; + if (tv_mode->burst_ena) + color_conversion = &sdtv_csc_yprpb; + else + color_conversion = &hdtv_csc_yprpb; + burst_ena = FALSE; + break; + case TV_TYPE_SVIDEO: + tv_ctl |= TV_ENC_OUTPUT_SVIDEO; + video_levels = tv_mode->svideo_levels; + color_conversion = tv_mode->svideo_color; + burst_ena = tv_mode->burst_ena; + break; + } + hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | + (tv_mode->htotal << TV_HTOTAL_SHIFT); + + hctl2 = (tv_mode->hburst_start << 16) | + (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT); + + if (burst_ena) + hctl2 |= TV_BURST_ENA; + + hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) | + (tv_mode->hblank_end << TV_HBLANK_END_SHIFT); + + vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) | + (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) | + (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT); + + vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) | + (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) | + (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT); + + vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) | + (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) | + (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT); + + if (tv_mode->veq_ena) + vctl3 |= TV_EQUAL_ENA; + + vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) | + (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT); + + vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) | + (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT); + + vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) | + (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT); + + vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | + (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); + + if (intel_crtc->pipe == 1) + tv_ctl |= TV_ENC_PIPEB_SELECT; + tv_ctl |= tv_mode->oversample; + + if (tv_mode->progressive) + tv_ctl |= TV_PROGRESSIVE; + if (tv_mode->trilevel_sync) + tv_ctl |= TV_TRILEVEL_SYNC; + if (tv_mode->pal_burst) + tv_ctl |= TV_PAL_BURST; + scctl1 = 0; + if (tv_mode->dda1_inc) + scctl1 |= TV_SC_DDA1_EN; + + if (tv_mode->dda2_inc) + scctl1 |= TV_SC_DDA2_EN; + + if (tv_mode->dda3_inc) + scctl1 |= TV_SC_DDA3_EN; + + scctl1 |= tv_mode->sc_reset; + scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; + scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT; + + scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | + tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT; + + scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT | + tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT; + + /* Enable two fixes for the chips that need them. */ + if (dev->pci_device < 0x2772) + tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX; + + I915_WRITE(TV_H_CTL_1, hctl1); + I915_WRITE(TV_H_CTL_2, hctl2); + I915_WRITE(TV_H_CTL_3, hctl3); + I915_WRITE(TV_V_CTL_1, vctl1); + I915_WRITE(TV_V_CTL_2, vctl2); + I915_WRITE(TV_V_CTL_3, vctl3); + I915_WRITE(TV_V_CTL_4, vctl4); + I915_WRITE(TV_V_CTL_5, vctl5); + I915_WRITE(TV_V_CTL_6, vctl6); + I915_WRITE(TV_V_CTL_7, vctl7); + I915_WRITE(TV_SC_CTL_1, scctl1); + I915_WRITE(TV_SC_CTL_2, scctl2); + I915_WRITE(TV_SC_CTL_3, scctl3); + + I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | + color_conversion->gy); + I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) | + color_conversion->ay); + I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | + color_conversion->gu); + I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | + color_conversion->au); + I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | + color_conversion->gv); + I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | + color_conversion->av); + + I915_WRITE(TV_CLR_KNOBS, 0x00606000); + I915_WRITE(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | + (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); + { + int pipeconf_reg = (intel_crtc->pipe == 0) ? + PIPEACONF : PIPEBCONF; + int dspcntr_reg = (intel_crtc->plane == 0) ? + DSPACNTR : DSPBCNTR; + int pipeconf = I915_READ(pipeconf_reg); + int dspcntr = I915_READ(dspcntr_reg); + int dspbase_reg = (intel_crtc->plane == 0) ? + DSPABASE : DSPBBASE; + int xpos = 0x0, ypos = 0x0; + unsigned int xsize, ysize; + /* Pipe must be off here */ + I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + + /* Wait for vblank for the disable to take effect */ + if (!IS_I9XX(dev)) + intel_wait_for_vblank(dev); + + I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); + /* Wait for vblank for the disable to take effect. */ + intel_wait_for_vblank(dev); + + /* Filter ctl must be set before TV_WIN_SIZE */ + I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); + xsize = tv_mode->hblank_start - tv_mode->hblank_end; + if (tv_mode->progressive) + ysize = tv_mode->nbr_end + 1; + else + ysize = 2*tv_mode->nbr_end + 1; + + xpos += tv_priv->margin[TV_MARGIN_LEFT]; + ypos += tv_priv->margin[TV_MARGIN_TOP]; + xsize -= (tv_priv->margin[TV_MARGIN_LEFT] + + tv_priv->margin[TV_MARGIN_RIGHT]); + ysize -= (tv_priv->margin[TV_MARGIN_TOP] + + tv_priv->margin[TV_MARGIN_BOTTOM]); + I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); + I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); + + I915_WRITE(pipeconf_reg, pipeconf); + I915_WRITE(dspcntr_reg, dspcntr); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + } + + j = 0; + for (i = 0; i < 60; i++) + I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); + for (i = 0; i < 60; i++) + I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); + for (i = 0; i < 43; i++) + I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); + for (i = 0; i < 43; i++) + I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); + I915_WRITE(TV_DAC, 0); + I915_WRITE(TV_CTL, tv_ctl); +} + +static const struct drm_display_mode reported_modes[] = { + { + .name = "NTSC 480i", + .clock = 107520, + .hdisplay = 1280, + .hsync_start = 1368, + .hsync_end = 1496, + .htotal = 1712, + + .vdisplay = 1024, + .vsync_start = 1027, + .vsync_end = 1034, + .vtotal = 1104, + .type = DRM_MODE_TYPE_DRIVER, + }, +}; + +/** + * Detects TV presence by checking for load. + * + * Requires that the current pipe's DPLL is active. + + * \return TRUE if TV is connected. + * \return FALSE if TV is disconnected. + */ +static int +intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + u32 tv_ctl, save_tv_ctl; + u32 tv_dac, save_tv_dac; + int type = TV_TYPE_UNKNOWN; + + tv_dac = I915_READ(TV_DAC); + /* + * Detect TV by polling) + */ + if (intel_output->load_detect_temp) { + /* TV not currently running, prod it with destructive detect */ + save_tv_dac = tv_dac; + tv_ctl = I915_READ(TV_CTL); + save_tv_ctl = tv_ctl; + tv_ctl &= ~TV_ENC_ENABLE; + tv_ctl &= ~TV_TEST_MODE_MASK; + tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; + tv_dac &= ~TVDAC_SENSE_MASK; + tv_dac |= (TVDAC_STATE_CHG_EN | + TVDAC_A_SENSE_CTL | + TVDAC_B_SENSE_CTL | + TVDAC_C_SENSE_CTL | + DAC_CTL_OVERRIDE | + DAC_A_0_7_V | + DAC_B_0_7_V | + DAC_C_0_7_V); + I915_WRITE(TV_CTL, tv_ctl); + I915_WRITE(TV_DAC, tv_dac); + intel_wait_for_vblank(dev); + tv_dac = I915_READ(TV_DAC); + I915_WRITE(TV_DAC, save_tv_dac); + I915_WRITE(TV_CTL, save_tv_ctl); + } + /* + * A B C + * 0 1 1 Composite + * 1 0 X svideo + * 0 0 0 Component + */ + if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { + DRM_DEBUG("Detected Composite TV connection\n"); + type = TV_TYPE_COMPOSITE; + } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { + DRM_DEBUG("Detected S-Video TV connection\n"); + type = TV_TYPE_SVIDEO; + } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { + DRM_DEBUG("Detected Component TV connection\n"); + type = TV_TYPE_COMPONENT; + } else { + DRM_DEBUG("No TV connection detected\n"); + type = TV_TYPE_NONE; + } + + return type; +} + +static int +intel_tv_format_configure_property (struct drm_output *output); + +/** + * Detect the TV connection. + * + * Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure + * we have a pipe programmed in order to probe the TV. + */ +static enum drm_output_status +intel_tv_detect(struct drm_output *output) +{ + struct drm_crtc *crtc; + struct drm_display_mode mode; + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; + int dpms_mode; + int type = tv_priv->type; + + mode = reported_modes[0]; + drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); +#if 0 + /* FIXME: pipe allocation for load detection */ + crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode); + if (crtc) { + type = intel_tv_detect_type(crtc, output); + i830ReleaseLoadDetectPipe (output, dpms_mode); + } +#endif + if (type != tv_priv->type) { + tv_priv->type = type; + intel_tv_format_configure_property (output); + } + + switch (type) { + case TV_TYPE_NONE: + return output_status_disconnected; + case TV_TYPE_UNKNOWN: + return output_status_unknown; + default: + return output_status_connected; + } +} + +static struct input_res { + char *name; + int w, h; +} input_res_table[] = +{ + {"640x480", 640, 480}, + {"800x600", 800, 600}, + {"1024x768", 1024, 768}, + {"1280x1024", 1280, 1024}, + {"848x480", 848, 480}, + {"1280x720", 1280, 720}, + {"1920x1080", 1920, 1080}, +}; + +/** + * Stub get_modes function. + * + * This should probably return a set of fixed modes, unless we can figure out + * how to probe modes off of TV connections. + */ + +static int +intel_tv_get_modes(struct drm_output *output) +{ + struct drm_display_mode *mode_ptr; + const struct tv_mode *tv_mode = intel_tv_mode_find(output); + int j; + + for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]); + j++) { + struct input_res *input = &input_res_table[j]; + unsigned int hactive_s = input->w; + unsigned int vactive_s = input->h; + + if (tv_mode->max_srcw && input->w > tv_mode->max_srcw) + continue; + + if (input->w > 1024 && (!tv_mode->progressive + && !tv_mode->component_only)) + continue; + + mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode), + DRM_MEM_DRIVER); + strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); + + mode_ptr->hdisplay = hactive_s; + mode_ptr->hsync_start = hactive_s + 1; + mode_ptr->hsync_end = hactive_s + 64; + if (mode_ptr->hsync_end <= mode_ptr->hsync_start) + mode_ptr->hsync_end = mode_ptr->hsync_start + 1; + mode_ptr->htotal = hactive_s + 96; + + mode_ptr->vdisplay = vactive_s; + mode_ptr->vsync_start = vactive_s + 1; + mode_ptr->vsync_end = vactive_s + 32; + if (mode_ptr->vsync_end <= mode_ptr->vsync_start) + mode_ptr->vsync_end = mode_ptr->vsync_start + 1; + mode_ptr->vtotal = vactive_s + 33; + + mode_ptr->clock = (int) (tv_mode->refresh * + mode_ptr->vtotal * + mode_ptr->htotal / 1000) / 1000; + + mode_ptr->type = DRM_MODE_TYPE_DRIVER; + drm_mode_probed_add(output, mode_ptr); + } + + return 0; +} + +static void +intel_tv_destroy (struct drm_output *output) +{ + if (output->driver_private) + drm_free(output->driver_private, sizeof(struct intel_tv_priv), + DRM_MEM_DRIVER); +} + +static bool +intel_tv_format_set_property(struct drm_output *output, + struct drm_property *prop, uint64_t val) +{ +#if 0 + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; + const struct tv_mode *tv_mode = + intel_tv_mode_lookup(tv_priv->tv_format); + int err; + + if (!tv_mode) + tv_mode = &tv_modes[0]; + err = RRChangeOutputProperty (output->randr_output, tv_format_atom, + XA_ATOM, 32, PropModeReplace, 1, + &tv_format_name_atoms[tv_mode - tv_modes], + FALSE, TRUE); + return err == Success; +#endif + return 0; +} + + +/** + * Configure the TV_FORMAT property to list only supported formats + * + * Unless the connector is component, list only the formats supported by + * svideo and composite + */ + +static int +intel_tv_format_configure_property(struct drm_output *output) +{ +#if 0 + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; + Atom current_atoms[NUM_TV_MODES]; + int num_atoms = 0; + int i; + + if (!output->randr_output) + return Success; + + for (i = 0; i < NUM_TV_MODES; i++) + if (!tv_modes[i].component_only || + tv_priv->type == TV_TYPE_COMPONENT) + current_atoms[num_atoms++] = tv_format_name_atoms[i]; + + return RRConfigureOutputProperty(output->randr_output, tv_format_atom, + TRUE, FALSE, FALSE, + num_atoms, (INT32 *) current_atoms); +#endif + return 0; +} + +static void +intel_tv_create_resources(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; + int i, err; + +#if 0 + /* Set up the tv_format property, which takes effect on mode set + * and accepts strings that match exactly + */ + tv_format_atom = MakeAtom(TV_FORMAT_NAME, sizeof(TV_FORMAT_NAME) - 1, + TRUE); + + for (i = 0; i < NUM_TV_MODES; i++) + tv_format_name_atoms[i] = MakeAtom (tv_modes[i].name, + strlen (tv_modes[i].name), + TRUE); + + err = intel_tv_format_configure_property (output); + + if (err != 0) { + xf86DrvMsg(dev->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + + /* Set the current value of the tv_format property */ + if (!intel_tv_format_set_property (output)) + xf86DrvMsg(dev->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + + for (i = 0; i < 4; i++) + { + INT32 range[2]; + margin_atoms[i] = MakeAtom(margin_names[i], strlen (margin_names[i]), + TRUE); + + range[0] = 0; + range[1] = 100; + err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i], + TRUE, TRUE, FALSE, 2, range); + + if (err != 0) + xf86DrvMsg(dev->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + + err = RRChangeOutputProperty(output->randr_output, margin_atoms[i], + XA_INTEGER, 32, PropModeReplace, + 1, &tv_priv->margin[i], + FALSE, TRUE); + if (err != 0) + xf86DrvMsg(dev->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } +#endif +} + +static bool +intel_tv_set_property(struct drm_output *output, struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = output->dev; + int ret = 0; + + if (property == dev->mode_config.tv_left_margin_property || + property == dev->mode_config.tv_right_margin_property || + property == dev->mode_config.tv_top_margin_property || + property == dev->mode_config.tv_bottom_margin_property) { + ret = drm_output_property_set_value(output, property, val); + } else { + /* TV mode handling here */ + } + + return ret; +} + +static const struct drm_output_funcs intel_tv_output_funcs = { + .dpms = intel_tv_dpms, + .save = intel_tv_save, + .restore = intel_tv_restore, + .mode_valid = intel_tv_mode_valid, + .mode_fixup = intel_tv_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_tv_mode_set, + .commit = intel_output_commit, + .detect = intel_tv_detect, + .get_modes = intel_tv_get_modes, + .cleanup = intel_tv_destroy, + .set_property = intel_tv_set_property, +}; + +void +intel_tv_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_output *output; + struct intel_output *intel_output; + struct intel_tv_priv *tv_priv; + u32 tv_dac_on, tv_dac_off, save_tv_dac; + + /* FIXME: better TV detection and/or quirks */ +#if 0 + if (tv_priv->quirk_flag & QUIRK_IGNORE_TV) + return; +#endif + if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) + return; + + /* + * Sanity check the TV output by checking to see if the + * DAC register holds a value + */ + save_tv_dac = I915_READ(TV_DAC); + + I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN); + tv_dac_on = I915_READ(TV_DAC); + + I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); + tv_dac_off = I915_READ(TV_DAC); + + I915_WRITE(TV_DAC, save_tv_dac); + + /* + * If the register does not hold the state change enable + * bit, (either as a 0 or a 1), assume it doesn't really + * exist + */ + if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 || + (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) + return; + + output = drm_output_create(dev, &intel_tv_output_funcs, + DRM_MODE_OUTPUT_TVDAC); + + if (!output) + return; + + intel_output = drm_calloc(1, sizeof(struct intel_output) + + sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); + if (!intel_output) { + drm_output_destroy(output); + return; + } + + tv_priv = (struct intel_tv_priv *)(intel_output + 1); + intel_output->type = INTEL_OUTPUT_TVOUT; + output->possible_crtcs = ((1 << 0) | (1 << 1)); + output->possible_clones = (1 << INTEL_OUTPUT_TVOUT); + intel_output->dev_priv = tv_priv; + tv_priv->type = TV_TYPE_UNKNOWN; + + tv_priv->tv_format = NULL; + + /* BIOS margin values */ + tv_priv->margin[TV_MARGIN_LEFT] = 54; + tv_priv->margin[TV_MARGIN_TOP] = 36; + tv_priv->margin[TV_MARGIN_RIGHT] = 46; + tv_priv->margin[TV_MARGIN_BOTTOM] = 37; + + if (!tv_priv->tv_format) + tv_priv->tv_format = kstrdup(tv_modes[0].name, GFP_KERNEL); + + output->driver_private = intel_output; + output->interlace_allowed = FALSE; + output->doublescan_allowed = FALSE; +} diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 19fec0fc..1432806d 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -1192,6 +1192,579 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); # define LVDS_B0B3_POWER_DOWN (0 << 2) # define LVDS_B0B3_POWER_UP (3 << 2) +#define TV_CTL 0x68000 +/** Enables the TV encoder */ +# define TV_ENC_ENABLE (1 << 31) +/** Sources the TV encoder input from pipe B instead of A. */ +# define TV_ENC_PIPEB_SELECT (1 << 30) +/** Outputs composite video (DAC A only) */ +# define TV_ENC_OUTPUT_COMPOSITE (0 << 28) +/** Outputs SVideo video (DAC B/C) */ +# define TV_ENC_OUTPUT_SVIDEO (1 << 28) +/** Outputs Component video (DAC A/B/C) */ +# define TV_ENC_OUTPUT_COMPONENT (2 << 28) +/** Outputs Composite and SVideo (DAC A/B/C) */ +# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE (3 << 28) +# define TV_TRILEVEL_SYNC (1 << 21) +/** Enables slow sync generation (945GM only) */ +# define TV_SLOW_SYNC (1 << 20) +/** Selects 4x oversampling for 480i and 576p */ +# define TV_OVERSAMPLE_4X (0 << 18) +/** Selects 2x oversampling for 720p and 1080i */ +# define TV_OVERSAMPLE_2X (1 << 18) +/** Selects no oversampling for 1080p */ +# define TV_OVERSAMPLE_NONE (2 << 18) +/** Selects 8x oversampling */ +# define TV_OVERSAMPLE_8X (3 << 18) +/** Selects progressive mode rather than interlaced */ +# define TV_PROGRESSIVE (1 << 17) +/** Sets the colorburst to PAL mode. Required for non-M PAL modes. */ +# define TV_PAL_BURST (1 << 16) +/** Field for setting delay of Y compared to C */ +# define TV_YC_SKEW_MASK (7 << 12) +/** Enables a fix for 480p/576p standard definition modes on the 915GM only */ +# define TV_ENC_SDP_FIX (1 << 11) +/** + * Enables a fix for the 915GM only. + * + * Not sure what it does. + */ +# define TV_ENC_C0_FIX (1 << 10) +/** Bits that must be preserved by software */ +# define TV_CTL_SAVE ((3 << 8) | (3 << 6)) +# define TV_FUSE_STATE_MASK (3 << 4) +/** Read-only state that reports all features enabled */ +# define TV_FUSE_STATE_ENABLED (0 << 4) +/** Read-only state that reports that Macrovision is disabled in hardware*/ +# define TV_FUSE_STATE_NO_MACROVISION (1 << 4) +/** Read-only state that reports that TV-out is disabled in hardware. */ +# define TV_FUSE_STATE_DISABLED (2 << 4) +/** Normal operation */ +# define TV_TEST_MODE_NORMAL (0 << 0) +/** Encoder test pattern 1 - combo pattern */ +# define TV_TEST_MODE_PATTERN_1 (1 << 0) +/** Encoder test pattern 2 - full screen vertical 75% color bars */ +# define TV_TEST_MODE_PATTERN_2 (2 << 0) +/** Encoder test pattern 3 - full screen horizontal 75% color bars */ +# define TV_TEST_MODE_PATTERN_3 (3 << 0) +/** Encoder test pattern 4 - random noise */ +# define TV_TEST_MODE_PATTERN_4 (4 << 0) +/** Encoder test pattern 5 - linear color ramps */ +# define TV_TEST_MODE_PATTERN_5 (5 << 0) +/** + * This test mode forces the DACs to 50% of full output. + * + * This is used for load detection in combination with TVDAC_SENSE_MASK + */ +# define TV_TEST_MODE_MONITOR_DETECT (7 << 0) +# define TV_TEST_MODE_MASK (7 << 0) +/** @} */ + +/** @defgroup TV_DAC + * @{ + */ +#define TV_DAC 0x68004 +/** + * Reports that DAC state change logic has reported change (RO). + * + * This gets cleared when TV_DAC_STATE_EN is cleared +*/ +# define TVDAC_STATE_CHG (1 << 31) +# define TVDAC_SENSE_MASK (7 << 28) +/** Reports that DAC A voltage is above the detect threshold */ +# define TVDAC_A_SENSE (1 << 30) +/** Reports that DAC B voltage is above the detect threshold */ +# define TVDAC_B_SENSE (1 << 29) +/** Reports that DAC C voltage is above the detect threshold */ +# define TVDAC_C_SENSE (1 << 28) +/** + * Enables DAC state detection logic, for load-based TV detection. + * + * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set + * to off, for load detection to work. + */ +# define TVDAC_STATE_CHG_EN (1 << 27) +/** Sets the DAC A sense value to high */ +# define TVDAC_A_SENSE_CTL (1 << 26) +/** Sets the DAC B sense value to high */ +# define TVDAC_B_SENSE_CTL (1 << 25) +/** Sets the DAC C sense value to high */ +# define TVDAC_C_SENSE_CTL (1 << 24) +/** Overrides the ENC_ENABLE and DAC voltage levels */ +# define DAC_CTL_OVERRIDE (1 << 7) +/** Sets the slew rate. Must be preserved in software */ +# define ENC_TVDAC_SLEW_FAST (1 << 6) +# define DAC_A_1_3_V (0 << 4) +# define DAC_A_1_1_V (1 << 4) +# define DAC_A_0_7_V (2 << 4) +# define DAC_A_OFF (3 << 4) +# define DAC_B_1_3_V (0 << 2) +# define DAC_B_1_1_V (1 << 2) +# define DAC_B_0_7_V (2 << 2) +# define DAC_B_OFF (3 << 2) +# define DAC_C_1_3_V (0 << 0) +# define DAC_C_1_1_V (1 << 0) +# define DAC_C_0_7_V (2 << 0) +# define DAC_C_OFF (3 << 0) +/** @} */ + +/** + * CSC coefficients are stored in a floating point format with 9 bits of + * mantissa and 2 or 3 bits of exponent. The exponent is represented as 2**-n, + * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with + * -1 (0x3) being the only legal negative value. + */ +#define TV_CSC_Y 0x68010 +# define TV_RY_MASK 0x07ff0000 +# define TV_RY_SHIFT 16 +# define TV_GY_MASK 0x00000fff +# define TV_GY_SHIFT 0 + +#define TV_CSC_Y2 0x68014 +# define TV_BY_MASK 0x07ff0000 +# define TV_BY_SHIFT 16 +/** + * Y attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AY_MASK 0x000003ff +# define TV_AY_SHIFT 0 + +#define TV_CSC_U 0x68018 +# define TV_RU_MASK 0x07ff0000 +# define TV_RU_SHIFT 16 +# define TV_GU_MASK 0x000007ff +# define TV_GU_SHIFT 0 + +#define TV_CSC_U2 0x6801c +# define TV_BU_MASK 0x07ff0000 +# define TV_BU_SHIFT 16 +/** + * U attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AU_MASK 0x000003ff +# define TV_AU_SHIFT 0 + +#define TV_CSC_V 0x68020 +# define TV_RV_MASK 0x0fff0000 +# define TV_RV_SHIFT 16 +# define TV_GV_MASK 0x000007ff +# define TV_GV_SHIFT 0 + +#define TV_CSC_V2 0x68024 +# define TV_BV_MASK 0x07ff0000 +# define TV_BV_SHIFT 16 +/** + * V attenuation for component video. + * + * Stored in 1.9 fixed point. + */ +# define TV_AV_MASK 0x000007ff +# define TV_AV_SHIFT 0 + +/** @defgroup TV_CSC_KNOBS + * @{ + */ +#define TV_CLR_KNOBS 0x68028 +/** 2s-complement brightness adjustment */ +# define TV_BRIGHTNESS_MASK 0xff000000 +# define TV_BRIGHTNESS_SHIFT 24 +/** Contrast adjustment, as a 2.6 unsigned floating point number */ +# define TV_CONTRAST_MASK 0x00ff0000 +# define TV_CONTRAST_SHIFT 16 +/** Saturation adjustment, as a 2.6 unsigned floating point number */ +# define TV_SATURATION_MASK 0x0000ff00 +# define TV_SATURATION_SHIFT 8 +/** Hue adjustment, as an integer phase angle in degrees */ +# define TV_HUE_MASK 0x000000ff +# define TV_HUE_SHIFT 0 +/** @} */ + +/** @defgroup TV_CLR_LEVEL + * @{ + */ +#define TV_CLR_LEVEL 0x6802c +/** Controls the DAC level for black */ +# define TV_BLACK_LEVEL_MASK 0x01ff0000 +# define TV_BLACK_LEVEL_SHIFT 16 +/** Controls the DAC level for blanking */ +# define TV_BLANK_LEVEL_MASK 0x000001ff +# define TV_BLANK_LEVEL_SHIFT 0 +/* @} */ + +/** @defgroup TV_H_CTL_1 + * @{ + */ +#define TV_H_CTL_1 0x68030 +/** Number of pixels in the hsync. */ +# define TV_HSYNC_END_MASK 0x1fff0000 +# define TV_HSYNC_END_SHIFT 16 +/** Total number of pixels minus one in the line (display and blanking). */ +# define TV_HTOTAL_MASK 0x00001fff +# define TV_HTOTAL_SHIFT 0 +/** @} */ + +/** @defgroup TV_H_CTL_2 + * @{ + */ +#define TV_H_CTL_2 0x68034 +/** Enables the colorburst (needed for non-component color) */ +# define TV_BURST_ENA (1 << 31) +/** Offset of the colorburst from the start of hsync, in pixels minus one. */ +# define TV_HBURST_START_SHIFT 16 +# define TV_HBURST_START_MASK 0x1fff0000 +/** Length of the colorburst */ +# define TV_HBURST_LEN_SHIFT 0 +# define TV_HBURST_LEN_MASK 0x0001fff +/** @} */ + +/** @defgroup TV_H_CTL_3 + * @{ + */ +#define TV_H_CTL_3 0x68038 +/** End of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_END_SHIFT 16 +# define TV_HBLANK_END_MASK 0x1fff0000 +/** Start of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_START_SHIFT 0 +# define TV_HBLANK_START_MASK 0x0001fff +/** @} */ + +/** @defgroup TV_V_CTL_1 + * @{ + */ +#define TV_V_CTL_1 0x6803c +/** XXX */ +# define TV_NBR_END_SHIFT 16 +# define TV_NBR_END_MASK 0x07ff0000 +/** XXX */ +# define TV_VI_END_F1_SHIFT 8 +# define TV_VI_END_F1_MASK 0x00003f00 +/** XXX */ +# define TV_VI_END_F2_SHIFT 0 +# define TV_VI_END_F2_MASK 0x0000003f +/** @} */ + +/** @defgroup TV_V_CTL_2 + * @{ + */ +#define TV_V_CTL_2 0x68040 +/** Length of vsync, in half lines */ +# define TV_VSYNC_LEN_MASK 0x07ff0000 +# define TV_VSYNC_LEN_SHIFT 16 +/** Offset of the start of vsync in field 1, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F1_MASK 0x00007f00 +# define TV_VSYNC_START_F1_SHIFT 8 +/** + * Offset of the start of vsync in field 2, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F2_MASK 0x0000007f +# define TV_VSYNC_START_F2_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_3 + * @{ + */ +#define TV_V_CTL_3 0x68044 +/** Enables generation of the equalization signal */ +# define TV_EQUAL_ENA (1 << 31) +/** Length of vsync, in half lines */ +# define TV_VEQ_LEN_MASK 0x007f0000 +# define TV_VEQ_LEN_SHIFT 16 +/** Offset of the start of equalization in field 1, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F1_MASK 0x0007f00 +# define TV_VEQ_START_F1_SHIFT 8 +/** + * Offset of the start of equalization in field 2, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F2_MASK 0x000007f +# define TV_VEQ_START_F2_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_4 + * @{ + */ +#define TV_V_CTL_4 0x68048 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F1_MASK 0x003f0000 +# define TV_VBURST_START_F1_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F1_MASK 0x000000ff +# define TV_VBURST_END_F1_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_5 + * @{ + */ +#define TV_V_CTL_5 0x6804c +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F2_MASK 0x003f0000 +# define TV_VBURST_START_F2_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F2_MASK 0x000000ff +# define TV_VBURST_END_F2_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_6 + * @{ + */ +#define TV_V_CTL_6 0x68050 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F3_MASK 0x003f0000 +# define TV_VBURST_START_F3_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F3_MASK 0x000000ff +# define TV_VBURST_END_F3_SHIFT 0 +/** @} */ + +/** @defgroup TV_V_CTL_7 + * @{ + */ +#define TV_V_CTL_7 0x68054 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F4_MASK 0x003f0000 +# define TV_VBURST_START_F4_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F4_MASK 0x000000ff +# define TV_VBURST_END_F4_SHIFT 0 +/** @} */ + +/** @defgroup TV_SC_CTL_1 + * @{ + */ +#define TV_SC_CTL_1 0x68060 +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA1_EN (1 << 31) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA2_EN (1 << 30) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA3_EN (1 << 29) +/** Sets the subcarrier DDA to reset frequency every other field */ +# define TV_SC_RESET_EVERY_2 (0 << 24) +/** Sets the subcarrier DDA to reset frequency every fourth field */ +# define TV_SC_RESET_EVERY_4 (1 << 24) +/** Sets the subcarrier DDA to reset frequency every eighth field */ +# define TV_SC_RESET_EVERY_8 (2 << 24) +/** Sets the subcarrier DDA to never reset the frequency */ +# define TV_SC_RESET_NEVER (3 << 24) +/** Sets the peak amplitude of the colorburst.*/ +# define TV_BURST_LEVEL_MASK 0x00ff0000 +# define TV_BURST_LEVEL_SHIFT 16 +/** Sets the increment of the first subcarrier phase generation DDA */ +# define TV_SCDDA1_INC_MASK 0x00000fff +# define TV_SCDDA1_INC_SHIFT 0 +/** @} */ + +/** @defgroup TV_SC_CTL_2 + * @{ + */ +#define TV_SC_CTL_2 0x68064 +/** Sets the rollover for the second subcarrier phase generation DDA */ +# define TV_SCDDA2_SIZE_MASK 0x7fff0000 +# define TV_SCDDA2_SIZE_SHIFT 16 +/** Sets the increent of the second subcarrier phase generation DDA */ +# define TV_SCDDA2_INC_MASK 0x00007fff +# define TV_SCDDA2_INC_SHIFT 0 +/** @} */ + +/** @defgroup TV_SC_CTL_3 + * @{ + */ +#define TV_SC_CTL_3 0x68068 +/** Sets the rollover for the third subcarrier phase generation DDA */ +# define TV_SCDDA3_SIZE_MASK 0x7fff0000 +# define TV_SCDDA3_SIZE_SHIFT 16 +/** Sets the increent of the third subcarrier phase generation DDA */ +# define TV_SCDDA3_INC_MASK 0x00007fff +# define TV_SCDDA3_INC_SHIFT 0 +/** @} */ + +/** @defgroup TV_WIN_POS + * @{ + */ +#define TV_WIN_POS 0x68070 +/** X coordinate of the display from the start of horizontal active */ +# define TV_XPOS_MASK 0x1fff0000 +# define TV_XPOS_SHIFT 16 +/** Y coordinate of the display from the start of vertical active (NBR) */ +# define TV_YPOS_MASK 0x00000fff +# define TV_YPOS_SHIFT 0 +/** @} */ + +/** @defgroup TV_WIN_SIZE + * @{ + */ +#define TV_WIN_SIZE 0x68074 +/** Horizontal size of the display window, measured in pixels*/ +# define TV_XSIZE_MASK 0x1fff0000 +# define TV_XSIZE_SHIFT 16 +/** + * Vertical size of the display window, measured in pixels. + * + * Must be even for interlaced modes. + */ +# define TV_YSIZE_MASK 0x00000fff +# define TV_YSIZE_SHIFT 0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_1 + * @{ + */ +#define TV_FILTER_CTL_1 0x68080 +/** + * Enables automatic scaling calculation. + * + * If set, the rest of the registers are ignored, and the calculated values can + * be read back from the register. + */ +# define TV_AUTO_SCALE (1 << 31) +/** + * Disables the vertical filter. + * + * This is required on modes more than 1024 pixels wide */ +# define TV_V_FILTER_BYPASS (1 << 29) +/** Enables adaptive vertical filtering */ +# define TV_VADAPT (1 << 28) +# define TV_VADAPT_MODE_MASK (3 << 26) +/** Selects the least adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_LEAST (0 << 26) +/** Selects the moderately adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MODERATE (1 << 26) +/** Selects the most adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MOST (3 << 26) +/** + * Sets the horizontal scaling factor. + * + * This should be the fractional part of the horizontal scaling factor divided + * by the oversampling rate. TV_HSCALE should be less than 1, and set to: + * + * (src width - 1) / ((oversample * dest width) - 1) + */ +# define TV_HSCALE_FRAC_MASK 0x00003fff +# define TV_HSCALE_FRAC_SHIFT 0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_2 + * @{ + */ +#define TV_FILTER_CTL_2 0x68084 +/** + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1) + */ +# define TV_VSCALE_INT_MASK 0x00038000 +# define TV_VSCALE_INT_SHIFT 15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * \sa TV_VSCALE_INT_MASK + */ +# define TV_VSCALE_FRAC_MASK 0x00007fff +# define TV_VSCALE_FRAC_SHIFT 0 +/** @} */ + +/** @defgroup TV_FILTER_CTL_3 + * @{ + */ +#define TV_FILTER_CTL_3 0x68088 +/** + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1)) + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + */ +# define TV_VSCALE_IP_INT_MASK 0x00038000 +# define TV_VSCALE_IP_INT_SHIFT 15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + * + * \sa TV_VSCALE_IP_INT_MASK + */ +# define TV_VSCALE_IP_FRAC_MASK 0x00007fff +# define TV_VSCALE_IP_FRAC_SHIFT 0 +/** @} */ + +/** @defgroup TV_CC_CONTROL + * @{ + */ +#define TV_CC_CONTROL 0x68090 +# define TV_CC_ENABLE (1 << 31) +/** + * Specifies which field to send the CC data in. + * + * CC data is usually sent in field 0. + */ +# define TV_CC_FID_MASK (1 << 27) +# define TV_CC_FID_SHIFT 27 +/** Sets the horizontal position of the CC data. Usually 135. */ +# define TV_CC_HOFF_MASK 0x03ff0000 +# define TV_CC_HOFF_SHIFT 16 +/** Sets the vertical position of the CC data. Usually 21 */ +# define TV_CC_LINE_MASK 0x0000003f +# define TV_CC_LINE_SHIFT 0 +/** @} */ + +/** @defgroup TV_CC_DATA + * @{ + */ +#define TV_CC_DATA 0x68094 +# define TV_CC_RDY (1 << 31) +/** Second word of CC data to be transmitted. */ +# define TV_CC_DATA_2_MASK 0x007f0000 +# define TV_CC_DATA_2_SHIFT 16 +/** First word of CC data to be transmitted. */ +# define TV_CC_DATA_1_MASK 0x0000007f +# define TV_CC_DATA_1_SHIFT 0 +/** @} + */ + +/** @{ */ +#define TV_H_LUMA_0 0x68100 +#define TV_H_LUMA_59 0x681ec +#define TV_H_CHROMA_0 0x68200 +#define TV_H_CHROMA_59 0x682ec +#define TV_V_LUMA_0 0x68300 +#define TV_V_LUMA_42 0x683a8 +#define TV_V_CHROMA_0 0x68400 +#define TV_V_CHROMA_42 0x684a8 + #define PIPEACONF 0x70008 #define PIPEACONF_ENABLE (1<<31) #define PIPEACONF_DISABLE 0 -- cgit v1.2.3 From 8caf6e95712bfae8d1a42ffabafcbb9686766116 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 19 Feb 2008 15:17:24 +0000 Subject: Fix up conflicts for DRI2 (untested) --- linux-core/i915_fence.c | 6 +++--- shared-core/i915_dma.c | 38 +++++--------------------------------- shared-core/i915_init.c | 13 +++++++++++++ 3 files changed, 21 insertions(+), 36 deletions(-) diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index de64a4f2..0f6cdeef 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -94,7 +94,7 @@ static void i915_fence_flush(struct drm_device *dev, static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, uint32_t waiting_types) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[0]; uint32_t sequence; @@ -147,7 +147,7 @@ static int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, uint32_t flags, uint32_t *sequence, uint32_t *native_type) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; if (unlikely(!dev_priv)) return -EINVAL; @@ -179,7 +179,7 @@ static int i915_fence_wait(struct drm_fence_object *fence, int lazy, int interruptible, uint32_t mask) { struct drm_device *dev = fence->dev; - drm_i915_private_t *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[0]; int ret; diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 3d489231..11c000b9 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -101,7 +101,7 @@ setup_dri2_sarea(struct drm_device * dev, struct drm_file *file_priv, drm_i915_init_t * init) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; unsigned int *p, *end, *next; @@ -129,8 +129,8 @@ setup_dri2_sarea(struct drm_device * dev, while (p < end && DRI2_SAREA_BLOCK_TYPE(*p) != DRI2_SAREA_BLOCK_END) { switch (DRI2_SAREA_BLOCK_TYPE(*p)) { case DRI2_SAREA_BLOCK_LOCK: - dev->lock.hw_lock = (void *) (p + 1); - dev->sigdata.lock = dev->lock.hw_lock; + dev->primary->master->lock.hw_lock = (void *) (p + 1); + dev->sigdata.lock = dev->primary->master->lock.hw_lock; break; } next = DRI2_SAREA_BLOCK_NEXT(p); @@ -152,6 +152,7 @@ static int i915_initialize(struct drm_device * dev, { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); if (!dev_priv->mmio_map) { i915_dma_cleanup(dev); @@ -228,14 +229,13 @@ static int i915_initialize(struct drm_device * dev, #endif if (init->func == I915_INIT_DMA2) { - ret = setup_dri2_sarea(dev, file_priv, init); + int ret = setup_dri2_sarea(dev, file_priv, init); if (ret) { i915_dma_cleanup(dev); DRM_ERROR("could not set up dri2 sarea\n"); return ret; } } - return 0; } @@ -1390,34 +1390,6 @@ static int i915_set_status_page(struct drm_device *dev, void *data, return 0; } -#if 0 /* FIXME DRI2 */ -void i915_driver_lastclose(struct drm_device * dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - if (drm_getsarea(dev) && dev_priv->sarea_priv) - i915_do_cleanup_pageflip(dev); - if (dev_priv->agp_heap) - i915_mem_takedown(&(dev_priv->agp_heap)); - - if (dev_priv->sarea_kmap.virtual) { - drm_bo_kunmap(&dev_priv->sarea_kmap); - dev_priv->sarea_kmap.virtual = NULL; - dev->lock.hw_lock = NULL; - dev->sigdata.lock = NULL; - } - - if (dev_priv->sarea_bo) { - mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(&dev_priv->sarea_bo); - mutex_unlock(&dev->struct_mutex); - dev_priv->sarea_bo = NULL; - } - - i915_dma_cleanup(dev); -} -#endif - struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index c2d8964e..fe2fb389 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -269,6 +269,19 @@ int i915_driver_unload(struct drm_device *dev) drm_core_ioremapfree(&dev_priv->ring.map, dev); } #endif + if (dev_priv->sarea_kmap.virtual) { + drm_bo_kunmap(&dev_priv->sarea_kmap); + dev_priv->sarea_kmap.virtual = NULL; + dev->primary->master->lock.hw_lock = NULL; + dev->sigdata.lock = NULL; + } + + if (dev_priv->sarea_bo) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&dev_priv->sarea_bo); + mutex_unlock(&dev->struct_mutex); + dev_priv->sarea_bo = NULL; + } if (dev_priv->status_page_dmah) { drm_pci_free(dev, dev_priv->status_page_dmah); -- cgit v1.2.3 From 2c409f9a07a9d815b95fc8a5a4705d7988afe5df Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 18 Feb 2008 10:39:21 +1000 Subject: ttm: make sure userspace can't destroy kernel create memory managers --- linux-core/drm_bo.c | 30 ++++++++++++++++++++---------- linux-core/drm_objects.h | 6 ++++-- shared-core/i915_init.c | 8 ++++---- shared-core/nouveau_mem.c | 6 +++--- shared-core/radeon_ms_drm.c | 8 ++++---- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1f3c2d2c..54b8baf8 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2178,7 +2178,7 @@ restart: return 0; } -int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type) +int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean) { struct drm_buffer_manager *bm = &dev->bm; struct drm_mem_type_manager *man = &bm->man[mem_type]; @@ -2194,6 +2194,13 @@ int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type) "memory manager type %u\n", mem_type); return ret; } + + if ((man->kern_init_type) && (kern_clean == 0)) { + DRM_ERROR("Trying to take down kernel initialized " + "memory manager type %u\n", mem_type); + return -EPERM; + } + man->use_type = 0; man->has_type = 0; @@ -2245,9 +2252,9 @@ static int drm_bo_lock_mm(struct drm_device *dev, unsigned mem_type) return ret; } -int drm_bo_init_mm(struct drm_device *dev, - unsigned type, - unsigned long p_offset, unsigned long p_size) +int drm_bo_init_mm(struct drm_device *dev, unsigned type, + unsigned long p_offset, unsigned long p_size, + int kern_init) { struct drm_buffer_manager *bm = &dev->bm; int ret = -EINVAL; @@ -2281,6 +2288,7 @@ int drm_bo_init_mm(struct drm_device *dev, } man->has_type = 1; man->use_type = 1; + man->kern_init_type = kern_init; INIT_LIST_HEAD(&man->lru); INIT_LIST_HEAD(&man->pinned); @@ -2313,7 +2321,7 @@ int drm_bo_driver_finish(struct drm_device *dev) man = &bm->man[i]; if (man->has_type) { man->use_type = 0; - if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) { + if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i, 1)) { ret = -EBUSY; DRM_ERROR("DRM memory manager type %d " "is not clean.\n", i); @@ -2384,7 +2392,7 @@ int drm_bo_driver_init(struct drm_device *dev) * Initialize the system memory buffer type. * Other types need to be driver / IOCTL initialized. */ - ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0); + ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0, 1); if (ret) goto out_unlock; @@ -2444,7 +2452,7 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_ goto out; } ret = drm_bo_init_mm(dev, arg->mem_type, - arg->p_offset, arg->p_size); + arg->p_offset, arg->p_size, 0); out: mutex_unlock(&dev->struct_mutex); @@ -2483,9 +2491,11 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f goto out; } ret = 0; - if (drm_bo_clean_mm(dev, arg->mem_type)) { - DRM_ERROR("Memory manager type %d not clean. " - "Delaying takedown\n", arg->mem_type); + if (ret = drm_bo_clean_mm(dev, arg->mem_type, 0)) { + if (ret == -EINVAL) + DRM_ERROR("Memory manager type %d not clean. " + "Delaying takedown\n", arg->mem_type); + ret = 0; } out: mutex_unlock(&dev->struct_mutex); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 7b585c3e..71da4b27 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -515,6 +515,7 @@ struct drm_buffer_object { struct drm_mem_type_manager { int has_type; int use_type; + int kern_init_type; struct drm_mm manager; struct list_head lru; struct list_head pinned; @@ -681,9 +682,10 @@ extern int drm_bo_mem_space(struct drm_buffer_object *bo, extern int drm_bo_move_buffer(struct drm_buffer_object *bo, uint64_t new_mem_flags, int no_wait, int move_unfenced); -extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type); +extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean); extern int drm_bo_init_mm(struct drm_device *dev, unsigned type, - unsigned long p_offset, unsigned long p_size); + unsigned long p_offset, unsigned long p_size, + int kern_init); extern int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, uint64_t flags, uint64_t mask, uint32_t hint, uint32_t fence_class, int use_old_fence_class, diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index fe2fb389..b2d3f0d0 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -167,8 +167,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); printk("setting up %ld bytes of VRAM space\n", prealloc_size); printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); - drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT); - drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT); + drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1); + drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT, 1); I915_WRITE(LP_RING + RING_LEN, 0); I915_WRITE(LP_RING + RING_HEAD, 0); @@ -305,11 +305,11 @@ int i915_driver_unload(struct drm_device *dev) mutex_lock(&dev->struct_mutex); drm_bo_usage_deref_locked(&dev_priv->ring_buffer); - if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { DRM_ERROR("Memory manager type 3 not clean. " "Delaying takedown\n"); } - if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { DRM_ERROR("Memory manager type 3 not clean. " "Delaying takedown\n"); } diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 3d376aed..80b2990d 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -376,7 +376,7 @@ nouveau_mem_init_ttm(struct drm_device *dev) bar1_size = drm_get_resource_len(dev, 1) >> PAGE_SHIFT; if (bar1_size < vram_size) { if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0, - bar1_size, vram_size - bar1_size))) { + bar1_size, vram_size - bar1_size, 1))) { DRM_ERROR("Failed PRIV0 mm init: %d\n", ret); return ret; } @@ -387,7 +387,7 @@ nouveau_mem_init_ttm(struct drm_device *dev) #ifdef HACK_OLD_MM vram_size /= 4; #endif - if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size))) { + if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size, 1))) { DRM_ERROR("Failed VRAM mm init: %d\n", ret); return ret; } @@ -407,7 +407,7 @@ nouveau_mem_init_ttm(struct drm_device *dev) if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, dev_priv->gart_info.aper_size >> - PAGE_SHIFT))) { + PAGE_SHIFT, 1))) { DRM_ERROR("Failed TT mm init: %d\n", ret); return ret; } diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index bf76b45d..857182ae 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -160,7 +160,7 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->fence_reg = SCRATCH_REG2; drm_bo_driver_init(dev); /* initialize vram */ - ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size); + ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size, 1); if (ret != 0) { radeon_ms_driver_unload(dev); return ret; @@ -176,7 +176,7 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) /* initialize ttm */ ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, - dev_priv->gpu_gart_size / RADEON_PAGE_SIZE); + dev_priv->gpu_gart_size / RADEON_PAGE_SIZE, 1); if (ret != 0) { radeon_ms_driver_unload(dev); return ret; @@ -277,7 +277,7 @@ int radeon_ms_driver_unload(struct drm_device *dev) DRM_INFO("[radeon_ms] unloading\n"); /* clean ttm memory manager */ mutex_lock(&dev->struct_mutex); - if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { DRM_ERROR("TT memory manager not clean. Delaying takedown\n"); } mutex_unlock(&dev->struct_mutex); @@ -289,7 +289,7 @@ int radeon_ms_driver_unload(struct drm_device *dev) DRM_INFO("[radeon_ms] bus down\n"); /* clean vram memory manager */ mutex_lock(&dev->struct_mutex); - if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) { + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { DRM_ERROR("VRAM memory manager not clean. Delaying takedown\n"); } mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From 8844245cfcc5b19caafc772fd457401ab3253a28 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 20 Feb 2008 10:51:19 +1000 Subject: drm/fb: get rid of offset from structure use bo offset --- linux-core/drm_crtc.h | 1 - linux-core/intel_fb.c | 3 +-- linux-core/radeon_ms_fb.c | 3 +-- shared-core/radeon_ms_crtc.c | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 43ef95ed..30970579 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -235,7 +235,6 @@ struct drm_framebuffer { struct list_head head; int id; /* idr assigned */ unsigned int pitch; - unsigned long offset; unsigned int width; unsigned int height; /* depth can be 15 or 16 */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 6df243b0..56403998 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -612,7 +612,6 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; } - fb->offset = fbo->offset; fb->bo = fbo; printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, fb->height, fbo->offset, fbo); @@ -639,7 +638,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->fix.mmio_start = 0; info->fix.mmio_len = 0; info->fix.line_length = fb->pitch; - info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base; info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index fc9e99ec..d7fb39e6 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -319,7 +319,6 @@ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; } - fb->offset = fb->bo->offset; DRM_INFO("[radeon_ms] framebuffer %dx%d at 0x%08lX\n", fb->width, fb->height, fb->bo->offset); @@ -340,7 +339,7 @@ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->fix.mmio_start = 0; info->fix.mmio_len = 0; info->fix.line_length = fb->pitch; - info->fix.smem_start = fb->offset + dev->mode_config.fb_base; + info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base; info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; DRM_INFO("[radeon_ms] fb physical start : 0x%lX\n", info->fix.smem_start); diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c index 0da5a5a4..b2383859 100644 --- a/shared-core/radeon_ms_crtc.c +++ b/shared-core/radeon_ms_crtc.c @@ -556,7 +556,7 @@ static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, } radeon_pll1_compute(crtc, adjusted_mode); - state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->offset); + state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->bo->offset); state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN | CRTC_GEN_CNTL__CRTC_EN | REG_S(CRTC_GEN_CNTL, CRTC_PIX_WIDTH, format); -- cgit v1.2.3 From e484681a43964502bf7e61a1701bb85ab6befab3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 20 Feb 2008 11:44:10 +1000 Subject: remove more offset --- linux-core/drm_crtc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 6b8cb9c7..ebd15c5e 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1787,7 +1787,6 @@ int drm_mode_addfb(struct drm_device *dev, fb->pitch = r->pitch; fb->bits_per_pixel = r->bpp; fb->depth = r->depth; - fb->offset = bo->offset; fb->bo = bo; r->buffer_id = fb->id; -- cgit v1.2.3 From 66cd6bd66667433f56feecdcc94a2bb228d5a7ca Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 19 Feb 2008 15:32:00 +0000 Subject: compatibility code for pci_get_bus_and_slot() --- linux-core/drm_compat.c | 15 +++++++++++++++ linux-core/drm_compat.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index cd4ff7df..e95269ec 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -764,3 +764,18 @@ unsigned long round_jiffies_relative(unsigned long j) } EXPORT_SYMBOL(round_jiffies_relative); #endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) +{ + struct pci_dev *dev = NULL; + + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if (pci_domain_nr(dev->bus) == 0 && + (dev->bus->number == bus && dev->devfn == devfn)) + return dev; + } + return NULL; +} +EXPORT_SYMBOL(pci_get_bus_and_slot); +#endif diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 92dcbc21..78545768 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -335,4 +335,8 @@ void *idr_replace(struct idr *idp, void *ptr, int id); extern unsigned long round_jiffies_relative(unsigned long j); #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +extern struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn); +#endif + #endif -- cgit v1.2.3 From 88cb873045b76bf947f45fb127baa96f055ad32c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 20 Feb 2008 19:54:36 +0000 Subject: minor test fixes --- tests/modedemo/demo.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- tests/modefb/demo.c | 14 ++++++++------ tests/modehotplug/demo.c | 2 +- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 474f04a5..db51cd66 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -16,6 +16,12 @@ #include #include #include +#ifdef CLEAN_FBDEV +#include +#include +#include +#include +#endif #include "xf86drm.h" #include "xf86drmMode.h" @@ -26,6 +32,11 @@ void testCursor(int fd, uint32_t crtc); void prettyColors(int fd, unsigned int handle); void prettyCursor(int fd, unsigned int handle, unsigned int color); +#ifdef CLEAN_FBDEV +struct fb_var_screeninfo var; +struct fb_fix_screeninfo fix; +#endif + /* structs for the demo_driver */ struct demo_driver; @@ -101,6 +112,20 @@ int main(int argc, char **argv) int num; int i; +#ifdef CLEAN_FBDEV + int fbdev_fd; + + fbdev_fd = open("/dev/fb0", O_RDWR); + + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); + + if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &var)) + printf("var %s\n", strerror(errno)); + if (ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fix)) + printf("fix %s\n", strerror(errno)); +#endif + printf("starting demo\n"); driver = demoCreateDriver(); @@ -155,10 +180,12 @@ int main(int argc, char **argv) #ifdef CLEAN_FBDEV if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &var)) printf("var %s\n", strerror(errno)); + + close(fbdev_fd); #endif - printf("ok\n"); - return 0; + printf("ok\n"); + return 0; } int demoCreateScreens(struct demo_driver *driver) @@ -296,8 +323,20 @@ void demoTakeDownScreen(struct demo_screen *screen) int i; drmBO bo; +#if 0 + /* This can bust the fbdev arrangement as it basically unhooks + * the outputs and the fbdev backend doesn't know how to put things + * back on track. Realistically, it's up to the crtc owner to restore + * things..... + * + * So if you are mixing API's make sure the modesetting owner puts + * back the original CRTC arrangement so fbdev can continue... + * + * Ho-hum.. + */ if (screen->crtc) drmModeSetCrtc(fd, screen->crtc->crtc_id, 0, 0, 0, 0, 0, 0); +#endif if (screen->fb) drmModeRmFB(fd, screen->fb->buffer_id); @@ -354,7 +393,7 @@ struct demo_driver* demoCreateDriver(void) memset(driver, 0, sizeof(struct demo_driver)); - driver->fd = drmOpenControl(0); + driver->fd = drmOpen("i915",NULL); if (driver->fd < 0) { printf("Failed to open the card fb\n"); diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c index 7fa3b93f..b6d1f65b 100644 --- a/tests/modefb/demo.c +++ b/tests/modefb/demo.c @@ -26,7 +26,12 @@ int main(int argc, char **argv) char name[100]; int i,d; int fd; - int drmfd = drmOpenControl(0); + int drmfd = drmOpen("i915", NULL); + + if (drmfd < 0) { + printf("drmOpenControl failed\n"); + return 1; + } /* try four devices */ for (d = 0; d < 4; d++) { @@ -38,11 +43,6 @@ int main(int argc, char **argv) return 1; } - if (drmfd < 0) { - printf("drmOpenControl failed\n"); - return 1; - } - memset(&var, 0, sizeof(struct fb_var_screeninfo)); memset(&fix, 0, sizeof(struct fb_fix_screeninfo)); @@ -79,6 +79,8 @@ int main(int argc, char **argv) printf("cursor (may show up on wrong CRTC - fixme)\n"); cursor(fd, drmfd); + + close(fd); } return 0; } diff --git a/tests/modehotplug/demo.c b/tests/modehotplug/demo.c index 1518e84c..4ef2e386 100644 --- a/tests/modehotplug/demo.c +++ b/tests/modehotplug/demo.c @@ -123,7 +123,7 @@ struct demo_driver* demoCreateDriver(void) memset(driver, 0, sizeof(struct demo_driver)); - driver->fd = drmOpenControl(0); + driver->fd = drmOpen("i915", NULL); if (driver->fd < 0) { printf("Failed to open the card fb\n"); -- cgit v1.2.3 From 3f6c8f64aa8c3a9e427d453433e828693fb4e017 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 20 Feb 2008 22:22:49 +0000 Subject: fix SAREA --- shared-core/i915_drm.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 6067fa02..b8eaa021 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -125,6 +125,15 @@ typedef struct drm_i915_sarea { int third_offset; int third_size; unsigned int third_tiled; + + /* buffer object handles for the static buffers. May change + * over the lifetime of the client, though it doesn't in our current + * implementation. + */ + unsigned int front_bo_handle; + unsigned int back_bo_handle; + unsigned int third_bo_handle; + unsigned int depth_bo_handle; } drm_i915_sarea_t; /* Driver specific fence types and classes. -- cgit v1.2.3 From 0d1cb1e8408d497fec66d9f31603f93800049c75 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 20 Feb 2008 13:26:40 +1000 Subject: hopefully shit works now without this... --- linux-core/drm_crtc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 30970579..d733d8ca 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -479,7 +479,7 @@ struct drm_output { struct drm_display_info *monitor_info; /* if any */ const struct drm_output_funcs *funcs; void *driver_private; - uint32_t make_shit_work; + struct list_head user_modes; struct drm_property_blob *edid_blob_ptr; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; -- cgit v1.2.3 From cdad850ebc3570e5ff5a0996f36832c965aa8a1d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 20 Feb 2008 13:27:10 +1000 Subject: add ioctl to get back memory managed area sized - used for kernel inited areas --- libdrm/xf86drm.c | 15 +++++++++++++++ libdrm/xf86mm.h | 1 + linux-core/drm_bo.c | 37 +++++++++++++++++++++++++++++++++++++ linux-core/drm_drv.c | 2 ++ linux-core/drm_objects.h | 2 ++ shared-core/drm.h | 7 +++++++ 6 files changed, 64 insertions(+) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 39a849c6..13e99555 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2883,6 +2883,21 @@ int drmMMUnlock(int fd, unsigned memType, int unlockBM) return drmIoctlTimeout(fd, DRM_IOCTL_MM_UNLOCK, &arg); } +int drmMMInfo(int fd, unsigned memType, uint64_t *size) +{ + struct drm_mm_info_arg arg; + + memset(&arg, 0, sizeof(arg)); + + arg.mem_type = memType; + + if (ioctl(fd, DRM_IOCTL_MM_INFO, &arg)) + return -errno; + + *size = arg.p_size; + return 0; +} + int drmBOVersion(int fd, unsigned int *major, unsigned int *minor, unsigned int *patchlevel) diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index c80288a7..bb573407 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -172,6 +172,7 @@ extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, extern int drmMMTakedown(int fd, unsigned memType); extern int drmMMLock(int fd, unsigned memType, int lockBM, int ignoreNoEvict); extern int drmMMUnlock(int fd, unsigned memType, int unlockBM); +extern int drmMMInfo(int fd, unsigned memType, uint64_t *size); extern int drmBOSetStatus(int fd, drmBO *buf, uint64_t flags, uint64_t mask, unsigned int hint, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 54b8baf8..ebba2fa7 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2289,6 +2289,7 @@ int drm_bo_init_mm(struct drm_device *dev, unsigned type, man->has_type = 1; man->use_type = 1; man->kern_init_type = kern_init; + man->size = p_size; INIT_LIST_HEAD(&man->lru); INIT_LIST_HEAD(&man->pinned); @@ -2562,6 +2563,42 @@ int drm_mm_unlock_ioctl(struct drm_device *dev, return 0; } +int drm_mm_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + struct drm_mm_info_arg *arg = data; + struct drm_buffer_manager *bm = &dev->bm; + struct drm_bo_driver *driver = dev->driver->bo_driver; + struct drm_mem_type_manager *man; + int ret = 0; + int mem_type = arg->mem_type; + + if (!driver) { + DRM_ERROR("Buffer objects are not supported by this driver\n"); + return -EINVAL; + } + + if (mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", arg->mem_type); + return -EINVAL; + } + + mutex_lock(&dev->struct_mutex); + if (!bm->initialized) { + DRM_ERROR("DRM memory manager was not initialized\n"); + ret = -EINVAL; + goto out; + } + + + man = &bm->man[arg->mem_type]; + + arg->p_size = man->size; + +out: + mutex_unlock(&dev->struct_mutex); + + return ret; +} /* * buffer object vm functions. */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 4f5b364e..4932ea59 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -164,6 +164,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_BO_INFO, drm_bo_info_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_WAIT_IDLE, drm_bo_wait_idle_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_BO_VERSION, drm_bo_version_ioctl, 0), + + DRM_IOCTL_DEF(DRM_IOCTL_MM_INFO, drm_mm_info_ioctl, 0), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 71da4b27..cce58178 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -525,6 +525,7 @@ struct drm_mem_type_manager { unsigned long io_offset; unsigned long io_size; void *io_addr; + uint64_t size; /* size of managed area for reporting to userspace */ }; struct drm_bo_lock { @@ -651,6 +652,7 @@ extern int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file extern int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mm_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_bo_version_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_bo_driver_finish(struct drm_device *dev); extern int drm_bo_driver_init(struct drm_device *dev); diff --git a/shared-core/drm.h b/shared-core/drm.h index 0d7cfd25..cbe83fd1 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -950,6 +950,12 @@ struct drm_mm_init_arg { uint64_t p_size; }; +struct drm_mm_info_arg { + unsigned int mem_type; + uint64_t p_size; +}; + + /* * Drm mode setting */ @@ -1209,6 +1215,7 @@ struct drm_mode_hotplug { #define DRM_IOCTL_BO_INFO DRM_IOWR(0xd4, struct drm_bo_reference_info_arg) #define DRM_IOCTL_BO_WAIT_IDLE DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg) #define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_arg) +#define DRM_IOCTL_MM_INFO DRM_IOWR(0xd7, struct drm_mm_info_arg) #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) -- cgit v1.2.3 From fad1db2d73f8dd95f17db10c7ea381c7774e3c29 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 21 Feb 2008 15:58:56 +1000 Subject: modesetting: fix memory leak and misallocation --- linux-core/drm_crtc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ebd15c5e..bf37730b 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1092,7 +1092,8 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_output *output; int count = 0, ro; - save_crtcs = kzalloc(dev->mode_config.num_crtc * sizeof(struct drm_crtc *), GFP_KERNEL); + /* this is meant to be num_output not num_crtc */ + save_crtcs = kzalloc(dev->mode_config.num_output * sizeof(struct drm_crtc *), GFP_KERNEL); if (!save_crtcs) return -ENOMEM; @@ -1663,10 +1664,10 @@ int drm_mode_setcrtc(struct drm_device *dev, } } - /* What happens to output_set, leak? */ ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb); out: + kfree(output_set); mutex_unlock(&dev->mode_config.mutex); return ret; } -- cgit v1.2.3 From a72399da2a89aecdcf293bc262d76d8c6e10d0ef Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 22 Feb 2008 11:38:08 +0000 Subject: silence warning --- linux-core/drm_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index ebba2fa7..b6115e8d 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2492,7 +2492,7 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f goto out; } ret = 0; - if (ret = drm_bo_clean_mm(dev, arg->mem_type, 0)) { + if ((ret = drm_bo_clean_mm(dev, arg->mem_type, 0))) { if (ret == -EINVAL) DRM_ERROR("Memory manager type %d not clean. " "Delaying takedown\n", arg->mem_type); -- cgit v1.2.3 From 879fb12e289e8997ef325dd5b0068d0d4d6c26df Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 26 Feb 2008 17:11:03 +1100 Subject: drm: fix pick crtcs mode selection code --- linux-core/drm_crtc.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bf37730b..73ab10ec 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -870,6 +870,7 @@ static void drm_pick_crtcs (struct drm_device *dev) struct drm_output *output, *output_equal; struct drm_crtc *crtc; struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; + int found; list_for_each_entry(output, &dev->mode_config.output_list, head) { output->crtc = NULL; @@ -890,17 +891,23 @@ static void drm_pick_crtcs (struct drm_device *dev) if (output->status != output_status_connected) continue; + if (list_empty(&output->modes)) + continue; + des_mode = NULL; + found = 0; list_for_each_entry(des_mode, &output->modes, head) { - if (des_mode->type & DRM_MODE_TYPE_PREFERRED) + if (des_mode->type & DRM_MODE_TYPE_PREFERRED) { + found = 1; break; + } } /* No preferred mode, let's just select the first available */ - if (!des_mode || !(des_mode->type & DRM_MODE_TYPE_PREFERRED)) { + if (!found) { + des_mode = NULL; list_for_each_entry(des_mode, &output->modes, head) { - if (des_mode) - break; + break; } } -- cgit v1.2.3 From 35d1b13b4a574faf3a95bf3b7cdd14897ef07f67 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 26 Feb 2008 16:11:39 +1000 Subject: i915_mmio: add overlay regs --- shared-core/i915_dma.c | 11 ++++++++++- shared-core/i915_drm.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 11c000b9..7a5d1d9f 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1300,7 +1300,16 @@ drm_i915_mmio_entry_t mmio_table[] = { I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, 0x2350, 8 - } + }, + [MMIO_REGS_DOVSTA] = { + I915_MMIO_MAY_READ, + 0x30008, + 1 + }, + [MMIO_REGS_GAMMAA] = { + I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, + 0x30010, + 6 }; static int mmio_table_size = sizeof(mmio_table)/sizeof(drm_i915_mmio_entry_t); diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index b8eaa021..a40cabdc 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -326,6 +326,8 @@ typedef struct drm_i915_vblank_swap { #define MMIO_REGS_CL_INVOCATION_COUNT 6 #define MMIO_REGS_PS_INVOCATION_COUNT 7 #define MMIO_REGS_PS_DEPTH_COUNT 8 +#define MMIO_REGS_DOVSTA 9 +#define MMIO_REGS_GAMMA 10 typedef struct drm_i915_mmio_entry { unsigned int flag; -- cgit v1.2.3 From b92e343dc46212b665f0465274ef6767882bb10c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 26 Feb 2008 16:19:54 +1000 Subject: i915: fix typos --- shared-core/i915_dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 7a5d1d9f..727aeee0 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1306,10 +1306,11 @@ drm_i915_mmio_entry_t mmio_table[] = { 0x30008, 1 }, - [MMIO_REGS_GAMMAA] = { + [MMIO_REGS_GAMMA] = { I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, 0x30010, 6 + } }; static int mmio_table_size = sizeof(mmio_table)/sizeof(drm_i915_mmio_entry_t); -- cgit v1.2.3 From 2476cb209ebbb11edace4bbce0cfaff4e1599dca Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 22 Feb 2008 11:46:22 +0000 Subject: Implement short circuit for base change only Allow mode to be set with fb_id set to -1, meaning set the mode with the current fb (if we have one bound). Allow intelfb to hook back up it's fb if modesetting clears it (maybe temporary). Move any crtc->fb related register changes to set_base in intel_fb. General intelfb cleanups. --- linux-core/drmP.h | 3 +- linux-core/drm_crtc.c | 35 ++++++++------ linux-core/drm_crtc.h | 2 +- linux-core/intel_display.c | 54 ++++++++++++--------- linux-core/intel_fb.c | 118 ++++++++++++++++++++------------------------- 5 files changed, 105 insertions(+), 107 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 0f42d5b6..181b3a97 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -173,8 +173,6 @@ struct drm_file; #include "drm_compat.h" -#include "drm_crtc.h" - /***********************************************************************/ /** \name Macros to make printk easier */ /*@{*/ @@ -610,6 +608,7 @@ struct drm_ati_pcigart_info { }; #include "drm_objects.h" +#include "drm_crtc.h" /* per-master structure */ struct drm_master { diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 73ab10ec..36d9fc56 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -418,7 +418,6 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, saved_mode; int saved_x, saved_y; bool didLock = false; - bool ret = false; struct drm_output *output; adjusted_mode = drm_mode_duplicate(dev, mode); @@ -442,8 +441,13 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, crtc->x = x; crtc->y = y; - /* XXX short-circuit changes to base location only */ - + if (drm_mode_equal(&saved_mode, &crtc->mode)) { + if (saved_x != crtc->x || saved_y != crtc->y) { + crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); + goto done; + } + } + /* Pass our mode to the outputs and the CRTC to give them a chance to * adjust it according to limitations or output properties, and also * a chance to reject the mode entirely. @@ -507,22 +511,15 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, /* XXX free adjustedmode */ drm_mode_destroy(dev, adjusted_mode); - ret = TRUE; /* TODO */ // if (scrn->pScreen) // drm_crtc_set_screen_sub_pixel_order(dev); done: - if (!ret) { - crtc->x = saved_x; - crtc->y = saved_y; - crtc->mode = saved_mode; - } - if (didLock) crtc->funcs->unlock (crtc); - return ret; + return true; } EXPORT_SYMBOL(drm_crtc_set_mode); @@ -1599,13 +1596,13 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_crtc *crtc_req = data; - struct drm_crtc *crtc; + struct drm_crtc *crtc, *crtcfb; struct drm_output **output_set = NULL, *output; struct drm_framebuffer *fb = NULL; struct drm_display_mode *mode = NULL; + uint32_t __user *set_outputs_ptr; int ret = 0; int i; - uint32_t __user *set_outputs_ptr; mutex_lock(&dev->mode_config.mutex); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req->crtc_id); @@ -1616,8 +1613,16 @@ int drm_mode_setcrtc(struct drm_device *dev, } if (crtc_req->mode_valid) { - /* if we have a mode we need a framebuffer */ - if (crtc_req->fb_id) { + /* If we have a mode we need a framebuffer. */ + /* If we pass -1, set the mode with the currently bound fb */ + if (crtc_req->fb_id == -1) { + list_for_each_entry(crtcfb, &dev->mode_config.crtc_list, head) { + if (crtcfb == crtc) { + DRM_INFO("Using current fb for setmode\n"); + fb = crtc->fb; + } + } + } else { fb = idr_find(&dev->mode_config.crtc_idr, crtc_req->fb_id); if (!fb || (fb->id != crtc_req->fb_id)) { DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d733d8ca..bbeab603 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -244,7 +244,7 @@ struct drm_framebuffer { struct drm_buffer_object *bo; void *fbdev; u32 pseudo_palette[17]; - void *virtual_base; + struct drm_bo_kmap_obj kmap; struct list_head filp_head; }; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 6a9d9808..003739d7 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -369,10 +369,42 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) unsigned long Start, Offset; int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); + int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; + int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; + u32 dspcntr; + + /* no fb bound */ + if (!crtc->fb) { + DRM_INFO("No FB bound\n"); + return; + } Start = crtc->fb->bo->offset; Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); + I915_WRITE(dspstride, crtc->fb->pitch); + + dspcntr = I915_READ(dspcntr_reg); + switch (crtc->fb->bits_per_pixel) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (crtc->fb->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 24: + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + DRM_ERROR("Unknown color depth\n"); + return; + } + I915_WRITE(dspcntr_reg, dspcntr); + DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); if (IS_I965G(dev)) { I915_WRITE(dspbase, Offset); @@ -691,7 +723,6 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; - int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; int refclk; @@ -804,26 +835,6 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; - switch (crtc->fb->bits_per_pixel) { - case 8: - dspcntr |= DISPPLANE_8BPP; - break; - case 16: - if (crtc->fb->depth == 15) - dspcntr |= DISPPLANE_15_16BPP; - else - dspcntr |= DISPPLANE_16BPP; - break; - case 24: - case 32: - dspcntr |= DISPPLANE_32BPP_NO_ALPHA; - break; - default: - DRM_ERROR("Unknown color depth\n"); - return; - } - - if (pipe == 0) dspcntr |= DISPPLANE_SEL_PIPE_A; else @@ -925,7 +936,6 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, ((adjusted_mode->crtc_vblank_end - 1) << 16)); I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | ((adjusted_mode->crtc_vsync_end - 1) << 16)); - I915_WRITE(dspstride_reg, crtc->fb->pitch); /* pipesrc and dspsize control the size that is scaled from, which should * always be the user's requested size. */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 56403998..e33494c6 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -48,6 +48,7 @@ struct intelfb_par { struct drm_device *dev; struct drm_crtc *crtc; struct drm_display_mode *fb_mode; + struct drm_framebuffer *fb; }; /* static int @@ -66,7 +67,7 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; struct drm_crtc *crtc = par->crtc; if (regno > 255) @@ -107,7 +108,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; /*struct drm_device *dev = par->dev;*/ - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; /*struct drm_output *output;*/ int depth/*, found = 0*/; @@ -216,41 +217,15 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, return 0; } -bool i915_drmfb_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2, unsigned int pixclock) -{ - - if (mode1->hdisplay == mode2->hdisplay && - mode1->hsync_start == mode2->hsync_start && - mode1->hsync_end == mode2->hsync_end && - mode1->htotal == mode2->htotal && - mode1->hskew == mode2->hskew && - mode1->vdisplay == mode2->vdisplay && - mode1->vsync_start == mode2->vsync_start && - mode1->vsync_end == mode2->vsync_end && - mode1->vtotal == mode2->vtotal && - mode1->vscan == mode2->vscan && - mode1->flags == mode2->flags) - { - if (mode1->clock == mode2->clock) - return true; - - if (KHZ2PICOS(mode2->clock) == pixclock) - return true; - return false; - } - - return false; -} - /* this will let fbcon do the mode init */ /* FIXME: take mode config lock? */ static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; - struct drm_output *output; + struct drm_output *output = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; @@ -295,15 +270,23 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + found = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc) + if (output->crtc == par->crtc){ + found = 1; break; + } } + /* no output bound, bail */ + if (!found) + return -EINVAL; + + found = 0; drm_mode_debug_printmodeline(dev, drm_mode); list_for_each_entry(search_mode, &output->modes, head) { drm_mode_debug_printmodeline(dev, search_mode); - if (i915_drmfb_mode_equal(drm_mode, search_mode, var->pixclock)) { + if (drm_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); drm_mode = search_mode; found = 1; @@ -311,8 +294,12 @@ static int intelfb_set_par(struct fb_info *info) } } + /* If we didn't find a matching mode that exists on our output, + * create a new attachment for the incoming user specified mode + */ if (!found) { if (par->fb_mode) { + /* this also destroys the mode */ drm_mode_detachmode_crtc(dev, par->fb_mode); } @@ -322,21 +309,13 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); } - if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; - } else if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) { - if (!par->crtc->funcs->mode_set_base) { - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; - } else { - par->crtc->funcs->mode_set_base(par->crtc, var->xoffset, var->yoffset); - par->crtc->x = var->xoffset; - par->crtc->y = var->yoffset; - } - } - } + /* re-attach fb */ + if (!par->crtc->fb) + par->crtc->fb = par->fb; + + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) + return -EINVAL; + return 0; } @@ -493,17 +472,14 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, DRM_DEBUG("\n"); - if (!crtc->funcs->mode_set_base) { - DRM_ERROR("panning not supported\n"); - return -EFAULT; - } - /* TODO add check size and pos*/ - crtc->funcs->mode_set_base(crtc, var->xoffset, var->yoffset); + /* re-attach fb */ + if (!crtc->fb) + crtc->fb = par->fb; + + drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); - par->crtc->x = var->xoffset; - par->crtc->y = var->yoffset; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; @@ -535,7 +511,7 @@ static struct fb_ops intelfb_ops = { */ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) { - struct fb_info *info; + struct fb_info *info; struct drm_framebuffer *fb; struct drm_display_mode *mode = crtc->desired_mode; @@ -559,7 +535,7 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; - /* avoid overflow */ + /* avoid overflow */ info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; return 0; @@ -596,7 +572,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->bits_per_pixel = 32; fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); fb->depth = 24; - ret = drm_buffer_object_create(dev, fb->width * fb->height * 4, + ret = drm_buffer_object_create(dev, fb->pitch * fb->height * 4, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | @@ -623,6 +599,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) par->dev = dev; par->crtc = crtc; + par->fb = fb; info->fbops = &intelfb_ops; @@ -635,19 +612,26 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_I830; info->fix.type_aux = 0; - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; + + if (IS_I9XX(dev)) { + info->fix.mmio_start = pci_resource_start(dev->pdev, 0); + info->fix.mmio_len = pci_resource_len(dev->pdev, 0); + } else { + info->fix.mmio_start = pci_resource_start(dev->pdev, 1); + info->fix.mmio_len = pci_resource_len(dev->pdev, 1); + } + info->fix.line_length = fb->pitch; info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base; info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; - ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); - if (ret) - DRM_ERROR("error mapping fb: %d\n", ret); - - info->screen_base = fb->virtual_base; + ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap); + if (ret) + DRM_ERROR("error mapping fb: %d\n", ret); + + info->screen_base = fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; @@ -757,10 +741,10 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) if (info) { unregister_framebuffer(info); - framebuffer_release(info); - drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + drm_bo_kunmap(&fb->kmap); drm_bo_usage_deref_unlocked(&fb->bo); drm_framebuffer_destroy(fb); + framebuffer_release(info); } return 0; } -- cgit v1.2.3 From 89f65c50d70fd2165433ead3cfaa88ee9519e261 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 26 Feb 2008 15:20:29 +0000 Subject: define PRETHAW --- linux-core/drm_compat.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 78545768..f5f06017 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -339,4 +339,8 @@ extern unsigned long round_jiffies_relative(unsigned long j); extern struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn); #endif +#ifndef PM_EVENT_PRETHAW +#define PM_EVENT_PRETHAW 3 +#endif + #endif -- cgit v1.2.3 From 191385d51880d5757c8038ff4b46ee5ccb3561c1 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 26 Feb 2008 15:20:59 +0000 Subject: DRM_INFO -> DRM_DEBUG --- linux-core/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 36d9fc56..1a4624c8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1618,7 +1618,7 @@ int drm_mode_setcrtc(struct drm_device *dev, if (crtc_req->fb_id == -1) { list_for_each_entry(crtcfb, &dev->mode_config.crtc_list, head) { if (crtcfb == crtc) { - DRM_INFO("Using current fb for setmode\n"); + DRM_DEBUG("Using current fb for setmode\n"); fb = crtc->fb; } } -- cgit v1.2.3 From 73cb02b5430b3881cbce5fb4852ac573c11ff831 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 26 Feb 2008 15:21:44 +0000 Subject: DRM_INFO -> DRM_DEBUG --- linux-core/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 003739d7..4b48a0b2 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -375,7 +375,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) /* no fb bound */ if (!crtc->fb) { - DRM_INFO("No FB bound\n"); + DRM_DEBUG("No FB bound\n"); return; } -- cgit v1.2.3 From 75c9e0d3462f04766d490fac5cc93569957a8365 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 26 Feb 2008 23:30:45 +0100 Subject: radeon: remove TTM from an earlier merge --- linux-core/Makefile.kernel | 2 +- linux-core/ati_pcigart.c | 196 +++------------------------------ linux-core/drmP.h | 1 - linux-core/radeon_buffer.c | 263 --------------------------------------------- linux-core/radeon_drv.c | 39 ------- linux-core/radeon_fence.c | 125 --------------------- shared-core/radeon_cp.c | 25 ----- shared-core/radeon_drv.h | 51 +-------- shared-core/radeon_irq.c | 24 ++--- 9 files changed, 26 insertions(+), 700 deletions(-) delete mode 100644 linux-core/radeon_buffer.c delete mode 100644 linux-core/radeon_fence.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 8f6f01ac..ad62eff4 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -33,7 +33,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_graph.o nv10_graph.o nv20_graph.o \ nv40_graph.o nv50_graph.o \ nv04_instmem.o nv50_instmem.o -radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_fence.o radeon_buffer.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \ radeon_ms_bus.o radeon_ms_fence.o \ diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 97a5dfb2..68029635 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -35,45 +35,6 @@ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ -static __inline__ void insert_page_into_table(struct drm_ati_pcigart_info *info, u32 page_base, u32 *pci_gart) -{ - switch(info->gart_reg_if) { - case DRM_ATI_GART_IGP: - *pci_gart = cpu_to_le32((page_base) | 0xc); - break; - case DRM_ATI_GART_PCIE: - *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); - break; - default: - case DRM_ATI_GART_PCI: - *pci_gart = cpu_to_le32(page_base); - break; - } -} - -static __inline__ u32 get_page_base_from_table(struct drm_ati_pcigart_info *info, u32 *pci_gart) -{ - u32 retval; - switch(info->gart_reg_if) { - case DRM_ATI_GART_IGP: - retval = *pci_gart; - retval &= ~0xc; - break; - case DRM_ATI_GART_PCIE: - retval = *pci_gart; - retval &= ~0xc; - retval <<= 8; - break; - default: - case DRM_ATI_GART_PCI: - retval = *pci_gart; - break; - } - return retval; -} - - - static void *drm_ati_alloc_pcigart_table(int order) { unsigned long address; @@ -246,7 +207,18 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga page_base = (u32) entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { - insert_page_into_table(gart_info, page_base, pci_gart); + switch(gart_info->gart_reg_if) { + case DRM_ATI_GART_IGP: + *pci_gart = cpu_to_le32((page_base) | 0xc); + break; + case DRM_ATI_GART_PCIE: + *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); + break; + default: + case DRM_ATI_GART_PCI: + *pci_gart = cpu_to_le32(page_base); + break; + } pci_gart++; page_base += ATI_PCIGART_PAGE_SIZE; } @@ -266,147 +238,3 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga return ret; } EXPORT_SYMBOL(drm_ati_pcigart_init); - -static int ati_pcigart_needs_unbind_cache_adjust(struct drm_ttm_backend *backend) -{ - return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); -} - -static int ati_pcigart_populate(struct drm_ttm_backend *backend, - unsigned long num_pages, - struct page **pages, - struct page *dummy_page) -{ - ati_pcigart_ttm_backend_t *atipci_be = - container_of(backend, ati_pcigart_ttm_backend_t, backend); - - DRM_ERROR("%ld\n", num_pages); - atipci_be->pages = pages; - atipci_be->num_pages = num_pages; - atipci_be->populated = 1; - return 0; -} - -static int ati_pcigart_bind_ttm(struct drm_ttm_backend *backend, - struct drm_bo_mem_reg *bo_mem) -{ - ati_pcigart_ttm_backend_t *atipci_be = - container_of(backend, ati_pcigart_ttm_backend_t, backend); - off_t j; - int i; - struct drm_ati_pcigart_info *info = atipci_be->gart_info; - u32 *pci_gart; - u32 page_base; - unsigned long offset = bo_mem->mm_node->start; - pci_gart = info->addr; - - DRM_ERROR("Offset is %08lX\n", bo_mem->mm_node->start); - j = offset; - while (j < (offset + atipci_be->num_pages)) { - if (get_page_base_from_table(info, pci_gart+j)) - return -EBUSY; - j++; - } - - for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { - struct page *cur_page = atipci_be->pages[i]; - /* write value */ - page_base = page_to_phys(cur_page); - insert_page_into_table(info, page_base, pci_gart + j); - } - -#if defined(__i386__) || defined(__x86_64__) - wbinvd(); -#else - mb(); -#endif - - atipci_be->gart_flush_fn(atipci_be->dev); - - atipci_be->bound = 1; - atipci_be->offset = offset; - /* need to traverse table and add entries */ - DRM_DEBUG("\n"); - return 0; -} - -static int ati_pcigart_unbind_ttm(struct drm_ttm_backend *backend) -{ - ati_pcigart_ttm_backend_t *atipci_be = - container_of(backend, ati_pcigart_ttm_backend_t, backend); - struct drm_ati_pcigart_info *info = atipci_be->gart_info; - unsigned long offset = atipci_be->offset; - int i; - off_t j; - u32 *pci_gart = info->addr; - - DRM_DEBUG("\n"); - - if (atipci_be->bound != 1) - return -EINVAL; - - for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { - *(pci_gart + j) = 0; - } - atipci_be->gart_flush_fn(atipci_be->dev); - atipci_be->bound = 0; - atipci_be->offset = 0; - return 0; -} - -static void ati_pcigart_clear_ttm(struct drm_ttm_backend *backend) -{ - ati_pcigart_ttm_backend_t *atipci_be = - container_of(backend, ati_pcigart_ttm_backend_t, backend); - - DRM_DEBUG("\n"); - if (atipci_be->pages) { - backend->func->unbind(backend); - atipci_be->pages = NULL; - - } - atipci_be->num_pages = 0; -} - -static void ati_pcigart_destroy_ttm(struct drm_ttm_backend *backend) -{ - ati_pcigart_ttm_backend_t *atipci_be; - if (backend) { - DRM_DEBUG("\n"); - atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend); - if (atipci_be) { - if (atipci_be->pages) { - backend->func->clear(backend); - } - drm_ctl_free(atipci_be, sizeof(*atipci_be), DRM_MEM_TTM); - } - } -} - -static struct drm_ttm_backend_func ati_pcigart_ttm_backend = -{ - .needs_ub_cache_adjust = ati_pcigart_needs_unbind_cache_adjust, - .populate = ati_pcigart_populate, - .clear = ati_pcigart_clear_ttm, - .bind = ati_pcigart_bind_ttm, - .unbind = ati_pcigart_unbind_ttm, - .destroy = ati_pcigart_destroy_ttm, -}; - -struct drm_ttm_backend *ati_pcigart_init_ttm(struct drm_device *dev, struct drm_ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev)) -{ - ati_pcigart_ttm_backend_t *atipci_be; - - atipci_be = drm_ctl_calloc(1, sizeof (*atipci_be), DRM_MEM_TTM); - if (!atipci_be) - return NULL; - - atipci_be->populated = 0; - atipci_be->backend.func = &ati_pcigart_ttm_backend; - atipci_be->gart_info = info; - atipci_be->gart_flush_fn = gart_flush_fn; - atipci_be->dev = dev; - - return &atipci_be->backend; -} -EXPORT_SYMBOL(ati_pcigart_init_ttm); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 181b3a97..51b02dc8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1273,7 +1273,6 @@ extern int drm_sg_free(struct drm_device *dev, void *data, /* ATI PCIGART support (ati_pcigart.h) */ extern int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); extern int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); -extern struct drm_ttm_backend *ati_pcigart_init_ttm(struct drm_device *dev, struct drm_ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev)); extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align, dma_addr_t maxaddr); diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c deleted file mode 100644 index 5dff1898..00000000 --- a/linux-core/radeon_buffer.c +++ /dev/null @@ -1,263 +0,0 @@ -/************************************************************************** - * - * Copyright 2007 Dave Airlie - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * - **************************************************************************/ -/* - * Authors: Dave Airlie - */ - -#include "drmP.h" -#include "radeon_drm.h" -#include "radeon_drv.h" - -struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device * dev) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - - if(dev_priv->flags & RADEON_IS_AGP) - return drm_agp_init_ttm(dev); - else - return ati_pcigart_init_ttm(dev, &dev_priv->gart_info, radeon_gart_flush); -} - -int radeon_fence_types(struct drm_buffer_object *bo, uint32_t * class, uint32_t * type) -{ - *class = 0; - if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) - *type = 3; - else - *type = 1; - return 0; -} - -int radeon_invalidate_caches(struct drm_device * dev, uint64_t flags) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - RING_LOCALS; - - BEGIN_RING(4); - RADEON_FLUSH_CACHE(); - RADEON_FLUSH_ZCACHE(); - ADVANCE_RING(); - return 0; -} - -uint64_t radeon_evict_flags(struct drm_buffer_object *bo) -{ - switch (bo->mem.mem_type) { - case DRM_BO_MEM_LOCAL: - case DRM_BO_MEM_TT: - return DRM_BO_FLAG_MEM_LOCAL; - case DRM_BO_MEM_VRAM: - if (bo->mem.num_pages > 128) - return DRM_BO_MEM_TT; - else - return DRM_BO_MEM_LOCAL; - default: - return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; - } -} - -int radeon_init_mem_type(struct drm_device * dev, uint32_t type, - struct drm_mem_type_manager * man) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - - switch (type) { - case DRM_BO_MEM_LOCAL: - man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_CACHED; - man->drm_bus_maptype = 0; - break; - case DRM_BO_MEM_VRAM: - man->flags = _DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_NEEDS_IOREMAP; - man->io_addr = NULL; - man->drm_bus_maptype = _DRM_FRAME_BUFFER; - man->io_offset = drm_get_resource_start(dev, 0); - man->io_size = drm_get_resource_len(dev, 0); - break; - case DRM_BO_MEM_TT: - if (dev_priv->flags & RADEON_IS_AGP) { - if (!(drm_core_has_AGP(dev) && dev->agp)) { - DRM_ERROR("AGP is not enabled for memory type %u\n", - (unsigned)type); - return -EINVAL; - } - man->io_offset = dev->agp->agp_info.aper_base; - man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; - man->io_addr = NULL; - man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; - man->drm_bus_maptype = _DRM_AGP; - } else { - man->io_offset = dev_priv->gart_vm_start; - man->io_size = dev_priv->gart_size; - man->io_addr = NULL; - man->flags = _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_MEMTYPE_CMA; - man->drm_bus_maptype = _DRM_SCATTER_GATHER; - } - break; - default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); - return -EINVAL; - } - return 0; -} - -static void radeon_emit_copy_blit(struct drm_device * dev, - uint32_t src_offset, - uint32_t dst_offset, - uint32_t pages, int direction) -{ - uint32_t cur_pages; - uint32_t stride = PAGE_SIZE; - drm_radeon_private_t *dev_priv = dev->dev_private; - uint32_t format, height; - RING_LOCALS; - - if (!dev_priv) - return; - - /* 32-bit copy format */ - format = RADEON_COLOR_FORMAT_ARGB8888; - - /* radeon limited to 16k stride */ - stride &= 0x3fff; - while(pages > 0) { - cur_pages = pages; - if (cur_pages > 2048) - cur_pages = 2048; - pages -= cur_pages; - - /* needs verification */ - BEGIN_RING(7); - OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); - OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | - RADEON_GMC_DST_PITCH_OFFSET_CNTL | - RADEON_GMC_BRUSH_NONE | - (format << 8) | - RADEON_GMC_SRC_DATATYPE_COLOR | - RADEON_ROP3_S | - RADEON_DP_SRC_SOURCE_MEMORY | - RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); - if (direction) { - OUT_RING((stride << 22) | (src_offset >> 10)); - OUT_RING((stride << 22) | (dst_offset >> 10)); - } else { - OUT_RING((stride << 22) | (dst_offset >> 10)); - OUT_RING((stride << 22) | (src_offset >> 10)); - } - OUT_RING(0); - OUT_RING(pages); /* x - y */ - OUT_RING((stride << 16) | cur_pages); - ADVANCE_RING(); - } - - BEGIN_RING(2); - RADEON_WAIT_UNTIL_2D_IDLE(); - ADVANCE_RING(); - - return; -} - -static int radeon_move_blit(struct drm_buffer_object * bo, - int evict, int no_wait, struct drm_bo_mem_reg *new_mem) -{ - struct drm_bo_mem_reg *old_mem = &bo->mem; - int dir = 0; - - if ((old_mem->mem_type == new_mem->mem_type) && - (new_mem->mm_node->start < - old_mem->mm_node->start + old_mem->mm_node->size)) { - dir = 1; - } - - radeon_emit_copy_blit(bo->dev, - old_mem->mm_node->start << PAGE_SHIFT, - new_mem->mm_node->start << PAGE_SHIFT, - new_mem->num_pages, dir); - - - return drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, - DRM_FENCE_TYPE_EXE | - DRM_RADEON_FENCE_TYPE_RW, - DRM_RADEON_FENCE_FLAG_FLUSHED, new_mem); -} - -static int radeon_move_flip(struct drm_buffer_object * bo, - int evict, int no_wait, struct drm_bo_mem_reg * new_mem) -{ - struct drm_device *dev = bo->dev; - struct drm_bo_mem_reg tmp_mem; - int ret; - - tmp_mem = *new_mem; - tmp_mem.mm_node = NULL; - tmp_mem.flags = DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING; - - ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); - if (ret) - return ret; - - ret = drm_ttm_bind(bo->ttm, &tmp_mem); - if (ret) - goto out_cleanup; - - ret = radeon_move_blit(bo, 1, no_wait, &tmp_mem); - if (ret) - goto out_cleanup; - - ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); -out_cleanup: - if (tmp_mem.mm_node) { - mutex_lock(&dev->struct_mutex); - if (tmp_mem.mm_node != bo->pinned_node) - drm_mm_put_block(tmp_mem.mm_node); - tmp_mem.mm_node = NULL; - mutex_unlock(&dev->struct_mutex); - } - return ret; -} - -int radeon_move(struct drm_buffer_object * bo, - int evict, int no_wait, struct drm_bo_mem_reg * new_mem) -{ - struct drm_bo_mem_reg *old_mem = &bo->mem; - - DRM_DEBUG("\n"); - if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { - if (radeon_move_flip(bo, evict, no_wait, new_mem)) - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else { - if (radeon_move_blit(bo, evict, no_wait, new_mem)) - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } - return 0; -} - diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 355e4c22..f0f3320e 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -56,38 +56,6 @@ static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; - -#ifdef RADEON_HAVE_FENCE -static struct drm_fence_driver radeon_fence_driver = { - .num_classes = 1, - .wrap_diff = (1 << 30), - .flush_diff = (1 << 29), - .sequence_mask = 0xffffffffU, - .lazy_capable = 1, - .emit = radeon_fence_emit_sequence, - .poke_flush = radeon_poke_flush, - .has_irq = radeon_fence_has_irq, -}; -#endif -#ifdef RADEON_HAVE_BUFFER - -static uint32_t radeon_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; -static uint32_t radeon_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; - -static struct drm_bo_driver radeon_bo_driver = { - .mem_type_prio = radeon_mem_prios, - .mem_busy_prio = radeon_busy_prios, - .num_mem_type_prio = sizeof(radeon_mem_prios)/sizeof(uint32_t), - .num_mem_busy_prio = sizeof(radeon_busy_prios)/sizeof(uint32_t), - .create_ttm_backend_entry = radeon_create_ttm_backend_entry, - .fence_type = radeon_fence_types, - .invalidate_caches = radeon_invalidate_caches, - .init_mem_type = radeon_init_mem_type, - .evict_flags = radeon_evict_flags, - .move = radeon_move, -}; -#endif - static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { .driver_features = @@ -133,13 +101,6 @@ static struct drm_driver driver = { .remove = __devexit_p(drm_cleanup_pci), }, -#ifdef RADEON_HAVE_FENCE - .fence_driver = &radeon_fence_driver, -#endif -#ifdef RADEON_HAVE_BUFFER - .bo_driver = &radeon_bo_driver, -#endif - .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c deleted file mode 100644 index 682f0bee..00000000 --- a/linux-core/radeon_fence.c +++ /dev/null @@ -1,125 +0,0 @@ -/************************************************************************** - * - * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * - **************************************************************************/ -/* - * Authors: Thomas Hellström - */ - -#include "drmP.h" -#include "drm.h" -#include "radeon_drm.h" -#include "radeon_drv.h" - -/* - * Implements an intel sync flush operation. - */ - -static void radeon_perform_flush(struct drm_device * dev) -{ - drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_class_manager *fc = &dev->fm.fence_class[0]; - struct drm_fence_driver *driver = dev->driver->fence_driver; - uint32_t pending_flush_types = 0; - uint32_t sequence; - - if (!dev_priv) - return; - - pending_flush_types = fc->pending_flush | - ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0); - - if (pending_flush_types) { - sequence = READ_BREADCRUMB(dev_priv); - - drm_fence_handler(dev, 0, sequence, pending_flush_types, 0); - } - - return; -} - -void radeon_poke_flush(struct drm_device * dev, uint32_t class) -{ - struct drm_fence_manager *fm = &dev->fm; - unsigned long flags; - - if (class != 0) - return; - - write_lock_irqsave(&fm->lock, flags); - radeon_perform_flush(dev); - write_unlock_irqrestore(&fm->lock, flags); -} - -int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, - uint32_t flags, uint32_t *sequence, - uint32_t *native_type) -{ - drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; - RING_LOCALS; - - if (!dev_priv) - return -EINVAL; - - *native_type = DRM_FENCE_TYPE_EXE; - if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) { - *native_type |= DRM_RADEON_FENCE_TYPE_RW; - - BEGIN_RING(4); - - RADEON_FLUSH_CACHE(); - RADEON_FLUSH_ZCACHE(); - ADVANCE_RING(); - } - - radeon_emit_irq(dev); - *sequence = (uint32_t) dev_priv->counter; - - - return 0; -} - -void radeon_fence_handler(struct drm_device * dev) -{ - struct drm_fence_manager *fm = &dev->fm; - - write_lock(&fm->lock); - radeon_perform_flush(dev); - write_unlock(&fm->lock); -} - -int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags) -{ - /* - * We have an irq that tells us when we have a new breadcrumb. - */ - - if (class == 0 && flags == DRM_FENCE_TYPE_EXE) - return 1; - - return 0; -} diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index f0eda664..ac46da38 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1518,28 +1518,6 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) } } -void radeon_gart_flush(struct drm_device *dev) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - - if (dev_priv->flags & RADEON_IS_IGPGART) { - RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); - RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1); - RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH); - RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0); - } else if (dev_priv->flags & RADEON_IS_PCIE) { - u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); - tmp |= RADEON_PCIE_TX_GART_INVALIDATE_TLB; - RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); - tmp &= ~RADEON_PCIE_TX_GART_INVALIDATE_TLB; - RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); - } else { - - - } - -} - static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -2455,9 +2433,6 @@ int radeon_driver_firstopen(struct drm_device *dev) if (ret != 0) return ret; -#ifdef RADEON_HAVE_BUFFER - drm_bo_driver_init(dev); -#endif return 0; } diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 0c503257..1cf03415 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -104,11 +104,6 @@ #define DRIVER_MINOR 28 #define DRIVER_PATCHLEVEL 0 -#if defined(__linux__) -#define RADEON_HAVE_FENCE -#define RADEON_HAVE_BUFFER -#endif - /* * Radeon chip families */ @@ -296,9 +291,8 @@ typedef struct drm_radeon_private { struct mem_block *fb_heap; /* SW interrupt */ - wait_queue_head_t irq_queue; - int counter; - + wait_queue_head_t swi_queue; + atomic_t swi_emitted; int vblank_crtc; uint32_t irq_enable_reg; int irq_enabled; @@ -361,7 +355,6 @@ extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void radeon_gart_flush(struct drm_device *dev); extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv); extern void radeon_freelist_reset(struct drm_device * dev); @@ -381,7 +374,6 @@ extern void radeon_mem_release(struct drm_file *file_priv, /* radeon_irq.c */ extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int radeon_emit_irq(struct drm_device * dev); extern void radeon_do_release(struct drm_device * dev); extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc); @@ -415,30 +407,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, struct drm_file *file_priv, drm_radeon_kcmd_buffer_t *cmdbuf); - -#ifdef RADEON_HAVE_FENCE -/* i915_fence.c */ - - -extern void radeon_fence_handler(struct drm_device *dev); -extern int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, - uint32_t flags, uint32_t *sequence, - uint32_t *native_type); -extern void radeon_poke_flush(struct drm_device *dev, uint32_t class); -extern int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags); -#endif - -#ifdef RADEON_HAVE_BUFFER -/* radeon_buffer.c */ -extern struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device *dev); -extern int radeon_fence_types(struct drm_buffer_object *bo, uint32_t *class, uint32_t *type); -extern int radeon_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags); -extern uint64_t radeon_evict_flags(struct drm_buffer_object *bo); -extern int radeon_init_mem_type(struct drm_device * dev, uint32_t type, - struct drm_mem_type_manager * man); -extern int radeon_move(struct drm_buffer_object * bo, - int evict, int no_wait, struct drm_bo_mem_reg * new_mem); -#endif /* Flags for stats.boxes */ #define RADEON_BOX_DMA_IDLE 0x1 @@ -1368,19 +1336,4 @@ do { \ write &= mask; \ } while (0) -/* Breadcrumb - swi irq */ -#define READ_BREADCRUMB(dev_priv) RADEON_READ(RADEON_LAST_SWI_REG) - -static inline int radeon_update_breadcrumb(struct drm_device *dev) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - - dev_priv->sarea_priv->last_fence = ++dev_priv->counter; - - if (dev_priv->counter > 0x7FFFFFFFUL) - dev_priv->sarea_priv->last_fence = dev_priv->counter = 1; - - return dev_priv->counter; -} - #endif /* __RADEON_DRV_H__ */ diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index 3f6ace88..79e4e866 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -128,12 +128,9 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) stat &= dev_priv->irq_enable_reg; /* SW interrupt */ - if (stat & RADEON_SW_INT_TEST) { - DRM_WAKEUP(&dev_priv->irq_queue); -#ifdef RADEON_HAVE_FENCE - radeon_fence_handler(dev); -#endif - } + if (stat & RADEON_SW_INT_TEST) + DRM_WAKEUP(&dev_priv->swi_queue); + /* VBLANK interrupt */ if (stat & RADEON_CRTC_VBLANK_STAT) drm_handle_vblank(dev, 0); @@ -143,13 +140,14 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_HANDLED; } -int radeon_emit_irq(struct drm_device * dev) +static int radeon_emit_irq(struct drm_device * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; unsigned int ret; RING_LOCALS; - ret = radeon_update_breadcrumb(dev); + atomic_inc(&dev_priv->swi_emitted); + ret = atomic_read(&dev_priv->swi_emitted); BEGIN_RING(4); OUT_RING_REG(RADEON_LAST_SWI_REG, ret); @@ -166,13 +164,13 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) (drm_radeon_private_t *) dev->dev_private; int ret = 0; - if (READ_BREADCRUMB(dev_priv) >= swi_nr) + if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) return 0; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; - DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, - READ_BREADCRUMB(dev_priv) >= swi_nr); + DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, + RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); return ret; } @@ -260,8 +258,8 @@ int radeon_driver_irq_postinstall(struct drm_device * dev) (drm_radeon_private_t *) dev->dev_private; int ret; - dev_priv->counter = 0; - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + atomic_set(&dev_priv->swi_emitted, 0); + DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); ret = drm_vblank_init(dev, 2); if (ret) -- cgit v1.2.3 From 132ba667f4a88bb182e2d2abc7c4e60699398380 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Feb 2008 12:59:39 +1000 Subject: drm: add a check for if modesetting is supported. This is Linux only code, it just uses sysfs to see if a control device has been registered on the requested PCI ID --- libdrm/xf86drmMode.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ libdrm/xf86drmMode.h | 1 + 2 files changed, 49 insertions(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 52fef81b..717e1fe2 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -41,6 +41,8 @@ #include "xf86drm.h" #include #include +#include +#include #define U642VOID(x) ((void *)(unsigned long)(x)) #define VOID2U64(x) ((uint64_t)(unsigned long)(x)) @@ -571,3 +573,49 @@ int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, return 0; } + +/* + * checks if a modesetting capable driver has attached to the pci id + * returns 0 if modesetting supported. + * -EINVAL or invalid bus id + * -ENOSYS if no modesetting support +*/ +int drmCheckModesettingSupported(const char *busid) +{ +#ifdef __linux__ + char pci_dev_dir[1024]; + char *bus_id_path; + char *bus_type; + int domain, bus, dev, func; + DIR *sysdir; + struct dirent *dent; + int found = 0, ret; + + ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); + if (ret != 4) + return -EINVAL; + + sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", + domain, bus, dev, func); + + sysdir = opendir(pci_dev_dir); + if (!sysdir) + return -EINVAL; + + dent = readdir(sysdir); + while (dent) { + if (!strncmp(dent->d_name, "drm:controlD", 12)) { + found = 1; + break; + } + + dent = readdir(sysdir); + } + + closedir(sysdir); + if (found) + return 0; +#endif + return -ENOSYS; + +} diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 7cc3ceca..71e779d4 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -243,3 +243,4 @@ extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id); extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); extern int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, uint64_t value); +extern int drmCheckModesettingSupported(const char *busid); -- cgit v1.2.3 From 01dcc47d895997f77c9457558e974d41c23ed4e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Feb 2008 16:24:17 +1000 Subject: drm: add modesetting as a driver feature. This change adds a driver feature that for i915 is controlled by a module parameter. You now need to do insmod i915.ko modeset=1 to enable it the modesetting paths. It also fixes up lots of X paths. I can run my new DDX driver on this code with and without modesetting enabled --- linux-core/drmP.h | 1 + linux-core/drm_drv.c | 3 +- linux-core/drm_fops.c | 3 +- linux-core/drm_irq.c | 5 ++ linux-core/drm_stub.c | 9 +- linux-core/i915_drv.c | 10 ++- shared-core/i915_dma.c | 49 +++++++++-- shared-core/i915_init.c | 226 ++++++++++++++++++++++++++++-------------------- 8 files changed, 200 insertions(+), 106 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 51b02dc8..1a0a5659 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -106,6 +106,7 @@ struct drm_file; #define DRIVER_IRQ_SHARED 0x80 #define DRIVER_DMA_QUEUE 0x100 #define DRIVER_FB_DMA 0x200 +#define DRIVER_MODESET 0x400 /*@}*/ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 4932ea59..dd76421f 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -414,7 +414,8 @@ static void drm_cleanup(struct drm_device * dev) drm_ht_remove(&dev->object_hash); drm_put_minor(&dev->primary); - drm_put_minor(&dev->control); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); if (drm_put_dev(dev)) DRM_ERROR("Cannot unload module\n"); } diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 5a74f424..fcadc544 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -481,7 +481,8 @@ int drm_release(struct inode *inode, struct file *filp) } mutex_unlock(&dev->ctxlist_mutex); - drm_fb_release(filp); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_fb_release(filp); file_priv->master = NULL; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 637f5e1d..7dddbe19 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -261,6 +261,9 @@ int drm_irq_uninstall(struct drm_device * dev) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + mutex_lock(&dev->struct_mutex); irq_enabled = dev->irq_enabled; dev->irq_enabled = 0; @@ -306,6 +309,8 @@ int drm_control(struct drm_device *dev, void *data, case DRM_INST_HANDLER: if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; if (dev->if_version < DRM_IF_VERSION(1, 2) && ctl->irq != dev->irq) return -EINVAL; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 334c8f03..6856075b 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -343,8 +343,10 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, goto err_g3; } - if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL))) - goto err_g3; + /* only add the control node on a modesetting platform */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL))) + goto err_g3; if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) goto err_g4; @@ -361,7 +363,8 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, err_g5: drm_put_minor(&dev->primary); err_g4: - drm_put_minor(&dev->control); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); err_g3: if (!drm_fb_loaded) pci_disable_device(pdev); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 6c12f1a1..b844dfe6 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -39,6 +39,9 @@ static struct pci_device_id pciidlist[] = { i915_PCI_IDS }; +unsigned int i915_modeset = 0; +module_param_named(modeset, i915_modeset, int, 0400); + #ifdef I915_HAVE_FENCE extern struct drm_fence_driver i915_fence_driver; #endif @@ -563,8 +566,8 @@ static struct drm_driver driver = { DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, .load = i915_driver_load, .unload = i915_driver_unload, -/* .lastclose = i915_driver_lastclose, - .preclose = i915_driver_preclose, */ + .lastclose = i915_driver_lastclose, + .preclose = i915_driver_preclose, .suspend = i915_suspend, .resume = i915_resume, .device_is_agp = i915_driver_device_is_agp, @@ -624,6 +627,9 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __init i915_init(void) { driver.num_ioctls = i915_max_ioctl; + if (i915_modeset == 1) + driver.driver_features |= DRIVER_MODESET; + return drm_init(&driver, pciidlist); } diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index eee24dd1..20095a95 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -66,6 +66,11 @@ void i915_kernel_lost_context(struct drm_device * dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_ring_buffer *ring = &(dev_priv->ring); + /* we should never lose context on the ring with modesetting + * as we don't expose it to userspace */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); @@ -75,6 +80,11 @@ void i915_kernel_lost_context(struct drm_device * dev) int i915_dma_cleanup(struct drm_device * dev) { + struct drm_i915_private *dev_priv = dev->dev_private; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + /* Make sure interrupts are disabled here because the uninstall ioctl * may not have been called from userspace and after dev_private * is freed, it's too late. @@ -82,6 +92,28 @@ int i915_dma_cleanup(struct drm_device * dev) if (dev->irq) drm_irq_uninstall(dev); + if (dev_priv->ring.virtual_start) { + drm_core_ioremapfree(&dev_priv->ring.map, dev); + dev_priv->ring.virtual_start = 0; + dev_priv->ring.map.handle = 0; + dev_priv->ring.map.size = 0; + dev_priv->ring.Size = 0; + } + + if (dev_priv->status_page_dmah) { + drm_pci_free(dev, dev_priv->status_page_dmah); + dev_priv->status_page_dmah = NULL; + /* Need to rewrite hardware status page */ + I915_WRITE(0x02080, 0x1ffff000); + } + + if (dev_priv->status_gfx_addr) { + dev_priv->status_gfx_addr = 0; + drm_core_ioremapfree(&dev_priv->hws_map, dev); + I915_WRITE(0x02080, 0x1ffff000); + } + + return 0; } @@ -153,13 +185,17 @@ static int i915_initialize(struct drm_device * dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; - dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); - if (!dev_priv->mmio_map) { - i915_dma_cleanup(dev); - DRM_ERROR("can not find mmio map!\n"); - return -EINVAL; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + if (init->mmio_offset != 0) + dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); + if (!dev_priv->mmio_map) { + i915_dma_cleanup(dev); + DRM_ERROR("can not find mmio map!\n"); + return -EINVAL; + } } + #ifdef I915_HAVE_BUFFER dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; #endif @@ -246,6 +282,9 @@ static int i915_dma_resume(struct drm_device * dev) DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + if (!dev_priv->mmio_map) { DRM_ERROR("can not find mmio map!\n"); return -EINVAL; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index b2d3f0d0..a2e08bc1 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -153,106 +153,113 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) DRM_DEBUG("fb_base: 0x%08lx\n", dev->mode_config.fb_base); ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, - _DRM_REGISTERS, _DRM_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map); + _DRM_REGISTERS, _DRM_KERNEL|_DRM_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map); if (ret != 0) { DRM_ERROR("Cannot add mapping for MMIO registers\n"); return ret; } +#ifdef __linux__ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + intel_init_chipset_flush_compat(dev); +#endif +#endif + /* * Initialize the memory manager for local and AGP space */ drm_bo_driver_init(dev); - i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); - printk("setting up %ld bytes of VRAM space\n", prealloc_size); - printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); - drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1); - drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT, 1); - - I915_WRITE(LP_RING + RING_LEN, 0); - I915_WRITE(LP_RING + RING_HEAD, 0); - I915_WRITE(LP_RING + RING_TAIL, 0); - - size = PRIMARY_RINGBUFFER_SIZE; - ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, - DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0x1, 0, - &dev_priv->ring_buffer); - if (ret < 0) { - DRM_ERROR("Unable to allocate or pin ring buffer\n"); - return -EINVAL; - } - - /* remap the buffer object properly */ - dev_priv->ring.Start = dev_priv->ring_buffer->offset; - dev_priv->ring.End = dev_priv->ring.Start + size; - dev_priv->ring.Size = size; - dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - - /* FIXME: need wrapper with PCI mem checks */ - ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, - (void **) &dev_priv->ring.virtual_start); - if (ret) - DRM_ERROR("error mapping ring buffer: %d\n", ret); - - DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start, - dev_priv->ring.virtual_start, dev_priv->ring.Size); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); + printk("setting up %ld bytes of VRAM space\n", prealloc_size); + printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); + drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1); + drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT, 1); + + I915_WRITE(LP_RING + RING_LEN, 0); + I915_WRITE(LP_RING + RING_HEAD, 0); + I915_WRITE(LP_RING + RING_TAIL, 0); + + size = PRIMARY_RINGBUFFER_SIZE; + ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0x1, 0, + &dev_priv->ring_buffer); + if (ret < 0) { + DRM_ERROR("Unable to allocate or pin ring buffer\n"); + return -EINVAL; + } + + /* remap the buffer object properly */ + dev_priv->ring.Start = dev_priv->ring_buffer->offset; + dev_priv->ring.End = dev_priv->ring.Start + size; + dev_priv->ring.Size = size; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + /* FIXME: need wrapper with PCI mem checks */ + ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, + (void **) &dev_priv->ring.virtual_start); + if (ret) + DRM_ERROR("error mapping ring buffer: %d\n", ret); + + DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start, + dev_priv->ring.virtual_start, dev_priv->ring.Size); // - memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); - - I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); - I915_WRITE(LP_RING + RING_LEN, - ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | - (RING_NO_REPORT | RING_VALID)); - - /* We are using separate values as placeholders for mechanisms for - * private backbuffer/depthbuffer usage. - */ - dev_priv->use_mi_batchbuffer_start = 0; + memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); + + I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); + I915_WRITE(LP_RING + RING_LEN, + ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | + (RING_NO_REPORT | RING_VALID)); + + /* We are using separate values as placeholders for mechanisms for + * private backbuffer/depthbuffer usage. + */ + dev_priv->use_mi_batchbuffer_start = 0; + + /* Allow hardware batchbuffers unless told otherwise. + */ + dev_priv->allow_batchbuffer = 1; + + /* Program Hardware Status Page */ + if (!IS_G33(dev)) { + dev_priv->status_page_dmah = + drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); + + if (!dev_priv->status_page_dmah) { + dev->dev_private = (void *)dev_priv; + i915_dma_cleanup(dev); + DRM_ERROR("Can not allocate hardware status page\n"); + return -ENOMEM; + } + dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + + I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); + } + DRM_DEBUG("Enabled hardware status page\n"); - /* Allow hardware batchbuffers unless told otherwise. - */ - dev_priv->allow_batchbuffer = 1; - - /* Program Hardware Status Page */ - if (!IS_G33(dev)) { - dev_priv->status_page_dmah = - drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); - - if (!dev_priv->status_page_dmah) { - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - DRM_ERROR("Can not allocate hardware status page\n"); - return -ENOMEM; + dev_priv->wq = create_singlethread_workqueue("i915"); + if (dev_priv == 0) { + DRM_DEBUG("Error\n"); } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + intel_modeset_init(dev); + drm_initial_config(dev, false); - I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); - } - DRM_DEBUG("Enabled hardware status page\n"); + drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); + drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); - dev_priv->wq = create_singlethread_workqueue("i915"); - if (dev_priv == 0) { - DRM_DEBUG("Error\n"); + drm_irq_install(dev); } - - intel_modeset_init(dev); - drm_initial_config(dev, false); - - drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); - drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); - - drm_irq_install(dev); - return 0; } @@ -262,7 +269,10 @@ int i915_driver_unload(struct drm_device *dev) I915_WRITE(LP_RING + RING_LEN, 0); - intel_modeset_cleanup(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + intel_modeset_cleanup(dev); + } #if 0 if (dev_priv->ring.virtual_start) { @@ -298,25 +308,33 @@ int i915_driver_unload(struct drm_device *dev) I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); } - drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, - dev_priv->ring.virtual_start); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, + dev_priv->ring.virtual_start); - DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage)); - mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(&dev_priv->ring_buffer); + DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage)); + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&dev_priv->ring_buffer); - if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { - DRM_ERROR("Memory manager type 3 not clean. " - "Delaying takedown\n"); - } - if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { - DRM_ERROR("Memory manager type 3 not clean. " - "Delaying takedown\n"); + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { + DRM_ERROR("Memory manager type 3 not clean. " + "Delaying takedown\n"); + } + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { + DRM_ERROR("Memory manager type 3 not clean. " + "Delaying takedown\n"); + } + mutex_unlock(&dev->struct_mutex); } - mutex_unlock(&dev->struct_mutex); drm_bo_driver_finish(dev); +#ifdef __linux__ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + intel_init_chipset_flush_compat(dev); +#endif +#endif + DRM_DEBUG("%p\n", dev_priv->mmio_map); drm_rmmap(dev, dev_priv->mmio_map); @@ -363,3 +381,23 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) master->driver_priv = NULL; } + +void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + i915_mem_release(dev, file_priv, dev_priv->agp_heap); +} + +void i915_driver_lastclose(struct drm_device * dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + if (dev_priv->agp_heap) + i915_mem_takedown(&(dev_priv->agp_heap)); + + i915_dma_cleanup(dev); +} -- cgit v1.2.3 From 0e72819629741339af46d0e303f33482acdf0972 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 29 Feb 2008 14:07:29 +1000 Subject: drm: change fb api to take a bo handle not the bo pointer. --- libdrm/xf86drmMode.c | 5 +++-- libdrm/xf86drmMode.h | 2 +- tests/mode/modetest.c | 2 +- tests/modedemo/demo.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 717e1fe2..dd1a6ca9 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -203,7 +203,8 @@ uint32_t drmModeGetHotplug(int fd) } int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, - uint8_t bpp, uint32_t pitch, drmBO *bo, uint32_t *buf_id) + uint8_t bpp, uint32_t pitch, uint32_t bo_handle, + uint32_t *buf_id) { struct drm_mode_fb_cmd f; int ret; @@ -213,7 +214,7 @@ int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, f.pitch = pitch; f.bpp = bpp; f.depth = depth; - f.handle = bo->handle; + f.handle = bo_handle; if (ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)) return ret; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 71e779d4..edf9efee 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -177,7 +177,7 @@ extern drmModeFBPtr drmModeGetFB(int fd, uint32_t bufferId); * Creates a new framebuffer with an buffer object as its scanout buffer. */ extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, - uint8_t bpp, uint32_t pitch, drmBO *bo, + uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id); /** * Destroies the given framebuffer. diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index ab0cdc9c..a50b0cc5 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -291,7 +291,7 @@ int testFrameBufferAdd(int fd, drmModeResPtr res) goto err; printf("\tAdding FB\n"); - ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, &bo, &fb); + ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, bo->handle, &fb); if (ret) goto err_bo; diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index db51cd66..00020bde 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -483,7 +483,7 @@ drmModeFBPtr createFB(int fd, drmModeResPtr res) goto err; } - ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, &bo, &fb); + ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, bo->handle, &fb); if (ret) goto err_bo; -- cgit v1.2.3 From 9c5ba9f5d153877ab2e7cb623cab5607aa5cd4a8 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Sun, 2 Mar 2008 21:48:40 +0000 Subject: Add FENCE registers to MMIO list --- shared-core/i915_dma.c | 10 ++++++++++ shared-core/i915_drm.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 20095a95..28835a04 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1469,6 +1469,16 @@ drm_i915_mmio_entry_t mmio_table[] = { I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, 0x30010, 6 + }, + [MMIO_REGS_FENCE] = { + I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, + 0x2000, + 8 + }, + [MMIO_REGS_FENCE_NEW] = { + I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE, + 0x3000, + 16 } }; diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index a40cabdc..824aee27 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -328,6 +328,8 @@ typedef struct drm_i915_vblank_swap { #define MMIO_REGS_PS_DEPTH_COUNT 8 #define MMIO_REGS_DOVSTA 9 #define MMIO_REGS_GAMMA 10 +#define MMIO_REGS_FENCE 11 +#define MMIO_REGS_FENCE_NEW 12 typedef struct drm_i915_mmio_entry { unsigned int flag; -- cgit v1.2.3 From 81db48536c9d7bb23c448af6a6f1de81df755585 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Mar 2008 10:31:43 +1000 Subject: remove unused functions + include header file --- libdrm/xf86drmMode.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index dd1a6ca9..30b434de 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -36,6 +36,7 @@ * platforms find which headers to include to get uint32_t */ #include +#include #include "xf86drmMode.h" #include "xf86drm.h" @@ -68,27 +69,6 @@ void* drmAllocCpy(void *array, int count, int entry_size) return r; } -/** - * Generate crtc and output ids. - * - * Will generate ids starting from 1 up to count if count is greater then 0. - */ -static uint32_t* drmAllocGenerate(int count) -{ - uint32_t *r; - int i; - - if(0 <= count) - return 0; - - if (!(r = drmMalloc(count*sizeof(*r)))) - return 0; - - for (i = 0; i < count; r[i] = ++i); - - return 0; -} - /* * A couple of free functions. */ -- cgit v1.2.3 From 4aa7efe398911bd58fb348703444a92114e45114 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Mar 2008 10:41:54 +1000 Subject: libdrm: fix warnings in mode code --- libdrm/xf86drmMode.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 30b434de..07b14dbf 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -37,6 +37,7 @@ */ #include #include +#include #include "xf86drmMode.h" #include "xf86drm.h" @@ -125,7 +126,6 @@ void drmModeFreeOutput(drmModeOutputPtr ptr) drmModeResPtr drmModeGetResources(int fd) { struct drm_mode_card_res res; - int i; drmModeResPtr r = 0; memset(&res, 0, sizeof(struct drm_mode_card_res)); @@ -196,7 +196,7 @@ int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, f.depth = depth; f.handle = bo_handle; - if (ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)) + if ((ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f))) return ret; *buf_id = f.buffer_id; @@ -243,7 +243,6 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) { struct drm_mode_crtc crtc; drmModeCrtcPtr r; - int i = 0; crtc.count_outputs = 0; crtc.outputs = 0; @@ -276,10 +275,6 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) r->possibles = crtc.possibles; return r; - -err_allocs: - - return 0; } @@ -433,8 +428,7 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) { struct drm_mode_get_property prop; drmModePropertyPtr r; - struct drm_mode_property_blob *blob_tmp; - int i; + prop.prop_id = property_id; prop.count_enum_blobs = 0; prop.count_values = 0; @@ -549,7 +543,7 @@ int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, osp.prop_id = property_id; osp.value = value; - if (ret = ioctl(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp)) + if ((ret = ioctl(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp))) return ret; return 0; @@ -565,8 +559,6 @@ int drmCheckModesettingSupported(const char *busid) { #ifdef __linux__ char pci_dev_dir[1024]; - char *bus_id_path; - char *bus_type; int domain, bus, dev, func; DIR *sysdir; struct dirent *dent; -- cgit v1.2.3 From 4dbf447f4305e3c2aa8914b5ccfc07d9bf8ef28e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Mar 2008 15:28:38 +1000 Subject: drm: fixup compat with old x.org drivers --- linux-core/drm_drv.c | 15 ++++++++++++--- linux-core/i915_drv.c | 5 +++-- shared-core/i915_init.c | 9 +++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index dd76421f..434789dd 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -187,7 +187,9 @@ int drm_lastclose(struct drm_device * dev) DRM_DEBUG("\n"); -/* return 0; */ + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + drm_bo_driver_finish(dev); + /* * We can't do much about this function failing. */ @@ -425,13 +427,20 @@ int drm_minors_cleanup(int id, void *ptr, void *data) struct drm_minor *minor = ptr; struct drm_device *dev; struct drm_driver *driver = data; - if (id < 127 || id > 192) - return 0; dev = minor->dev; if (minor->dev->driver != driver) return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + if (minor->type != DRM_MINOR_CONTROL) + return 0; + } else { + if (minor->type != DRM_MINOR_LEGACY) + return 0; + } + + if (dev) pci_dev_put(dev->pdev); drm_cleanup(dev); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index b844dfe6..0e65c0cd 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -48,8 +48,8 @@ extern struct drm_fence_driver i915_fence_driver; #ifdef I915_HAVE_BUFFER -static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; -static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; +static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; +static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; static struct drm_bo_driver i915_bo_driver = { .mem_type_prio = i915_mem_prios, @@ -566,6 +566,7 @@ static struct drm_driver driver = { DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, .load = i915_driver_load, .unload = i915_driver_unload, + .firstopen = i915_driver_firstopen, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .suspend = i915_suspend, diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index a2e08bc1..1f22d171 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -401,3 +401,12 @@ void i915_driver_lastclose(struct drm_device * dev) i915_dma_cleanup(dev); } + +int i915_driver_firstopen(struct drm_device *dev) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + drm_bo_driver_init(dev); + return 0; +} -- cgit v1.2.3 From f78cdac8e512642db1aaf09bf9178e23ede25586 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Mar 2008 15:28:59 +1000 Subject: fixup previous merge --- linux-core/drm_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index b7b8e395..9b982662 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -806,5 +806,5 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, } EXPORT_SYMBOL(kmap_atomic_prot_pfn); - +#endif -- cgit v1.2.3 From 5662934ee467c3a29f9551a40fc7b2f6ee16280a Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 4 Mar 2008 17:50:59 +0000 Subject: Fix connector description table --- linux-core/drm_crtc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1a4624c8..345569b6 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -48,7 +48,8 @@ static struct drm_prop_enum_list drm_dpms_enum_list[] = { DPMSModeOff, "Off" } }; static struct drm_prop_enum_list drm_conn_enum_list[] = -{ { ConnectorVGA, "VGA" }, +{ { ConnectorUnknown, "Unknown" }, + { ConnectorVGA, "VGA" }, { ConnectorDVII, "DVI-I" }, { ConnectorDVID, "DVI-D" }, { ConnectorDVIA, "DVI-A" }, -- cgit v1.2.3 From 3ea1902be993e88c068ce67355e2b3d253d1c9f2 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 4 Mar 2008 17:51:56 +0000 Subject: propogate failed fixups back up --- linux-core/drm_crtc.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 345569b6..5f93275a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -458,12 +458,12 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, if (output->crtc != crtc) continue; - if (!output->funcs->mode_fixup(output, mode, adjusted_mode)) { + if (!(ret = output->funcs->mode_fixup(output, mode, adjusted_mode))) { goto done; } } - if (!crtc->funcs->mode_fixup(crtc, mode, adjusted_mode)) { + if (!(ret = crtc->funcs->mode_fixup(crtc, mode, adjusted_mode))) { goto done; } @@ -517,10 +517,16 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, // drm_crtc_set_screen_sub_pixel_order(dev); done: + if (!ret) { + crtc->mode = saved_mode; + crtc->x = saved_x; + crtc->y = saved_y; + } + if (didLock) crtc->funcs->unlock (crtc); - return true; + return ret; } EXPORT_SYMBOL(drm_crtc_set_mode); -- cgit v1.2.3 From 8bfe29d9e44690a3896406acb25ca654dfad054d Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 4 Mar 2008 17:52:37 +0000 Subject: Use ARRAY_SIZE --- linux-core/drm_crtc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 5f93275a..dfa0987f 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -735,20 +735,20 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) "EDID", 0); dev->mode_config.dpms_property = - drm_property_create(dev, DRM_MODE_PROP_ENUM, "DPMS", 4); - + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "DPMS", ARRAY_SIZE(drm_dpms_enum_list)); for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++) drm_property_add_enum(dev->mode_config.dpms_property, i, drm_dpms_enum_list[i].type, drm_dpms_enum_list[i].name); dev->mode_config.connector_type_property = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, - "Connector Type", 10); + "Connector Type", ARRAY_SIZE(drm_conn_enum_list)); for (i = 0; i < ARRAY_SIZE(drm_conn_enum_list); i++) drm_property_add_enum(dev->mode_config.connector_type_property, i, drm_conn_enum_list[i].type, drm_conn_enum_list[i].name); dev->mode_config.connector_num_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, - "Connector ID", 2); + "Connector ID", 2); dev->mode_config.connector_num_property->values[0] = 0; dev->mode_config.connector_num_property->values[1] = 20; @@ -783,7 +783,6 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) dev->mode_config.tv_bottom_margin_property->values[0] = 0; dev->mode_config.tv_bottom_margin_property->values[1] = 100; - return 0; } -- cgit v1.2.3 From 1a959a2095aef397ea14a6f6cbdf2a035ec0eb5c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 4 Mar 2008 17:53:04 +0000 Subject: Check mode before adding to EDID --- linux-core/drm_edid.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 41aa8f5e..9762567b 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -223,8 +223,10 @@ static int add_established_modes(struct drm_output *output, struct edid *edid) if (est_bits & (1<standard_timings[i]); - drm_mode_probed_add(output, newmode); - modes++; + if (newmode) { + drm_mode_probed_add(output, newmode); + modes++; + } } return modes; @@ -283,11 +287,13 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) if (timing->pixel_clock) { newmode = drm_mode_detailed(dev, timing); /* First detailed mode is preferred */ - if (i == 0 && edid->preferred_timing) - newmode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(output, newmode); + if (newmode) { + if (i == 0 && edid->preferred_timing) + newmode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(output, newmode); - modes++; + modes++; + } continue; } @@ -312,8 +318,10 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) std = &data->data.timings[j]; newmode = drm_mode_std(dev, std); - drm_mode_probed_add(output, newmode); - modes++; + if (newmode) { + drm_mode_probed_add(output, newmode); + modes++; + } } break; default: -- cgit v1.2.3 From b87c7ff79ee88ec39a285bc17bd2996252b9fd48 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 5 Mar 2008 10:33:16 +0000 Subject: Add property info. fix bo handle --- tests/modedemo/demo.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 00020bde..83a33aa6 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -429,7 +429,7 @@ void demoUpdateRes(struct demo_driver *driver) int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out) { int count = 0; - int i; + int i,j; int fd = driver->fd; drmModeResPtr res = driver->res; @@ -441,10 +441,20 @@ int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, if (!output) continue; - if (output->connection != DRM_MODE_CONNECTED) { + if (output->connection == DRM_MODE_DISCONNECTED) { drmModeFreeOutput(output); continue; } + + for (j = 0; j < output->count_props; j++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(fd, output->props[j]); + + printf("Property: %s\n",prop->name); + if (prop->count_enums) + printf("%s\n",prop->enums[output->prop_values[j]].name); + } out[count++] = output; } @@ -483,7 +493,7 @@ drmModeFBPtr createFB(int fd, drmModeResPtr res) goto err; } - ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, bo->handle, &fb); + ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, bo.handle, &fb); if (ret) goto err_bo; -- cgit v1.2.3 From fef1c93aa87a1ccbc473749a7e42557fc90a1fca Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 5 Mar 2008 10:33:57 +0000 Subject: build fix --- linux-core/drm_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index dfa0987f..be491908 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -420,14 +420,14 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int saved_x, saved_y; bool didLock = false; struct drm_output *output; + bool ret = true; adjusted_mode = drm_mode_duplicate(dev, mode); crtc->enabled = drm_crtc_in_use(crtc); - if (!crtc->enabled) { + if (!crtc->enabled) return true; - } didLock = crtc->funcs->lock(crtc); -- cgit v1.2.3 From 48a166af14d7455835b9dc2ffd831347d18635d2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 08:49:27 +1000 Subject: woah somehow got these upstream --- shared-core/drm.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index 753af6b7..6b3c6229 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1052,7 +1052,6 @@ struct drm_mm_info_arg { #define DRM_IOCTL_BO_WAIT_IDLE DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg) #define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_arg) #define DRM_IOCTL_MM_INFO DRM_IOWR(0xd7, struct drm_mm_info_arg) -<<<<<<< HEAD:shared-core/drm.h #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) @@ -1070,8 +1069,6 @@ struct drm_mm_info_arg { #define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property) #define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xAC, struct drm_mode_cursor) #define DRM_IOCTL_MODE_HOTPLUG DRM_IOWR(0xAD, struct drm_mode_hotplug) -======= ->>>>>>> d5c0101252e9f48ef1b59f48c05fea7007df97f0:shared-core/drm.h /*@}*/ -- cgit v1.2.3 From add7d21c79e2bd2012d92bb0043023230ec9aa74 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 08:56:20 +1000 Subject: drm: fixup for new sysfs API --- libdrm/xf86drmMode.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 07b14dbf..f86cc48f 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -568,6 +568,25 @@ int drmCheckModesettingSupported(const char *busid) if (ret != 4) return -EINVAL; + sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm", + domain, bus, dev, func); + + sysdir = opendir(pci_dev_dir); + if (sysdir) { + dent = readdir(sysdir); + while (dent) { + if (!strncmp(dent->d_name, "controlD", 8)) { + found = 1; + break; + } + + dent = readdir(sysdir); + } + closedir(sysdir); + if (found) + return 0; + } + sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", domain, bus, dev, func); -- cgit v1.2.3 From ccae12a837e7b17c4e9211295ecbd18807020742 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 08:58:24 +1000 Subject: I really screwed up that merge somehow --- shared-core/drm.h | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/shared-core/drm.h b/shared-core/drm.h index 6b3c6229..303a84b6 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -960,6 +960,175 @@ struct drm_mm_info_arg { uint64_t p_size; }; + +/* + * Drm mode setting + */ +#define DRM_DISPLAY_INFO_LEN 32 +#define DRM_OUTPUT_NAME_LEN 32 +#define DRM_DISPLAY_MODE_LEN 32 +#define DRM_PROP_NAME_LEN 32 + +#define DRM_MODE_TYPE_BUILTIN (1<<0) +#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED (1<<3) +#define DRM_MODE_TYPE_DEFAULT (1<<4) +#define DRM_MODE_TYPE_USERDEF (1<<5) +#define DRM_MODE_TYPE_DRIVER (1<<6) + +struct drm_mode_modeinfo { + unsigned int clock; + unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; + unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; + + unsigned int vrefresh; /* vertical refresh * 1000 */ + + unsigned int flags; + unsigned int type; + char name[DRM_DISPLAY_MODE_LEN]; +}; + +struct drm_mode_card_res { + uint64_t fb_id_ptr; + uint64_t crtc_id_ptr; + uint64_t output_id_ptr; + int count_fbs; + int count_crtcs; + int count_outputs; + int min_width, max_width; + int min_height, max_height; +}; + +struct drm_mode_crtc { + uint64_t set_outputs_ptr; + + unsigned int crtc_id; /**< Id */ + unsigned int fb_id; /**< Id of framebuffer */ + + int x, y; /**< Position on the frameuffer */ + + int count_outputs; + unsigned int outputs; /**< Outputs that are connected */ + + int count_possibles; + unsigned int possibles; /**< Outputs that can be connected */ + int gamma_size; + int mode_valid; + struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_OUTPUT_NONE 0 +#define DRM_MODE_OUTPUT_DAC 1 +#define DRM_MODE_OUTPUT_TMDS 2 +#define DRM_MODE_OUTPUT_LVDS 3 +#define DRM_MODE_OUTPUT_TVDAC 4 + +struct drm_mode_get_output { + + uint64_t modes_ptr; + uint64_t props_ptr; + uint64_t prop_values_ptr; + + int count_modes; + int count_props; + unsigned int output; /**< Id */ + unsigned int crtc; /**< Id of crtc */ + unsigned int output_type; + unsigned int output_type_id; + + unsigned int connection; + unsigned int mm_width, mm_height; /**< HxW in millimeters */ + unsigned int subpixel; + int count_crtcs; + int count_clones; + unsigned int crtcs; /**< possible crtc to connect to */ + unsigned int clones; /**< list of clones */ +}; + +#define DRM_MODE_PROP_PENDING (1<<0) +#define DRM_MODE_PROP_RANGE (1<<1) +#define DRM_MODE_PROP_IMMUTABLE (1<<2) +#define DRM_MODE_PROP_ENUM (1<<3) // enumerated type with text strings +#define DRM_MODE_PROP_BLOB (1<<4) + +struct drm_mode_property_enum { + uint64_t value; + unsigned char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_mode_get_property { + uint64_t values_ptr; /* values and blob lengths */ + uint64_t enum_blob_ptr; /* enum and blob id ptrs */ + + unsigned int prop_id; + unsigned int flags; + unsigned char name[DRM_PROP_NAME_LEN]; + + int count_values; + int count_enum_blobs; +}; + +struct drm_mode_output_set_property { + uint64_t value; + unsigned int prop_id; + unsigned int output_id; +}; + +struct drm_mode_get_blob { + uint32_t blob_id; + uint32_t length; + uint64_t data; +}; + +struct drm_mode_fb_cmd { + unsigned int buffer_id; + unsigned int width, height; + unsigned int pitch; + unsigned int bpp; + unsigned int handle; + unsigned int depth; +}; + +struct drm_mode_mode_cmd { + unsigned int output_id; + struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_CURSOR_BO 0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 + +/* + * depending on the value in flags diffrent members are used. + * + * CURSOR_BO uses + * crtc + * width + * height + * handle - if 0 turns the cursor of + * + * CURSOR_MOVE uses + * crtc + * x + * y + */ +struct drm_mode_cursor { + unsigned int flags; + unsigned int crtc; + int x; + int y; + uint32_t width; + uint32_t height; + unsigned int handle; +}; + +/* + * oh so ugly hotplug + */ +struct drm_mode_hotplug { + uint32_t counter; +}; + /** * \name Ioctls Definitions */ -- cgit v1.2.3 From 47b7ec71fefc2574293c48172c563f549c31f87a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 12:15:38 +1100 Subject: drm/modesetting: fixup irq removal on exit --- linux-core/drm_irq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 7dddbe19..6b740b18 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -261,9 +261,6 @@ int drm_irq_uninstall(struct drm_device * dev) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return 0; - mutex_lock(&dev->struct_mutex); irq_enabled = dev->irq_enabled; dev->irq_enabled = 0; @@ -318,6 +315,8 @@ int drm_control(struct drm_device *dev, void *data, case DRM_UNINST_HANDLER: if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; return drm_irq_uninstall(dev); default: return -EINVAL; -- cgit v1.2.3 From 348d95e00be73b650dabcf121e6b18d669bf4192 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 12:25:26 +1100 Subject: worst merge effort ever --- linux-core/drm_stub.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index ba13e5e5..6856075b 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -355,10 +355,6 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, if ((ret = dev->driver->load(dev, ent->driver_data))) goto err_g5; - if (dev->driver->load) - if ((ret = dev->driver->load(dev, ent->driver_data))) - goto err_g4; - DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, dev->primary->index); -- cgit v1.2.3 From cf28ca4212662c3c7e4bfbe51aee307ac539fb3d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 13:03:32 +1100 Subject: actually turn the irq off --- shared-core/i915_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 1f22d171..3d8a1dca 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -271,6 +271,7 @@ int i915_driver_unload(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_irq_uninstall(dev); intel_modeset_cleanup(dev); } -- cgit v1.2.3 From 33cb42a9f7c7c4f4dd91756af55de7352944efa4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 13:03:42 +1100 Subject: make startup of Xorg smoother if the mode doesn't change. just flip the framebuffer in when required. --- linux-core/drm_crtc.c | 10 ++++++++-- linux-core/intel_fb.c | 29 +++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index be491908..e0c85cef 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1110,13 +1110,17 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ if (crtc->fb != fb) - changed = true; + flip_or_move = true; if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) flip_or_move = true; - if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) + if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) { + DRM_DEBUG("modes are different\n"); + drm_mode_debug_printmodeline(dev, &crtc->mode); + drm_mode_debug_printmodeline(dev, new_mode); changed = true; + } list_for_each_entry(output, &dev->mode_config.output_list, head) { save_crtcs[count++] = output->crtc; @@ -1161,6 +1165,8 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, } drm_disable_unused_functions(dev); } else if (flip_or_move) { + if (crtc->fb != fb) + crtc->fb = fb; crtc->funcs->mode_set_base(crtc, crtc_info->x, crtc_info->y); } diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index e33494c6..931bc1b6 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -228,6 +228,7 @@ static int intelfb_set_par(struct fb_info *info) struct drm_output *output = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; + int changed = 0; DRM_DEBUG("\n"); @@ -310,11 +311,22 @@ static int intelfb_set_par(struct fb_info *info) } /* re-attach fb */ - if (!par->crtc->fb) + if (!par->crtc->fb) { par->crtc->fb = par->fb; + changed = 1; + } - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; + if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) + changed = 1; + + drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(dev, &par->crtc->mode); + if (!drm_mode_equal(drm_mode, &par->crtc->mode)) + changed = 1; + + if (changed) + if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) + return -EINVAL; return 0; } @@ -469,16 +481,21 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; struct drm_crtc *crtc = par->crtc; - + int changed = 0; DRM_DEBUG("\n"); /* TODO add check size and pos*/ + if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) + changed = 1; /* re-attach fb */ - if (!crtc->fb) + if (!crtc->fb) { crtc->fb = par->fb; + changed = 1; + } - drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); + if (changed) + drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; -- cgit v1.2.3 From 9f19e79f955281b9de393219e4ad9835ffe29c49 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 7 Mar 2008 17:09:51 +1100 Subject: drm: we already worked out the pitch. multiplying by 4 is just madness.. --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 931bc1b6..52ff3a67 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -589,7 +589,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->bits_per_pixel = 32; fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); fb->depth = 24; - ret = drm_buffer_object_create(dev, fb->pitch * fb->height * 4, + ret = drm_buffer_object_create(dev, fb->pitch * fb->height, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | -- cgit v1.2.3 From a7dc4d08b9b4f8fe6fcaa4c778f6dd3718d1e36a Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 10 Mar 2008 23:35:07 +0100 Subject: rradeon_ms: rework fence code and bring radeon ms up to date --- linux-core/radeon_ms_drv.c | 4 +- linux-core/radeon_ms_fb.c | 13 +-- shared-core/radeon_ms.h | 14 +-- shared-core/radeon_ms_drm.c | 22 ++-- shared-core/radeon_ms_drm.h | 23 ++-- shared-core/radeon_ms_exec.c | 2 +- shared-core/radeon_ms_fence.c | 248 ++++++++++++++++++++++++++++++++---------- shared-core/radeon_ms_irq.c | 4 +- 8 files changed, 234 insertions(+), 96 deletions(-) diff --git a/linux-core/radeon_ms_drv.c b/linux-core/radeon_ms_drv.c index d7b0eecc..cf9699f4 100644 --- a/linux-core/radeon_ms_drv.c +++ b/linux-core/radeon_ms_drv.c @@ -28,7 +28,7 @@ #include "drm_pciids.h" #include "radeon_ms.h" -extern struct drm_fence_driver radeon_ms_fence_driver; +extern struct drm_fence_driver r3xx_fence_driver; extern struct drm_bo_driver radeon_ms_bo_driver; extern struct drm_ioctl_desc radeon_ms_ioctls[]; extern int radeon_ms_num_ioctls; @@ -71,7 +71,7 @@ static struct drm_driver driver = { .set_version = NULL, .fb_probe = radeonfb_probe, .fb_remove = radeonfb_remove, - .fence_driver = &radeon_ms_fence_driver, + .fence_driver = &r3xx_fence_driver, .bo_driver = &radeon_ms_bo_driver, .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index d7fb39e6..a8fba712 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -345,12 +345,11 @@ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) DRM_INFO("[radeon_ms] fb physical start : 0x%lX\n", info->fix.smem_start); DRM_INFO("[radeon_ms] fb physical size : %d\n", info->fix.smem_len); - ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base); - if (ret) { - DRM_ERROR("error mapping fb: %d\n", ret); + ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap); + if (ret) { + DRM_ERROR("error mapping fb: %d\n", ret); } - - info->screen_base = fb->virtual_base; + info->screen_base = fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; @@ -445,10 +444,10 @@ int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc) if (info) { unregister_framebuffer(info); - framebuffer_release(info); - drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base); + drm_bo_kunmap(&fb->kmap); drm_bo_usage_deref_unlocked(&fb->bo); drm_framebuffer_destroy(fb); + framebuffer_release(info); } return 0; } diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index 903de97d..12c945f9 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -31,6 +31,7 @@ #define __RADEON_MS_H__ #include "radeon_ms_drv.h" +#include "amd_r3xx_fence.h" #include "radeon_ms_reg.h" #include "radeon_ms_drm.h" #include "radeon_ms_rom.h" @@ -328,6 +329,7 @@ struct drm_radeon_private { /* abstract asic specific structures */ struct radeon_ms_rom rom; struct radeon_ms_properties properties; + void *fence; }; @@ -425,15 +427,9 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, int radeon_ms_family_init(struct drm_device *dev); /* radeon_ms_fence.c */ -int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class, - uint32_t flags, uint32_t *sequence, - uint32_t *native_type); -void radeon_ms_fence_handler(struct drm_device * dev); -int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class, - uint32_t flags); -int radeon_ms_fence_types(struct drm_buffer_object *bo, - uint32_t * class, uint32_t * type); -void radeon_ms_poke_flush(struct drm_device * dev, uint32_t class); +void r3xx_fence_handler(struct drm_device * dev); +int r3xx_fence_types(struct drm_buffer_object *bo, + uint32_t * class, uint32_t * type); /* radeon_ms_fb.c */ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc); diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index 857182ae..b9245d99 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -43,24 +43,13 @@ static uint32_t radeon_ms_busy_prios[] = { DRM_BO_MEM_LOCAL, }; -struct drm_fence_driver radeon_ms_fence_driver = { - .num_classes = 1, - .wrap_diff = (1 << 30), - .flush_diff = (1 << 29), - .sequence_mask = 0xffffffffU, - .lazy_capable = 1, - .emit = radeon_ms_fence_emit_sequence, - .poke_flush = radeon_ms_poke_flush, - .has_irq = radeon_ms_fence_has_irq, -}; - struct drm_bo_driver radeon_ms_bo_driver = { .mem_type_prio = radeon_ms_mem_prios, .mem_busy_prio = radeon_ms_busy_prios, .num_mem_type_prio = sizeof(radeon_ms_mem_prios)/sizeof(uint32_t), .num_mem_busy_prio = sizeof(radeon_ms_busy_prios)/sizeof(uint32_t), .create_ttm_backend_entry = radeon_ms_create_ttm_backend, - .fence_type = radeon_ms_fence_types, + .fence_type = r3xx_fence_types, .invalidate_caches = radeon_ms_invalidate_caches, .init_mem_type = radeon_ms_init_mem_type, .evict_flags = radeon_ms_evict_flags, @@ -127,6 +116,13 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) return ret; } + dev_priv->fence = drm_alloc(sizeof(struct r3xx_fence), DRM_MEM_DRIVER); + if (dev_priv->fence == NULL) { + radeon_ms_driver_unload(dev); + return -ENOMEM; + } + memset(dev_priv->fence, 0, sizeof(struct r3xx_fence)); + /* we don't want userspace to be able to map this so don't use * drm_addmap */ dev_priv->mmio.offset = drm_get_resource_start(dev, 2); @@ -309,9 +305,11 @@ int radeon_ms_driver_unload(struct drm_device *dev) drm_core_ioremapfree(&dev_priv->vram, dev); } DRM_INFO("[radeon_ms] map released\n"); + drm_free(dev_priv->fence, sizeof(struct r3xx_fence), DRM_MEM_DRIVER); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; + DRM_INFO("[radeon_ms] that's all the folks\n"); return 0; } diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h index 842d5331..39c050ad 100644 --- a/shared-core/radeon_ms_drm.h +++ b/shared-core/radeon_ms_drm.h @@ -30,16 +30,23 @@ #ifndef __RADEON_MS_DRM_H__ #define __RADEON_MS_DRM_H__ -/* fence definitions */ -/* The only fence class we support */ -#define DRM_RADEON_FENCE_CLASS_ACCEL 0 -/* Fence type that guarantees read-write flush */ -#define DRM_RADEON_FENCE_TYPE_RW 2 -/* cache flushes programmed just before the fence */ -#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000 +/* Fence + * We have only one fence class as we submit command through th + * same fifo so there is no need to synchronize buffer btw different + * cmd stream. + * + * Set DRM_RADEON_FENCE_FLAG_FLUSHED if you want a flush with + * emission of the fence + * + * For fence type we have the native DRM EXE type and the radeon RW + * type. + */ +#define DRM_RADEON_FENCE_CLASS_ACCEL 0 +#define DRM_RADEON_FENCE_TYPE_RW 2 +#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000 /* radeon ms ioctl */ -#define DRM_RADEON_EXECBUFFER 0x00 +#define DRM_RADEON_EXECBUFFER 0x00 struct drm_radeon_execbuffer_arg { uint64_t next; diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c index b2ce3cbb..8e28b19e 100644 --- a/shared-core/radeon_ms_exec.c +++ b/shared-core/radeon_ms_exec.c @@ -223,7 +223,7 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, fence_arg->handle = fence->base.hash.key; fence_arg->fence_class = fence->fence_class; fence_arg->type = fence->type; - fence_arg->signaled = fence->signaled; + fence_arg->signaled = fence->signaled_types; fence_arg->sequence = fence->sequence; } } diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c index 6fcf5437..162d37d6 100644 --- a/shared-core/radeon_ms_fence.c +++ b/shared-core/radeon_ms_fence.c @@ -27,103 +27,241 @@ * Jerome Glisse */ #include "radeon_ms.h" +#include "amd_r3xx_fence.h" -static void radeon_ms_fence_flush(struct drm_device *dev) +#define R3XX_FENCE_SEQUENCE_RW_FLUSH 0x80000000u + +static inline int r3xx_fence_emit_sequence(struct drm_device *dev, + struct drm_radeon_private *dev_priv, + uint32_t sequence) { - struct drm_radeon_private *dev_priv = dev->dev_private; - struct drm_fence_class_manager *fc = &dev->fm.fence_class[0]; - uint32_t pending_flush_types = 0; + struct r3xx_fence *r3xx_fence = dev_priv->fence; + uint32_t cmd[2]; + int i, r; + + if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) { + r3xx_fence->sequence_last_flush = + sequence & ~R3XX_FENCE_SEQUENCE_RW_FLUSH; + /* Ask flush for VERTEX & FRAGPROG pipeline + * have 3D idle */ + dev_priv->flush_cache(dev); + } + cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0); + cmd[1] = sequence; + for (i = 0; i < dev_priv->usec_timeout; i++) { + r = radeon_ms_ring_emit(dev, cmd, 2); + if (!r) { + dev_priv->irq_emit(dev); + return 0; + } + } + return -EBUSY; +} + +static inline uint32_t r3xx_fence_sequence(struct r3xx_fence *r3xx_fence) +{ + r3xx_fence->sequence += 1; + if (unlikely(r3xx_fence->sequence > 0x7fffffffu)) { + r3xx_fence->sequence = 1; + } + return r3xx_fence->sequence; +} + +static inline void r3xx_fence_report(struct drm_device *dev, + struct drm_radeon_private *dev_priv, + struct r3xx_fence *r3xx_fence) +{ + uint32_t fence_types = DRM_FENCE_TYPE_EXE; uint32_t sequence; if (dev_priv == NULL) { return; } - pending_flush_types = fc->pending_flush | - ((fc->pending_exe_flush) ? - DRM_FENCE_TYPE_EXE : 0); - if (pending_flush_types) { - sequence = mmio_read(dev_priv, dev_priv->fence_reg); - drm_fence_handler(dev, 0, sequence, pending_flush_types, 0); + sequence = mmio_read(dev_priv, dev_priv->fence_reg); + if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) { + sequence &= ~R3XX_FENCE_SEQUENCE_RW_FLUSH; + fence_types |= DRM_RADEON_FENCE_TYPE_RW; + if (sequence == r3xx_fence->sequence_last_flush) { + r3xx_fence->sequence_last_flush = 0; + } } + /* avoid to report already reported sequence */ + if (sequence != r3xx_fence->sequence_last_reported) { + drm_fence_handler(dev, 0, sequence, fence_types, 0); + r3xx_fence->sequence_last_reported = sequence; + } +} + +static void r3xx_fence_flush(struct drm_device *dev, uint32_t class) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct r3xx_fence *r3xx_fence = dev_priv->fence; + uint32_t sequence; + + sequence = r3xx_fence_sequence(r3xx_fence); + sequence |= R3XX_FENCE_SEQUENCE_RW_FLUSH; + r3xx_fence_emit_sequence(dev, dev_priv, sequence); } -int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class, - uint32_t flags, uint32_t *sequence, - uint32_t *native_type) +static void r3xx_fence_poll(struct drm_device *dev, uint32_t fence_class, + uint32_t waiting_types) { struct drm_radeon_private *dev_priv = dev->dev_private; - uint32_t fence_id, cmd[2], i, ret; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; + struct r3xx_fence *r3xx_fence = dev_priv->fence; + + if (unlikely(!dev_priv)) { + return; + } + /* if there is a RW flush pending then submit new sequence + * preceded by flush cmds */ + if (fc->pending_flush & DRM_RADEON_FENCE_TYPE_RW) { + r3xx_fence_flush(dev, 0); + fc->pending_flush &= ~DRM_RADEON_FENCE_TYPE_RW; + } + r3xx_fence_report(dev, dev_priv, r3xx_fence); + return; +} + +static int r3xx_fence_emit(struct drm_device *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct r3xx_fence *r3xx_fence = dev_priv->fence; + uint32_t tmp; if (!dev_priv || dev_priv->cp_ready != 1) { return -EINVAL; } - fence_id = (++dev_priv->fence_id_last); - if (dev_priv->fence_id_last > 0x7FFFFFFF) { - fence_id = dev_priv->fence_id_last = 1; - } - *sequence = fence_id; + *sequence = tmp = r3xx_fence_sequence(r3xx_fence); *native_type = DRM_FENCE_TYPE_EXE; if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) { *native_type |= DRM_RADEON_FENCE_TYPE_RW; - dev_priv->flush_cache(dev); + tmp |= R3XX_FENCE_SEQUENCE_RW_FLUSH; } - cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0); - cmd[1] = fence_id; - for (i = 0; i < dev_priv->usec_timeout; i++) { - ret = radeon_ms_ring_emit(dev, cmd, 2); - if (!ret) { - dev_priv->irq_emit(dev); + return r3xx_fence_emit_sequence(dev, dev_priv, tmp); +} + +static int r3xx_fence_has_irq(struct drm_device *dev, + uint32_t class, uint32_t type) +{ + const uint32_t type_irq_mask = DRM_FENCE_TYPE_EXE | + DRM_RADEON_FENCE_TYPE_RW; + /* + * We have an irq for EXE & RW fence. + */ + if (class == 0 && (type & type_irq_mask)) { + return 1; + } + return 0; +} + +static uint32_t r3xx_fence_needed_flush(struct drm_fence_object *fence) +{ + struct drm_device *dev = fence->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct r3xx_fence *r3xx_fence = dev_priv->fence; + struct drm_fence_driver *driver = dev->driver->fence_driver; + uint32_t flush_types, diff; + + flush_types = fence->waiting_types & + ~(DRM_FENCE_TYPE_EXE | fence->signaled_types); + + if (flush_types == 0 || ((flush_types & ~fence->native_types) == 0)) { + return 0; + } + if (unlikely(dev_priv == NULL)) { + return 0; + } + if (r3xx_fence->sequence_last_flush) { + diff = (r3xx_fence->sequence_last_flush - fence->sequence) & + driver->sequence_mask; + if (diff < driver->wrap_diff) { return 0; } } - return -EBUSY; + return flush_types; } -void radeon_ms_fence_handler(struct drm_device * dev) +static int r3xx_fence_wait(struct drm_fence_object *fence, + int lazy, int interruptible, uint32_t mask) { - struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_device *dev = fence->dev; struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + int r; - if (dev_priv == NULL) { - return; + drm_fence_object_flush(fence, mask); + if (likely(interruptible)) { + r = wait_event_interruptible_timeout( + fc->fence_queue, + drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), + 3 * DRM_HZ); + } else { + r = wait_event_timeout( + fc->fence_queue, + drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), + 3 * DRM_HZ); + } + if (unlikely(r == -ERESTARTSYS)) { + return -EAGAIN; + } + if (unlikely(r == 0)) { + return -EBUSY; } - write_lock(&fm->lock); - radeon_ms_fence_flush(dev); - write_unlock(&fm->lock); -} + if (likely(mask == DRM_FENCE_TYPE_EXE || + drm_fence_object_signaled(fence, mask))) { + return 0; + } -int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class, - uint32_t flags) -{ /* - * We have an irq that tells us when we have a new breadcrumb. + * Poll for sync flush completion. */ - if (class == 0 && flags == DRM_FENCE_TYPE_EXE) - return 1; - - return 0; + return drm_fence_wait_polling(fence, lazy, interruptible, + mask, 3 * DRM_HZ); } -int radeon_ms_fence_types(struct drm_buffer_object *bo, - uint32_t *class, uint32_t *type) +struct drm_fence_driver r3xx_fence_driver = { + .num_classes = 1, + .wrap_diff = (1 << 29), + .flush_diff = (1 << 28), + .sequence_mask = 0x7fffffffU, + .has_irq = r3xx_fence_has_irq, + .emit = r3xx_fence_emit, + .flush = r3xx_fence_flush, + .poll = r3xx_fence_poll, + .needed_flush = r3xx_fence_needed_flush, + .wait = r3xx_fence_wait, +}; + +/* this are used by the buffer object code */ +int r3xx_fence_types(struct drm_buffer_object *bo, + uint32_t *class, uint32_t *type) { *class = 0; - if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) - *type = 3; - else - *type = 1; + if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) { + *type = DRM_FENCE_TYPE_EXE | DRM_RADEON_FENCE_TYPE_RW; + } else { + *type = DRM_FENCE_TYPE_EXE; + } return 0; } -void radeon_ms_poke_flush(struct drm_device *dev, uint32_t class) +/* this are used by the irq code */ +void r3xx_fence_handler(struct drm_device * dev) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_fence_manager *fm = &dev->fm; - unsigned long flags; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; - if (class != 0) + if (unlikely(dev_priv == NULL)) { return; - write_lock_irqsave(&fm->lock, flags); - radeon_ms_fence_flush(dev); - write_unlock_irqrestore(&fm->lock, flags); + } + + write_lock(&fm->lock); + r3xx_fence_poll(dev, 0, fc->waiting_types); + write_unlock(&fm->lock); } diff --git a/shared-core/radeon_ms_irq.c b/shared-core/radeon_ms_irq.c index 2f94118f..5c68c902 100644 --- a/shared-core/radeon_ms_irq.c +++ b/shared-core/radeon_ms_irq.c @@ -92,9 +92,9 @@ irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS) /* SW interrupt */ if (GEN_INT_STATUS__SW_INT & status) { - radeon_ms_fence_handler(dev); + r3xx_fence_handler(dev); } - radeon_ms_fence_handler(dev); + r3xx_fence_handler(dev); return IRQ_HANDLED; } -- cgit v1.2.3 From 52748d17923b7e501b707b950227864c0b64d8a1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 11 Mar 2008 11:49:27 +1000 Subject: drm: hopefully fix cursors on 965 --- linux-core/intel_display.c | 18 +++++++++++------- linux-core/intel_drv.h | 2 +- shared-core/i915_drv.h | 3 ++- shared-core/i915_init.c | 8 ++++++++ 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 4b48a0b2..fa2b9bea 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1007,7 +1007,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL; uint32_t base = (pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE; uint32_t temp; - size_t adder; + size_t addr; DRM_DEBUG("\n"); @@ -1039,17 +1039,21 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, return -ENOMEM; } - adder = dev_priv->stolen_base + bo->offset; - intel_crtc->cursor_adder = adder; + if (dev_priv->cursor_needs_physical) + addr = dev_priv->stolen_base + bo->offset; + else + addr = bo->offset; + + intel_crtc->cursor_addr = addr; temp = 0; /* set the pipe for the cursor */ temp |= (pipe << 28); temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; - DRM_DEBUG("cusror base %x\n", adder); + DRM_DEBUG("cusror base %x\n", addr); I915_WRITE(control, temp); - I915_WRITE(base, adder); + I915_WRITE(base, addr); return 0; } @@ -1075,7 +1079,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); - adder = intel_crtc->cursor_adder; + adder = intel_crtc->cursor_addr; I915_WRITE((pipe == 0) ? CURSOR_A_POSITION : CURSOR_B_POSITION, temp); I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder); @@ -1241,7 +1245,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->lut_b[i] = i; } - intel_crtc->cursor_adder = 0; + intel_crtc->cursor_addr = 0; crtc->driver_private = intel_crtc; } diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 72ba01da..a36fd3f1 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -56,7 +56,7 @@ struct intel_output { struct intel_crtc { int pipe; int plane; - uint32_t cursor_adder; + uint32_t cursor_addr; u8 lut_r[256], lut_g[256], lut_b[256]; }; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index f6c0005d..b8dfbc34 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -139,9 +139,10 @@ struct drm_i915_private { int fence_irq_on; uint32_t irq_enable_reg; int irq_enabled; - struct workqueue_struct *wq; + bool cursor_needs_physical; + #ifdef I915_HAVE_FENCE uint32_t flush_sequence; uint32_t flush_flags; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 3d8a1dca..274322e1 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -130,6 +130,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->types[8] = _DRM_STAT_SECONDARY; dev->types[9] = _DRM_STAT_DMA; + if (IS_MOBILE(dev) || IS_I9XX(dev)) + dev_priv->cursor_needs_physical = true; + else + dev_priv->cursor_needs_physical = false; + + if (IS_I965G(dev) || IS_G33(dev)) + dev_priv->cursor_needs_physical = false; + if (IS_I9XX(dev)) { pci_read_config_dword(dev->pdev, 0x5C, &dev_priv->stolen_base); DRM_DEBUG("stolen base %p\n", (void*)dev_priv->stolen_base); -- cgit v1.2.3 From 5a7f4b3074d5cda909fc7329bc91da11d89181e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 11 Mar 2008 16:05:26 +1000 Subject: drm: fix oops on unload. if we are unloading the module, there is no master so therefore no lock --- shared-core/i915_init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 274322e1..fa2fc3da 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -277,7 +277,6 @@ int i915_driver_unload(struct drm_device *dev) I915_WRITE(LP_RING + RING_LEN, 0); - if (drm_core_check_feature(dev, DRIVER_MODESET)) { drm_irq_uninstall(dev); intel_modeset_cleanup(dev); @@ -291,7 +290,6 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->sarea_kmap.virtual) { drm_bo_kunmap(&dev_priv->sarea_kmap); dev_priv->sarea_kmap.virtual = NULL; - dev->primary->master->lock.hw_lock = NULL; dev->sigdata.lock = NULL; } -- cgit v1.2.3 From 903d9231d6f998657cc80ee6f20ded4df68e691b Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 11 Mar 2008 20:29:37 +0000 Subject: Add support for monitor hotplug signals/waits Also adjust i915 irq handling as it follows the 16bit'ism's of the i8xx series. --- linux-core/drmP.h | 20 ++++ linux-core/drm_crtc.c | 15 ++- linux-core/drm_drv.c | 1 + linux-core/drm_irq.c | 166 ++++++++++++++++++++++++++++---- linux-core/i915_fence.c | 4 +- linux-core/intel_crt.c | 15 +-- linux-core/intel_sdvo.c | 14 --- shared-core/drm.h | 34 +++++++ shared-core/i915_drv.h | 17 ++-- shared-core/i915_irq.c | 246 +++++++++++++++++++++++++++++++----------------- 10 files changed, 384 insertions(+), 148 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 47974856..7b21f8a1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -591,6 +591,13 @@ struct drm_vbl_sig { struct task_struct *task; }; +struct drm_hotplug_sig { + struct list_head head; + unsigned int counter; + struct siginfo info; + struct task_struct *task; +}; + /* location of GART table */ #define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_FB 2 @@ -867,6 +874,15 @@ struct drm_device { struct work_struct work; + /** \name HOTPLUG IRQ support */ + /*@{ */ + wait_queue_head_t hotplug_queue; /**< HOTPLUG wait queue */ + spinlock_t hotplug_lock; + struct list_head *hotplug_sigs; /**< signal list to send on HOTPLUG */ + atomic_t hotplug_signal_pending; /* number of signals pending on all crtcs*/ + + /*@} */ + /** \name VBLANK IRQ support */ /*@{ */ @@ -1193,13 +1209,17 @@ extern void drm_driver_irq_preinstall(struct drm_device *dev); extern void drm_driver_irq_postinstall(struct drm_device *dev); extern void drm_driver_irq_uninstall(struct drm_device *dev); +extern int drm_hotplug_init(struct drm_device *dev); +extern int drm_wait_hotplug(struct drm_device *dev, void *data, struct drm_file *filp); extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp); +extern int drm_wait_hotplug(struct drm_device *dev, void *data, struct drm_file *filp); extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq); extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); extern u32 drm_vblank_count(struct drm_device *dev, int crtc); extern void drm_update_vblank_count(struct drm_device *dev, int crtc); extern void drm_handle_vblank(struct drm_device *dev, int crtc); +extern void drm_handle_hotplug(struct drm_device *dev); extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e0c85cef..0cd0ebd0 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -947,6 +947,7 @@ static void drm_pick_crtcs (struct drm_device *dev) if (drm_mode_equal (modes, modes_equal)) { if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) { printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones); + des_mode = modes; assigned = 0; goto clone; } @@ -1180,7 +1181,7 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, * @output hotpluged output * * LOCKING. - * Caller must hold mode config lock, function might grap struct lock. + * Caller must hold mode config lock, function might grab struct lock. * * Stage two of a hotplug. * @@ -1192,10 +1193,11 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, { int has_config = 0; + dev->mode_config.hotplug_counter++; + /* We might want to do something more here */ if (!connected) { DRM_DEBUG("not connected\n"); - dev->mode_config.hotplug_counter++; return 0; } @@ -1211,10 +1213,10 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, if (!output->crtc || !output->crtc->desired_mode) { DRM_DEBUG("could not find a desired mode or crtc for output\n"); - goto out_err; + return 1; } - /* We should realy check if there is a fb using this crtc */ + /* We should really check if there is a fb using this crtc */ if (!has_config) dev->driver->fb_probe(dev, output->crtc); else { @@ -1226,12 +1228,7 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, drm_disable_unused_functions(dev); - dev->mode_config.hotplug_counter++; return 0; - -out_err: - dev->mode_config.hotplug_counter++; - return 1; } EXPORT_SYMBOL(drm_hotplug_stage_two); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 434789dd..09372c71 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -136,6 +136,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY | DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_HOTPLUG, drm_mode_hotplug_ioctl, DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_WAIT_HOTPLUG, drm_wait_hotplug, 0), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 6b740b18..230ef3cc 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -90,32 +90,41 @@ static void vblank_disable_fn(unsigned long arg) static void drm_vblank_cleanup(struct drm_device *dev) { - /* Bail if the driver didn't call drm_vblank_init() */ - if (dev->num_crtcs == 0) - return; - del_timer(&dev->vblank_disable_timer); vblank_disable_fn((unsigned long)dev); - drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, + if (dev->vbl_queue) + drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, + + if (dev->vbl_sigs) + drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * + + if (dev->_vblank_count) + drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * + + if (dev->vblank_refcount) + drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * + + if (dev->vblank_enabled) + drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, + + if (dev->last_vblank) + drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * + + if (dev->vblank_premodeset) + drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, - DRM_MEM_DRIVER); - dev->num_crtcs = 0; + if (dev->vblank_offset) + drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, + DRM_MEM_DRIVER); } int drm_vblank_init(struct drm_device *dev, int num_crtcs) @@ -182,6 +191,82 @@ err: } EXPORT_SYMBOL(drm_vblank_init); +int drm_wait_hotplug(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + union drm_wait_hotplug *hotplugwait = data; + struct timeval now; + int ret = 0; + unsigned int flags; + + if ((!dev->irq) || (!dev->irq_enabled)) + return -EINVAL; + + flags = hotplugwait->request.type; + + if (flags & _DRM_HOTPLUG_SIGNAL) { + unsigned long irqflags; + struct list_head *hotplug_sigs = dev->hotplug_sigs; + struct drm_hotplug_sig *hotplug_sig; + + hotplug_sig = drm_calloc(1, sizeof(struct drm_hotplug_sig), + DRM_MEM_DRIVER); + if (!hotplug_sig) + return -ENOMEM; + + atomic_inc(&dev->hotplug_signal_pending); + + hotplug_sig->info.si_signo = hotplugwait->request.signal; + hotplug_sig->task = current; + hotplug_sig->counter = + hotplugwait->reply.counter = + dev->mode_config.hotplug_counter; + + spin_lock_irqsave(&dev->hotplug_lock, irqflags); + + list_add_tail(&hotplug_sig->head, hotplug_sigs); + + spin_unlock_irqrestore(&dev->hotplug_lock, irqflags); + } else { + int cur_hotplug = dev->mode_config.hotplug_counter; + + DRM_WAIT_ON(ret, dev->hotplug_queue, 3 * DRM_HZ, + dev->mode_config.hotplug_counter > cur_hotplug); + + do_gettimeofday(&now); + + hotplugwait->reply.tval_sec = now.tv_sec; + hotplugwait->reply.tval_usec = now.tv_usec; + hotplugwait->reply.counter = dev->mode_config.hotplug_counter; + } + + return ret; +} + +static void drm_hotplug_cleanup(struct drm_device *dev) +{ + if (dev->hotplug_sigs) + drm_free(dev->hotplug_sigs, sizeof(*dev->hotplug_sigs), + DRM_MEM_DRIVER); +} +EXPORT_SYMBOL(drm_hotplug_cleanup); + +int drm_hotplug_init(struct drm_device *dev) +{ + spin_lock_init(&dev->hotplug_lock); + atomic_set(&dev->hotplug_signal_pending, 0); + + dev->hotplug_sigs = drm_alloc(sizeof(struct list_head), DRM_MEM_DRIVER); + if (!dev->hotplug_sigs) + return -ENOMEM; + + INIT_LIST_HEAD(dev->hotplug_sigs); + init_waitqueue_head(&dev->hotplug_queue); + + return 0; +} +EXPORT_SYMBOL(drm_hotplug_init); + /** * Install IRQ handler. * @@ -277,6 +362,8 @@ int drm_irq_uninstall(struct drm_device * dev) drm_vblank_cleanup(dev); + drm_hotplug_cleanup(dev); + dev->locked_tasklet_func = NULL; return 0; @@ -530,7 +617,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; - struct drm_vbl_sig *vbl_sig; + struct drm_vbl_sig *vbl_sig, *tmp; spin_lock_irqsave(&dev->vbl_lock, irqflags); @@ -538,7 +625,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, * for the same vblank sequence number; nothing to be done in * that case */ - list_for_each_entry(vbl_sig, vbl_sigs, head) { + list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) { if (vbl_sig->sequence == vblwait->request.sequence && vbl_sig->info.si_signo == vblwait->request.signal @@ -659,6 +746,53 @@ void drm_handle_vblank(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_handle_vblank); +/** + * Send the HOTPLUG signals. + * + * \param dev DRM device. + * + * Sends a signal for each task in drm_device::hotplug_sigs and empties the list. + */ +static void drm_hotplug_send_signals(struct drm_device * dev) +{ + struct drm_hotplug_sig *hotplug_sig, *tmp; + struct list_head *hotplug_sigs; + unsigned long flags; + + spin_lock_irqsave(&dev->hotplug_lock, flags); + + hotplug_sigs = dev->hotplug_sigs; + + list_for_each_entry_safe(hotplug_sig, tmp, hotplug_sigs, head) { + hotplug_sig->info.si_code = hotplug_sig->counter; + + send_sig_info(hotplug_sig->info.si_signo, + &hotplug_sig->info, hotplug_sig->task); + + list_del(&hotplug_sig->head); + + drm_free(hotplug_sig, sizeof(*hotplug_sig), + DRM_MEM_DRIVER); + atomic_dec(&dev->hotplug_signal_pending); + } + + spin_unlock_irqrestore(&dev->hotplug_lock, flags); +} + +/** + * drm_handle_hotplug - handle a hotplug event + * @dev: DRM device + * @crtc: where this event occurred + * + * Drivers should call this routine in their hotplug interrupt handlers. + */ +void drm_handle_hotplug(struct drm_device *dev) +{ + DRM_WAKEUP(&dev->hotplug_queue); + drm_hotplug_send_signals(dev); +} +EXPORT_SYMBOL(drm_handle_hotplug); + /** * Tasklet wrapper function. * diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 0f6cdeef..f392e8e6 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -120,11 +120,11 @@ static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, if (dev_priv->fence_irq_on && !(fc->waiting_types & DRM_FENCE_TYPE_EXE)) { - i915_user_irq_off(dev_priv); + i915_user_irq_off(dev); dev_priv->fence_irq_on = 0; } else if (!dev_priv->fence_irq_on && (fc->waiting_types & DRM_FENCE_TYPE_EXE)) { - i915_user_irq_on(dev_priv); + i915_user_irq_on(dev); dev_priv->fence_irq_on = 1; } } diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index a9fb50a3..915e430d 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -132,7 +132,7 @@ static void intel_crt_mode_set(struct drm_output *output, /** * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. * - * Only for I945G/GM. + * Not for i915G/i915GM * * \return TRUE if CRT is connected. * \return FALSE if CRT is disconnected. @@ -142,7 +142,7 @@ static bool intel_crt_detect_hotplug(struct drm_output *output) struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 temp; -#if 1 + unsigned long timeout = jiffies + msecs_to_jiffies(1000); temp = I915_READ(PORT_HOTPLUG_EN); @@ -161,15 +161,6 @@ static bool intel_crt_detect_hotplug(struct drm_output *output) return true; return false; -#else - temp = I915_READ(PORT_HOTPLUG_STAT); - DRM_DEBUG("HST 0x%08x\n", temp); - - if (temp & (1 << 8) && temp & (1 << 9)) - return true; - - return false; -#endif } static bool intel_crt_detect_ddc(struct drm_output *output) @@ -187,7 +178,7 @@ static enum drm_output_status intel_crt_detect(struct drm_output *output) { struct drm_device *dev = output->dev; - if (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) { + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { if (intel_crt_detect_hotplug(output)) return output_status_connected; else diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 3887df00..a8441d8f 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -53,7 +53,6 @@ struct intel_sdvo_priv { struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2; struct intel_sdvo_dtd save_output_dtd[16]; u32 save_SDVOX; - int hotplug_enabled; }; /** @@ -72,14 +71,8 @@ void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) if (sdvo_priv->output_device == SDVOB) { cval = I915_READ(SDVOC); - - if (sdvo_priv->hotplug_enabled) - bval = bval | (1 << 26); } else { bval = I915_READ(SDVOB); - - if (sdvo_priv->hotplug_enabled) - cval = cval | (1 << 26); } /* * Write the registers twice for luck. Sometimes, @@ -933,8 +926,6 @@ int intel_sdvo_supports_hotplug(struct drm_output *output) void intel_sdvo_set_hotplug(struct drm_output *output, int on) { - struct intel_output *intel_output = output->driver_private; - struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u8 response[2]; u8 status; @@ -942,15 +933,11 @@ void intel_sdvo_set_hotplug(struct drm_output *output, int on) intel_sdvo_read_response(output, &response, 2); if (on) { - sdvo_priv->hotplug_enabled = 1; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); status = intel_sdvo_read_response(output, &response, 2); intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); } else { - sdvo_priv->hotplug_enabled = 0; - response[0] = 0; response[1] = 0; intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); @@ -1074,7 +1061,6 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) } sdvo_priv->output_device = output_device; - sdvo_priv->hotplug_enabled = 0; intel_output->i2c_bus = i2cbus; intel_output->dev_priv = sdvo_priv; diff --git a/shared-core/drm.h b/shared-core/drm.h index 303a84b6..a1ebfb93 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -555,6 +555,39 @@ union drm_wait_vblank { struct drm_wait_vblank_reply reply; }; +/* Handle monitor hotplug. + * + * May want to extend this later to pass reply information which + * details the outputs which generated the hotplug event. + * Some chipsets can't determine that though, and we'd need to leave + * it to the higher levels to determine exactly what changed. + */ +enum drm_hotplug_seq_type { + _DRM_HOTPLUG_SIGNAL = 0x00000001, /**< Send signal instead of blocking */ +}; + +struct drm_wait_hotplug_request { + enum drm_hotplug_seq_type type; + unsigned long signal; +}; + +struct drm_wait_hotplug_reply { + enum drm_hotplug_seq_type type; + unsigned int counter; + long tval_sec; + long tval_usec; +}; + +/** + * DRM_IOCTL_WAIT_HOTPLUG ioctl argument type. + * + * \sa drmWaitHotplug(). + */ +union drm_wait_hotplug { + struct drm_wait_hotplug_request request; + struct drm_wait_hotplug_reply reply; +}; + enum drm_modeset_ctl_cmd { _DRM_PRE_MODESET = 1, _DRM_POST_MODESET = 2, @@ -1238,6 +1271,7 @@ struct drm_mode_hotplug { #define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property) #define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xAC, struct drm_mode_cursor) #define DRM_IOCTL_MODE_HOTPLUG DRM_IOWR(0xAD, struct drm_mode_hotplug) +#define DRM_IOCTL_WAIT_HOTPLUG DRM_IOWR(0xAE, union drm_wait_hotplug) /*@}*/ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index b8dfbc34..fb855933 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -307,8 +307,8 @@ extern void i915_disable_vblank(struct drm_device *dev, int crtc); extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc); extern int i915_vblank_swap(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void i915_user_irq_on(struct drm_i915_private *dev_priv); -extern void i915_user_irq_off(struct drm_i915_private *dev_priv); +extern void i915_user_irq_on(struct drm_device *dev); +extern void i915_user_irq_off(struct drm_device *dev); /* i915_mem.c */ extern int i915_mem_alloc(struct drm_device *dev, void *data, @@ -536,6 +536,12 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915REG_PIPEASTAT 0x70024 #define I915REG_PIPEBSTAT 0x71024 + +#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) +#define I915_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) +#define I915_HOTPLUG_CLEAR (1UL<<10) +#define I915_VBLANK_CLEAR (1UL<<1) + /* * The two pipe frame counter registers are not synchronized, so * reading a stable value is somewhat tricky. The following code @@ -567,9 +573,6 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define PIPE_PIXEL_MASK 0x00ffffff #define PIPE_PIXEL_SHIFT 0 -#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) -#define I915_VBLANK_CLEAR (1UL<<1) - #define GPIOA 0x5010 #define GPIOB 0x5014 #define GPIOC 0x5018 @@ -1153,8 +1156,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define SDVOB_PCIE_CONCURRENCY (1 << 3) #define SDVO_DETECTED (1 << 2) /* Bits to be preserved when writing */ -#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14)) -#define SDVOC_PRESERVE_MASK (1 << 17) +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26)) +#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26)) /** @defgroup LVDS * @{ diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index b9d137f4..4127383a 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -34,7 +34,9 @@ #include "intel_drv.h" #define USER_INT_FLAG (1<<1) +#define EVENT_PIPEB_FLAG (1<<4) #define VSYNC_PIPEB_FLAG (1<<5) +#define EVENT_PIPEA_FLAG (1<<6) #define VSYNC_PIPEA_FLAG (1<<7) #define HOTPLUG_FLAG (1 << 17) @@ -158,13 +160,14 @@ static void i915_vblank_tasklet(struct drm_device *dev) int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; unsigned counter[2]; struct drm_drawable_info *drw; - struct drm_i915_sarea *sarea_priv; + struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv; u32 cpp = dev_priv->cpp, offsets[3]; u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB) : XY_SRC_COPY_BLT_CMD; - u32 pitchropcpp; + u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | + (cpp << 23) | (1 << 24); RING_LOCALS; counter[0] = drm_vblank_count(dev, 0); @@ -434,7 +437,7 @@ static struct drm_device *hotplug_dev; static int hotplug_cmd = 0; static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; -static void i915_hotplug_crt(struct drm_device *dev, bool connected) +static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) { struct drm_output *output; struct intel_output *iout; @@ -453,7 +456,7 @@ static void i915_hotplug_crt(struct drm_device *dev, bool connected) if (iout == 0) goto unlock; - drm_hotplug_stage_two(dev, output, connected); + drm_hotplug_stage_two(dev, output, isconnected); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -468,10 +471,8 @@ static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) output = intel_sdvo_find(dev, sdvoB); - if (!output) { - DRM_ERROR("could not find sdvo%s output\n", sdvoB ? "B" : "C"); + if (!output) goto unlock; - } status = output->funcs->detect(output); @@ -480,7 +481,6 @@ static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) else drm_hotplug_stage_two(dev, output, true); - /* wierd hw bug, sdvo stop sending interupts */ intel_sdvo_set_hotplug(output, 1); unlock: @@ -521,6 +521,7 @@ static void i915_hotplug_work_func(struct work_struct *work) if (sdvoC) i915_hotplug_sdvo(dev, 0); + drm_handle_hotplug(dev); } static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) @@ -575,45 +576,21 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; u32 temp = 0; - u32 temp2; u32 pipea_stats, pipeb_stats; - pipea_stats = I915_READ(I915REG_PIPEASTAT); - pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - - /* On i8xx hw the IIR and IER are 16bit on i9xx its 32bit */ - if (IS_I9XX(dev)) + /* On i8xx/i915 hw the IIR and IER are 16bit on i9xx its 32bit */ + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) temp = I915_READ(I915REG_INT_IDENTITY_R); else temp = I915_READ16(I915REG_INT_IDENTITY_R); - temp2 = temp; temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG); -#if 0 - /* ugly despamification of pipeb event irq */ - if (temp & (0xFFFFFFF ^ ((1 << 5) | (1 << 7)))) { - DRM_DEBUG("IIR %08x\n", temp2); - DRM_DEBUG("MSK %08x\n", dev_priv->irq_enable_reg | USER_INT_FLAG); - DRM_DEBUG("M&I %08x\n", temp); - DRM_DEBUG("HOT %08x\n", I915_READ(PORT_HOTPLUG_STAT)); - } -#else -#if 0 - DRM_DEBUG("flag=%08x\n", temp); -#endif -#endif - if (temp == 0) return IRQ_NONE; - if (IS_I9XX(dev)) { - I915_WRITE(I915REG_INT_IDENTITY_R, temp); - (void) I915_READ(I915REG_INT_IDENTITY_R); - } else { - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); - (void) I915_READ16(I915REG_INT_IDENTITY_R); - } + pipea_stats = I915_READ(I915REG_PIPEASTAT); + pipeb_stats = I915_READ(I915REG_PIPEBSTAT); /* * Clear the PIPE(A|B)STAT regs before the IIR otherwise @@ -621,25 +598,40 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) */ if (temp & VSYNC_PIPEA_FLAG) { drm_handle_vblank(dev, i915_get_plane(dev, 0)); - I915_WRITE(I915REG_PIPEASTAT, - pipea_stats | I915_VBLANK_INTERRUPT_ENABLE | - I915_VBLANK_CLEAR); + + pipea_stats |= I915_VBLANK_INTERRUPT_ENABLE | + I915_VBLANK_CLEAR; } if (temp & VSYNC_PIPEB_FLAG) { drm_handle_vblank(dev, i915_get_plane(dev, 1)); - I915_WRITE(I915REG_PIPEBSTAT, - pipeb_stats | I915_VBLANK_INTERRUPT_ENABLE | - I915_VBLANK_CLEAR); + + pipeb_stats |= I915_VBLANK_INTERRUPT_ENABLE | + I915_VBLANK_CLEAR; } - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); - (void) I915_READ16(I915REG_INT_IDENTITY_R); /* Flush posted write */ + if (temp & EVENT_PIPEA_FLAG) + pipea_stats |= I915_HOTPLUG_INTERRUPT_ENABLE | + I915_HOTPLUG_CLEAR; - DRM_READMEMORYBARRIER(); + if (temp & EVENT_PIPEB_FLAG) + pipeb_stats |= I915_HOTPLUG_INTERRUPT_ENABLE | + I915_HOTPLUG_CLEAR; + + I915_WRITE(I915REG_PIPEASTAT, pipea_stats); + (void) I915_READ(I915REG_PIPEASTAT); + I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); + (void) I915_READ(I915REG_PIPEBSTAT); + + /* Clear the generated interrupt */ + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + I915_WRITE(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ(I915REG_INT_IDENTITY_R); + } else { + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ16(I915REG_INT_IDENTITY_R); + } - temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | VSYNC_PIPEA_FLAG | - VSYNC_PIPEB_FLAG); if (dev->primary->master) { master_priv = dev->primary->master->driver_priv; @@ -658,15 +650,43 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) drm_locked_tasklet(dev, i915_vblank_tasklet); } - /* for now lest just ack it */ - if (temp & (1 << 17)) { - DRM_DEBUG("Hotplug event received\n"); + if (temp & (HOTPLUG_FLAG | EVENT_PIPEA_FLAG | EVENT_PIPEB_FLAG)) { + u32 temp2 = 0; - temp2 = I915_READ(PORT_HOTPLUG_STAT); + DRM_INFO("Hotplug event received\n"); - i915_run_hotplug_tasklet(dev, temp2); + if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) { +#if 0 + u32 b,c; + + b = I915_READ(SDVOB) & SDVO_PIPE_B_SELECT; + c = I915_READ(SDVOC) & SDVO_PIPE_B_SELECT; + + if (temp & EVENT_PIPEA_FLAG) { + if (!b) + temp2 |= SDVOB_HOTPLUG_INT_STATUS; + if (!c) + temp2 |= SDVOC_HOTPLUG_INT_STATUS; + + } + + if (temp & EVENT_PIPEB_FLAG) { + if (b) + temp2 |= SDVOB_HOTPLUG_INT_STATUS; + if (c) + temp2 |= SDVOC_HOTPLUG_INT_STATUS; + + } +#else + temp2 |= SDVOB_HOTPLUG_INT_STATUS | + SDVOC_HOTPLUG_INT_STATUS; +#endif + } else { + temp2 = I915_READ(PORT_HOTPLUG_STAT); - I915_WRITE(PORT_HOTPLUG_STAT,temp2); + I915_WRITE(PORT_HOTPLUG_STAT, temp2); + } + i915_run_hotplug_tasklet(dev, temp2); } return IRQ_HANDLED; @@ -691,23 +711,33 @@ int i915_emit_irq(struct drm_device *dev) return dev_priv->counter; } -void i915_user_irq_on(struct drm_i915_private *dev_priv) +void i915_user_irq_on(struct drm_device *dev) { + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + DRM_SPINLOCK(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= USER_INT_FLAG; - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + else + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } -void i915_user_irq_off(struct drm_i915_private *dev_priv) +void i915_user_irq_off(struct drm_device *dev) { + struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + DRM_SPINLOCK(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { // dev_priv->irq_enable_reg &= ~USER_INT_FLAG; - // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + // if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + // I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + // else + // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } @@ -725,10 +755,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (READ_BREADCRUMB(dev_priv) >= irq_nr) return 0; - i915_user_irq_on(dev_priv); + i915_user_irq_on(dev); DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); - i915_user_irq_off(dev_priv); + i915_user_irq_off(dev); if (ret == -EBUSY) { DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", @@ -803,7 +833,10 @@ int i915_enable_vblank(struct drm_device *dev, int plane) break; } - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + else + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); return 0; } @@ -826,7 +859,10 @@ void i915_disable_vblank(struct drm_device *dev, int plane) break; } - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + else + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } void i915_enable_interrupt (struct drm_device *dev) @@ -836,40 +872,62 @@ void i915_enable_interrupt (struct drm_device *dev) dev_priv->irq_enable_reg |= USER_INT_FLAG; - if (IS_I9XX(dev) && dev->mode_config.num_output) { - dev_priv->irq_enable_reg |= HOTPLUG_FLAG; + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + if (dev->mode_config.num_output) + dev_priv->irq_enable_reg |= HOTPLUG_FLAG; + } else { + if (dev->mode_config.num_output) + dev_priv->irq_enable_reg |= EVENT_PIPEA_FLAG | EVENT_PIPEB_FLAG; + + I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR); + I915_WRITE(I915REG_PIPEBSTAT, I915_READ(I915REG_PIPEBSTAT) | I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR); + } + + if (dev_priv->irq_enable_reg & (HOTPLUG_FLAG | EVENT_PIPEA_FLAG | EVENT_PIPEB_FLAG)) { + u32 temp = 0; - /* Activate the CRT */ - I915_WRITE(PORT_HOTPLUG_EN, CRT_HOTPLUG_INT_EN); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + temp = I915_READ(PORT_HOTPLUG_EN); - /* SDVOB */ - o = intel_sdvo_find(dev, 1); - if (o && intel_sdvo_supports_hotplug(o)) { - intel_sdvo_set_hotplug(o, 1); - I915_WRITE(PORT_HOTPLUG_EN, SDVOB_HOTPLUG_INT_EN); + /* Activate the CRT */ + temp |= CRT_HOTPLUG_INT_EN; } - /* SDVOC */ - o = intel_sdvo_find(dev, 0); - if (o && intel_sdvo_supports_hotplug(o)) { - intel_sdvo_set_hotplug(o, 1); - I915_WRITE(PORT_HOTPLUG_EN, SDVOC_HOTPLUG_INT_EN); + if (IS_I9XX(dev)) { + /* SDVOB */ + o = intel_sdvo_find(dev, 1); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + temp |= SDVOB_HOTPLUG_INT_EN; + } + + /* SDVOC */ + o = intel_sdvo_find(dev, 0); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + temp |= SDVOC_HOTPLUG_INT_EN; + } + + I915_WRITE(SDVOB, I915_READ(SDVOB) | SDVO_INTERRUPT_ENABLE); + I915_WRITE(SDVOC, I915_READ(SDVOC) | SDVO_INTERRUPT_ENABLE); + } else { + /* DVO ???? */ } + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { + I915_WRITE(PORT_HOTPLUG_EN, temp); + + DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN)); + DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT)); + + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + } } - if (IS_I9XX(dev)) { + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); - } else { + else I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); - } - - DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN)); - DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT)); - DRM_DEBUG("IER %08x\n",I915_READ(I915REG_INT_ENABLE_R)); - DRM_DEBUG("SDB %08x\n",I915_READ(SDVOB)); - - I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); dev_priv->irq_enabled = 1; } @@ -909,7 +967,11 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, return -EINVAL; } - flag = I915_READ(I915REG_INT_ENABLE_R); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) + flag = I915_READ(I915REG_INT_ENABLE_R); + else + flag = I915_READ16(I915REG_INT_ENABLE_R); + pipe->pipe = 0; if (flag & VSYNC_PIPEA_FLAG) pipe->pipe |= DRM_I915_VBLANK_PIPE_A; @@ -1086,8 +1148,10 @@ void i915_driver_irq_preinstall(struct drm_device * dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + I915_WRITE(I915REG_PIPEASTAT, 0xffff); + I915_WRITE(I915REG_PIPEBSTAT, 0xffff); I915_WRITE16(I915REG_HWSTAM, 0xeffe); - if (IS_I9XX(dev)) { + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { I915_WRITE(I915REG_INT_MASK_R, 0x0); I915_WRITE(I915REG_INT_ENABLE_R, 0x0); } else { @@ -1114,6 +1178,10 @@ int i915_driver_irq_postinstall(struct drm_device * dev) if (ret) return ret; + ret = drm_hotplug_init(dev); + if (ret) + return ret; + dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ i915_enable_interrupt(dev); @@ -1138,7 +1206,9 @@ void i915_driver_irq_uninstall(struct drm_device * dev) dev_priv->irq_enabled = 0; - if(IS_I9XX(dev)) { + I915_WRITE(I915REG_PIPEASTAT, 0xffff); + I915_WRITE(I915REG_PIPEBSTAT, 0xffff); + if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { I915_WRITE(I915REG_HWSTAM, 0xffffffff); I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); I915_WRITE(I915REG_INT_ENABLE_R, 0x0); -- cgit v1.2.3 From cf1a2499ed9a0051bcd8627136fb53b496b6484c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 11 Mar 2008 21:24:29 +0000 Subject: global hotplug events happen in the pipe A stat register, they are not pipe A specific. Remove pipe B code. --- shared-core/i915_irq.c | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4127383a..558693f1 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -577,6 +577,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; u32 temp = 0; u32 pipea_stats, pipeb_stats; + int hotplug = 0; /* On i8xx/i915 hw the IIR and IER are 16bit on i9xx its 32bit */ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) @@ -610,13 +611,15 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_VBLANK_CLEAR; } - if (temp & EVENT_PIPEA_FLAG) + /* This is a global event, and not a pipe A event */ + if (temp & EVENT_PIPEA_FLAG) { + if (pipea_stats & I915_HOTPLUG_CLEAR) + hotplug = 1; + pipea_stats |= I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR; - if (temp & EVENT_PIPEB_FLAG) - pipeb_stats |= I915_HOTPLUG_INTERRUPT_ENABLE | - I915_HOTPLUG_CLEAR; + } I915_WRITE(I915REG_PIPEASTAT, pipea_stats); (void) I915_READ(I915REG_PIPEASTAT); @@ -650,37 +653,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) drm_locked_tasklet(dev, i915_vblank_tasklet); } - if (temp & (HOTPLUG_FLAG | EVENT_PIPEA_FLAG | EVENT_PIPEB_FLAG)) { + if ((temp & HOTPLUG_FLAG) || hotplug) { u32 temp2 = 0; DRM_INFO("Hotplug event received\n"); if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) { -#if 0 - u32 b,c; - - b = I915_READ(SDVOB) & SDVO_PIPE_B_SELECT; - c = I915_READ(SDVOC) & SDVO_PIPE_B_SELECT; - - if (temp & EVENT_PIPEA_FLAG) { - if (!b) - temp2 |= SDVOB_HOTPLUG_INT_STATUS; - if (!c) - temp2 |= SDVOC_HOTPLUG_INT_STATUS; - - } - - if (temp & EVENT_PIPEB_FLAG) { - if (b) - temp2 |= SDVOB_HOTPLUG_INT_STATUS; - if (c) - temp2 |= SDVOC_HOTPLUG_INT_STATUS; - - } -#else temp2 |= SDVOB_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS; -#endif } else { temp2 = I915_READ(PORT_HOTPLUG_STAT); @@ -879,8 +859,8 @@ void i915_enable_interrupt (struct drm_device *dev) if (dev->mode_config.num_output) dev_priv->irq_enable_reg |= EVENT_PIPEA_FLAG | EVENT_PIPEB_FLAG; + /* Enable global interrupts for hotplug - not a pipeA event */ I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR); - I915_WRITE(I915REG_PIPEBSTAT, I915_READ(I915REG_PIPEBSTAT) | I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR); } if (dev_priv->irq_enable_reg & (HOTPLUG_FLAG | EVENT_PIPEA_FLAG | EVENT_PIPEB_FLAG)) { -- cgit v1.2.3 From 981f515e2bd4d570ea33bb74ae82cd5b56cc9121 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 12 Mar 2008 14:48:01 +1000 Subject: drm: fix fd closing ordering. If the master fd goes away before the aiglx fd, we try and get a lock that actually doesn't exist. --- linux-core/drm_fops.c | 96 +++++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index fcadc544..0ca43824 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -402,59 +402,63 @@ int drm_release(struct inode *inode, struct file *filp) current->pid, (long)old_encode_dev(file_priv->minor->device), dev->open_count); - if (dev->driver->reclaim_buffers_locked && file_priv->master->lock.hw_lock) { - if (drm_i_have_hw_lock(dev, file_priv)) { - dev->driver->reclaim_buffers_locked(dev, file_priv); - } else { - unsigned long _end=jiffies + 3*DRM_HZ; - int locked = 0; - - drm_idlelock_take(&file_priv->master->lock); - - /* - * Wait for a while. - */ - - do{ - spin_lock(&file_priv->master->lock.spinlock); - locked = file_priv->master->lock.idle_has_lock; - spin_unlock(&file_priv->master->lock.spinlock); - if (locked) - break; - schedule(); - } while (!time_after_eq(jiffies, _end)); - - if (!locked) { - DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" - "\tdriver to use reclaim_buffers_idlelocked() instead.\n" - "\tI will go on reclaiming the buffers anyway.\n"); + /* if the master has gone away we can't do anything with the lock */ + if (file_priv->minor->master) { + if (dev->driver->reclaim_buffers_locked && file_priv->master->lock.hw_lock) { + if (drm_i_have_hw_lock(dev, file_priv)) { + dev->driver->reclaim_buffers_locked(dev, file_priv); + } else { + unsigned long _end=jiffies + 3*DRM_HZ; + int locked = 0; + + drm_idlelock_take(&file_priv->master->lock); + + /* + * Wait for a while. + */ + + do{ + spin_lock(&file_priv->master->lock.spinlock); + locked = file_priv->master->lock.idle_has_lock; + spin_unlock(&file_priv->master->lock.spinlock); + if (locked) + break; + schedule(); + } while (!time_after_eq(jiffies, _end)); + + if (!locked) { + DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" + "\tdriver to use reclaim_buffers_idlelocked() instead.\n" + "\tI will go on reclaiming the buffers anyway.\n"); + } + + dev->driver->reclaim_buffers_locked(dev, file_priv); + drm_idlelock_release(&file_priv->master->lock); } + } - dev->driver->reclaim_buffers_locked(dev, file_priv); + if (dev->driver->reclaim_buffers_idlelocked && file_priv->master->lock.hw_lock) { + + drm_idlelock_take(&file_priv->master->lock); + dev->driver->reclaim_buffers_idlelocked(dev, file_priv); drm_idlelock_release(&file_priv->master->lock); + } - } - - if (dev->driver->reclaim_buffers_idlelocked && file_priv->master->lock.hw_lock) { - drm_idlelock_take(&file_priv->master->lock); - dev->driver->reclaim_buffers_idlelocked(dev, file_priv); - drm_idlelock_release(&file_priv->master->lock); - - } - - if (drm_i_have_hw_lock(dev, file_priv)) { - DRM_DEBUG("File %p released, freeing lock for context %d\n", - filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); - - drm_lock_free(&file_priv->master->lock, - _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); - } + if (drm_i_have_hw_lock(dev, file_priv)) { + DRM_DEBUG("File %p released, freeing lock for context %d\n", + filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); + + drm_lock_free(&file_priv->master->lock, + _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); + } + - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && - !dev->driver->reclaim_buffers_locked) { - dev->driver->reclaim_buffers(dev, file_priv); + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && + !dev->driver->reclaim_buffers_locked) { + dev->driver->reclaim_buffers(dev, file_priv); + } } drm_fasync(-1, filp, 0); -- cgit v1.2.3 From 7f04dd06e6003dd492ae5ddc876121a686f49157 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 12 Mar 2008 09:47:52 +0000 Subject: Add sample code to test hotplug events --- tests/modedemo/demo.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 83a33aa6..3fad984d 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -22,6 +22,7 @@ #include #include #endif +#include #include "xf86drm.h" #include "xf86drmMode.h" @@ -387,9 +388,28 @@ drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr out return crtc; } +static int driverfd; + +static void +hotplugSIGNAL(int sig, siginfo_t *si, void *d) +{ + union drm_wait_hotplug hw; + int ret; + + printf("GOT HOTPLUG EVENT!\n"); + + /* ask for another hotplug event ! */ + memset(&hw, 0, sizeof(hw)); + hw.request.type = _DRM_HOTPLUG_SIGNAL; + hw.request.signal = SIGUSR1; + ret = ioctl(driverfd, DRM_IOCTL_WAIT_HOTPLUG, &hw); +} + struct demo_driver* demoCreateDriver(void) { struct demo_driver* driver = malloc(sizeof(struct demo_driver)); + union drm_wait_hotplug hw; + int ret = 0; memset(driver, 0, sizeof(struct demo_driver)); @@ -400,6 +420,33 @@ struct demo_driver* demoCreateDriver(void) goto err_driver; } +#if 0 + /* ioctl wait for hotplug */ + do { + memset(&hw, 0, sizeof(hw)); + ret = ioctl(driver->fd, DRM_IOCTL_WAIT_HOTPLUG, &hw); + printf("HOTPLUG %d %d %d\n",ret,errno,hw.reply.counter); + } while (ret && errno == EBUSY); +#else + /* signal for hotplug */ + { + struct sigaction sa; + struct sigaction osa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = hotplugSIGNAL; + sigaction(SIGUSR1, &sa, &osa); + + driverfd = driver->fd; + + memset(&hw, 0, sizeof(hw)); + hw.request.type = _DRM_HOTPLUG_SIGNAL; + hw.request.signal = SIGUSR1; + ret = ioctl(driver->fd, DRM_IOCTL_WAIT_HOTPLUG, &hw); + } +#endif + demoUpdateRes(driver); if (!driver->res) { printf("could not retrive resources\n"); -- cgit v1.2.3 From 631c6af4d926fd1fe73f017cfb032538cee7ea7d Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 13 Mar 2008 11:47:37 +0000 Subject: Fix green offset --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 52ff3a67..7c4b0632 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -157,7 +157,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, break; case 16: var->red.offset = 11; - var->green.offset = 6; + var->green.offset = 5; var->blue.offset = 0; var->red.length = 5; var->green.length = 6; -- cgit v1.2.3 From d1513528d7e1a7bd119468087baa6839897627f4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 17 Mar 2008 16:32:27 +1000 Subject: drm: select the correct master to attempt to remove the lock from. When destroying DRI sarea, make sure you use the master associated with the sarea and not the one currently in charge --- linux-core/drm_bufs.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 031f8ba0..f6ff75ab 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -380,10 +380,12 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) struct drm_map_list *r_list = NULL, *list_t; drm_dma_handle_t dmah; int found = 0; + struct drm_master *master; /* Find the list entry for the map and remove it */ list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { if (r_list->map == map) { + master = r_list->master; list_del(&r_list->head); drm_ht_remove_key(&dev->map_hash, r_list->user_token >> PAGE_SHIFT); @@ -413,9 +415,13 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) break; case _DRM_SHM: vfree(map->handle); - dev->sigdata.lock = dev->primary->master->lock.hw_lock = NULL; /* SHM removed */ - dev->primary->master->lock.file_priv = NULL; - wake_up_interruptible(&dev->primary->master->lock.lock_queue); + if (master) { + if (dev->sigdata.lock == master->lock.hw_lock) + dev->sigdata.lock = NULL; + master->lock.hw_lock = NULL; /* SHM removed */ + master->lock.file_priv = NULL; + wake_up_interruptible(&master->lock.lock_queue); + } break; case _DRM_AGP: case _DRM_SCATTER_GATHER: -- cgit v1.2.3 From e6be93b2a6f508b2284a6d352f5f0640ef1a542a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 17 Mar 2008 16:33:15 +1000 Subject: drm: pick correct master for cleaning up When a master is exiting, make sure we clean it up and not the currently in charge master. --- linux-core/drm_fops.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 0ca43824..d5c59b19 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -488,13 +488,15 @@ int drm_release(struct inode *inode, struct file *filp) if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_fb_release(filp); - file_priv->master = NULL; - if (file_priv->is_master) { - drm_put_master(file_priv->minor->master); - file_priv->minor->master = NULL; + if (file_priv->minor->master == file_priv->master) + file_priv->minor->master = NULL; + drm_put_master(file_priv->master); } + file_priv->master = NULL; + file_priv->is_master = 0; + mutex_lock(&dev->struct_mutex); drm_object_release(filp); if (file_priv->remove_auth_on_close == 1) { -- cgit v1.2.3 From 2d0411cb7544ea45b5879d4f454cb9ee3c9ff5fb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 17 Mar 2008 16:34:15 +1000 Subject: i915: safety check the sarea map still exists --- shared-core/i915_init.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index fa2fc3da..a76acb4e 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -383,7 +383,9 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) if (!master_priv) return; - drm_rmmap(dev, master_priv->sarea); + if (master_priv->sarea) + drm_rmmap(dev, master_priv->sarea); + drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); master->driver_priv = NULL; -- cgit v1.2.3 From 607964ed9e5f6d86a0960bef2341e7f5de9c71da Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 17 Mar 2008 16:37:46 +1000 Subject: drm: add master set/drop protocol this may not survive long - just need something for testing --- libdrm/xf86drm.c | 17 +++++++++++++++++ libdrm/xf86drm.h | 3 +++ linux-core/drmP.h | 4 ++++ linux-core/drm_drv.c | 3 +++ linux-core/drm_stub.c | 23 +++++++++++++++++++++++ shared-core/drm.h | 3 +++ 6 files changed, 53 insertions(+) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index bcf562d5..53275f52 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2977,3 +2977,20 @@ void drmCloseOnce(int fd) } } } + +int drmSetMaster(int fd) +{ + int ret; + + fprintf(stderr,"Setting master \n"); + ret = ioctl(fd, DRM_IOCTL_SET_MASTER, 0); + return ret; +} + +int drmDropMaster(int fd) +{ + int ret; + fprintf(stderr,"Dropping master \n"); + ret = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); + return ret; +} diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 7b418604..35780aca 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -660,6 +660,9 @@ extern int drmSLLookupNeighbors(void *l, unsigned long key, extern int drmOpenOnce(void *unused, const char *BusID, int *newlyopened); extern void drmCloseOnce(int fd); +extern int drmSetMaster(int fd); +extern int drmDropMaster(int fd); + #include "xf86mm.h" #endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 8273c879..c2c3cdde 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1266,6 +1266,10 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); extern struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev); extern void drm_agp_chipset_flush(struct drm_device *dev); /* Stub support (drm_stub.h) */ +extern int drm_setmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern struct drm_master *drm_get_master(struct drm_minor *minor); extern void drm_put_master(struct drm_master *master); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 09372c71..649d4cae 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -76,6 +76,9 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 6856075b..f66dec07 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -88,6 +88,29 @@ again: return new_id; } +int drm_setmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + if (file_priv->minor->master && file_priv->minor->master != file_priv->master) + return -EINVAL; + + if (!file_priv->master) + return -EINVAL; + + if (!file_priv->minor->master && file_priv->minor->master != file_priv->master) + file_priv->minor->master = file_priv->master; + return 0; +} + +int drm_dropmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + if (!file_priv->master) + return -EINVAL; + file_priv->minor->master = NULL; + return 0; +} + struct drm_master *drm_get_master(struct drm_minor *minor) { struct drm_master *master; diff --git a/shared-core/drm.h b/shared-core/drm.h index a1ebfb93..a72263ae 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1200,6 +1200,9 @@ struct drm_mode_hotplug { #define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map) #define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) +#define DRM_IOCTL_SET_MASTER DRM_IO(0x1e) +#define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f) + #define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx) #define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx) #define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx) -- cgit v1.2.3 From 6ef119abf5d19c85fe039fd19d12e9bd64fd44df Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 20 Mar 2008 17:43:43 +0100 Subject: radeon_ms: fix fence --- linux-core/amd_legacy_fence.h | 1 + shared-core/amd_legacy_fence.h | 39 +++++++++++++++++++++++++++++++++++++++ shared-core/radeon_ms.h | 1 - shared-core/radeon_ms_drm.c | 7 ++++--- shared-core/radeon_ms_fence.c | 16 ++++++++-------- 5 files changed, 52 insertions(+), 12 deletions(-) create mode 120000 linux-core/amd_legacy_fence.h create mode 100644 shared-core/amd_legacy_fence.h diff --git a/linux-core/amd_legacy_fence.h b/linux-core/amd_legacy_fence.h new file mode 120000 index 00000000..e7b30f25 --- /dev/null +++ b/linux-core/amd_legacy_fence.h @@ -0,0 +1 @@ +../shared-core/amd_legacy_fence.h \ No newline at end of file diff --git a/shared-core/amd_legacy_fence.h b/shared-core/amd_legacy_fence.h new file mode 100644 index 00000000..d82138ba --- /dev/null +++ b/shared-core/amd_legacy_fence.h @@ -0,0 +1,39 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Dave Airlie + * Jerome Glisse + */ +#ifndef __AMD_LEGACY_FENCE_H__ +#define __AMD_LEGACY_FENCE_H__ + +struct legacy_fence +{ + uint32_t sequence; + uint32_t sequence_last_reported; + uint32_t sequence_last_flush; + uint32_t fence_reg; +}; + +#endif diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index 12c945f9..d9aa0351 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -31,7 +31,6 @@ #define __RADEON_MS_H__ #include "radeon_ms_drv.h" -#include "amd_r3xx_fence.h" #include "radeon_ms_reg.h" #include "radeon_ms_drm.h" #include "radeon_ms_rom.h" diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index b9245d99..40f5d791 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -29,6 +29,7 @@ */ #include "drm_pciids.h" #include "radeon_ms.h" +#include "amd_legacy_fence.h" static uint32_t radeon_ms_mem_prios[] = { @@ -116,12 +117,12 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) return ret; } - dev_priv->fence = drm_alloc(sizeof(struct r3xx_fence), DRM_MEM_DRIVER); + dev_priv->fence = drm_alloc(sizeof(struct legacy_fence), DRM_MEM_DRIVER); if (dev_priv->fence == NULL) { radeon_ms_driver_unload(dev); return -ENOMEM; } - memset(dev_priv->fence, 0, sizeof(struct r3xx_fence)); + memset(dev_priv->fence, 0, sizeof(struct legacy_fence)); /* we don't want userspace to be able to map this so don't use * drm_addmap */ @@ -305,7 +306,7 @@ int radeon_ms_driver_unload(struct drm_device *dev) drm_core_ioremapfree(&dev_priv->vram, dev); } DRM_INFO("[radeon_ms] map released\n"); - drm_free(dev_priv->fence, sizeof(struct r3xx_fence), DRM_MEM_DRIVER); + drm_free(dev_priv->fence, sizeof(struct legacy_fence), DRM_MEM_DRIVER); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c index 162d37d6..994c3e48 100644 --- a/shared-core/radeon_ms_fence.c +++ b/shared-core/radeon_ms_fence.c @@ -27,7 +27,7 @@ * Jerome Glisse */ #include "radeon_ms.h" -#include "amd_r3xx_fence.h" +#include "amd_legacy_fence.h" #define R3XX_FENCE_SEQUENCE_RW_FLUSH 0x80000000u @@ -35,7 +35,7 @@ static inline int r3xx_fence_emit_sequence(struct drm_device *dev, struct drm_radeon_private *dev_priv, uint32_t sequence) { - struct r3xx_fence *r3xx_fence = dev_priv->fence; + struct legacy_fence *r3xx_fence = dev_priv->fence; uint32_t cmd[2]; int i, r; @@ -58,7 +58,7 @@ static inline int r3xx_fence_emit_sequence(struct drm_device *dev, return -EBUSY; } -static inline uint32_t r3xx_fence_sequence(struct r3xx_fence *r3xx_fence) +static inline uint32_t r3xx_fence_sequence(struct legacy_fence *r3xx_fence) { r3xx_fence->sequence += 1; if (unlikely(r3xx_fence->sequence > 0x7fffffffu)) { @@ -69,7 +69,7 @@ static inline uint32_t r3xx_fence_sequence(struct r3xx_fence *r3xx_fence) static inline void r3xx_fence_report(struct drm_device *dev, struct drm_radeon_private *dev_priv, - struct r3xx_fence *r3xx_fence) + struct legacy_fence *r3xx_fence) { uint32_t fence_types = DRM_FENCE_TYPE_EXE; uint32_t sequence; @@ -95,7 +95,7 @@ static inline void r3xx_fence_report(struct drm_device *dev, static void r3xx_fence_flush(struct drm_device *dev, uint32_t class) { struct drm_radeon_private *dev_priv = dev->dev_private; - struct r3xx_fence *r3xx_fence = dev_priv->fence; + struct legacy_fence *r3xx_fence = dev_priv->fence; uint32_t sequence; sequence = r3xx_fence_sequence(r3xx_fence); @@ -109,7 +109,7 @@ static void r3xx_fence_poll(struct drm_device *dev, uint32_t fence_class, struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_fence_manager *fm = &dev->fm; struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; - struct r3xx_fence *r3xx_fence = dev_priv->fence; + struct legacy_fence *r3xx_fence = dev_priv->fence; if (unlikely(!dev_priv)) { return; @@ -129,7 +129,7 @@ static int r3xx_fence_emit(struct drm_device *dev, uint32_t class, uint32_t *native_type) { struct drm_radeon_private *dev_priv = dev->dev_private; - struct r3xx_fence *r3xx_fence = dev_priv->fence; + struct legacy_fence *r3xx_fence = dev_priv->fence; uint32_t tmp; if (!dev_priv || dev_priv->cp_ready != 1) { @@ -162,7 +162,7 @@ static uint32_t r3xx_fence_needed_flush(struct drm_fence_object *fence) { struct drm_device *dev = fence->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct r3xx_fence *r3xx_fence = dev_priv->fence; + struct legacy_fence *r3xx_fence = dev_priv->fence; struct drm_fence_driver *driver = dev->driver->fence_driver; uint32_t flush_types, diff; -- cgit v1.2.3 From acb6c9ef97df999f3fa87639b1bb4f2840970f71 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 27 Mar 2008 15:55:49 +1000 Subject: drm: remove authentication on master exit. using contexts for this is bad for multiple masters --- linux-core/drmP.h | 1 - linux-core/drm_context.c | 3 --- linux-core/drm_fops.c | 13 +++++++------ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index c2c3cdde..f96e6bee 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -415,7 +415,6 @@ struct drm_file { unsigned long ioctl_count; struct list_head lhead; struct drm_minor *minor; - int remove_auth_on_close; unsigned long lock_count; /* diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index febee9f7..f3d69ff7 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -444,9 +444,6 @@ int drm_rmctx(struct drm_device *dev, void *data, struct drm_ctx *ctx = data; DRM_DEBUG("%d\n", ctx->handle); - if (ctx->handle == DRM_KERNEL_CONTEXT + 1) { - file_priv->remove_auth_on_close = 1; - } if (ctx->handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_dtor) dev->driver->context_dtor(dev, ctx->handle); diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index d5c59b19..043552fd 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -489,6 +489,13 @@ int drm_release(struct inode *inode, struct file *filp) drm_fb_release(filp); if (file_priv->is_master) { + struct drm_file *temp; + list_for_each_entry(temp, &dev->filelist, lhead) { + if ((temp->master == file_priv->master) && + (temp != file_priv)) + temp->authenticated = 0; + } + if (file_priv->minor->master == file_priv->master) file_priv->minor->master = NULL; drm_put_master(file_priv->master); @@ -499,15 +506,9 @@ int drm_release(struct inode *inode, struct file *filp) mutex_lock(&dev->struct_mutex); drm_object_release(filp); - if (file_priv->remove_auth_on_close == 1) { - struct drm_file *temp; - list_for_each_entry(temp, &dev->filelist, lhead) - temp->authenticated = 0; - } list_del(&file_priv->lhead); - mutex_unlock(&dev->struct_mutex); if (dev->driver->postclose) -- cgit v1.2.3 From 0da289bafd2da72a14f3d5cf82fec836d30f7b8d Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 27 Mar 2008 20:08:37 +0100 Subject: radeon_ms: this is a modesetting driver, bring things up to date --- linux-core/radeon_ms_drv.c | 1 + shared-core/radeon_ms_drm.c | 15 ++++++++++++++- shared-core/radeon_ms_exec.c | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_ms_drv.c b/linux-core/radeon_ms_drv.c index cf9699f4..fc3c106a 100644 --- a/linux-core/radeon_ms_drv.c +++ b/linux-core/radeon_ms_drv.c @@ -132,6 +132,7 @@ static void __exit radeon_ms_driver_exit(void) static int __init radeon_ms_driver_init(void) { driver.num_ioctls = radeon_ms_num_ioctls; + driver.driver_features |= DRIVER_MODESET; return drm_init(&driver, pciidlist); } diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index 40f5d791..b3fb7e03 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -155,7 +155,13 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) /* init bo driver */ dev_priv->fence_id_last = 1; dev_priv->fence_reg = SCRATCH_REG2; - drm_bo_driver_init(dev); + ret = drm_bo_driver_init(dev); + if (ret != 0) { + DRM_INFO("[radeon_ms] failed to init bo driver %d.\n", ret); + radeon_ms_driver_unload(dev); + return ret; + } + DRM_INFO("[radeon_ms] bo driver succesfull %d.\n", dev->bm.initialized); /* initialize vram */ ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size, 1); if (ret != 0) { @@ -239,6 +245,13 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) return ret; } + if (dev->primary && dev->control) { + DRM_INFO("[radeon_ms] control 0x%lx, render 0x%lx\n", + (long)dev->primary->device, (long)dev->control->device); + } else { + DRM_INFO("[radeon_ms] error control 0x%lx, render 0x%lx\n", + (long)dev->primary, (long)dev->control); + } DRM_INFO("[radeon_ms] successfull initialization\n"); return 0; } diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c index 8e28b19e..d8f67842 100644 --- a/shared-core/radeon_ms_exec.c +++ b/shared-core/radeon_ms_exec.c @@ -79,10 +79,10 @@ static int radeon_ms_execbuffer_args(struct drm_device *dev, if (args_count >= 1) { ret = drm_bo_handle_validate(file_priv, arg.d.req.bo_req.handle, - arg.d.req.bo_req.fence_class, arg.d.req.bo_req.flags, arg.d.req.bo_req.mask, arg.d.req.bo_req.hint, + arg.d.req.bo_req.fence_class, 0, &rep.bo_info, &buffers[args_count]); -- cgit v1.2.3 From 2d9eccfd056425e4ebdf1a7b879979fd0a9d1340 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 30 Mar 2008 12:45:57 +0200 Subject: radeon_ms: add hang debuging helper functions --- shared-core/Makefile.am | 1 + shared-core/radeon_ms.h | 2 ++ shared-core/radeon_ms_cp.c | 51 ++++++++++++++++++++++++++--- shared-core/radeon_ms_drm.c | 1 + shared-core/radeon_ms_drm.h | 1 + shared-core/radeon_ms_exec.c | 34 ++++++++++--------- shared-core/radeon_ms_gpu.c | 59 +++++++++++++++++++-------------- shared-core/radeon_ms_reg.h | 77 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 182 insertions(+), 44 deletions(-) diff --git a/shared-core/Makefile.am b/shared-core/Makefile.am index 7193e527..42e08e75 100644 --- a/shared-core/Makefile.am +++ b/shared-core/Makefile.am @@ -32,6 +32,7 @@ klibdrminclude_HEADERS = \ nouveau_drm.h \ r128_drm.h \ radeon_drm.h \ + radeon_ms_drm.h \ savage_drm.h \ sis_drm.h \ via_drm.h \ diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index d9aa0351..13e41e1b 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -373,6 +373,8 @@ void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state); void radeon_ms_cp_stop(struct drm_device *dev); int radeon_ms_cp_wait(struct drm_device *dev, int n); int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count); +int radeon_ms_resetcp(struct drm_device *dev, void *data, + struct drm_file *file_priv); /* radeon_ms_crtc.c */ int radeon_ms_crtc_create(struct drm_device *dev, int crtc); diff --git a/shared-core/radeon_ms_cp.c b/shared-core/radeon_ms_cp.c index c01769bd..7b26c0ba 100644 --- a/shared-core/radeon_ms_cp.c +++ b/shared-core/radeon_ms_cp.c @@ -156,7 +156,7 @@ int radeon_ms_cp_init(struct drm_device *dev) dev_priv->ring_buffer_object->mem.num_pages, &dev_priv->ring_buffer_map); if (ret) { - DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); + DRM_INFO("[radeon_ms] error mapping ring buffer: %d\n", ret); return ret; } dev_priv->ring_buffer = dev_priv->ring_buffer_map.virtual; @@ -275,15 +275,32 @@ void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state) void radeon_ms_cp_stop(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t rbbm_status, rbbm_status_cp_mask; - MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE, - CSQ_MODE__CSQ_PRIDIS_INDDIS)); + dev_priv->cp_ready = 0; + MMIO_W(CP_CSQ_CNTL, 0); + MMIO_R(CP_CSQ_CNTL); + MMIO_W(CP_CSQ_MODE, 0); + MMIO_R(CP_CSQ_MODE); + MMIO_W(RBBM_SOFT_RESET, RBBM_SOFT_RESET__SOFT_RESET_CP); + MMIO_R(RBBM_SOFT_RESET); + MMIO_W(RBBM_SOFT_RESET, 0); + MMIO_R(RBBM_SOFT_RESET); + rbbm_status = MMIO_R(RBBM_STATUS); + rbbm_status_cp_mask = (RBBM_STATUS__CPRQ_ON_RBB | + RBBM_STATUS__CPRQ_IN_RTBUF | + RBBM_STATUS__CP_CMDSTRM_BUSY); + if (rbbm_status & rbbm_status_cp_mask) { + DRM_INFO("[radeon_ms] cp busy (RBBM_STATUS: 0x%08X " + "RBBM_STATUS(cp_mask): 0x%08X)\n", rbbm_status, + rbbm_status_cp_mask); + } MMIO_W(CP_RB_CNTL, CP_RB_CNTL__RB_RPTR_WR_ENA); MMIO_W(CP_RB_RPTR_WR, 0); MMIO_W(CP_RB_WPTR, 0); DRM_UDELAY(5); dev_priv->ring_wptr = dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR); - MMIO_W(CP_RB_WPTR, dev_priv->ring_wptr); + MMIO_W(CP_RB_CNTL, 0); } int radeon_ms_cp_wait(struct drm_device *dev, int n) @@ -332,6 +349,7 @@ int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count) dev_priv->ring_free -= count; for (i = 0; i < count; i++) { dev_priv->ring_buffer[dev_priv->ring_wptr] = cmd[i]; + DRM_INFO("ring[%d] = 0x%08X\n", dev_priv->ring_wptr, cmd[i]); dev_priv->ring_wptr++; dev_priv->ring_wptr &= dev_priv->ring_mask; } @@ -343,3 +361,28 @@ int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count) spin_unlock(&ring_lock); return 0; } + +int radeon_ms_resetcp(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + DRM_INFO("[radeon_ms]--------------------------------------------\n"); + + /* reset VAP */ + DRM_INFO("[radeon_ms] status before VAP : RBBM_STATUS: 0x%08X\n", + MMIO_R(RBBM_STATUS)); + MMIO_W(RBBM_SOFT_RESET, RBBM_SOFT_RESET__SOFT_RESET_VAP); + MMIO_R(RBBM_SOFT_RESET); + MMIO_W(RBBM_SOFT_RESET, 0); + MMIO_R(RBBM_SOFT_RESET); + for (i = 0; i < 100; i++) { + DRM_UDELAY(100); + } + DRM_INFO("[radeon_ms] status after VAP : RBBM_STATUS: 0x%08X\n", + MMIO_R(RBBM_STATUS)); + + DRM_INFO("[radeon_ms]--------------------------------------------\n"); + return 0; +} diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index b3fb7e03..869ccac4 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -60,6 +60,7 @@ struct drm_bo_driver radeon_ms_bo_driver = { struct drm_ioctl_desc radeon_ms_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_EXECBUFFER, radeon_ms_execbuffer, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_RESETCP, radeon_ms_resetcp, DRM_AUTH), }; int radeon_ms_num_ioctls = DRM_ARRAY_SIZE(radeon_ms_ioctls); diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h index 39c050ad..e1b4c18c 100644 --- a/shared-core/radeon_ms_drm.h +++ b/shared-core/radeon_ms_drm.h @@ -47,6 +47,7 @@ /* radeon ms ioctl */ #define DRM_RADEON_EXECBUFFER 0x00 +#define DRM_RADEON_RESETCP 0x01 struct drm_radeon_execbuffer_arg { uint64_t next; diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c index d8f67842..68b3e145 100644 --- a/shared-core/radeon_ms_exec.c +++ b/shared-core/radeon_ms_exec.c @@ -210,24 +210,26 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, } /* fence */ - ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); - if (ret) { - drm_putback_buffer_objects(dev); - DRM_ERROR("[radeon_ms] fence buffer objects failed\n"); - goto out_free_release; - } - if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) { - ret = drm_fence_add_user_object(file_priv, fence, - fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE); - if (!ret) { - fence_arg->handle = fence->base.hash.key; - fence_arg->fence_class = fence->fence_class; - fence_arg->type = fence->type; - fence_arg->signaled = fence->signaled_types; - fence_arg->sequence = fence->sequence; + if (execbuffer->args_count > 1) { + ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); + if (ret) { + drm_putback_buffer_objects(dev); + DRM_ERROR("[radeon_ms] fence buffer objects failed\n"); + goto out_free_release; + } + if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) { + ret = drm_fence_add_user_object(file_priv, fence, + fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE); + if (!ret) { + fence_arg->handle = fence->base.hash.key; + fence_arg->fence_class = fence->fence_class; + fence_arg->type = fence->type; + fence_arg->signaled = fence->signaled_types; + fence_arg->sequence = fence->sequence; + } } + drm_fence_usage_deref_unlocked(&fence); } - drm_fence_usage_deref_unlocked(&fence); out_free_release: drm_bo_kunmap(&cmd_kmap); radeon_ms_execbuffer_args_clean(dev, buffers, execbuffer->args_count); diff --git a/shared-core/radeon_ms_gpu.c b/shared-core/radeon_ms_gpu.c index 28683781..21c86027 100644 --- a/shared-core/radeon_ms_gpu.c +++ b/shared-core/radeon_ms_gpu.c @@ -128,9 +128,20 @@ static void radeon_ms_gpu_reset(struct drm_device *dev) MMIO_W(RBBM_SOFT_RESET, 0); MMIO_R(RBBM_SOFT_RESET); +#if 0 cache_mode = MMIO_R(RB2D_DSTCACHE_MODE); MMIO_W(RB2D_DSTCACHE_MODE, cache_mode | RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE); +#else + reset_mask = RBBM_SOFT_RESET__SOFT_RESET_CP | + RBBM_SOFT_RESET__SOFT_RESET_HI | + RBBM_SOFT_RESET__SOFT_RESET_E2; + MMIO_W(RBBM_SOFT_RESET, rbbm_soft_reset | reset_mask); + MMIO_R(RBBM_SOFT_RESET); + MMIO_W(RBBM_SOFT_RESET, 0); + cache_mode = MMIO_R(RB3D_DSTCACHE_CTLSTAT); + MMIO_W(RB3D_DSTCACHE_CTLSTAT, cache_mode | (0xf)); +#endif MMIO_W(HOST_PATH_CNTL, host_path_cntl | HOST_PATH_CNTL__HDP_SOFT_RESET); MMIO_R(HOST_PATH_CNTL); @@ -166,7 +177,7 @@ static void radeon_ms_gpu_resume(struct drm_device *dev) DRM_UDELAY(1); } if (i >= dev_priv->usec_timeout) { - DRM_ERROR("[radeon_ms] timeout waiting for crtc...\n"); + DRM_INFO("[radeon_ms] timeout waiting for crtc...\n"); } for (i = 0; i < dev_priv->usec_timeout; i++) { if (!(CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET & @@ -176,7 +187,7 @@ static void radeon_ms_gpu_resume(struct drm_device *dev) DRM_UDELAY(1); } if (i >= dev_priv->usec_timeout) { - DRM_ERROR("[radeon_ms] timeout waiting for crtc...\n"); + DRM_INFO("[radeon_ms] timeout waiting for crtc...\n"); } DRM_UDELAY(10000); } @@ -187,7 +198,6 @@ static void radeon_ms_gpu_stop(struct drm_device *dev) uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl; uint32_t crtc2_gen_cntl, i; - radeon_ms_wait_for_idle(dev); /* Capture MC_STATUS in case things go wrong ... */ ov0_scale_cntl = dev_priv->ov0_scale_cntl = MMIO_R(OV0_SCALE_CNTL); crtc_ext_cntl = dev_priv->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL); @@ -244,10 +254,10 @@ static void radeon_ms_gpu_stop(struct drm_device *dev) } break; default: - DRM_ERROR("Unknown radeon family, aborting\n"); + DRM_INFO("Unknown radeon family, aborting\n"); return; } - DRM_ERROR("[radeon_ms] failed to stop gpu...will proceed anyway\n"); + DRM_INFO("[radeon_ms] failed to stop gpu...will proceed anyway\n"); DRM_UDELAY(20000); } @@ -264,7 +274,7 @@ static int radeon_ms_wait_for_fifo(struct drm_device *dev, int num_fifo) return 0; DRM_UDELAY(1); } - DRM_ERROR("[radeon_ms] failed to wait for fifo\n"); + DRM_INFO("[radeon_ms] failed to wait for fifo\n"); return -EBUSY; } @@ -391,7 +401,7 @@ void radeon_ms_gpu_flush(struct drm_device *dev) MMIO_W(RB3D_DSTCACHE_CTLSTAT_R3, purge3d); break; default: - DRM_ERROR("Unknown radeon family, aborting\n"); + DRM_INFO("Unknown radeon family, aborting\n"); return; } for (i = 0; i < dev_priv->usec_timeout; i++) { @@ -401,7 +411,7 @@ void radeon_ms_gpu_flush(struct drm_device *dev) } DRM_UDELAY(1); } - DRM_ERROR("[radeon_ms] gpu flush timeout\n"); + DRM_INFO("[radeon_ms] gpu flush timeout\n"); } void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) @@ -478,8 +488,8 @@ void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) ret = radeon_ms_wait_for_fifo(dev, 2); if (ret) { ok = 0; - DRM_ERROR("[radeon_ms] no fifo for setting up dst & src gui\n"); - DRM_ERROR("[radeon_ms] proceed anyway\n"); + DRM_INFO("[radeon_ms] no fifo for setting up dst & src gui\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); } fbstart = (MC_FB_LOCATION__MC_FB_START__MASK & MMIO_R(MC_FB_LOCATION)) << 16; @@ -491,8 +501,8 @@ void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) ret = radeon_ms_wait_for_fifo(dev, 1); if (ret) { ok = 0; - DRM_ERROR("[radeon_ms] no fifo for setting up dp data type\n"); - DRM_ERROR("[radeon_ms] proceed anyway\n"); + DRM_INFO("[radeon_ms] no fifo for setting up dp data type\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); } #ifdef __BIG_ENDIAN MMIO_W(DP_DATATYPE, DP_DATATYPE__DP_BYTE_PIX_ORDER); @@ -503,16 +513,16 @@ void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) ret = radeon_ms_wait_for_fifo(dev, 1); if (ret) { ok = 0; - DRM_ERROR("[radeon_ms] no fifo for setting up surface cntl\n"); - DRM_ERROR("[radeon_ms] proceed anyway\n"); + DRM_INFO("[radeon_ms] no fifo for setting up surface cntl\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); } MMIO_W(SURFACE_CNTL, SURFACE_CNTL__SURF_TRANSLATION_DIS); ret = radeon_ms_wait_for_fifo(dev, 2); if (ret) { ok = 0; - DRM_ERROR("[radeon_ms] no fifo for setting scissor\n"); - DRM_ERROR("[radeon_ms] proceed anyway\n"); + DRM_INFO("[radeon_ms] no fifo for setting scissor\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); } MMIO_W(DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff); MMIO_W(DEFAULT2_SC_BOTTOM_RIGHT, 0x1fff1fff); @@ -520,16 +530,16 @@ void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) ret = radeon_ms_wait_for_fifo(dev, 1); if (ret) { ok = 0; - DRM_ERROR("[radeon_ms] no fifo for setting up gui cntl\n"); - DRM_ERROR("[radeon_ms] proceed anyway\n"); + DRM_INFO("[radeon_ms] no fifo for setting up gui cntl\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); } MMIO_W(DP_GUI_MASTER_CNTL, 0); ret = radeon_ms_wait_for_fifo(dev, 5); if (ret) { ok = 0; - DRM_ERROR("[radeon_ms] no fifo for setting up clear color\n"); - DRM_ERROR("[radeon_ms] proceed anyway\n"); + DRM_INFO("[radeon_ms] no fifo for setting up clear color\n"); + DRM_INFO("[radeon_ms] proceed anyway\n"); } MMIO_W(DP_BRUSH_BKGD_CLR, 0x00000000); MMIO_W(DP_BRUSH_FRGD_CLR, 0xffffffff); @@ -538,7 +548,7 @@ void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state) MMIO_W(DP_WRITE_MSK, 0xffffffff); if (!ok) { - DRM_ERROR("[radeon_ms] engine restore not enough fifo\n"); + DRM_INFO("[radeon_ms] engine restore not enough fifo\n"); } } @@ -566,12 +576,13 @@ void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state) int radeon_ms_wait_for_idle(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; int i, j, ret; for (i = 0; i < 2; i++) { ret = radeon_ms_wait_for_fifo(dev, 64); if (ret) { - DRM_ERROR("[radeon_ms] fifo not empty\n"); + DRM_INFO("[radeon_ms] fifo not empty\n"); } for (j = 0; j < dev_priv->usec_timeout; j++) { if (!(RBBM_STATUS__GUI_ACTIVE & MMIO_R(RBBM_STATUS))) { @@ -580,10 +591,10 @@ int radeon_ms_wait_for_idle(struct drm_device *dev) } DRM_UDELAY(1); } - DRM_ERROR("[radeon_ms] idle timed out: status=0x%08x\n", + DRM_INFO("[radeon_ms] idle timed out: status=0x%08x\n", MMIO_R(RBBM_STATUS)); - radeon_ms_gpu_stop(dev); radeon_ms_gpu_reset(dev); + radeon_ms_gpu_resume(dev); } return -EBUSY; } diff --git a/shared-core/radeon_ms_reg.h b/shared-core/radeon_ms_reg.h index 56963c63..adb6434b 100644 --- a/shared-core/radeon_ms_reg.h +++ b/shared-core/radeon_ms_reg.h @@ -226,6 +226,16 @@ #define SCRATCH_REG7 0x000015FC #define SCRATCH_REG7__SCRATCH_REG7__MASK 0xFFFFFFFF #define SCRATCH_REG7__SCRATCH_REG7__SHIFT 0 +#define SC_SCISSOR0 0x000043E0 +#define SC_SCISSOR0__XS0__MASK 0x00001FFF +#define SC_SCISSOR0__XS0__SHIFT 0 +#define SC_SCISSOR0__YS0__MASK 0x03FFE000 +#define SC_SCISSOR0__YS0__SHIFT 13 +#define SC_SCISSOR1 0x000043E4 +#define SC_SCISSOR1__XS1__MASK 0x00001FFF +#define SC_SCISSOR1__XS1__SHIFT 0 +#define SC_SCISSOR1__YS1__MASK 0x03FFE000 +#define SC_SCISSOR1__YS1__SHIFT 13 #define PCIE_INDEX 0x00000030 #define PCIE_INDEX__PCIE_INDEX__MASK 0x000007FF #define PCIE_INDEX__PCIE_INDEX__SHIFT 0 @@ -276,6 +286,17 @@ #define PCIE_TX_GART_ERROR__GART_INVALID_WRITE 0x00000008 #define PCIE_TX_GART_ERROR__GART_INVALID_ADDR__MASK 0xFFFFFFF0 #define PCIE_TX_GART_ERROR__GART_INVALID_ADDR__SHIFT 4 +#define CP_CSQ_MODE 0x00000744 +#define CP_CSQ_MODE__INDIRECT2_START__MASK 0x0000007F +#define CP_CSQ_MODE__INDIRECT2_START__SHIFT 0 +#define CP_CSQ_MODE__INDIRECT1_START__MASK 0x00007F00 +#define CP_CSQ_MODE__INDIRECT1_START__SHIFT 8 +#define CP_CSQ_MODE__CSQ_INDIRECT2_MODE 0x04000000 +#define CP_CSQ_MODE__CSQ_INDIRECT2_ENABLE 0x08000000 +#define CP_CSQ_MODE__CSQ_INDIRECT1_MODE 0x10000000 +#define CP_CSQ_MODE__CSQ_INDIRECT1_ENABLE 0x20000000 +#define CP_CSQ_MODE__CSQ_PRIMARY_MODE 0x40000000 +#define CP_CSQ_MODE__CSQ_PRIMARY_ENABLE 0x80000000 #define CP_RB_CNTL 0x00000704 #define CP_RB_CNTL__RB_BUFSZ__MASK 0x0000003F #define CP_RB_CNTL__RB_BUFSZ__SHIFT 0 @@ -1265,6 +1286,33 @@ #define ISYNC_CNTL__ISYNC_TRIG3D_IDLE2D 0x00000008 #define ISYNC_CNTL__ISYNC_WAIT_IDLEGUI 0x00000010 #define ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI 0x00000020 +#define GA_SOFT_RESET 0x0000429C +#define GA_SOFT_RESET__SOFT_RESET_COUNT__MASK 0x0000FFFF +#define GA_SOFT_RESET__SOFT_RESET_COUNT__SHIFT 0 +#define RBBM_CNTL 0x000000EC +#define RBBM_CNTL__RB_SETTLE__MASK 0x0000000F +#define RBBM_CNTL__RB_SETTLE__SHIFT 0 +#define RBBM_CNTL__ABORTCLKS_HI__MASK 0x00000070 +#define RBBM_CNTL__ABORTCLKS_HI__SHIFT 4 +#define RBBM_CNTL__ABORTCLKS_CP__MASK 0x00000700 +#define RBBM_CNTL__ABORTCLKS_CP__SHIFT 8 +#define RBBM_CNTL__ABORTCLKS_CFIFO__MASK 0x00007000 +#define RBBM_CNTL__ABORTCLKS_CFIFO__SHIFT 12 +#define RBBM_CNTL__CPQ_DATA_SWAP 0x00020000 +#define RBBM_CNTL__NO_ABORT_IDCT 0x00200000 +#define RBBM_CNTL__NO_ABORT_BIOS 0x00400000 +#define RBBM_CNTL__NO_ABORT_FB 0x00800000 +#define RBBM_CNTL__NO_ABORT_CP 0x01000000 +#define RBBM_CNTL__NO_ABORT_HI 0x02000000 +#define RBBM_CNTL__NO_ABORT_HDP 0x04000000 +#define RBBM_CNTL__NO_ABORT_MC 0x08000000 +#define RBBM_CNTL__NO_ABORT_AIC 0x10000000 +#define RBBM_CNTL__NO_ABORT_VIP 0x20000000 +#define RBBM_CNTL__NO_ABORT_DISP 0x40000000 +#define RBBM_CNTL__NO_ABORT_CG 0x80000000 +#define RBBM_CNTL__NO_ABORT_VAP 0x00080000 +#define RBBM_CNTL__NO_ABORT_GA 0x00100000 +#define RBBM_CNTL__NO_ABORT_TVOUT 0x00800000 #define RBBM_STATUS 0x00000E40 #define RBBM_STATUS__CMDFIFO_AVAIL__MASK 0x0000007F #define RBBM_STATUS__CMDFIFO_AVAIL__SHIFT 0 @@ -1307,6 +1355,19 @@ #define RBBM_SOFT_RESET__SOFT_RESET_VAP 0x00000004 #define RBBM_SOFT_RESET__SOFT_RESET_GA 0x00002000 #define RBBM_SOFT_RESET__SOFT_RESET_IDCT 0x00004000 +#define RBBM_CMDFIFO_ADDR 0x00000E70 +#define RBBM_CMDFIFO_ADDR__CMDFIFO_ADDR__MASK 0x0000003F +#define RBBM_CMDFIFO_ADDR__CMDFIFO_ADDR__SHIFT 0 +#define RBBM_CMDFIFO_ADDR__CMDFIFO_ADDR_R3__MASK 0x000001FF +#define RBBM_CMDFIFO_ADDR__CMDFIFO_ADDR_R3__SHIFT 0 +#define RBBM_CMDFIFO_DATA 0x00000E74 +#define RBBM_CMDFIFO_DATA__CMDFIFO_DATA__MASK 0xFFFFFFFF +#define RBBM_CMDFIFO_DATA__CMDFIFO_DATA__SHIFT 0 +#define RBBM_CMDFIFO_STAT 0x00000E7C +#define RBBM_CMDFIFO_STAT__CMDFIFO_RPTR__MASK 0x0000003F +#define RBBM_CMDFIFO_STAT__CMDFIFO_RPTR__SHIFT 0 +#define RBBM_CMDFIFO_STAT__CMDFIFO_WPTR__MASK 0x00003F00 +#define RBBM_CMDFIFO_STAT__CMDFIFO_WPTR__SHIFT 8 #define WAIT_UNTIL 0x00001720 #define WAIT_UNTIL__WAIT_CRTC_PFLIP 0x00000001 #define WAIT_UNTIL__WAIT_RE_CRTC_VLINE 0x00000002 @@ -1677,5 +1738,21 @@ #define DP_WRITE_MSK 0x000016CC #define DP_WRITE_MSK__DP_WRITE_MSK__MASK 0xFFFFFFFF #define DP_WRITE_MSK__DP_WRITE_MSK__SHIFT 0 +#define US_CONFIG 0x00004600 +#define US_CONFIG__NLEVEL__MASK 0x00000007 +#define US_CONFIG__NLEVEL__SHIFT 0 +#define US_CONFIG__FIRST_TEX 0x00000008 +#define US_CONFIG__PERF0__MASK 0x000001F0 +#define US_CONFIG__PERF0__SHIFT 4 +#define US_CONFIG__PERF1__MASK 0x00003E00 +#define US_CONFIG__PERF1__SHIFT 9 +#define US_CONFIG__PERF2__MASK 0x0007C000 +#define US_CONFIG__PERF2__SHIFT 14 +#define US_CONFIG__PERF3__MASK 0x00F80000 +#define US_CONFIG__PERF3__SHIFT 19 +#define US_RESET 0x0000460C +#define VAP_PVS_STATE_FLUSH_REG 0x00002284 +#define VAP_PVS_STATE_FLUSH_REG__DATA_REGISTER__MASK 0xFFFFFFFF +#define VAP_PVS_STATE_FLUSH_REG__DATA_REGISTER__SHIFT 0 #endif -- cgit v1.2.3 From 09e637848a6afa54a091c4c70fdfbfbdce7ac805 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 31 Mar 2008 00:55:05 +0200 Subject: radeon_ms: initial pass at command buffer validation --- linux-core/amd_cbuffer.h | 1 + shared-core/amd_cbuffer.h | 51 ++++++ shared-core/radeon_ms.h | 16 +- shared-core/radeon_ms_bo.c | 11 +- shared-core/radeon_ms_bus.c | 3 +- shared-core/radeon_ms_cp.c | 31 +--- shared-core/radeon_ms_exec.c | 359 +++++++++++++++++++++++++++++++---------- shared-core/radeon_ms_family.c | 1 + shared-core/radeon_ms_gpu.c | 3 +- shared-core/radeon_ms_reg.h | 29 ++++ 10 files changed, 377 insertions(+), 128 deletions(-) create mode 120000 linux-core/amd_cbuffer.h create mode 100644 shared-core/amd_cbuffer.h diff --git a/linux-core/amd_cbuffer.h b/linux-core/amd_cbuffer.h new file mode 120000 index 00000000..780b9d8f --- /dev/null +++ b/linux-core/amd_cbuffer.h @@ -0,0 +1 @@ +../shared-core/amd_cbuffer.h \ No newline at end of file diff --git a/shared-core/amd_cbuffer.h b/shared-core/amd_cbuffer.h new file mode 100644 index 00000000..bca05751 --- /dev/null +++ b/shared-core/amd_cbuffer.h @@ -0,0 +1,51 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#ifndef __AMD_CBUFFER_H__ +#define __AMD_CBUFFER_H__ + +/* struct amd_cbuffer are for command buffer, this is the structure passed + * around during command validation (ie check that user have the right to + * execute the given command). + */ + +struct amd_cbuffer_arg +{ + struct list_head list; + struct drm_buffer_object *buffer; + int32_t dw_id; +}; + +struct amd_cbuffer +{ + uint32_t *cbuffer; + uint32_t cbuffer_dw_count; + struct amd_cbuffer_arg arg_unused; + struct amd_cbuffer_arg arg_used; + struct amd_cbuffer_arg *args; +}; + +#endif diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index 13e41e1b..e4010d84 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -35,6 +35,7 @@ #include "radeon_ms_drm.h" #include "radeon_ms_rom.h" #include "radeon_ms_properties.h" +#include "amd_cbuffer.h" #define DRIVER_AUTHOR "Jerome Glisse, Dave Airlie, Gareth Hughes, "\ "Keith Whitwell, others." @@ -483,21 +484,6 @@ void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state); void radeon_ms_state_restore(struct drm_device *dev, struct radeon_state *state); - -/* packect stuff **************************************************************/ -#define RADEON_CP_PACKET0 0x00000000 -#define CP_PACKET0(reg, n) \ - (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2)) -#define CP_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 -# define GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) -# define GMC_DST_PITCH_OFFSET_CNTL (1 << 1) -# define GMC_BRUSH_NONE (15 << 4) -# define GMC_SRC_DATATYPE_COLOR (3 << 12) -# define ROP3_S 0x00cc0000 -# define DP_SRC_SOURCE_MEMORY (2 << 24) -# define GMC_CLR_CMP_CNTL_DIS (1 << 28) -# define GMC_WR_MSK_DIS (1 << 30) - /* helper macro & functions ***************************************************/ #define REG_S(rn, bn, v) (((v) << rn##__##bn##__SHIFT) & rn##__##bn##__MASK) #define REG_G(rn, bn, v) (((v) & rn##__##bn##__MASK) >> rn##__##bn##__SHIFT) diff --git a/shared-core/radeon_ms_bo.c b/shared-core/radeon_ms_bo.c index 6d9a97c1..015595a4 100644 --- a/shared-core/radeon_ms_bo.c +++ b/shared-core/radeon_ms_bo.c @@ -33,6 +33,15 @@ #include "radeon_ms.h" +#define GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +#define GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +#define GMC_BRUSH_NONE (15 << 4) +#define GMC_SRC_DATATYPE_COLOR (3 << 12) +#define ROP3_S 0x00cc0000 +#define DP_SRC_SOURCE_MEMORY (2 << 24) +#define GMC_CLR_CMP_CNTL_DIS (1 << 28) +#define GMC_WR_MSK_DIS (1 << 30) + void radeon_ms_bo_copy_blit(struct drm_device *dev, uint32_t src_offset, uint32_t dst_offset, @@ -60,7 +69,7 @@ void radeon_ms_bo_copy_blit(struct drm_device *dev, if (c >= 8192) { c = 8191; } - cmd[0] = CP_PACKET3_CNTL_BITBLT_MULTI | (5 << 16); + cmd[0] = CP_PACKET3(PACKET3_OPCODE_BITBLT, 5); cmd[1] = GMC_SRC_PITCH_OFFSET_CNTL | GMC_DST_PITCH_OFFSET_CNTL | GMC_BRUSH_NONE | diff --git a/shared-core/radeon_ms_bus.c b/shared-core/radeon_ms_bus.c index ed8fb211..333fd558 100644 --- a/shared-core/radeon_ms_bus.c +++ b/shared-core/radeon_ms_bus.c @@ -218,6 +218,7 @@ int radeon_ms_agp_finish(struct drm_device *dev) return 0; } dev_priv->bus_ready = 0; + DRM_INFO("[radeon_ms] release agp\n"); drm_agp_release(dev); return 0; } @@ -237,7 +238,7 @@ int radeon_ms_agp_init(struct drm_device *dev) } ret = drm_agp_acquire(dev); if (ret) { - DRM_ERROR("[radeon_ms] error failed to acquire agp\n"); + DRM_ERROR("[radeon_ms] error failed to acquire agp %d\n", ret); return ret; } agp_status = MMIO_R(AGP_STATUS); diff --git a/shared-core/radeon_ms_cp.c b/shared-core/radeon_ms_cp.c index 7b26c0ba..f551000a 100644 --- a/shared-core/radeon_ms_cp.c +++ b/shared-core/radeon_ms_cp.c @@ -156,7 +156,7 @@ int radeon_ms_cp_init(struct drm_device *dev) dev_priv->ring_buffer_object->mem.num_pages, &dev_priv->ring_buffer_map); if (ret) { - DRM_INFO("[radeon_ms] error mapping ring buffer: %d\n", ret); + DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); return ret; } dev_priv->ring_buffer = dev_priv->ring_buffer_map.virtual; @@ -275,32 +275,15 @@ void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state) void radeon_ms_cp_stop(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; - uint32_t rbbm_status, rbbm_status_cp_mask; - dev_priv->cp_ready = 0; - MMIO_W(CP_CSQ_CNTL, 0); - MMIO_R(CP_CSQ_CNTL); - MMIO_W(CP_CSQ_MODE, 0); - MMIO_R(CP_CSQ_MODE); - MMIO_W(RBBM_SOFT_RESET, RBBM_SOFT_RESET__SOFT_RESET_CP); - MMIO_R(RBBM_SOFT_RESET); - MMIO_W(RBBM_SOFT_RESET, 0); - MMIO_R(RBBM_SOFT_RESET); - rbbm_status = MMIO_R(RBBM_STATUS); - rbbm_status_cp_mask = (RBBM_STATUS__CPRQ_ON_RBB | - RBBM_STATUS__CPRQ_IN_RTBUF | - RBBM_STATUS__CP_CMDSTRM_BUSY); - if (rbbm_status & rbbm_status_cp_mask) { - DRM_INFO("[radeon_ms] cp busy (RBBM_STATUS: 0x%08X " - "RBBM_STATUS(cp_mask): 0x%08X)\n", rbbm_status, - rbbm_status_cp_mask); - } + MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE, + CSQ_MODE__CSQ_PRIDIS_INDDIS)); MMIO_W(CP_RB_CNTL, CP_RB_CNTL__RB_RPTR_WR_ENA); MMIO_W(CP_RB_RPTR_WR, 0); MMIO_W(CP_RB_WPTR, 0); DRM_UDELAY(5); dev_priv->ring_wptr = dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR); - MMIO_W(CP_RB_CNTL, 0); + MMIO_W(CP_RB_WPTR, dev_priv->ring_wptr); } int radeon_ms_cp_wait(struct drm_device *dev, int n) @@ -349,7 +332,7 @@ int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count) dev_priv->ring_free -= count; for (i = 0; i < count; i++) { dev_priv->ring_buffer[dev_priv->ring_wptr] = cmd[i]; - DRM_INFO("ring[%d] = 0x%08X\n", dev_priv->ring_wptr, cmd[i]); + DRM_INFO("ring[%d]=0x%08X\n", dev_priv->ring_wptr, cmd[i]); dev_priv->ring_wptr++; dev_priv->ring_wptr &= dev_priv->ring_mask; } @@ -363,7 +346,7 @@ int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count) } int radeon_ms_resetcp(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file_priv) { struct drm_radeon_private *dev_priv = dev->dev_private; int i; @@ -381,7 +364,7 @@ int radeon_ms_resetcp(struct drm_device *dev, void *data, DRM_UDELAY(100); } DRM_INFO("[radeon_ms] status after VAP : RBBM_STATUS: 0x%08X\n", - MMIO_R(RBBM_STATUS)); + MMIO_R(RBBM_STATUS)); DRM_INFO("[radeon_ms]--------------------------------------------\n"); return 0; diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c index 68b3e145..574e5a06 100644 --- a/shared-core/radeon_ms_exec.c +++ b/shared-core/radeon_ms_exec.c @@ -25,14 +25,15 @@ * Jerome Glisse */ #include "radeon_ms.h" +#include "amd_cbuffer.h" static void radeon_ms_execbuffer_args_clean(struct drm_device *dev, - struct drm_buffer_object **buffers, + struct amd_cbuffer *cbuffer, uint32_t args_count) { mutex_lock(&dev->struct_mutex); while (args_count--) { - drm_bo_usage_deref_locked(&buffers[args_count]); + drm_bo_usage_deref_locked(&cbuffer->args[args_count].buffer); } mutex_unlock(&dev->struct_mutex); } @@ -40,8 +41,7 @@ static void radeon_ms_execbuffer_args_clean(struct drm_device *dev, static int radeon_ms_execbuffer_args(struct drm_device *dev, struct drm_file *file_priv, struct drm_radeon_execbuffer *execbuffer, - struct drm_buffer_object **buffers, - uint32_t *relocs) + struct amd_cbuffer *cbuffer) { struct drm_radeon_execbuffer_arg arg; struct drm_bo_arg_rep rep; @@ -57,17 +57,18 @@ static int radeon_ms_execbuffer_args(struct drm_device *dev, ret = -EINVAL; goto out_err; } - buffers[args_count] = NULL; + INIT_LIST_HEAD(&cbuffer->args[args_count].list); + cbuffer->args[args_count].buffer = NULL; if (copy_from_user(&arg, (void __user *)((unsigned)data), sizeof(struct drm_radeon_execbuffer_arg))) { ret = -EFAULT; goto out_err; } mutex_lock(&dev->struct_mutex); - buffers[args_count] = + cbuffer->args[args_count].buffer = drm_lookup_buffer_object(file_priv, arg.d.req.arg_handle, 1); - relocs[args_count] = arg.reloc_offset; + cbuffer->args[args_count].dw_id = arg.reloc_offset; mutex_unlock(&dev->struct_mutex); if (arg.d.req.op != drm_bo_validate) { DRM_ERROR("[radeon_ms] buffer object operation wasn't " @@ -76,17 +77,15 @@ static int radeon_ms_execbuffer_args(struct drm_device *dev, goto out_err; } memset(&rep, 0, sizeof(struct drm_bo_arg_rep)); - if (args_count >= 1) { - ret = drm_bo_handle_validate(file_priv, - arg.d.req.bo_req.handle, - arg.d.req.bo_req.flags, - arg.d.req.bo_req.mask, - arg.d.req.bo_req.hint, - arg.d.req.bo_req.fence_class, - 0, - &rep.bo_info, - &buffers[args_count]); - } + ret = drm_bo_handle_validate(file_priv, + arg.d.req.bo_req.handle, + arg.d.req.bo_req.flags, + arg.d.req.bo_req.mask, + arg.d.req.bo_req.hint, + arg.d.req.bo_req.fence_class, + 0, + &rep.bo_info, + &cbuffer->args[args_count].buffer); if (ret) { DRM_ERROR("[radeon_ms] error on handle validate %d\n", ret); @@ -101,6 +100,10 @@ static int radeon_ms_execbuffer_args(struct drm_device *dev, goto out_err; } data = next; + + list_add_tail(&cbuffer->args[args_count].list, + &cbuffer->arg_unused.list); + args_count++; } while (next != 0); if (args_count != execbuffer->args_count) { @@ -111,34 +114,201 @@ static int radeon_ms_execbuffer_args(struct drm_device *dev, } return 0; out_err: - radeon_ms_execbuffer_args_clean(dev, buffers, args_count); + radeon_ms_execbuffer_args_clean(dev, cbuffer, args_count); return ret; } -static int radeon_ms_execbuffer_check(struct drm_device *dev, - struct drm_file *file_priv, - struct drm_radeon_execbuffer *execbuffer, - struct drm_buffer_object **buffers, - uint32_t *relocs, - uint32_t *cmd) +enum { + REGISTER_FORBIDDEN = 0, + REGISTER_SAFE, + REGISTER_SET_OFFSET, +}; +static uint8_t _r3xx_register_right[0x5000 >> 2]; + +static int amd_cbuffer_packet0_set_offset(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + uint32_t reg, int dw_id, + struct amd_cbuffer_arg *arg) +{ + uint32_t gpu_addr; + int ret; + + ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, &gpu_addr); + if (ret) { + return ret; + } + switch (reg) { + default: + return -EINVAL; + } + return 0; +} + +static struct amd_cbuffer_arg * +amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id) +{ + struct amd_cbuffer_arg *arg; + + list_for_each_entry(arg, &head->list, list) { + if (arg->dw_id == dw_id) { + return arg; + } + } + /* no buffer at this dw index */ + return NULL; +} + +static int amd_cbuffer_packet0_check(struct drm_device *dev, + struct drm_file *file_priv, + struct amd_cbuffer *cbuffer, + int dw_id, + uint8_t *register_right) { - uint32_t i, gpu_addr; + struct amd_cbuffer_arg *arg; + uint32_t reg, count, r, i; int ret; - for (i = 0; i < execbuffer->args_count; i++) { - if (relocs[i]) { - ret = radeon_ms_bo_get_gpu_addr(dev, &buffers[i]->mem, - &gpu_addr); + reg = cbuffer->cbuffer[dw_id] & PACKET0_REG_MASK; + count = (cbuffer->cbuffer[dw_id] & PACKET0_COUNT_MASK) >> + PACKET0_COUNT_SHIFT; + for (r = reg, i = 0; i <= count; i++, r++) { + switch (register_right[i]) { + case REGISTER_FORBIDDEN: + return -EINVAL; + case REGISTER_SAFE: + break; + case REGISTER_SET_OFFSET: + arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, + dw_id + i +1); + if (arg == NULL) { + return -EINVAL; + } + /* remove from unparsed list */ + list_del(&arg->list); + list_add_tail(&arg->list, &cbuffer->arg_used.list); + /* set the offset */ + ret = amd_cbuffer_packet0_set_offset(dev, cbuffer, + r, dw_id + i + 1, + arg); if (ret) { return ret; } - cmd[relocs[i]] |= (gpu_addr) >> 10; + break; } } - for (i = 0; i < execbuffer->cmd_size; i++) { -#if 0 - DRM_INFO("cmd[%d]=0x%08X\n", i, cmd[i]); -#endif + /* header + N + 1 dword passed test */ + return count + 2; +} + +static int amd_cbuffer_packet3_check(struct drm_device *dev, + struct drm_file *file_priv, + struct amd_cbuffer *cbuffer, + int dw_id) +{ + struct amd_cbuffer_arg *arg; + uint32_t opcode, count; + uint32_t s_auth, s_mask; + uint32_t gpu_addr; + int ret; + + opcode = (cbuffer->cbuffer[dw_id] & PACKET3_OPCODE_MASK) >> + PACKET3_OPCODE_SHIFT; + count = (cbuffer->cbuffer[dw_id] & PACKET3_COUNT_MASK) >> + PACKET3_COUNT_SHIFT; + switch (opcode) { + case PACKET3_OPCODE_NOP: + break; + case PACKET3_OPCODE_BITBLT: + case PACKET3_OPCODE_BITBLT_MULTI: + DRM_INFO("[radeon_ms] exec step - [05][P3]00.00\n"); + /* we only alow simple blit */ + if (count != 5) { + return -EINVAL; + } + DRM_INFO("[radeon_ms] exec step - [05][P3]01.00\n"); + s_mask = 0xf; + s_auth = 0x3; + if ((cbuffer->cbuffer[dw_id + 1] & s_mask) != s_auth) { + return -EINVAL; + } + DRM_INFO("[radeon_ms] exec step - [05][P3]02.00\n"); + arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, dw_id+2); + if (arg == NULL) { + return -EINVAL; + } + DRM_INFO("[radeon_ms] exec step - [05][P3]03.00\n"); + ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, + &gpu_addr); + if (ret) { + return ret; + } + DRM_INFO("[radeon_ms] exec step - [05][P3]04.00\n"); + gpu_addr = (gpu_addr >> 10) & 0x003FFFFF; + cbuffer->cbuffer[dw_id + 2] &= 0xFFC00000; + cbuffer->cbuffer[dw_id + 2] |= gpu_addr; + arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, dw_id+3); + if (arg == NULL) { + return -EINVAL; + } + DRM_INFO("[radeon_ms] exec step - [05][P3]05.00\n"); + ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, + &gpu_addr); + if (ret) { + return ret; + } + DRM_INFO("[radeon_ms] exec step - [05][P3]06.00\n"); + gpu_addr = (gpu_addr >> 10) & 0x003FFFFF; + cbuffer->cbuffer[dw_id + 3] &= 0xFFC00000; + cbuffer->cbuffer[dw_id + 3] |= gpu_addr; + DRM_INFO("[radeon_ms] exec step - [05][P3]07.00\n"); + /* FIXME: check that source & destination are big enough + * for requested blit */ + break; + default: + return -EINVAL; + } + /* header + N + 1 dword passed test */ + return count + 2; +} + +static int amd_cbuffer_check(struct drm_device *dev, + struct drm_file *file_priv, + struct amd_cbuffer *cbuffer) +{ + uint32_t i; + int ret; + + for (i = 0; i < cbuffer->cbuffer_dw_count;) { + DRM_INFO("[radeon_ms] exec step - [05]00.00 %d 0x%08X\n", + i, cbuffer->cbuffer[i]); + switch (PACKET_HEADER_GET(cbuffer->cbuffer[i])) { + case 0: + ret = amd_cbuffer_packet0_check(dev, file_priv, + cbuffer, i, + _r3xx_register_right); + if (ret) { + return ret; + } + /* advance to next packet */ + i += ret; + break; + case 1: + /* we don't accept packet 1 */ + return -EINVAL; + case 2: + /* packet 2 */ + i += 1; + break; + case 3: + ret = amd_cbuffer_packet3_check(dev, file_priv, + cbuffer, i); + if (ret) { + return ret; + } + /* advance to next packet */ + i += ret; + break; + } } return 0; } @@ -148,97 +318,116 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, { struct drm_radeon_execbuffer *execbuffer = data; struct drm_fence_arg *fence_arg = &execbuffer->fence_arg; - struct drm_buffer_object **buffers; struct drm_bo_kmap_obj cmd_kmap; struct drm_fence_object *fence; - uint32_t *relocs; - uint32_t *cmd; int cmd_is_iomem; int ret = 0; + struct amd_cbuffer cbuffer; + /* command buffer dword count must be >= 0 */ + if (execbuffer->cmd_size < 0) { + return -EINVAL; + } + /* FIXME: Lock buffer manager, is this really needed ? + */ + DRM_INFO("[radeon_ms] exec step - 00.00\n"); ret = drm_bo_read_lock(&dev->bm.bm_lock); if (ret) { return ret; } - relocs = drm_calloc(execbuffer->args_count, sizeof(uint32_t), - DRM_MEM_DRIVER); - if (relocs == NULL) { - drm_bo_read_unlock(&dev->bm.bm_lock); - return -ENOMEM; - } - buffers = drm_calloc(execbuffer->args_count, - sizeof(struct drm_buffer_object *), - DRM_MEM_DRIVER); - if (buffers == NULL) { - drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)), - DRM_MEM_DRIVER); - drm_bo_read_unlock(&dev->bm.bm_lock); - return -ENOMEM; + DRM_INFO("[radeon_ms] exec step - 01.00\n"); + cbuffer.args = drm_calloc(execbuffer->args_count, + sizeof(struct amd_cbuffer_arg), + DRM_MEM_DRIVER); + if (cbuffer.args == NULL) { + ret = -ENOMEM; + goto out_free; } + + INIT_LIST_HEAD(&cbuffer.arg_unused.list); + INIT_LIST_HEAD(&cbuffer.arg_used.list); + /* process arguments */ - ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer, - buffers, relocs); + DRM_INFO("[radeon_ms] exec step - 02.00\n"); + ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer, &cbuffer); if (ret) { DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n"); goto out_free; } + /* map command buffer */ + DRM_INFO("[radeon_ms] exec step - 03.00\n"); + cbuffer.cbuffer_dw_count = (cbuffer.args[0].buffer->mem.num_pages * + PAGE_SIZE) >> 2; + if (execbuffer->cmd_size > cbuffer.cbuffer_dw_count) { + ret = -EINVAL; + goto out_free_release; + } + DRM_INFO("[radeon_ms] exec step - 04.00\n"); + cbuffer.cbuffer_dw_count = execbuffer->cmd_size; memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj)); - ret = drm_bo_kmap(buffers[0], - 0, - buffers[0]->mem.num_pages, - &cmd_kmap); + ret = drm_bo_kmap(cbuffer.args[0].buffer, 0, + cbuffer.args[0].buffer->mem.num_pages, &cmd_kmap); if (ret) { DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); goto out_free_release; } - cmd = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem); + DRM_INFO("[radeon_ms] exec step - 05.00\n"); + cbuffer.cbuffer = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem); + DRM_INFO("[radeon_ms] exec step - 05.01\n"); + list_del(&cbuffer.args[0].list); + DRM_INFO("[radeon_ms] exec step - 05.02\n"); + list_add_tail(&cbuffer.args[0].list , &cbuffer.arg_used.list); + DRM_INFO("[radeon_ms] exec step - 05.03\n"); + /* do cmd checking & relocations */ - ret = radeon_ms_execbuffer_check(dev, file_priv, execbuffer, - buffers, relocs, cmd); + ret = amd_cbuffer_check(dev, file_priv, &cbuffer); if (ret) { drm_putback_buffer_objects(dev); goto out_free_release; } + DRM_INFO("[radeon_ms] exec step - 06.00\n"); - ret = radeon_ms_ring_emit(dev, cmd, execbuffer->cmd_size); + ret = radeon_ms_ring_emit(dev, cbuffer.cbuffer, + cbuffer.cbuffer_dw_count); if (ret) { drm_putback_buffer_objects(dev); goto out_free_release; } + DRM_INFO("[radeon_ms] exec step - 07.00\n"); /* fence */ - if (execbuffer->args_count > 1) { - ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); - if (ret) { - drm_putback_buffer_objects(dev); - DRM_ERROR("[radeon_ms] fence buffer objects failed\n"); - goto out_free_release; - } - if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) { - ret = drm_fence_add_user_object(file_priv, fence, - fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE); - if (!ret) { - fence_arg->handle = fence->base.hash.key; - fence_arg->fence_class = fence->fence_class; - fence_arg->type = fence->type; - fence_arg->signaled = fence->signaled_types; - fence_arg->sequence = fence->sequence; - } + ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); + if (ret) { + drm_putback_buffer_objects(dev); + DRM_ERROR("[radeon_ms] fence buffer objects failed\n"); + goto out_free_release; + } + if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) { + ret = drm_fence_add_user_object(file_priv, fence, + fence_arg->flags & + DRM_FENCE_FLAG_SHAREABLE); + if (!ret) { + fence_arg->handle = fence->base.hash.key; + fence_arg->fence_class = fence->fence_class; + fence_arg->type = fence->type; + fence_arg->signaled = fence->signaled_types; + fence_arg->sequence = fence->sequence; } - drm_fence_usage_deref_unlocked(&fence); } + drm_fence_usage_deref_unlocked(&fence); + DRM_INFO("[radeon_ms] exec step - 08.00\n"); out_free_release: drm_bo_kunmap(&cmd_kmap); - radeon_ms_execbuffer_args_clean(dev, buffers, execbuffer->args_count); + radeon_ms_execbuffer_args_clean(dev, &cbuffer, execbuffer->args_count); + DRM_INFO("[radeon_ms] exec step - 09.00\n"); out_free: - drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)), - DRM_MEM_DRIVER); - drm_free(buffers, - (execbuffer->args_count * sizeof(struct drm_buffer_object *)), + drm_free(cbuffer.args, + (execbuffer->args_count * sizeof(struct amd_cbuffer_arg)), DRM_MEM_DRIVER); drm_bo_read_unlock(&dev->bm.bm_lock); + DRM_INFO("[radeon_ms] exec step - 10.00\n"); return ret; } diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c index b70dca20..5e83766a 100644 --- a/shared-core/radeon_ms_family.c +++ b/shared-core/radeon_ms_family.c @@ -117,6 +117,7 @@ int radeon_ms_family_init(struct drm_device *dev) switch (dev_priv->bus_type) { case RADEON_AGP: dev_priv->create_ttm = drm_agp_init_ttm; + dev_priv->bus_finish = radeon_ms_agp_finish; dev_priv->bus_init = radeon_ms_agp_init; dev_priv->bus_restore = radeon_ms_agp_restore; dev_priv->bus_save = radeon_ms_agp_save; diff --git a/shared-core/radeon_ms_gpu.c b/shared-core/radeon_ms_gpu.c index 21c86027..5b03dc35 100644 --- a/shared-core/radeon_ms_gpu.c +++ b/shared-core/radeon_ms_gpu.c @@ -128,7 +128,7 @@ static void radeon_ms_gpu_reset(struct drm_device *dev) MMIO_W(RBBM_SOFT_RESET, 0); MMIO_R(RBBM_SOFT_RESET); -#if 0 +#if 1 cache_mode = MMIO_R(RB2D_DSTCACHE_MODE); MMIO_W(RB2D_DSTCACHE_MODE, cache_mode | RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE); @@ -576,7 +576,6 @@ void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state) int radeon_ms_wait_for_idle(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_state *state = &dev_priv->driver_state; int i, j, ret; for (i = 0; i < 2; i++) { diff --git a/shared-core/radeon_ms_reg.h b/shared-core/radeon_ms_reg.h index adb6434b..25063990 100644 --- a/shared-core/radeon_ms_reg.h +++ b/shared-core/radeon_ms_reg.h @@ -1755,4 +1755,33 @@ #define VAP_PVS_STATE_FLUSH_REG__DATA_REGISTER__MASK 0xFFFFFFFF #define VAP_PVS_STATE_FLUSH_REG__DATA_REGISTER__SHIFT 0 +/* packet stuff **************************************************************/ +#define PACKET_HEADER_MASK 0xC0000000 +#define PACKET_HEADER_SHIFT 30 +#define PACKET_HEADER_GET(p) (((p) & PACKET_HEADER_MASK) >> PACKET_HEADER_SHIFT) +#define PACKET_HEADER_SET(p) (((p) << PACKET_HEADER_SHIFT) & PACKET_HEADER_MASK) + +#define PACKET0_HEADER 0x0 +# define PACKET0_REG_MASK 0x00001FFF +# define PACKET0_REG_SHIFT 0 +# define PACKET0_COUNT_MASK 0x3FFF0000 +# define PACKET0_COUNT_SHIFT 16 +#define PACKET1_HEADER 0x1 +#define PACKET2_HEADER 0x2 +#define PACKET3_HEADER 0x3 +# define PACKET3_OPCODE_MASK 0x0000FF00 +# define PACKET3_OPCODE_SHIFT 8 +# define PACKET3_OPCODE_NOP 0x10 +# define PACKET3_OPCODE_BITBLT 0x92 +# define PACKET3_OPCODE_BITBLT_MULTI 0x9B +# define PACKET3_COUNT_MASK 0x3FFF0000 +# define PACKET3_COUNT_SHIFT 16 + +#define CP_PACKET0(r, n) (PACKET_HEADER_SET(PACKET0_HEADER) |\ + ((((r)>>2)< Date: Mon, 31 Mar 2008 21:50:02 +0200 Subject: radeon_ms: small fix & cleanup to command checking --- shared-core/radeon_ms_exec.c | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c index 574e5a06..32b55eaf 100644 --- a/shared-core/radeon_ms_exec.c +++ b/shared-core/radeon_ms_exec.c @@ -220,47 +220,40 @@ static int amd_cbuffer_packet3_check(struct drm_device *dev, break; case PACKET3_OPCODE_BITBLT: case PACKET3_OPCODE_BITBLT_MULTI: - DRM_INFO("[radeon_ms] exec step - [05][P3]00.00\n"); /* we only alow simple blit */ if (count != 5) { return -EINVAL; } - DRM_INFO("[radeon_ms] exec step - [05][P3]01.00\n"); s_mask = 0xf; s_auth = 0x3; if ((cbuffer->cbuffer[dw_id + 1] & s_mask) != s_auth) { return -EINVAL; } - DRM_INFO("[radeon_ms] exec step - [05][P3]02.00\n"); arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, dw_id+2); if (arg == NULL) { return -EINVAL; } - DRM_INFO("[radeon_ms] exec step - [05][P3]03.00\n"); ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, &gpu_addr); if (ret) { return ret; } - DRM_INFO("[radeon_ms] exec step - [05][P3]04.00\n"); gpu_addr = (gpu_addr >> 10) & 0x003FFFFF; cbuffer->cbuffer[dw_id + 2] &= 0xFFC00000; cbuffer->cbuffer[dw_id + 2] |= gpu_addr; + arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, dw_id+3); if (arg == NULL) { return -EINVAL; } - DRM_INFO("[radeon_ms] exec step - [05][P3]05.00\n"); ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, &gpu_addr); if (ret) { return ret; } - DRM_INFO("[radeon_ms] exec step - [05][P3]06.00\n"); gpu_addr = (gpu_addr >> 10) & 0x003FFFFF; cbuffer->cbuffer[dw_id + 3] &= 0xFFC00000; cbuffer->cbuffer[dw_id + 3] |= gpu_addr; - DRM_INFO("[radeon_ms] exec step - [05][P3]07.00\n"); /* FIXME: check that source & destination are big enough * for requested blit */ break; @@ -279,14 +272,12 @@ static int amd_cbuffer_check(struct drm_device *dev, int ret; for (i = 0; i < cbuffer->cbuffer_dw_count;) { - DRM_INFO("[radeon_ms] exec step - [05]00.00 %d 0x%08X\n", - i, cbuffer->cbuffer[i]); switch (PACKET_HEADER_GET(cbuffer->cbuffer[i])) { case 0: ret = amd_cbuffer_packet0_check(dev, file_priv, cbuffer, i, _r3xx_register_right); - if (ret) { + if (ret <= 0) { return ret; } /* advance to next packet */ @@ -302,7 +293,7 @@ static int amd_cbuffer_check(struct drm_device *dev, case 3: ret = amd_cbuffer_packet3_check(dev, file_priv, cbuffer, i); - if (ret) { + if (ret <= 0) { return ret; } /* advance to next packet */ @@ -331,13 +322,11 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, /* FIXME: Lock buffer manager, is this really needed ? */ - DRM_INFO("[radeon_ms] exec step - 00.00\n"); ret = drm_bo_read_lock(&dev->bm.bm_lock); if (ret) { return ret; } - DRM_INFO("[radeon_ms] exec step - 01.00\n"); cbuffer.args = drm_calloc(execbuffer->args_count, sizeof(struct amd_cbuffer_arg), DRM_MEM_DRIVER); @@ -350,7 +339,6 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, INIT_LIST_HEAD(&cbuffer.arg_used.list); /* process arguments */ - DRM_INFO("[radeon_ms] exec step - 02.00\n"); ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer, &cbuffer); if (ret) { DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n"); @@ -358,14 +346,12 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, } /* map command buffer */ - DRM_INFO("[radeon_ms] exec step - 03.00\n"); cbuffer.cbuffer_dw_count = (cbuffer.args[0].buffer->mem.num_pages * PAGE_SIZE) >> 2; if (execbuffer->cmd_size > cbuffer.cbuffer_dw_count) { ret = -EINVAL; goto out_free_release; } - DRM_INFO("[radeon_ms] exec step - 04.00\n"); cbuffer.cbuffer_dw_count = execbuffer->cmd_size; memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj)); ret = drm_bo_kmap(cbuffer.args[0].buffer, 0, @@ -374,13 +360,9 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); goto out_free_release; } - DRM_INFO("[radeon_ms] exec step - 05.00\n"); cbuffer.cbuffer = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem); - DRM_INFO("[radeon_ms] exec step - 05.01\n"); list_del(&cbuffer.args[0].list); - DRM_INFO("[radeon_ms] exec step - 05.02\n"); list_add_tail(&cbuffer.args[0].list , &cbuffer.arg_used.list); - DRM_INFO("[radeon_ms] exec step - 05.03\n"); /* do cmd checking & relocations */ ret = amd_cbuffer_check(dev, file_priv, &cbuffer); @@ -388,7 +370,6 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, drm_putback_buffer_objects(dev); goto out_free_release; } - DRM_INFO("[radeon_ms] exec step - 06.00\n"); ret = radeon_ms_ring_emit(dev, cbuffer.cbuffer, cbuffer.cbuffer_dw_count); @@ -396,7 +377,6 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, drm_putback_buffer_objects(dev); goto out_free_release; } - DRM_INFO("[radeon_ms] exec step - 07.00\n"); /* fence */ ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); @@ -418,16 +398,13 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, } } drm_fence_usage_deref_unlocked(&fence); - DRM_INFO("[radeon_ms] exec step - 08.00\n"); out_free_release: drm_bo_kunmap(&cmd_kmap); radeon_ms_execbuffer_args_clean(dev, &cbuffer, execbuffer->args_count); - DRM_INFO("[radeon_ms] exec step - 09.00\n"); out_free: drm_free(cbuffer.args, (execbuffer->args_count * sizeof(struct amd_cbuffer_arg)), DRM_MEM_DRIVER); drm_bo_read_unlock(&dev->bm.bm_lock); - DRM_INFO("[radeon_ms] exec step - 10.00\n"); return ret; } -- cgit v1.2.3 From 4dfb959238cbaac6b4db425d9349c7907f4e32fd Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 3 Apr 2008 03:14:52 +0200 Subject: radeon_ms: fixes fb handling --- linux-core/radeon_ms_fb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index a8fba712..a7f39f12 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -45,6 +45,7 @@ struct radeonfb_par { struct drm_device *dev; struct drm_crtc *crtc; struct drm_display_mode *fb_mode; + struct drm_framebuffer *fb; }; static int radeonfb_setcolreg(unsigned regno, unsigned red, @@ -52,7 +53,7 @@ static int radeonfb_setcolreg(unsigned regno, unsigned red, unsigned transp, struct fb_info *info) { struct radeonfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; struct drm_crtc *crtc = par->crtc; if (regno > 255) { @@ -88,7 +89,7 @@ static int radeonfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct radeonfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; if (!var->pixclock) return -EINVAL; @@ -177,7 +178,7 @@ static bool radeonfb_mode_equal(struct drm_display_mode *mode1, static int radeonfb_set_par(struct fb_info *info) { struct radeonfb_par *par = info->par; - struct drm_framebuffer *fb = par->crtc->fb; + struct drm_framebuffer *fb = par->fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; struct drm_output *output; @@ -326,6 +327,7 @@ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) par = info->par; par->dev = dev; par->crtc = crtc; + par->fb = fb; info->fbops = &radeonfb_ops; strcpy(info->fix.id, "radeonfb"); info->fix.type = FB_TYPE_PACKED_PIXELS; -- cgit v1.2.3 From dfc8d2b2fe70a84de53f72f0eeff911c58469089 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 3 Apr 2008 03:15:47 +0200 Subject: radeon_ms: add crtc set base callback & fix palette --- shared-core/radeon_ms_crtc.c | 95 +++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 64 deletions(-) diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c index b2383859..63bd4a0a 100644 --- a/shared-core/radeon_ms_crtc.c +++ b/shared-core/radeon_ms_crtc.c @@ -638,6 +638,17 @@ static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, radeon_ms_crtc1_restore(dev, state); } +static void radeon_ms_crtc1_mode_set_base(struct drm_crtc *crtc, int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_state *state = &dev_priv->driver_state; + + DRM_INFO("[radeon_ms] mode_set_base\n"); + state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->bo->offset); + radeon_ms_crtc1_restore(dev, state); +} + static void radeon_ms_crtc_mode_commit(struct drm_crtc *crtc) { crtc->funcs->dpms(crtc, DPMSModeOn); @@ -651,6 +662,9 @@ static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r, struct radeon_state *state = &dev_priv->driver_state; uint32_t color; + if (regno >= 256) { + return; + } switch(radeon_ms_crtc->crtc) { case 1: state->dac_cntl2 &= ~DAC_CNTL2__PALETTE_ACCESS_CNTL; @@ -660,70 +674,22 @@ static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r, break; } MMIO_W(DAC_CNTL2, state->dac_cntl2); - if (crtc->fb->bits_per_pixel == 16 && crtc->fb->depth == 16) { - if (regno >= 64) { - return; - } - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, - regno * 4)); - color = 0; - color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); - MMIO_W(PALETTE_DATA, color); - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno * 4)); - color = 0; - color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); - MMIO_W(PALETTE_30_DATA, color); - radeon_ms_crtc->lut_r[regno * 4] = r; - radeon_ms_crtc->lut_g[regno * 4] = g; - radeon_ms_crtc->lut_b[regno * 4] = b; - if (regno < 32) { - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, - regno * 8)); - color = 0; - color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); - MMIO_W(PALETTE_DATA, color); - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, - regno * 8)); - color = 0; - color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R,r >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_G,g >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_B,b >> 6); - MMIO_W(PALETTE_30_DATA, color); - radeon_ms_crtc->lut_r[regno * 8] = r; - radeon_ms_crtc->lut_g[regno * 8] = g; - radeon_ms_crtc->lut_b[regno * 8] = b; - } - } else { - if (regno >= 256) { - return; - } - radeon_ms_crtc->lut_r[regno] = r; - radeon_ms_crtc->lut_g[regno] = g; - radeon_ms_crtc->lut_b[regno] = b; - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); - color = 0; - color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | - REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); - MMIO_W(PALETTE_DATA, color); - MMIO_W(PALETTE_INDEX, - REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); - color = 0; - color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | - REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); - } + radeon_ms_crtc->lut_r[regno] = r; + radeon_ms_crtc->lut_g[regno] = g; + radeon_ms_crtc->lut_b[regno] = b; + MMIO_W(PALETTE_INDEX, REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); + color = 0; + color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) | + REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8); + MMIO_W(PALETTE_DATA, color); + MMIO_W(PALETTE_INDEX, + REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno)); + color = 0; + color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) | + REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6); + MMIO_W(PALETTE_30_DATA, color); } static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc) @@ -762,6 +728,7 @@ static const struct drm_crtc_funcs radeon_ms_crtc1_funcs= { .commit = radeon_ms_crtc_mode_commit, .mode_fixup = radeon_ms_crtc_mode_fixup, .mode_set = radeon_ms_crtc1_mode_set, + .mode_set_base = radeon_ms_crtc1_mode_set_base, .gamma_set = radeon_ms_crtc_gamma_set, .cleanup = NULL, /* XXX */ }; -- cgit v1.2.3 From 91bfd69745dbb62dc28c57f940ff44da867e96ea Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 6 Apr 2008 19:01:31 +0200 Subject: radeon_ms: check for NULL fb --- shared-core/radeon_ms_crtc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c index 63bd4a0a..83dd0777 100644 --- a/shared-core/radeon_ms_crtc.c +++ b/shared-core/radeon_ms_crtc.c @@ -537,6 +537,10 @@ static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, adjusted_mode->hsync_end, adjusted_mode->htotal, adjusted_mode->vdisplay, adjusted_mode->vsync_start, adjusted_mode->vsync_end, adjusted_mode->vtotal, adjusted_mode->type); + if (crtc->fb == NULL) { + DRM_INFO("[radeon_ms] no FB bound\n"); + return; + } /* only support RGB555,RGB565,ARGB8888 should satisfy all users */ switch (crtc->fb->bits_per_pixel) { @@ -551,7 +555,7 @@ static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, format = 6; break; default: - DRM_ERROR("Unknown color depth\n"); + DRM_ERROR("Unknown color depth %d\n", crtc->fb->bits_per_pixel); return; } radeon_pll1_compute(crtc, adjusted_mode); @@ -665,6 +669,7 @@ static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r, if (regno >= 256) { return; } + DRM_INFO("[radeon_ms] gamma[%d]=(%d, %d, %d)\n", regno, r, g, b); switch(radeon_ms_crtc->crtc) { case 1: state->dac_cntl2 &= ~DAC_CNTL2__PALETTE_ACCESS_CNTL; -- cgit v1.2.3 From 060e725a0e8aa1f1157f97ca8e7dfa60d02d17ac Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 6 Apr 2008 19:23:20 +0200 Subject: radeon_ms: fix framebuffer code --- linux-core/amd.h | 1 + linux-core/radeon_ms_fb.c | 44 ++++++++++++++++++++++++-------------------- shared-core/amd.h | 40 ++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_ms.h | 3 +++ 4 files changed, 68 insertions(+), 20 deletions(-) create mode 120000 linux-core/amd.h create mode 100644 shared-core/amd.h diff --git a/linux-core/amd.h b/linux-core/amd.h new file mode 120000 index 00000000..b4882447 --- /dev/null +++ b/linux-core/amd.h @@ -0,0 +1 @@ +../shared-core/amd.h \ No newline at end of file diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index a7f39f12..8b720f88 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -40,19 +40,14 @@ #include "drm.h" #include "drm_crtc.h" #include "radeon_ms.h" +#include "amd.h" -struct radeonfb_par { - struct drm_device *dev; - struct drm_crtc *crtc; - struct drm_display_mode *fb_mode; - struct drm_framebuffer *fb; -}; static int radeonfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { - struct radeonfb_par *par = info->par; + struct amd_fb *par = info->par; struct drm_framebuffer *fb = par->fb; struct drm_crtc *crtc = par->crtc; @@ -88,7 +83,7 @@ static int radeonfb_setcolreg(unsigned regno, unsigned red, static int radeonfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - struct radeonfb_par *par = info->par; + struct amd_fb *par = info->par; struct drm_framebuffer *fb = par->fb; if (!var->pixclock) @@ -177,7 +172,7 @@ static bool radeonfb_mode_equal(struct drm_display_mode *mode1, static int radeonfb_set_par(struct fb_info *info) { - struct radeonfb_par *par = info->par; + struct amd_fb *par = info->par; struct drm_framebuffer *fb = par->fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; @@ -249,6 +244,7 @@ static int radeonfb_set_par(struct fb_info *info) if (par->crtc->enabled) { if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { + par->crtc->fb = par->fb; if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) { return -EINVAL; } @@ -275,14 +271,15 @@ static struct fb_ops radeonfb_ops = { int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct fb_info *info; - struct radeonfb_par *par; + struct amd_fb *par; struct device *device = &dev->pdev->dev; struct drm_framebuffer *fb; struct drm_display_mode *mode = crtc->desired_mode; int ret; - info = framebuffer_alloc(sizeof(struct radeonfb_par), device); + info = framebuffer_alloc(sizeof(struct amd_fb), device); if (!info){ DRM_INFO("[radeon_ms] framebuffer_alloc failed\n"); return -EINVAL; @@ -325,6 +322,7 @@ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->fbdev = info; par = info->par; + dev_priv->fb = par; par->dev = dev; par->crtc = crtc; par->fb = fb; @@ -441,16 +439,22 @@ EXPORT_SYMBOL(radeonfb_probe); int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc) { - struct drm_framebuffer *fb = crtc->fb; - struct fb_info *info = fb->fbdev; - - if (info) { - unregister_framebuffer(info); - drm_bo_kunmap(&fb->kmap); - drm_bo_usage_deref_unlocked(&fb->bo); - drm_framebuffer_destroy(fb); - framebuffer_release(info); + struct drm_radeon_private *dev_priv = dev->dev_private; + struct amd_fb *fb = dev_priv->fb; + struct fb_info *info; + + if (fb == NULL || fb->fb == NULL || fb->fb->fbdev == NULL) { + DRM_INFO("[radeon_ms] %s: no crtc, or fb or fbdev\n", + __func__); + return 0; } + info = fb->fb->fbdev; + unregister_framebuffer(info); + drm_bo_kunmap(&fb->fb->kmap); + drm_bo_usage_deref_unlocked(&fb->fb->bo); + drm_framebuffer_destroy(fb->fb); + framebuffer_release(info); + dev_priv->fb = NULL; return 0; } EXPORT_SYMBOL(radeonfb_remove); diff --git a/shared-core/amd.h b/shared-core/amd.h new file mode 100644 index 00000000..ac6195e2 --- /dev/null +++ b/shared-core/amd.h @@ -0,0 +1,40 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#ifndef __AMD_H__ +#define __AMD_H__ + +/* struct amd_fb amd is for storing amd framebuffer informations + */ +struct amd_fb +{ + struct drm_device *dev; + struct drm_crtc *crtc; + struct drm_display_mode *fb_mode; + struct drm_framebuffer *fb; +}; + +#endif diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index e4010d84..bbd0477b 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -35,6 +35,7 @@ #include "radeon_ms_drm.h" #include "radeon_ms_rom.h" #include "radeon_ms_properties.h" +#include "amd.h" #include "amd_cbuffer.h" #define DRIVER_AUTHOR "Jerome Glisse, Dave Airlie, Gareth Hughes, "\ @@ -292,6 +293,8 @@ struct drm_radeon_private { uint32_t *ring_buffer; uint32_t *write_back_area; const uint32_t *microcode; + /* framebuffer */ + struct amd_fb *fb; /* card family */ uint32_t usec_timeout; uint32_t family; -- cgit v1.2.3 From fee64980c4581f1c3cac4be834fa5fb663c2029b Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 7 Apr 2008 20:49:36 +0200 Subject: radeon_ms: another fb fix reset mode if fb changed --- linux-core/radeon_ms_fb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index 8b720f88..dbbddaf4 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -243,7 +243,8 @@ static int radeonfb_set_par(struct fb_info *info) } if (par->crtc->enabled) { - if (!drm_mode_equal(&par->crtc->mode, drm_mode)) { + if (!drm_mode_equal(&par->crtc->mode, drm_mode) || + par->crtc->fb != par->fb) { par->crtc->fb = par->fb; if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) { return -EINVAL; -- cgit v1.2.3 From 779e826c1e2c127f4950c78a56cc314c43b7eb56 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Tue, 8 Apr 2008 02:18:14 +0200 Subject: radeon_ms: command buffer validation use array of function pointer --- linux-core/Makefile.kernel | 3 +- linux-core/amd_cbuffer.h | 1 - linux-core/amd_legacy.h | 1 + linux-core/amd_legacy_cbuffer.c | 1 + shared-core/amd.h | 37 +++++ shared-core/amd_cbuffer.h | 51 ------- shared-core/amd_legacy.h | 33 +++++ shared-core/amd_legacy_cbuffer.c | 306 +++++++++++++++++++++++++++++++++++++++ shared-core/radeon_ms.h | 4 +- shared-core/radeon_ms_drm.c | 10 ++ shared-core/radeon_ms_exec.c | 195 ++++++++----------------- 11 files changed, 456 insertions(+), 186 deletions(-) delete mode 120000 linux-core/amd_cbuffer.h create mode 120000 linux-core/amd_legacy.h create mode 120000 linux-core/amd_legacy_cbuffer.c delete mode 100644 shared-core/amd_cbuffer.h create mode 100644 shared-core/amd_legacy.h create mode 100644 shared-core/amd_legacy_cbuffer.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index ad62eff4..91decfc8 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -40,7 +40,8 @@ radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ radeon_ms_cp.o radeon_ms_cp_mc.o radeon_ms_i2c.o \ radeon_ms_output.o radeon_ms_crtc.o radeon_ms_fb.o \ radeon_ms_exec.o radeon_ms_gpu.o radeon_ms_dac.o \ - radeon_ms_properties.o radeon_ms_rom.o radeon_ms_combios.o + radeon_ms_properties.o radeon_ms_rom.o radeon_ms_combios.o \ + amd_legacy_cbuffer.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/amd_cbuffer.h b/linux-core/amd_cbuffer.h deleted file mode 120000 index 780b9d8f..00000000 --- a/linux-core/amd_cbuffer.h +++ /dev/null @@ -1 +0,0 @@ -../shared-core/amd_cbuffer.h \ No newline at end of file diff --git a/linux-core/amd_legacy.h b/linux-core/amd_legacy.h new file mode 120000 index 00000000..1a7786fc --- /dev/null +++ b/linux-core/amd_legacy.h @@ -0,0 +1 @@ +../shared-core/amd_legacy.h \ No newline at end of file diff --git a/linux-core/amd_legacy_cbuffer.c b/linux-core/amd_legacy_cbuffer.c new file mode 120000 index 00000000..eab329b5 --- /dev/null +++ b/linux-core/amd_legacy_cbuffer.c @@ -0,0 +1 @@ +../shared-core/amd_legacy_cbuffer.c \ No newline at end of file diff --git a/shared-core/amd.h b/shared-core/amd.h index ac6195e2..31cf3eff 100644 --- a/shared-core/amd.h +++ b/shared-core/amd.h @@ -27,6 +27,43 @@ #ifndef __AMD_H__ #define __AMD_H__ +/* struct amd_cbuffer are for command buffer, this is the structure passed + * around during command validation (ie check that user have the right to + * execute the given command). + */ +struct amd_cbuffer_arg +{ + struct list_head list; + struct drm_buffer_object *buffer; + int32_t dw_id; +}; + +struct amd_cbuffer +{ + uint32_t *cbuffer; + uint32_t cbuffer_dw_count; + struct amd_cbuffer_arg arg_unused; + struct amd_cbuffer_arg arg_used; + struct amd_cbuffer_arg *args; + void *driver; +}; + +struct amd_cbuffer_checker +{ + uint32_t numof_p0_checkers; + uint32_t numof_p3_checkers; + int (*check)(struct drm_device *dev, struct amd_cbuffer *cbuffer); + int (**check_p0)(struct drm_device *dev, struct amd_cbuffer *cbuffer, + int dw_id, int reg); + int (**check_p3)(struct drm_device *dev, struct amd_cbuffer *cbuffer, + int dw_id, int op, int count); +}; + +struct amd_cbuffer_arg * +amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id); +int amd_cbuffer_check(struct drm_device *dev, struct amd_cbuffer *cbuffer); + + /* struct amd_fb amd is for storing amd framebuffer informations */ struct amd_fb diff --git a/shared-core/amd_cbuffer.h b/shared-core/amd_cbuffer.h deleted file mode 100644 index bca05751..00000000 --- a/shared-core/amd_cbuffer.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2007 Jérôme Glisse - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: - * Jerome Glisse - */ -#ifndef __AMD_CBUFFER_H__ -#define __AMD_CBUFFER_H__ - -/* struct amd_cbuffer are for command buffer, this is the structure passed - * around during command validation (ie check that user have the right to - * execute the given command). - */ - -struct amd_cbuffer_arg -{ - struct list_head list; - struct drm_buffer_object *buffer; - int32_t dw_id; -}; - -struct amd_cbuffer -{ - uint32_t *cbuffer; - uint32_t cbuffer_dw_count; - struct amd_cbuffer_arg arg_unused; - struct amd_cbuffer_arg arg_used; - struct amd_cbuffer_arg *args; -}; - -#endif diff --git a/shared-core/amd_legacy.h b/shared-core/amd_legacy.h new file mode 100644 index 00000000..92997dcd --- /dev/null +++ b/shared-core/amd_legacy.h @@ -0,0 +1,33 @@ +/* + * Copyright 2007 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#ifndef __AMD_LEGACY_H__ +#define __AMD_LEGACY_H__ + +int amd_legacy_cbuffer_destroy(struct drm_device *dev); +int amd_legacy_cbuffer_initialize(struct drm_device *dev); + +#endif diff --git a/shared-core/amd_legacy_cbuffer.c b/shared-core/amd_legacy_cbuffer.c new file mode 100644 index 00000000..f1b7a44b --- /dev/null +++ b/shared-core/amd_legacy_cbuffer.c @@ -0,0 +1,306 @@ +/* + * Copyright 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#include "radeon_ms.h" +#include "amd.h" + +#define RADEON_DST_Y_X 0x1438 +#define RADEON_SRC_Y_X 0x1434 +#define RADEON_DP_CNTL 0x16c0 +#define RADEON_DP_GUI_MASTER_CNTL 0x146c +#define RADEON_DP_BRUSH_BKGD_CLR 0x1478 +#define RADEON_DP_BRUSH_FRGD_CLR 0x147c +#define RADEON_DP_WRITE_MASK 0x16cc +#define RADEON_DST_PITCH_OFFSET 0x142c +#define RADEON_SRC_PITCH_OFFSET 0x1428 +#define RADEON_DST_HEIGHT_WIDTH 0x143c + +struct legacy_check +{ + /* for 2D operations */ + uint32_t dp_gui_master_cntl; + uint32_t dst_offset; + uint32_t dst_pitch; + struct amd_cbuffer_arg *dst; + uint32_t dst_x; + uint32_t dst_y; + uint32_t dst_h; + uint32_t dst_w; + struct amd_cbuffer_arg *src; + uint32_t src_pitch; + uint32_t src_x; + uint32_t src_y; +}; + +static int check_blit(struct drm_device *dev, struct amd_cbuffer *cbuffer) +{ + struct legacy_check *legacy_check; + long bpp, start, end; + + legacy_check = (struct legacy_check *)cbuffer->driver; + /* check that gui master cntl have been set */ + if (legacy_check->dp_gui_master_cntl == 0xffffffff) { + return -EINVAL; + } + switch ((legacy_check->dp_gui_master_cntl >> 8) & 0xf) { + case 2: + bpp = 1; + break; + case 3: + case 4: + bpp = 2; + break; + case 6: + bpp = 4; + break; + default: + return -EINVAL; + } + /* check that a destination have been set */ + if (legacy_check->dst == (void *)-1) { + return -EINVAL; + } + if (legacy_check->dst_pitch == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->dst_x == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->dst_y == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->dst_w == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->dst_h == 0xffffffff) { + return -EINVAL; + } + /* compute start offset of blit */ + start = legacy_check->dst_pitch * legacy_check->dst_y + + legacy_check->dst_x * bpp; + /* compute end offset of blit */ + end = legacy_check->dst_pitch * legacy_check->dst_h + + legacy_check->dst_w * bpp; + /* FIXME: check that end offset is inside dst bo */ + + /* check that a destination have been set */ + if (legacy_check->dp_gui_master_cntl & 1) { + if (legacy_check->src == (void *)-1) { + return -EINVAL; + } + if (legacy_check->src_pitch == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->src_x == 0xffffffff) { + return -EINVAL; + } + if (legacy_check->src_y == 0xffffffff) { + return -EINVAL; + } + /* compute start offset of blit */ + start = legacy_check->src_pitch * legacy_check->src_y + + legacy_check->src_x * bpp; + /* compute end offset of blit */ + end = legacy_check->src_pitch * legacy_check->dst_h + + legacy_check->dst_w * bpp + start; + /* FIXME: check that end offset is inside src bo */ + } + return 0; +} + +static int p0_dp_gui_master_cntl(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->dp_gui_master_cntl = cbuffer->cbuffer[dw_id]; + /* we only accept src data type to be same as dst */ + if (((legacy_check->dp_gui_master_cntl >> 12) & 0x3) != 3) { + return -EINVAL; + } + return 0; +} + +static int p0_dst_pitch_offset(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + uint32_t gpu_addr; + int ret; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->dst_pitch = ((cbuffer->cbuffer[dw_id] >> 22) & 0xff) << 6; + legacy_check->dst = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, + dw_id); + if (legacy_check->dst == NULL) { + return -EINVAL; + } + ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->dst->buffer->mem, + &gpu_addr); + if (ret) { + return -EINVAL; + } + cbuffer->cbuffer[dw_id] &= 0xffc00000; + cbuffer->cbuffer[dw_id] |= (gpu_addr >> 10); + return 0; +} + +static int p0_src_pitch_offset(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + uint32_t gpu_addr; + int ret; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->src_pitch = ((cbuffer->cbuffer[dw_id] >> 22) & 0xff) << 6; + legacy_check->src = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, + dw_id); + if (legacy_check->dst == NULL) { + return -EINVAL; + } + ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->src->buffer->mem, + &gpu_addr); + if (ret) { + return -EINVAL; + } + cbuffer->cbuffer[dw_id] &= 0xffc00000; + cbuffer->cbuffer[dw_id] |= (gpu_addr >> 10); + return 0; +} + +static int p0_dst_y_x(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->dst_x = cbuffer->cbuffer[dw_id] & 0xffff; + legacy_check->dst_y = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; + return 0; +} + +static int p0_src_y_x(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->src_x = cbuffer->cbuffer[dw_id] & 0xffff; + legacy_check->src_y = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; + return 0; +} + +static int p0_dst_h_w(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id, int reg) +{ + struct legacy_check *legacy_check; + + legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check->dst_w = cbuffer->cbuffer[dw_id] & 0xffff; + legacy_check->dst_h = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; + return check_blit(dev, cbuffer); +} + +static int legacy_cbuffer_check(struct drm_device *dev, + struct amd_cbuffer *cbuffer) +{ + struct legacy_check legacy_check; + + memset(&legacy_check, 0xff, sizeof(struct legacy_check)); + cbuffer->driver = &legacy_check; + return amd_cbuffer_check(dev, cbuffer); +} + +int amd_legacy_cbuffer_destroy(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + dev_priv->cbuffer_checker.check = NULL; + if (dev_priv->cbuffer_checker.numof_p0_checkers) { + drm_free(dev_priv->cbuffer_checker.check_p0, + dev_priv->cbuffer_checker.numof_p0_checkers * + sizeof(void*), DRM_MEM_DRIVER); + dev_priv->cbuffer_checker.numof_p0_checkers = 0; + } + if (dev_priv->cbuffer_checker.numof_p3_checkers) { + drm_free(dev_priv->cbuffer_checker.check_p3, + dev_priv->cbuffer_checker.numof_p3_checkers * + sizeof(void*), DRM_MEM_DRIVER); + dev_priv->cbuffer_checker.numof_p3_checkers = 0; + } + return 0; +} + +int amd_legacy_cbuffer_initialize(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct amd_cbuffer_checker *checker = &dev_priv->cbuffer_checker; + long size; + + /* packet 0 */ + checker->numof_p0_checkers = 0x5000 >> 2; + size = checker->numof_p0_checkers * sizeof(void*); + checker->check_p0 = drm_alloc(size, DRM_MEM_DRIVER); + if (checker->check_p0 == NULL) { + amd_legacy_cbuffer_destroy(dev); + return -ENOMEM; + } + /* initialize to -1 */ + memset(checker->check_p0, 0xff, size); + + /* packet 3 */ + checker->numof_p3_checkers = 20; + size = checker->numof_p3_checkers * sizeof(void*); + checker->check_p3 = drm_alloc(size, DRM_MEM_DRIVER); + if (checker->check_p3 == NULL) { + amd_legacy_cbuffer_destroy(dev); + return -ENOMEM; + } + /* initialize to -1 */ + memset(checker->check_p3, 0xff, size); + + /* initialize packet0 checker */ + checker->check_p0[RADEON_DST_Y_X >> 2] = p0_dst_y_x; + checker->check_p0[RADEON_SRC_Y_X >> 2] = p0_src_y_x; + checker->check_p0[RADEON_DST_HEIGHT_WIDTH >> 2] = p0_dst_h_w; + checker->check_p0[RADEON_DST_PITCH_OFFSET >> 2] = p0_dst_pitch_offset; + checker->check_p0[RADEON_SRC_PITCH_OFFSET >> 2] = p0_src_pitch_offset; + checker->check_p0[RADEON_DP_GUI_MASTER_CNTL>>2] = p0_dp_gui_master_cntl; + checker->check_p0[RADEON_DP_BRUSH_FRGD_CLR >> 2] = NULL; + checker->check_p0[RADEON_DP_WRITE_MASK >> 2] = NULL; + checker->check_p0[RADEON_DP_CNTL >> 2] = NULL; + + checker->check = legacy_cbuffer_check; + return 0; +} diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index bbd0477b..ec264207 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -36,7 +36,7 @@ #include "radeon_ms_rom.h" #include "radeon_ms_properties.h" #include "amd.h" -#include "amd_cbuffer.h" +#include "amd_legacy.h" #define DRIVER_AUTHOR "Jerome Glisse, Dave Airlie, Gareth Hughes, "\ "Keith Whitwell, others." @@ -329,6 +329,8 @@ struct drm_radeon_private { uint8_t cp_ready; uint8_t bus_ready; uint8_t write_back; + /* command buffer informations */ + struct amd_cbuffer_checker cbuffer_checker; /* abstract asic specific structures */ struct radeon_ms_rom rom; struct radeon_ms_properties properties; diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index 869ccac4..0d327925 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -246,6 +246,13 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) return ret; } + /* initialze driver specific */ + ret = amd_legacy_cbuffer_initialize(dev); + if (ret != 0) { + radeon_ms_driver_unload(dev); + return ret; + } + if (dev->primary && dev->control) { DRM_INFO("[radeon_ms] control 0x%lx, render 0x%lx\n", (long)dev->primary->device, (long)dev->control->device); @@ -277,6 +284,9 @@ int radeon_ms_driver_unload(struct drm_device *dev) radeon_ms_outputs_restore(dev, &dev_priv->load_state); radeon_ms_connectors_destroy(dev); radeon_ms_outputs_destroy(dev); + + /* shutdown specific driver */ + amd_legacy_cbuffer_destroy(dev); /* shutdown cp engine */ radeon_ms_cp_finish(dev); diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c index 32b55eaf..28fcc180 100644 --- a/shared-core/radeon_ms_exec.c +++ b/shared-core/radeon_ms_exec.c @@ -25,7 +25,7 @@ * Jerome Glisse */ #include "radeon_ms.h" -#include "amd_cbuffer.h" +#include "amd.h" static void radeon_ms_execbuffer_args_clean(struct drm_device *dev, struct amd_cbuffer *cbuffer, @@ -118,155 +118,69 @@ out_err: return ret; } -enum { - REGISTER_FORBIDDEN = 0, - REGISTER_SAFE, - REGISTER_SET_OFFSET, -}; -static uint8_t _r3xx_register_right[0x5000 >> 2]; - -static int amd_cbuffer_packet0_set_offset(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - uint32_t reg, int dw_id, - struct amd_cbuffer_arg *arg) -{ - uint32_t gpu_addr; - int ret; - - ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, &gpu_addr); - if (ret) { - return ret; - } - switch (reg) { - default: - return -EINVAL; - } - return 0; -} - -static struct amd_cbuffer_arg * -amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id) +static int cbuffer_packet0_check(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id) { - struct amd_cbuffer_arg *arg; - - list_for_each_entry(arg, &head->list, list) { - if (arg->dw_id == dw_id) { - return arg; - } - } - /* no buffer at this dw index */ - return NULL; -} - -static int amd_cbuffer_packet0_check(struct drm_device *dev, - struct drm_file *file_priv, - struct amd_cbuffer *cbuffer, - int dw_id, - uint8_t *register_right) -{ - struct amd_cbuffer_arg *arg; + struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t reg, count, r, i; int ret; reg = cbuffer->cbuffer[dw_id] & PACKET0_REG_MASK; count = (cbuffer->cbuffer[dw_id] & PACKET0_COUNT_MASK) >> PACKET0_COUNT_SHIFT; + if (reg + count > dev_priv->cbuffer_checker.numof_p0_checkers) { + return -EINVAL; + } for (r = reg, i = 0; i <= count; i++, r++) { - switch (register_right[i]) { - case REGISTER_FORBIDDEN: + if (dev_priv->cbuffer_checker.check_p0[r] == NULL) { + continue; + } + if (dev_priv->cbuffer_checker.check_p0[r] == (void *)-1) { + DRM_INFO("[radeon_ms] check_f: %d %d -1 checker\n", + r, r << 2); + return -EINVAL; + } + ret = dev_priv->cbuffer_checker.check_p0[r](dev, cbuffer, + dw_id + i + 1, reg); + if (ret) { + DRM_INFO("[radeon_ms] check_f: %d %d checker ret=%d\n", + r, r << 2, ret); return -EINVAL; - case REGISTER_SAFE: - break; - case REGISTER_SET_OFFSET: - arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, - dw_id + i +1); - if (arg == NULL) { - return -EINVAL; - } - /* remove from unparsed list */ - list_del(&arg->list); - list_add_tail(&arg->list, &cbuffer->arg_used.list); - /* set the offset */ - ret = amd_cbuffer_packet0_set_offset(dev, cbuffer, - r, dw_id + i + 1, - arg); - if (ret) { - return ret; - } - break; } } /* header + N + 1 dword passed test */ return count + 2; } -static int amd_cbuffer_packet3_check(struct drm_device *dev, - struct drm_file *file_priv, - struct amd_cbuffer *cbuffer, - int dw_id) +static int cbuffer_packet3_check(struct drm_device *dev, + struct amd_cbuffer *cbuffer, + int dw_id) { - struct amd_cbuffer_arg *arg; + struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t opcode, count; - uint32_t s_auth, s_mask; - uint32_t gpu_addr; int ret; opcode = (cbuffer->cbuffer[dw_id] & PACKET3_OPCODE_MASK) >> PACKET3_OPCODE_SHIFT; + if (opcode > dev_priv->cbuffer_checker.numof_p3_checkers) { + return -EINVAL; + } count = (cbuffer->cbuffer[dw_id] & PACKET3_COUNT_MASK) >> PACKET3_COUNT_SHIFT; - switch (opcode) { - case PACKET3_OPCODE_NOP: - break; - case PACKET3_OPCODE_BITBLT: - case PACKET3_OPCODE_BITBLT_MULTI: - /* we only alow simple blit */ - if (count != 5) { - return -EINVAL; - } - s_mask = 0xf; - s_auth = 0x3; - if ((cbuffer->cbuffer[dw_id + 1] & s_mask) != s_auth) { - return -EINVAL; - } - arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, dw_id+2); - if (arg == NULL) { - return -EINVAL; - } - ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, - &gpu_addr); - if (ret) { - return ret; - } - gpu_addr = (gpu_addr >> 10) & 0x003FFFFF; - cbuffer->cbuffer[dw_id + 2] &= 0xFFC00000; - cbuffer->cbuffer[dw_id + 2] |= gpu_addr; - - arg = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, dw_id+3); - if (arg == NULL) { - return -EINVAL; - } - ret = radeon_ms_bo_get_gpu_addr(dev, &arg->buffer->mem, - &gpu_addr); - if (ret) { - return ret; - } - gpu_addr = (gpu_addr >> 10) & 0x003FFFFF; - cbuffer->cbuffer[dw_id + 3] &= 0xFFC00000; - cbuffer->cbuffer[dw_id + 3] |= gpu_addr; - /* FIXME: check that source & destination are big enough - * for requested blit */ - break; - default: + if (dev_priv->cbuffer_checker.check_p3[opcode] == NULL) { + return -EINVAL; + } + ret = dev_priv->cbuffer_checker.check_p3[opcode](dev, cbuffer, + dw_id + 1, opcode, + count); + if (ret) { return -EINVAL; } - /* header + N + 1 dword passed test */ return count + 2; } -static int amd_cbuffer_check(struct drm_device *dev, - struct drm_file *file_priv, - struct amd_cbuffer *cbuffer) +int amd_cbuffer_check(struct drm_device *dev, struct amd_cbuffer *cbuffer) { uint32_t i; int ret; @@ -274,9 +188,7 @@ static int amd_cbuffer_check(struct drm_device *dev, for (i = 0; i < cbuffer->cbuffer_dw_count;) { switch (PACKET_HEADER_GET(cbuffer->cbuffer[i])) { case 0: - ret = amd_cbuffer_packet0_check(dev, file_priv, - cbuffer, i, - _r3xx_register_right); + ret = cbuffer_packet0_check(dev, cbuffer, i); if (ret <= 0) { return ret; } @@ -287,12 +199,10 @@ static int amd_cbuffer_check(struct drm_device *dev, /* we don't accept packet 1 */ return -EINVAL; case 2: - /* packet 2 */ - i += 1; - break; + /* FIXME: accept packet 2 */ + return -EINVAL; case 3: - ret = amd_cbuffer_packet3_check(dev, file_priv, - cbuffer, i); + ret = cbuffer_packet3_check(dev, cbuffer, i); if (ret <= 0) { return ret; } @@ -304,9 +214,25 @@ static int amd_cbuffer_check(struct drm_device *dev, return 0; } +struct amd_cbuffer_arg * +amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id) +{ + struct amd_cbuffer_arg *arg; + + list_for_each_entry(arg, &head->list, list) { + if (arg->dw_id == dw_id) { + return arg; + } + } + /* no buffer at this dw index */ + return NULL; +} + + int radeon_ms_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_radeon_execbuffer *execbuffer = data; struct drm_fence_arg *fence_arg = &execbuffer->fence_arg; struct drm_bo_kmap_obj cmd_kmap; @@ -365,8 +291,13 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, list_add_tail(&cbuffer.args[0].list , &cbuffer.arg_used.list); /* do cmd checking & relocations */ - ret = amd_cbuffer_check(dev, file_priv, &cbuffer); - if (ret) { + if (dev_priv->cbuffer_checker.check) { + ret = dev_priv->cbuffer_checker.check(dev, &cbuffer); + if (ret) { + drm_putback_buffer_objects(dev); + goto out_free_release; + } + } else { drm_putback_buffer_objects(dev); goto out_free_release; } -- cgit v1.2.3 From 5a3ce06f3a3dfa9412b9660c1e1f35d24c815dbb Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 8 Apr 2008 12:42:23 -0700 Subject: Improved DRM sysfs support This patch ties outputs, output properties and hotplug events into the DRM core. Each output has a corresponding directory under the primary DRM device (usually card0) containing dpms, edid, modes, and connection status files. New hotplug change events occur when outputs are added or hotplug events are detected. --- linux-core/drmP.h | 4 + linux-core/drm_crtc.c | 46 +++++++++++ linux-core/drm_crtc.h | 6 ++ linux-core/drm_sysfs.c | 197 ++++++++++++++++++++++++++++++++++++++++++--- linux-core/intel_display.c | 5 +- linux-core/intel_drv.h | 1 + 6 files changed, 249 insertions(+), 10 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f96e6bee..24f8c3d8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1311,7 +1311,11 @@ struct drm_sysfs_class; extern struct class *drm_sysfs_create(struct module *owner, char *name); extern void drm_sysfs_destroy(void); extern int drm_sysfs_device_add(struct drm_minor *minor); +extern void drm_sysfs_hotplug_event(struct drm_device *dev); extern void drm_sysfs_device_remove(struct drm_minor *minor); +extern char *drm_get_output_status_name(enum drm_output_status status); +extern int drm_sysfs_output_add(struct drm_output *output); +extern void drm_sysfs_output_remove(struct drm_output *output); /* * Basic memory manager support (drm_mm.c) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 0cd0ebd0..19155e1f 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -47,6 +47,18 @@ static struct drm_prop_enum_list drm_dpms_enum_list[] = { DPMSModeSuspend, "Suspend" }, { DPMSModeOff, "Off" } }; + +char *drm_get_dpms_name(int val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++) + if (drm_dpms_enum_list[i].type == val) + return drm_dpms_enum_list[i].name; + + return "unknown"; +} + static struct drm_prop_enum_list drm_conn_enum_list[] = { { ConnectorUnknown, "Unknown" }, { ConnectorVGA, "VGA" }, @@ -79,6 +91,16 @@ char *drm_get_output_name(struct drm_output *output) return buf; } +char *drm_get_output_status_name(enum drm_output_status status) +{ + if (status == output_status_connected) + return "connected"; + else if (status == output_status_disconnected) + return "disconnected"; + else + return "unknown"; +} + /** * drm_idr_get - allocate a new identifier * @dev: DRM device @@ -629,6 +651,8 @@ struct drm_output *drm_output_create(struct drm_device *dev, /* output_set_monitor(output)? */ /* check for output_ignored(output)? */ + drm_sysfs_output_add(output); + mutex_lock(&dev->mode_config.mutex); list_add_tail(&output->head, &dev->mode_config.output_list); dev->mode_config.num_output++; @@ -659,6 +683,8 @@ void drm_output_destroy(struct drm_output *output) struct drm_device *dev = output->dev; struct drm_display_mode *mode, *t; + drm_sysfs_output_remove(output); + if (*output->funcs->cleanup) (*output->funcs->cleanup)(output); @@ -1226,6 +1252,8 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, DRM_ERROR("failed to set mode after hotplug\n"); } + drm_sysfs_hotplug_event(dev); + drm_disable_unused_functions(dev); return 0; @@ -2223,6 +2251,24 @@ int drm_output_property_set_value(struct drm_output *output, } EXPORT_SYMBOL(drm_output_property_set_value); +int drm_output_property_get_value(struct drm_output *output, + struct drm_property *property, uint64_t *val) +{ + int i; + + for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { + if (output->property_ids[i] == property->id) { + *val = output->property_values[i]; + break; + } + } + + if (i == DRM_OUTPUT_MAX_PROPERTY) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(drm_output_property_get_value); + int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index bbeab603..ac0d2d5a 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -451,6 +451,8 @@ struct drm_output_funcs { */ struct drm_output { struct drm_device *dev; + struct device kdev; + struct device_attribute *attr; struct list_head head; struct drm_crtc *crtc; int id; /* idr assigned */ @@ -563,6 +565,7 @@ struct drm_output *drm_output_create(struct drm_device *dev, int type); extern char *drm_get_output_name(struct drm_output *output); +extern char *drm_get_dpms_name(int val); extern void drm_output_destroy(struct drm_output *output); extern void drm_fb_release(struct file *filp); @@ -606,6 +609,9 @@ extern int drm_mode_output_update_edid_property(struct drm_output *output, extern int drm_output_property_set_value(struct drm_output *output, struct drm_property *property, uint64_t value); +extern int drm_output_property_get_value(struct drm_output *output, + struct drm_property *property, + uint64_t *value); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 3372a713..3e682c99 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -133,10 +133,6 @@ static ssize_t show_dri(struct device *device, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name); } -static struct device_attribute device_attrs[] = { - __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), -}; - /** * drm_sysfs_device_release - do nothing * @dev: Linux device @@ -150,6 +146,189 @@ static void drm_sysfs_device_release(struct device *dev) return; } +/* + * Output properties + */ +static ssize_t status_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_output *output = container_of(device, struct drm_output, kdev); + return snprintf(buf, PAGE_SIZE, "%s", + drm_get_output_status_name(output->funcs->detect(output))); +} + +static ssize_t dpms_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_output *output = container_of(device, struct drm_output, kdev); + struct drm_device *dev = output->dev; + uint64_t dpms_status; + int ret; + + ret = drm_output_property_get_value(output, + dev->mode_config.dpms_property, + &dpms_status); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); +} + +static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *output_dev = container_of(kobj, struct device, kobj); + struct drm_output *output = container_of(output_dev, struct drm_output, + kdev); + unsigned char *edid; + size_t size; + + if (!output->edid_blob_ptr) + return 0; + + edid = output->edid_blob_ptr->data; + size = output->edid_blob_ptr->length; + if (!edid) + return 0; + + if (off >= size) + return 0; + + if (off + count > size) + count = size - off; + memcpy(buf, edid + off, count); + + return count; +} + +static ssize_t modes_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_output *output = container_of(device, struct drm_output, kdev); + struct drm_display_mode *mode; + int written = 0; + + list_for_each_entry(mode, &output->modes, head) { + written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", + mode->name); + } + + return written; +} + +static struct device_attribute output_attrs[] = { + __ATTR_RO(status), + __ATTR_RO(dpms), + __ATTR_RO(modes), +}; + +static struct bin_attribute edid_attr = { + .attr.name = "edid", + .size = 128, + .read = edid_show, +}; + +/** + * drm_sysfs_output_add - add an output to sysfs + * @output: output to add + * + * Create an output device in sysfs, along with its associated output + * properties (so far, connection status, dpms, mode list & edid) and + * generate a hotplug event so userspace knows there's a new output + * available. + */ +int drm_sysfs_output_add(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + int ret = 0, i, j; + + if (device_is_registered(&output->kdev)) + return 0; + + output->kdev.parent = &dev->primary->kdev; + output->kdev.class = drm_class; + output->kdev.release = drm_sysfs_device_release; + + DRM_DEBUG("adding \"%s\" to sysfs", drm_get_output_name(output)); + + snprintf(output->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", + dev->primary->index, drm_get_output_name(output)); + ret = device_register(&output->kdev); + + if (ret) { + DRM_ERROR("failed to register output device: %d\n", ret); + goto out; + } + + for (i = 0; i < ARRAY_SIZE(output_attrs); i++) { + ret = device_create_file(&output->kdev, &output_attrs[i]); + if (ret) + goto err_out_files; + } + + ret = sysfs_create_bin_file(&output->kdev.kobj, &edid_attr); + if (ret) + goto err_out_files; + + /* Let userspace know we have a new output */ + drm_sysfs_hotplug_event(dev); + + return 0; + +err_out_files: + if (i > 0) + for (j = 0; j < i; j++) + device_remove_file(&output->kdev, &output_attrs[i]); + device_unregister(&output->kdev); + +out: + return ret; +} + +/** + * drm_sysfs_output_remove - remove an output device from sysfs + * @output: output to remove + * + * Remove @output and its associated attributes from sysfs. Note that + * the device model core will take care of sending the "remove" uevent + * at this time, so we don't need to do it. + */ +void drm_sysfs_output_remove(struct drm_output *output) +{ + int i; + + DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_output_name(output)); + for (i = 0; i < i; i++) + device_remove_file(&output->kdev, &output_attrs[i]); + sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); + device_unregister(&output->kdev); +} + +/** + * drm_sysfs_hotplug_event - generate a DRM uevent + * @dev: DRM device + * + * Send a uevent for the DRM device specified by @dev. Currently we only + * set HOTPLUG=1 in the uevent environment, but this could be expanded to + * deal with other types of events. + */ +void drm_sysfs_hotplug_event(struct drm_device *dev) +{ + char *event_string = "HOTPLUG=1"; + char *envp[] = { event_string, NULL }; + + DRM_DEBUG("generating hotplug event\n"); + + kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); +} + +static struct device_attribute dri_attrs[] = { + __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), +}; + /** * drm_sysfs_device_add - adds a class device to sysfs for a character driver * @dev: DRM device to be added @@ -184,8 +363,8 @@ int drm_sysfs_device_add(struct drm_minor *minor) goto err_out; } - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - err = device_create_file(&minor->kdev, &device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(dri_attrs); i++) { + err = device_create_file(&minor->kdev, &dri_attrs[i]); if (err) goto err_out_files; } @@ -195,7 +374,7 @@ int drm_sysfs_device_add(struct drm_minor *minor) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&minor->kdev, &device_attrs[i]); + device_remove_file(&minor->kdev, &dri_attrs[i]); device_unregister(&minor->kdev); err_out: @@ -213,7 +392,7 @@ void drm_sysfs_device_remove(struct drm_minor *minor) { int i; - for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(&minor->kdev, &device_attrs[i]); + for (i = 0; i < ARRAY_SIZE(dri_attrs); i++) + device_remove_file(&minor->kdev, &dri_attrs[i]); device_unregister(&minor->kdev); } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index fa2b9bea..0615c1c4 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1292,7 +1292,10 @@ static void intel_setup_outputs(struct drm_device *dev) intel_sdvo_init(dev, SDVOB); intel_sdvo_init(dev, SDVOC); } - +#if 0 + if (IS_I9XX(dev) && !IS_I915G(dev)) + intel_tv_init(dev); +#endif list_for_each_entry(output, &dev->mode_config.output_list, head) { struct intel_output *intel_output = output->driver_private; int crtc_mask = 0, clone_mask = 0; diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index a36fd3f1..62e21a5e 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -68,6 +68,7 @@ extern bool intel_ddc_probe(struct drm_output *output); extern void intel_crt_init(struct drm_device *dev); extern void intel_sdvo_init(struct drm_device *dev, int output_device); +extern void intel_tv_init(struct drm_device *dev); extern void intel_lvds_init(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); -- cgit v1.2.3 From a2edd07f20df67e741026097c5d46f12296d7c9d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 8 Apr 2008 12:44:52 -0700 Subject: Add devname in modeset case If the driver is 'modeset' enabled, it'll register it's interrupt handler at load time. Set the devname in this case so that /proc/interrupts makes sense. --- shared-core/i915_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index a76acb4e..ce6f1656 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -265,6 +265,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); + dev->devname = DRIVER_NAME; drm_irq_install(dev); } -- cgit v1.2.3 From fa116081a919e716eb95fcfa421d93f10f6f0a4f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 9 Apr 2008 11:30:15 -0700 Subject: Fixup sysfs output registration Put off registering new outputs with sysfs until they're properly configured, or we may get duplicates if the type hasn't been set yet (as is the case with SDVO initialization). This also means moving de-registration into the cleanup function instead of output destroy, since the latter occurs during the normal course of setup when an output isn't found (and therefore not registered with sysfs yet. --- linux-core/drm_crtc.c | 5 +---- linux-core/drm_sysfs.c | 2 ++ linux-core/intel_crt.c | 2 ++ linux-core/intel_lvds.c | 1 + linux-core/intel_sdvo.c | 2 ++ linux-core/intel_tv.c | 2 ++ 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 19155e1f..f54ceb76 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -651,8 +651,6 @@ struct drm_output *drm_output_create(struct drm_device *dev, /* output_set_monitor(output)? */ /* check for output_ignored(output)? */ - drm_sysfs_output_add(output); - mutex_lock(&dev->mode_config.mutex); list_add_tail(&output->head, &dev->mode_config.output_list); dev->mode_config.num_output++; @@ -683,8 +681,6 @@ void drm_output_destroy(struct drm_output *output) struct drm_device *dev = output->dev; struct drm_display_mode *mode, *t; - drm_sysfs_output_remove(output); - if (*output->funcs->cleanup) (*output->funcs->cleanup)(output); @@ -1080,6 +1076,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_property *property, *pt; list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { + drm_sysfs_output_remove(output); drm_output_destroy(output); } diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 3e682c99..427a2e54 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -287,6 +287,7 @@ err_out_files: out: return ret; } +EXPORT_SYMBOL(drm_sysfs_output_add); /** * drm_sysfs_output_remove - remove an output device from sysfs @@ -306,6 +307,7 @@ void drm_sysfs_output_remove(struct drm_output *output) sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); device_unregister(&output->kdev); } +EXPORT_SYMBOL(drm_sysfs_output_remove); /** * drm_sysfs_hotplug_event - generate a DRM uevent diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 915e430d..ef40871e 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -261,5 +261,7 @@ void intel_crt_init(struct drm_device *dev) output->interlace_allowed = 0; output->doublescan_allowed = 0; + drm_sysfs_output_add(output); + drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA); } diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 80f77af6..378ce457 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -500,6 +500,7 @@ void intel_lvds_init(struct drm_device *dev) #endif out: + drm_sysfs_output_add(output); drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorLVDS); return; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index a8441d8f..4fb3f21c 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1123,6 +1123,8 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) output->output_type = output_type; output->output_type_id = output_id; + drm_sysfs_output_add(output); + /* Set the input timing to the screen. Assume always input 0. */ intel_sdvo_set_target_input(output, true, false); diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 0edbdbac..cc50f8c1 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1760,4 +1760,6 @@ intel_tv_init(struct drm_device *dev) output->driver_private = intel_output; output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; + + drm_sysfs_output_add(output); } -- cgit v1.2.3 From 61a81a043cce747a32e514bf0e78fe3993a62f00 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Wed, 9 Apr 2008 22:07:40 +0100 Subject: Older kernels don't have kobject_uevent_env(), so punt the event for these older kernels. --- linux-core/drm_compat.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 03838a18..046c7122 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -339,6 +339,15 @@ extern unsigned long round_jiffies_relative(unsigned long j); extern struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn); #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +static inline int kobject_uevent_env(struct kobject *kobj, + enum kobject_action action, + char *envp[]) +{ + return 0; +} +#endif + #ifndef PM_EVENT_PRETHAW #define PM_EVENT_PRETHAW 3 #endif -- cgit v1.2.3 From 256a96135e6b48f5d3545896f7226edea8c70a0c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 9 Apr 2008 14:06:36 -0700 Subject: Add newline to debug output for output add --- linux-core/drm_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 427a2e54..ef73cc83 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -252,7 +252,7 @@ int drm_sysfs_output_add(struct drm_output *output) output->kdev.class = drm_class; output->kdev.release = drm_sysfs_device_release; - DRM_DEBUG("adding \"%s\" to sysfs", drm_get_output_name(output)); + DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_output_name(output)); snprintf(output->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", dev->primary->index, drm_get_output_name(output)); -- cgit v1.2.3 From 6c92689dcc627886c32afd4eca8f0da25bd07183 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 9 Apr 2008 14:07:55 -0700 Subject: Port pipe reservation code for load detection TV out needs to do load detection, which means we have to find an available pipe to use for the detection. Port over the pipe reservation code for this purpose. --- linux-core/drm_crtc.h | 1 + linux-core/intel_display.c | 130 ++++++++++++++++++++++++++++++++++++++++++++- linux-core/intel_drv.h | 6 +++ 3 files changed, 135 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index ac0d2d5a..52e5ab5c 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -622,6 +622,7 @@ extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); +extern bool drm_crtc_in_use(struct drm_crtc *crtc); extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected); extern int drm_output_attach_property(struct drm_output *output, diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 0615c1c4..13936ee2 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -567,6 +567,8 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); break; } + + intel_crtc->dpms_mode = mode; } static bool intel_crtc_lock(struct drm_crtc *crtc) @@ -1097,6 +1099,129 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, intel_crtc->lut_b[regno] = blue >> 8; } +/** + * Get a pipe with a simple mode set on it for doing load-based monitor + * detection. + * + * It will be up to the load-detect code to adjust the pipe as appropriate for + * its requirements. The pipe will be connected to no other outputs. + * + * Currently this code will only succeed if there is a pipe with no outputs + * configured for it. In the future, it could choose to temporarily disable + * some outputs to free up a pipe for its use. + * + * \return crtc, or NULL if no pipes are available. + */ + +/* VESA 640x480x72Hz mode to set on the pipe */ +static struct drm_display_mode load_detect_mode = { + DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, + 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC), +}; + +struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, + struct drm_display_mode *mode, + int *dpms_mode) +{ + struct drm_device *dev = output->dev; + struct intel_output *intel_output = output->driver_private; + struct intel_crtc *intel_crtc; + struct drm_crtc *possible_crtc; + struct drm_crtc *supported_crtc =NULL; + struct drm_crtc *crtc = NULL; + int i = 0; + + /* + * Algorithm gets a little messy: + * - if the output already has an assigned crtc, use it (but make + * sure it's on first) + * - try to find the first unused crtc that can drive this output, + * and use that if we find one + * - if there are no unused crtcs available, try to use the first + * one we found that supports the output + */ + + /* See if we already have a CRTC for this output */ + if (output->crtc) { + crtc = output->crtc; + /* Make sure the crtc and output are running */ + intel_crtc = crtc->driver_private; + *dpms_mode = intel_crtc->dpms_mode; + if (intel_crtc->dpms_mode != DPMSModeOn) { + crtc->funcs->dpms(crtc, DPMSModeOn); + output->funcs->dpms(output, DPMSModeOn); + } + return crtc; + } + + /* Find an unused one (if possible) */ + list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { + i++; + if (!(output->possible_crtcs & (1 << i))) + continue; + if (!possible_crtc->enabled) { + crtc = possible_crtc; + break; + } + if (!supported_crtc) + supported_crtc = possible_crtc; + } + + /* + * If we didn't find an unused CRTC, use the first available one + * that can drive this output. + */ + if (!crtc) { + crtc = supported_crtc; + if (!crtc) + return NULL; + } + + output->crtc = crtc; + intel_output->load_detect_temp = TRUE; + + intel_crtc = crtc->driver_private; + *dpms_mode = intel_crtc->dpms_mode; + + if (!crtc->enabled) { + if (!mode) + mode = &load_detect_mode; + drm_crtc_set_mode(crtc, mode, 0, 0); + } else { + if (intel_crtc->dpms_mode != DPMSModeOn) + crtc->funcs->dpms(crtc, DPMSModeOn); + + /* Add this output to the crtc */ + output->funcs->mode_set(output, &crtc->mode, &crtc->mode); + output->funcs->commit(output); + } + /* let the output get through one full cycle before testing */ + intel_wait_for_vblank(dev); + + return crtc; +} + +void intel_release_load_detect_pipe(struct drm_output *output, int dpms_mode) +{ + struct drm_device *dev = output->dev; + struct intel_output *intel_output = output->driver_private; + struct drm_crtc *crtc = output->crtc; + + if (intel_output->load_detect_temp) { + output->crtc = NULL; + intel_output->load_detect_temp = FALSE; + crtc->enabled = drm_crtc_in_use(crtc); + drm_disable_unused_functions(dev); + } + + /* Switch crtc and output back off if necessary */ + if (crtc->enabled && dpms_mode != DPMSModeOn) { + if (output->crtc == crtc) + output->funcs->dpms(output, dpms_mode); + crtc->funcs->dpms(crtc, dpms_mode); + } +} + /* Returns the clock of the currently programmed mode of the given pipe. */ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) { @@ -1246,6 +1371,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) } intel_crtc->cursor_addr = 0; + intel_crtc->dpms_mode = DPMSModeOff; crtc->driver_private = intel_crtc; } @@ -1292,10 +1418,10 @@ static void intel_setup_outputs(struct drm_device *dev) intel_sdvo_init(dev, SDVOB); intel_sdvo_init(dev, SDVOC); } -#if 0 + if (IS_I9XX(dev) && !IS_I915G(dev)) intel_tv_init(dev); -#endif + list_for_each_entry(output, &dev->mode_config.output_list, head) { struct intel_output *intel_output = output->driver_private; int crtc_mask = 0, clone_mask = 0; diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 62e21a5e..51c52c84 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -58,6 +58,7 @@ struct intel_crtc { int plane; uint32_t cursor_addr; u8 lut_r[256], lut_g[256], lut_b[256]; + int dpms_mode; }; struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, @@ -78,6 +79,11 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_wait_for_vblank(struct drm_device *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); +extern struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, + struct drm_display_mode *mode, + int *dpms_mode); +extern void intel_release_load_detect_pipe(struct drm_output *output, + int dpms_mode); extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern int intel_sdvo_supports_hotplug(struct drm_output *output); -- cgit v1.2.3 From b3737f3fd9210aead1f7fc4187dd05eea77ed0a6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 9 Apr 2008 14:09:29 -0700 Subject: Fix TV load detection Now that we can allocate load detect pipes, we can perform TV out load detection correctly. Call the new routines and enable proper TV detection. --- linux-core/intel_tv.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index cc50f8c1..84825eb8 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1438,17 +1438,16 @@ intel_tv_detect(struct drm_output *output) mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); -#if 0 - /* FIXME: pipe allocation for load detection */ - crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode); + + crtc = intel_get_load_detect_pipe(output, &mode, &dpms_mode); if (crtc) { type = intel_tv_detect_type(crtc, output); - i830ReleaseLoadDetectPipe (output, dpms_mode); + intel_release_load_detect_pipe(output, dpms_mode); } -#endif + if (type != tv_priv->type) { tv_priv->type = type; - intel_tv_format_configure_property (output); + intel_tv_format_configure_property(output); } switch (type) { -- cgit v1.2.3 From 386ea38b8e3af9bc9166d4ab63c4beb7e0e2267b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 9 Apr 2008 14:12:56 -0700 Subject: Add TV out hotplug detection Doesn't yet work on my i915 test machine, but most of the necessary bits should be there. --- shared-core/i915_drv.h | 3 +++ shared-core/i915_irq.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 64faac9b..e32c36f1 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -554,7 +554,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) #define I915_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) +#define I915_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) #define I915_HOTPLUG_CLEAR (1UL<<10) +#define I915_HOTPLUG_TV_CLEAR (1UL<<2) #define I915_VBLANK_CLEAR (1UL<<1) /* @@ -669,6 +671,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6) #define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) #define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) +#define I915_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) #define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ #define I915_VBLANK_INTERRUPT_STATUS (1UL<<1) #define I915_OVERLAY_UPDATED_STATUS (1UL<<0) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index abd8a7d3..8f136c8f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -424,11 +424,41 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) #define HOTPLUG_CMD_CRT_DIS 2 #define HOTPLUG_CMD_SDVOB 4 #define HOTPLUG_CMD_SDVOC 8 +#define HOTPLUG_CMD_TV 16 static struct drm_device *hotplug_dev; static int hotplug_cmd = 0; static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; +static void i915_hotplug_tv(struct drm_device *dev) +{ + struct drm_output *output; + struct intel_output *iout; + enum drm_output_status status; + + mutex_lock(&dev->mode_config.mutex); + + /* find the crt output */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + iout = output->driver_private; + if (iout->type == INTEL_OUTPUT_TVOUT) + break; + else + iout = 0; + } + + if (iout == 0) + goto unlock; + + /* may need to I915_WRITE(TVDAC, 1<<31) to ack the interrupt */ + status = output->funcs->detect(output); + drm_hotplug_stage_two(dev, output, + status == output_status_connected ? 1 : 0); + +unlock: + mutex_unlock(&dev->mode_config.mutex); +} + static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) { struct drm_output *output; @@ -493,8 +523,10 @@ static void i915_hotplug_work_func(struct work_struct *work) int crtDis; int sdvoB; int sdvoC; + int tv; spin_lock(&hotplug_lock); + tv = hotplug_cmd & HOTPLUG_CMD_TV; crt = hotplug_cmd & HOTPLUG_CMD_CRT; crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS; sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; @@ -502,6 +534,8 @@ static void i915_hotplug_work_func(struct work_struct *work) hotplug_cmd = 0; spin_unlock(&hotplug_lock); + if (tv) + i915_hotplug_tv(dev); if (crt) i915_hotplug_crt(dev, true); if (crtDis) @@ -527,6 +561,14 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) hotplug_dev = dev; + if (stat & TV_HOTPLUG_INT_STATUS) { + DRM_DEBUG("TV event\n"); + + spin_lock(&hotplug_lock); + hotplug_cmd |= HOTPLUG_CMD_TV; + spin_unlock(&hotplug_lock); + } + if (stat & CRT_HOTPLUG_INT_STATUS) { DRM_DEBUG("CRT event\n"); @@ -584,12 +626,14 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_DEBUG("flag=%08x\n", iir); #endif if (iir == 0) { +#if 0 DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", iir, I915_READ(I915REG_INT_MASK_R), I915_READ(I915REG_INT_ENABLE_R), I915_READ(I915REG_PIPEASTAT), I915_READ(I915REG_PIPEBSTAT)); +#endif return IRQ_NONE; } @@ -607,7 +651,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } /* This is a global event, and not a pipe A event */ - if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) + if ((pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) || + (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS)) hotplug = 1; I915_WRITE(I915REG_PIPEASTAT, pipea_stats); @@ -656,8 +701,11 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_INFO("Hotplug event received\n"); if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) { - temp2 |= SDVOB_HOTPLUG_INT_STATUS | - SDVOC_HOTPLUG_INT_STATUS; + if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) + temp2 |= SDVOB_HOTPLUG_INT_STATUS | + SDVOC_HOTPLUG_INT_STATUS; + if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS) + temp2 |= TV_HOTPLUG_INT_STATUS; } else { temp2 = I915_READ(PORT_HOTPLUG_STAT); @@ -898,7 +946,11 @@ void i915_enable_interrupt (struct drm_device *dev) dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; /* Enable global interrupts for hotplug - not a pipeA event */ - I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | I915_HOTPLUG_INTERRUPT_ENABLE | I915_HOTPLUG_CLEAR); + I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | + I915_HOTPLUG_INTERRUPT_ENABLE | + I915_HOTPLUG_TV_INTERRUPT_ENABLE | + I915_HOTPLUG_TV_CLEAR | + I915_HOTPLUG_CLEAR); } if (dev_priv->irq_enable_reg & (I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) { -- cgit v1.2.3 From 0a6e301e6de3421f116d1b5d8205ca4f442091e2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 10 Apr 2008 11:23:55 -0700 Subject: Keep display info in struct display_info Some fields had snuck into the drm_output structure. Put them back and fill in more stuff from the EDID block. --- linux-core/drm_crtc.c | 7 +++---- linux-core/drm_crtc.h | 18 ++++-------------- linux-core/drm_edid.c | 28 +++++++++++++++++++++++++++- linux-core/intel_lvds.c | 27 +++++++++------------------ linux-core/intel_sdvo.c | 8 ++++---- 5 files changed, 47 insertions(+), 41 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f54ceb76..f4377821 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -643,7 +643,6 @@ struct drm_output *drm_output_create(struct drm_device *dev, output->id = drm_idr_get(dev, output); output->output_type = output_type; output->output_type_id = 1; /* TODO */ - output->subpixel_order = SubPixelUnknown; INIT_LIST_HEAD(&output->user_modes); INIT_LIST_HEAD(&output->probed_modes); INIT_LIST_HEAD(&output->modes); @@ -1555,9 +1554,9 @@ int drm_mode_getoutput(struct drm_device *dev, out_resp->output_type = output->output_type; out_resp->output_type_id = output->output_type_id; - out_resp->mm_width = output->mm_width; - out_resp->mm_height = output->mm_height; - out_resp->subpixel = output->subpixel_order; + out_resp->mm_width = output->display_info.width_mm; + out_resp->mm_height = output->display_info.height_mm; + out_resp->subpixel = output->display_info.subpixel_order; out_resp->connection = output->status; if (output->crtc) out_resp->crtc = output->crtc->id; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 52e5ab5c..ec5b20b0 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -199,7 +199,7 @@ struct drm_display_info { bool gtf_supported; bool standard_color; enum { - monochrome, + monochrome = 0, rgb, other, unknown, @@ -225,6 +225,8 @@ struct drm_display_info { unsigned int wpx2, wpy2; unsigned int wpgamma2; + enum subpixel_order subpixel_order; + /* Preferred mode (if any) */ struct drm_display_mode *preferred_mode; char *raw_edid; /* if any */ @@ -376,8 +378,6 @@ struct drm_crtc { int desired_x, desired_y; const struct drm_crtc_funcs *funcs; void *driver_private; - - /* RRCrtcPtr randr_crtc? */ }; extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, @@ -438,9 +438,6 @@ struct drm_output_funcs { * @initial_x: initial x position for this output * @initial_y: initial y position for this output * @status: output connected? - * @subpixel_order: for this output - * @mm_width: displayable width of output in mm - * @mm_height: displayable height of output in mm * @funcs: output control functions * @driver_private: private driver data * @@ -465,20 +462,13 @@ struct drm_output { bool doublescan_allowed; struct list_head modes; /* list of modes on this output */ - /* - OptionInfoPtr options; - XF86ConfMonitorPtr conf_monitor; - */ int initial_x, initial_y; enum drm_output_status status; /* these are modes added by probing with DDC or the BIOS */ struct list_head probed_modes; - /* xf86MonPtr MonInfo; */ - enum subpixel_order subpixel_order; - int mm_width, mm_height; - struct drm_display_info *monitor_info; /* if any */ + struct drm_display_info display_info; const struct drm_output_funcs *funcs; void *driver_private; diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 9762567b..e033abdf 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -291,7 +291,11 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) if (i == 0 && edid->preferred_timing) newmode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(output, newmode); - + + /* Use first one for output's preferred mode */ + if (!output->display_info.preferred_mode) + output->display_info.preferred_mode = + newmode; modes++; } continue; @@ -460,6 +464,9 @@ struct edid *drm_get_edid(struct drm_output *output, kfree(edid); return NULL; } + + output->display_info.raw_edid = (char *)edid; + return edid; } EXPORT_SYMBOL(drm_get_edid); @@ -488,6 +495,25 @@ int drm_add_edid_modes(struct drm_output *output, struct edid *edid) num_modes += add_established_modes(output, edid); num_modes += add_standard_modes(output, edid); num_modes += add_detailed_info(output, edid); + + output->display_info.serration_vsync = edid->serration_vsync; + output->display_info.sync_on_green = edid->sync_on_green; + output->display_info.composite_sync = edid->composite_sync; + output->display_info.separate_syncs = edid->separate_syncs; + output->display_info.blank_to_black = edid->blank_to_black; + output->display_info.video_level = edid->video_level; + output->display_info.digital = edid->digital; + output->display_info.width_mm = edid->width_cm * 10; + output->display_info.height_mm = edid->height_cm * 10; + output->display_info.gamma = edid->gamma; + output->display_info.gtf_supported = edid->default_gtf; + output->display_info.standard_color = edid->standard_color; + output->display_info.display_type = edid->display_type; + output->display_info.active_off_supported = edid->pm_active_off; + output->display_info.suspend_supported = edid->pm_suspend; + output->display_info.standby_supported = edid->pm_standby; + output->display_info.gamma = edid->gamma; + return num_modes; } EXPORT_SYMBOL(drm_add_edid_modes); diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 378ce457..92a1d600 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -298,24 +298,15 @@ static int intel_lvds_get_modes(struct drm_output *output) if (ret) return ret; - /* Didn't get an EDID */ - if (!output->monitor_info) { - struct drm_display_info *dspinfo; - dspinfo = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL); - if (!dspinfo) - goto out; - - /* Set wide sync ranges so we get all modes - * handed to valid_mode for checking - */ - dspinfo->min_vfreq = 0; - dspinfo->max_vfreq = 200; - dspinfo->min_hfreq = 0; - dspinfo->max_hfreq = 200; - output->monitor_info = dspinfo; - } + /* Didn't get an EDID, so + * Set wide sync ranges so we get all modes + * handed to valid_mode for checking + */ + output->display_info.min_vfreq = 0; + output->display_info.max_vfreq = 200; + output->display_info.min_hfreq = 0; + output->display_info.max_hfreq = 200; -out: if (dev_priv->panel_fixed_mode != NULL) { struct drm_display_mode *mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); @@ -385,7 +376,7 @@ void intel_lvds_init(struct drm_device *dev) intel_output->type = INTEL_OUTPUT_LVDS; output->driver_private = intel_output; - output->subpixel_order = SubPixelHorizontalRGB; + output->display_info.subpixel_order = SubPixelHorizontalRGB; output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 4fb3f21c..c9e65af4 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1083,28 +1083,28 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; - output->subpixel_order = SubPixelHorizontalRGB; + output->display_info.subpixel_order = SubPixelHorizontalRGB; output_type = DRM_MODE_OUTPUT_DAC; connector_type = ConnectorVGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; - output->subpixel_order = SubPixelHorizontalRGB; + output->display_info.subpixel_order = SubPixelHorizontalRGB; output_type = DRM_MODE_OUTPUT_DAC; connector_type = ConnectorVGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; - output->subpixel_order = SubPixelHorizontalRGB; + output->display_info.subpixel_order = SubPixelHorizontalRGB; output_type = DRM_MODE_OUTPUT_TMDS; connector_type = ConnectorDVID; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; - output->subpixel_order = SubPixelHorizontalRGB; + output->display_info.subpixel_order = SubPixelHorizontalRGB; output_type = DRM_MODE_OUTPUT_TMDS; connector_type = ConnectorDVID; } -- cgit v1.2.3 From ebd154497383e3bcb6b5c6284148aff3633a5d99 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 10 Apr 2008 11:27:39 -0700 Subject: Fix masking in get_load_detect_pipe Start i at -1 so that the masking works right. --- linux-core/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 13936ee2..5ca33f7f 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1129,7 +1129,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, struct drm_crtc *possible_crtc; struct drm_crtc *supported_crtc =NULL; struct drm_crtc *crtc = NULL; - int i = 0; + int i = -1; /* * Algorithm gets a little messy: -- cgit v1.2.3 From bee546ad696e3157b878dfa90e563786b5b5c7ac Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 10 Apr 2008 19:02:53 -0700 Subject: Remove structure fields & code Cleanup some random cruft left over from the initial port. --- linux-core/drm_crtc.c | 6 ------ linux-core/drm_crtc.h | 11 ----------- linux-core/intel_display.c | 21 --------------------- linux-core/intel_sdvo.c | 25 ------------------------- 4 files changed, 63 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f4377821..b33edce7 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -440,7 +440,6 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode, saved_mode; int saved_x, saved_y; - bool didLock = false; struct drm_output *output; bool ret = true; @@ -451,8 +450,6 @@ bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, if (!crtc->enabled) return true; - didLock = crtc->funcs->lock(crtc); - saved_mode = crtc->mode; saved_x = crtc->x; saved_y = crtc->y; @@ -544,9 +541,6 @@ done: crtc->x = saved_x; crtc->y = saved_y; } - - if (didLock) - crtc->funcs->unlock (crtc); return ret; } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index ec5b20b0..74316aa5 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -308,13 +308,10 @@ struct drm_crtc_funcs { */ void (*dpms)(struct drm_crtc *crtc, int mode); - /* JJJ: Are these needed? */ /* Save CRTC state */ void (*save)(struct drm_crtc *crtc); /* suspend? */ /* Restore CRTC state */ void (*restore)(struct drm_crtc *crtc); /* resume? */ - bool (*lock)(struct drm_crtc *crtc); - void (*unlock)(struct drm_crtc *crtc); void (*prepare)(struct drm_crtc *crtc); void (*commit)(struct drm_crtc *crtc); @@ -367,10 +364,6 @@ struct drm_crtc { bool enabled; - /* JJJ: are these needed? */ - bool cursor_in_range; - bool cursor_shown; - struct drm_display_mode mode; int x, y; @@ -418,7 +411,6 @@ struct drm_output_funcs { struct drm_display_mode *adjusted_mode); enum drm_output_status (*detect)(struct drm_output *output); int (*get_modes)(struct drm_output *output); - /* JJJ: type checking for properties via property value type */ bool (*set_property)(struct drm_output *output, struct drm_property *property, uint64_t val); void (*cleanup)(struct drm_output *output); @@ -519,7 +511,6 @@ struct drm_mode_config { int num_output; struct list_head output_list; - /* int compat_output? */ int num_crtc; struct list_head crtc_list; @@ -527,8 +518,6 @@ struct drm_mode_config { int min_width, min_height; int max_width, max_height; - /* DamagePtr rotationDamage? */ - /* DGA stuff? */ struct drm_mode_config_funcs *funcs; unsigned long fb_base; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 5ca33f7f..6aa61256 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -571,25 +571,6 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc->dpms_mode = mode; } -static bool intel_crtc_lock(struct drm_crtc *crtc) -{ - /* Sync the engine before mode switch */ -// i830WaitSync(crtc->scrn); - -#if 0 // TODO def XF86DRI - return I830DRILock(crtc->scrn); -#else - return FALSE; -#endif -} - -static void intel_crtc_unlock (struct drm_crtc *crtc) -{ -#if 0 // TODO def XF86DRI - I830DRIUnlock (crtc->scrn); -#endif -} - static void intel_crtc_prepare (struct drm_crtc *crtc) { crtc->funcs->dpms(crtc, DPMSModeOff); @@ -1334,8 +1315,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, static const struct drm_crtc_funcs intel_crtc_funcs = { .dpms = intel_crtc_dpms, - .lock = intel_crtc_lock, - .unlock = intel_crtc_unlock, .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index c9e65af4..ba6fe9a8 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -126,14 +126,6 @@ static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr, return false; } - -static bool intel_sdvo_read_byte_quiet(struct drm_output *output, int addr, - u8 *ch) -{ - return true; - -} - static bool intel_sdvo_write_byte(struct drm_output *output, int addr, u8 ch) { @@ -863,23 +855,6 @@ static bool intel_sdvo_get_capabilities(struct drm_output *output, struct intel_ return true; } - -static void intel_sdvo_dump_cmd(struct drm_output *output, int opcode) -{ - - -} - -static void intel_sdvo_dump_device(struct drm_output *output) -{ - -} - -void intel_sdvo_dump(void) -{ - -} - struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB) { struct drm_output *output = 0; -- cgit v1.2.3 From 83c3acb7da1043a63d260d5443f7149b2c664b08 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 10 Apr 2008 20:30:12 -0700 Subject: Split TV property creation into its own routine It needs to take arguments from the caller about supported TV formats, so declare it in drm_crtc.h and export it. --- linux-core/drm_crtc.c | 39 ++++++++++++++++++++++++++++++--------- linux-core/drm_crtc.h | 2 ++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index b33edce7..1e5195db 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -767,9 +767,25 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) dev->mode_config.connector_num_property->values[0] = 0; dev->mode_config.connector_num_property->values[1] = 20; - /* - * TV specific properties - */ + return 0; +} + +/** + * drm_create_tv_properties - create TV specific output properties + * @dev: DRM device + * @num_modes: number of different TV formats (modes) supported + * @modes: array of pointers to strings containing name of each format + * + * Called by a driver's TV initialization routine, this function creates + * the TV specific output properties for a given device. Caller is + * responsible for allocating a list of format names and passing them to + * this routine. + */ +bool drm_create_tv_properties(struct drm_device *dev, int num_modes, + char *modes[]) +{ + int i; + dev->mode_config.tv_left_margin_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, @@ -778,28 +794,33 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) dev->mode_config.tv_left_margin_property->values[1] = 100; dev->mode_config.tv_right_margin_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE | - DRM_MODE_PROP_IMMUTABLE, + drm_property_create(dev, DRM_MODE_PROP_RANGE, "right margin", 2); dev->mode_config.tv_right_margin_property->values[0] = 0; dev->mode_config.tv_right_margin_property->values[1] = 100; dev->mode_config.tv_top_margin_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE | - DRM_MODE_PROP_IMMUTABLE, + drm_property_create(dev, DRM_MODE_PROP_RANGE, "top margin", 2); dev->mode_config.tv_top_margin_property->values[0] = 0; dev->mode_config.tv_top_margin_property->values[1] = 100; dev->mode_config.tv_bottom_margin_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE | - DRM_MODE_PROP_IMMUTABLE, + drm_property_create(dev, DRM_MODE_PROP_RANGE, "bottom margin", 2); dev->mode_config.tv_bottom_margin_property->values[0] = 0; dev->mode_config.tv_bottom_margin_property->values[1] = 100; + dev->mode_config.tv_mode_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "mode", num_modes); + for (i = 0; i < num_modes; i++) + drm_property_add_enum(dev->mode_config.tv_mode_property, i, + i, modes[i]); + return 0; } +EXPORT_SYMBOL(drm_create_tv_properties); /** * drm_mode_config_init - initialize DRM mode_configuration structure diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 74316aa5..20b1ea06 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -611,6 +611,8 @@ extern struct drm_property *drm_property_create(struct drm_device *dev, int flag extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); +extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, + char *formats[]); /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, -- cgit v1.2.3 From 3b32ee36ae58f733f281a2fa569ea8a8a926bb6d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 10 Apr 2008 20:31:31 -0700 Subject: Fixup Intel TV property code Use the new TV property creation routine and fixup the set_property code to actually do a mode set call when properties change. --- linux-core/intel_tv.c | 266 ++++++++++++++++++-------------------------------- 1 file changed, 97 insertions(+), 169 deletions(-) diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 84825eb8..89bdda1c 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -37,14 +37,6 @@ #include "i915_drm.h" #include "i915_drv.h" -enum tv_type { - TV_TYPE_NONE, - TV_TYPE_UNKNOWN, - TV_TYPE_COMPOSITE, - TV_TYPE_SVIDEO, - TV_TYPE_COMPONENT -}; - enum tv_margin { TV_MARGIN_LEFT, TV_MARGIN_TOP, TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM @@ -1145,14 +1137,14 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, switch (tv_priv->type) { default: - case TV_TYPE_UNKNOWN: - case TV_TYPE_COMPOSITE: + case ConnectorUnknown: + case ConnectorComposite: tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; video_levels = tv_mode->composite_levels; color_conversion = tv_mode->composite_color; burst_ena = tv_mode->burst_ena; break; - case TV_TYPE_COMPONENT: + case ConnectorComponent: tv_ctl |= TV_ENC_OUTPUT_COMPONENT; video_levels = &component_levels; if (tv_mode->burst_ena) @@ -1161,7 +1153,7 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, color_conversion = &hdtv_csc_yprpb; burst_ena = FALSE; break; - case TV_TYPE_SVIDEO: + case ConnectorSVIDEO: tv_ctl |= TV_ENC_OUTPUT_SVIDEO; video_levels = tv_mode->svideo_levels; color_conversion = tv_mode->svideo_color; @@ -1218,8 +1210,11 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, if (tv_mode->pal_burst) tv_ctl |= TV_PAL_BURST; scctl1 = 0; - if (tv_mode->dda1_inc) + /* dda1 implies valid video levels */ + if (tv_mode->dda1_inc) { scctl1 |= TV_SC_DDA1_EN; + scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; + } if (tv_mode->dda2_inc) scctl1 |= TV_SC_DDA2_EN; @@ -1228,7 +1223,6 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, scctl1 |= TV_SC_DDA3_EN; scctl1 |= tv_mode->sc_reset; - scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT; scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | @@ -1255,22 +1249,26 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, I915_WRITE(TV_SC_CTL_2, scctl2); I915_WRITE(TV_SC_CTL_3, scctl3); - I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | - color_conversion->gy); - I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) | - color_conversion->ay); - I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | - color_conversion->gu); - I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | - color_conversion->au); - I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | - color_conversion->gv); - I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | - color_conversion->av); + if (color_conversion) { + I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | + color_conversion->gy); + I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) | + color_conversion->ay); + I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | + color_conversion->gu); + I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | + color_conversion->au); + I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | + color_conversion->gv); + I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | + color_conversion->av); + } I915_WRITE(TV_CLR_KNOBS, 0x00606000); - I915_WRITE(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | - (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); + if (video_levels) + I915_WRITE(TV_CLR_LEVEL, + ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | + (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); { int pipeconf_reg = (intel_crtc->pipe == 0) ? PIPEACONF : PIPEBCONF; @@ -1364,7 +1362,7 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) struct intel_output *intel_output = output->driver_private; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; - int type = TV_TYPE_UNKNOWN; + int type = ConnectorUnknown; tv_dac = I915_READ(TV_DAC); /* @@ -1402,24 +1400,21 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) */ if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { DRM_DEBUG("Detected Composite TV connection\n"); - type = TV_TYPE_COMPOSITE; + type = ConnectorComposite; } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { DRM_DEBUG("Detected S-Video TV connection\n"); - type = TV_TYPE_SVIDEO; + type = ConnectorSVIDEO; } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { DRM_DEBUG("Detected Component TV connection\n"); - type = TV_TYPE_COMPONENT; + type = ConnectorComponent; } else { DRM_DEBUG("No TV connection detected\n"); - type = TV_TYPE_NONE; + type = -1; } return type; } -static int -intel_tv_format_configure_property (struct drm_output *output); - /** * Detect the TV connection. * @@ -1446,18 +1441,18 @@ intel_tv_detect(struct drm_output *output) } if (type != tv_priv->type) { + struct drm_property *connector_property = + output->dev->mode_config.connector_type_property; + tv_priv->type = type; - intel_tv_format_configure_property(output); + drm_output_property_set_value(output, connector_property, + type); } - switch (type) { - case TV_TYPE_NONE: + if (type < 0) return output_status_disconnected; - case TV_TYPE_UNKNOWN: - return output_status_unknown; - default: - return output_status_connected; - } + + return output_status_connected; } static struct input_res { @@ -1538,135 +1533,41 @@ intel_tv_destroy (struct drm_output *output) DRM_MEM_DRIVER); } -static bool -intel_tv_format_set_property(struct drm_output *output, - struct drm_property *prop, uint64_t val) -{ -#if 0 - struct intel_output *intel_output = output->driver_private; - struct intel_tv_priv *tv_priv = intel_output->dev_priv; - const struct tv_mode *tv_mode = - intel_tv_mode_lookup(tv_priv->tv_format); - int err; - - if (!tv_mode) - tv_mode = &tv_modes[0]; - err = RRChangeOutputProperty (output->randr_output, tv_format_atom, - XA_ATOM, 32, PropModeReplace, 1, - &tv_format_name_atoms[tv_mode - tv_modes], - FALSE, TRUE); - return err == Success; -#endif - return 0; -} - - -/** - * Configure the TV_FORMAT property to list only supported formats - * - * Unless the connector is component, list only the formats supported by - * svideo and composite - */ - -static int -intel_tv_format_configure_property(struct drm_output *output) -{ -#if 0 - struct intel_output *intel_output = output->driver_private; - struct intel_tv_priv *tv_priv = intel_output->dev_priv; - Atom current_atoms[NUM_TV_MODES]; - int num_atoms = 0; - int i; - - if (!output->randr_output) - return Success; - - for (i = 0; i < NUM_TV_MODES; i++) - if (!tv_modes[i].component_only || - tv_priv->type == TV_TYPE_COMPONENT) - current_atoms[num_atoms++] = tv_format_name_atoms[i]; - - return RRConfigureOutputProperty(output->randr_output, tv_format_atom, - TRUE, FALSE, FALSE, - num_atoms, (INT32 *) current_atoms); -#endif - return 0; -} - -static void -intel_tv_create_resources(struct drm_output *output) -{ - struct drm_device *dev = output->dev; - struct intel_output *intel_output = output->driver_private; - struct intel_tv_priv *tv_priv = intel_output->dev_priv; - int i, err; - -#if 0 - /* Set up the tv_format property, which takes effect on mode set - * and accepts strings that match exactly - */ - tv_format_atom = MakeAtom(TV_FORMAT_NAME, sizeof(TV_FORMAT_NAME) - 1, - TRUE); - - for (i = 0; i < NUM_TV_MODES; i++) - tv_format_name_atoms[i] = MakeAtom (tv_modes[i].name, - strlen (tv_modes[i].name), - TRUE); - - err = intel_tv_format_configure_property (output); - - if (err != 0) { - xf86DrvMsg(dev->scrnIndex, X_ERROR, - "RRConfigureOutputProperty error, %d\n", err); - } - - /* Set the current value of the tv_format property */ - if (!intel_tv_format_set_property (output)) - xf86DrvMsg(dev->scrnIndex, X_ERROR, - "RRChangeOutputProperty error, %d\n", err); - - for (i = 0; i < 4; i++) - { - INT32 range[2]; - margin_atoms[i] = MakeAtom(margin_names[i], strlen (margin_names[i]), - TRUE); - - range[0] = 0; - range[1] = 100; - err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i], - TRUE, TRUE, FALSE, 2, range); - - if (err != 0) - xf86DrvMsg(dev->scrnIndex, X_ERROR, - "RRConfigureOutputProperty error, %d\n", err); - - err = RRChangeOutputProperty(output->randr_output, margin_atoms[i], - XA_INTEGER, 32, PropModeReplace, - 1, &tv_priv->margin[i], - FALSE, TRUE); - if (err != 0) - xf86DrvMsg(dev->scrnIndex, X_ERROR, - "RRChangeOutputProperty error, %d\n", err); - } -#endif -} - static bool intel_tv_set_property(struct drm_output *output, struct drm_property *property, uint64_t val) { struct drm_device *dev = output->dev; + struct intel_output *intel_output = output->driver_private; + struct intel_tv_priv *tv_priv = intel_output->dev_priv; int ret = 0; - - if (property == dev->mode_config.tv_left_margin_property || - property == dev->mode_config.tv_right_margin_property || - property == dev->mode_config.tv_top_margin_property || - property == dev->mode_config.tv_bottom_margin_property) { - ret = drm_output_property_set_value(output, property, val); + + ret = drm_output_property_set_value(output, property, val); + if (ret < 0) + goto out; + + if (property == dev->mode_config.tv_left_margin_property) + tv_priv->margin[TV_MARGIN_LEFT] = val; + else if (property == dev->mode_config.tv_right_margin_property) + tv_priv->margin[TV_MARGIN_RIGHT] = val; + else if (property == dev->mode_config.tv_top_margin_property) + tv_priv->margin[TV_MARGIN_TOP] = val; + else if (property == dev->mode_config.tv_bottom_margin_property) + tv_priv->margin[TV_MARGIN_BOTTOM] = val; + else if (property == dev->mode_config.tv_mode_property) { + if (val >= NUM_TV_MODES) { + ret = -EINVAL; + goto out; + } + tv_priv->tv_format = tv_modes[val].name; + intel_tv_mode_set(output, NULL, NULL); } else { - /* TV mode handling here */ + ret = -EINVAL; + goto out; } + intel_tv_mode_set(output, NULL, NULL); +out: return ret; } @@ -1693,6 +1594,8 @@ intel_tv_init(struct drm_device *dev) struct intel_output *intel_output; struct intel_tv_priv *tv_priv; u32 tv_dac_on, tv_dac_off, save_tv_dac; + char **tv_format_names; + int i, initial_mode = 0; /* FIXME: better TV detection and/or quirks */ #if 0 @@ -1743,22 +1646,47 @@ intel_tv_init(struct drm_device *dev) output->possible_crtcs = ((1 << 0) | (1 << 1)); output->possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_output->dev_priv = tv_priv; - tv_priv->type = TV_TYPE_UNKNOWN; + tv_priv->type = ConnectorUnknown; - tv_priv->tv_format = NULL; - /* BIOS margin values */ tv_priv->margin[TV_MARGIN_LEFT] = 54; tv_priv->margin[TV_MARGIN_TOP] = 36; tv_priv->margin[TV_MARGIN_RIGHT] = 46; tv_priv->margin[TV_MARGIN_BOTTOM] = 37; - if (!tv_priv->tv_format) - tv_priv->tv_format = kstrdup(tv_modes[0].name, GFP_KERNEL); + tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); output->driver_private = intel_output; output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; + drm_output_attach_property(output, + dev->mode_config.connector_type_property, + ConnectorUnknown); + + /* Create TV properties then attach current values */ + tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, + DRM_MEM_DRIVER); + if (!tv_format_names) + goto out; + for (i = 0; i < NUM_TV_MODES; i++) + tv_format_names[i] = tv_modes[i].name; + drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + + drm_output_attach_property(output, dev->mode_config.tv_mode_property, + initial_mode); + drm_output_attach_property(output, + dev->mode_config.tv_left_margin_property, + tv_priv->margin[TV_MARGIN_LEFT]); + drm_output_attach_property(output, + dev->mode_config.tv_top_margin_property, + tv_priv->margin[TV_MARGIN_TOP]); + drm_output_attach_property(output, + dev->mode_config.tv_right_margin_property, + tv_priv->margin[TV_MARGIN_RIGHT]); + drm_output_attach_property(output, + dev->mode_config.tv_bottom_margin_property, + tv_priv->margin[TV_MARGIN_BOTTOM]); +out: drm_sysfs_output_add(output); } -- cgit v1.2.3 From 5891b0bd2ae441d738e78737a4c4826bd2e60b43 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sat, 12 Apr 2008 00:15:12 +0200 Subject: radeon_ms: rework command submission ioctl & cleanup --- shared-core/amd.h | 57 +++-- shared-core/amd_legacy.h | 4 +- shared-core/amd_legacy_cbuffer.c | 146 +++++++------ shared-core/radeon_ms.h | 6 +- shared-core/radeon_ms_bo.c | 5 +- shared-core/radeon_ms_cp.c | 2 +- shared-core/radeon_ms_crtc.c | 3 +- shared-core/radeon_ms_drm.c | 8 +- shared-core/radeon_ms_drm.h | 64 +++--- shared-core/radeon_ms_exec.c | 442 ++++++++++++++++++++++----------------- shared-core/radeon_ms_fence.c | 32 +-- 11 files changed, 436 insertions(+), 333 deletions(-) diff --git a/shared-core/amd.h b/shared-core/amd.h index 31cf3eff..f8096053 100644 --- a/shared-core/amd.h +++ b/shared-core/amd.h @@ -31,38 +31,55 @@ * around during command validation (ie check that user have the right to * execute the given command). */ -struct amd_cbuffer_arg +struct amd_cmd_bo { - struct list_head list; - struct drm_buffer_object *buffer; - int32_t dw_id; + struct list_head list; + uint64_t *offsets; + uint32_t *cdw_id; + struct drm_buffer_object *bo; + unsigned int handle; + uint64_t mask; + uint64_t flags; + uint32_t type; }; -struct amd_cbuffer +struct amd_cmd { - uint32_t *cbuffer; - uint32_t cbuffer_dw_count; - struct amd_cbuffer_arg arg_unused; - struct amd_cbuffer_arg arg_used; - struct amd_cbuffer_arg *args; - void *driver; + uint32_t *cdw; + uint32_t cdw_count; + struct drm_bo_kmap_obj cdw_kmap; + size_t cdw_size; + struct amd_cmd_bo *cdw_bo; + struct amd_cmd_bo bo_unused; + struct amd_cmd_bo bo_used; + struct amd_cmd_bo *bo; + uint32_t bo_count; + void *driver; }; -struct amd_cbuffer_checker +struct amd_cmd_module { uint32_t numof_p0_checkers; uint32_t numof_p3_checkers; - int (*check)(struct drm_device *dev, struct amd_cbuffer *cbuffer); - int (**check_p0)(struct drm_device *dev, struct amd_cbuffer *cbuffer, - int dw_id, int reg); - int (**check_p3)(struct drm_device *dev, struct amd_cbuffer *cbuffer, - int dw_id, int op, int count); + int (*check)(struct drm_device *dev, struct amd_cmd *cmd); + int (**check_p0)(struct drm_device *dev, struct amd_cmd *cmd, + int cdw_id, int reg); + int (**check_p3)(struct drm_device *dev, struct amd_cmd *cmd, + int cdw_id, int op, int count); }; -struct amd_cbuffer_arg * -amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id); -int amd_cbuffer_check(struct drm_device *dev, struct amd_cbuffer *cbuffer); +int amd_cmd_check(struct drm_device *dev, struct amd_cmd *cmd); +int amd_ioctl_cmd(struct drm_device *dev, void *data, struct drm_file *file); +static inline struct amd_cmd_bo *amd_cmd_get_bo(struct amd_cmd *cmd, int i) +{ + if (i < cmd->bo_count && cmd->bo[i].type == DRM_AMD_CMD_BO_TYPE_DATA) { + list_del(&cmd->bo[i].list); + list_add_tail(&cmd->bo[i].list, &cmd->bo_used.list); + return &cmd->bo[i]; + } + return NULL; +} /* struct amd_fb amd is for storing amd framebuffer informations */ diff --git a/shared-core/amd_legacy.h b/shared-core/amd_legacy.h index 92997dcd..c1e5f5da 100644 --- a/shared-core/amd_legacy.h +++ b/shared-core/amd_legacy.h @@ -27,7 +27,7 @@ #ifndef __AMD_LEGACY_H__ #define __AMD_LEGACY_H__ -int amd_legacy_cbuffer_destroy(struct drm_device *dev); -int amd_legacy_cbuffer_initialize(struct drm_device *dev); +int amd_legacy_cmd_module_destroy(struct drm_device *dev); +int amd_legacy_cmd_module_initialize(struct drm_device *dev); #endif diff --git a/shared-core/amd_legacy_cbuffer.c b/shared-core/amd_legacy_cbuffer.c index f1b7a44b..7971ee67 100644 --- a/shared-core/amd_legacy_cbuffer.c +++ b/shared-core/amd_legacy_cbuffer.c @@ -44,23 +44,23 @@ struct legacy_check uint32_t dp_gui_master_cntl; uint32_t dst_offset; uint32_t dst_pitch; - struct amd_cbuffer_arg *dst; + struct amd_cmd_bo *dst; uint32_t dst_x; uint32_t dst_y; uint32_t dst_h; uint32_t dst_w; - struct amd_cbuffer_arg *src; + struct amd_cmd_bo *src; uint32_t src_pitch; uint32_t src_x; uint32_t src_y; }; -static int check_blit(struct drm_device *dev, struct amd_cbuffer *cbuffer) +static int check_blit(struct drm_device *dev, struct amd_cmd *cmd) { struct legacy_check *legacy_check; long bpp, start, end; - legacy_check = (struct legacy_check *)cbuffer->driver; + legacy_check = (struct legacy_check *)cmd->driver; /* check that gui master cntl have been set */ if (legacy_check->dp_gui_master_cntl == 0xffffffff) { return -EINVAL; @@ -132,13 +132,13 @@ static int check_blit(struct drm_device *dev, struct amd_cbuffer *cbuffer) } static int p0_dp_gui_master_cntl(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - int dw_id, int reg) + struct amd_cmd *cmd, + int cdw_id, int reg) { struct legacy_check *legacy_check; - legacy_check = (struct legacy_check *)cbuffer->driver; - legacy_check->dp_gui_master_cntl = cbuffer->cbuffer[dw_id]; + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->dp_gui_master_cntl = cmd->cdw[cdw_id]; /* we only accept src data type to be same as dst */ if (((legacy_check->dp_gui_master_cntl >> 12) & 0x3) != 3) { return -EINVAL; @@ -147,125 +147,139 @@ static int p0_dp_gui_master_cntl(struct drm_device *dev, } static int p0_dst_pitch_offset(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - int dw_id, int reg) + struct amd_cmd *cmd, + int cdw_id, int reg) { struct legacy_check *legacy_check; - uint32_t gpu_addr; + uint32_t tmp; int ret; - legacy_check = (struct legacy_check *)cbuffer->driver; - legacy_check->dst_pitch = ((cbuffer->cbuffer[dw_id] >> 22) & 0xff) << 6; - legacy_check->dst = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, - dw_id); + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->dst_pitch = ((cmd->cdw[cdw_id] >> 22) & 0xff) << 6; + tmp = cmd->cdw[cdw_id] & 0x003fffff; + legacy_check->dst = amd_cmd_get_bo(cmd, tmp); if (legacy_check->dst == NULL) { + DRM_ERROR("invalid bo (%d) for DST_PITCH_OFFSET register.\n", + tmp); return -EINVAL; } - ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->dst->buffer->mem, - &gpu_addr); + ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->dst->bo->mem, &tmp); if (ret) { + DRM_ERROR("failed to get GPU offset for bo 0x%x.\n", + legacy_check->dst->handle); return -EINVAL; } - cbuffer->cbuffer[dw_id] &= 0xffc00000; - cbuffer->cbuffer[dw_id] |= (gpu_addr >> 10); + if (tmp & 0x3fff) { + DRM_ERROR("bo 0x%x offset doesn't meet alignement 0x%x.\n", + legacy_check->dst->handle, tmp); + } + cmd->cdw[cdw_id] &= 0xffc00000; + cmd->cdw[cdw_id] |= (tmp >> 10); return 0; } static int p0_src_pitch_offset(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - int dw_id, int reg) + struct amd_cmd *cmd, + int cdw_id, int reg) { struct legacy_check *legacy_check; - uint32_t gpu_addr; + uint32_t tmp; int ret; - legacy_check = (struct legacy_check *)cbuffer->driver; - legacy_check->src_pitch = ((cbuffer->cbuffer[dw_id] >> 22) & 0xff) << 6; - legacy_check->src = amd_cbuffer_arg_from_dw_id(&cbuffer->arg_unused, - dw_id); - if (legacy_check->dst == NULL) { + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->src_pitch = ((cmd->cdw[cdw_id] >> 22) & 0xff) << 6; + tmp = cmd->cdw[cdw_id] & 0x003fffff; + legacy_check->src = amd_cmd_get_bo(cmd, tmp); + if (legacy_check->src == NULL) { + DRM_ERROR("invalid bo (%d) for SRC_PITCH_OFFSET register.\n", + tmp); return -EINVAL; } - ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->src->buffer->mem, - &gpu_addr); + ret = radeon_ms_bo_get_gpu_addr(dev, &legacy_check->src->bo->mem, &tmp); if (ret) { + DRM_ERROR("failed to get GPU offset for bo 0x%x.\n", + legacy_check->src->handle); return -EINVAL; } - cbuffer->cbuffer[dw_id] &= 0xffc00000; - cbuffer->cbuffer[dw_id] |= (gpu_addr >> 10); + if (tmp & 0x3fff) { + DRM_ERROR("bo 0x%x offset doesn't meet alignement 0x%x.\n", + legacy_check->src->handle, tmp); + } + cmd->cdw[cdw_id] &= 0xffc00000; + cmd->cdw[cdw_id] |= (tmp >> 10); return 0; } static int p0_dst_y_x(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - int dw_id, int reg) + struct amd_cmd *cmd, + int cdw_id, int reg) { struct legacy_check *legacy_check; - legacy_check = (struct legacy_check *)cbuffer->driver; - legacy_check->dst_x = cbuffer->cbuffer[dw_id] & 0xffff; - legacy_check->dst_y = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->dst_x = cmd->cdw[cdw_id] & 0xffff; + legacy_check->dst_y = (cmd->cdw[cdw_id] >> 16) & 0xffff; return 0; } static int p0_src_y_x(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - int dw_id, int reg) + struct amd_cmd *cmd, + int cdw_id, int reg) { struct legacy_check *legacy_check; - legacy_check = (struct legacy_check *)cbuffer->driver; - legacy_check->src_x = cbuffer->cbuffer[dw_id] & 0xffff; - legacy_check->src_y = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->src_x = cmd->cdw[cdw_id] & 0xffff; + legacy_check->src_y = (cmd->cdw[cdw_id] >> 16) & 0xffff; return 0; } static int p0_dst_h_w(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - int dw_id, int reg) + struct amd_cmd *cmd, + int cdw_id, int reg) { struct legacy_check *legacy_check; - legacy_check = (struct legacy_check *)cbuffer->driver; - legacy_check->dst_w = cbuffer->cbuffer[dw_id] & 0xffff; - legacy_check->dst_h = (cbuffer->cbuffer[dw_id] >> 16) & 0xffff; - return check_blit(dev, cbuffer); + legacy_check = (struct legacy_check *)cmd->driver; + legacy_check->dst_w = cmd->cdw[cdw_id] & 0xffff; + legacy_check->dst_h = (cmd->cdw[cdw_id] >> 16) & 0xffff; + return check_blit(dev, cmd); } -static int legacy_cbuffer_check(struct drm_device *dev, - struct amd_cbuffer *cbuffer) +static int legacy_cmd_check(struct drm_device *dev, + struct amd_cmd *cmd) { struct legacy_check legacy_check; memset(&legacy_check, 0xff, sizeof(struct legacy_check)); - cbuffer->driver = &legacy_check; - return amd_cbuffer_check(dev, cbuffer); + cmd->driver = &legacy_check; + return amd_cmd_check(dev, cmd); } -int amd_legacy_cbuffer_destroy(struct drm_device *dev) +int amd_legacy_cmd_module_destroy(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; - dev_priv->cbuffer_checker.check = NULL; - if (dev_priv->cbuffer_checker.numof_p0_checkers) { - drm_free(dev_priv->cbuffer_checker.check_p0, - dev_priv->cbuffer_checker.numof_p0_checkers * + dev_priv->cmd_module.check = NULL; + if (dev_priv->cmd_module.numof_p0_checkers) { + drm_free(dev_priv->cmd_module.check_p0, + dev_priv->cmd_module.numof_p0_checkers * sizeof(void*), DRM_MEM_DRIVER); - dev_priv->cbuffer_checker.numof_p0_checkers = 0; + dev_priv->cmd_module.numof_p0_checkers = 0; } - if (dev_priv->cbuffer_checker.numof_p3_checkers) { - drm_free(dev_priv->cbuffer_checker.check_p3, - dev_priv->cbuffer_checker.numof_p3_checkers * + if (dev_priv->cmd_module.numof_p3_checkers) { + drm_free(dev_priv->cmd_module.check_p3, + dev_priv->cmd_module.numof_p3_checkers * sizeof(void*), DRM_MEM_DRIVER); - dev_priv->cbuffer_checker.numof_p3_checkers = 0; + dev_priv->cmd_module.numof_p3_checkers = 0; } return 0; } -int amd_legacy_cbuffer_initialize(struct drm_device *dev) +int amd_legacy_cmd_module_initialize(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; - struct amd_cbuffer_checker *checker = &dev_priv->cbuffer_checker; + struct amd_cmd_module *checker = &dev_priv->cmd_module; long size; /* packet 0 */ @@ -273,7 +287,7 @@ int amd_legacy_cbuffer_initialize(struct drm_device *dev) size = checker->numof_p0_checkers * sizeof(void*); checker->check_p0 = drm_alloc(size, DRM_MEM_DRIVER); if (checker->check_p0 == NULL) { - amd_legacy_cbuffer_destroy(dev); + amd_legacy_cmd_module_destroy(dev); return -ENOMEM; } /* initialize to -1 */ @@ -284,7 +298,7 @@ int amd_legacy_cbuffer_initialize(struct drm_device *dev) size = checker->numof_p3_checkers * sizeof(void*); checker->check_p3 = drm_alloc(size, DRM_MEM_DRIVER); if (checker->check_p3 == NULL) { - amd_legacy_cbuffer_destroy(dev); + amd_legacy_cmd_module_destroy(dev); return -ENOMEM; } /* initialize to -1 */ @@ -301,6 +315,6 @@ int amd_legacy_cbuffer_initialize(struct drm_device *dev) checker->check_p0[RADEON_DP_WRITE_MASK >> 2] = NULL; checker->check_p0[RADEON_DP_CNTL >> 2] = NULL; - checker->check = legacy_cbuffer_check; + checker->check = legacy_cmd_check; return 0; } diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index ec264207..dd34683e 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -330,7 +330,7 @@ struct drm_radeon_private { uint8_t bus_ready; uint8_t write_back; /* command buffer informations */ - struct amd_cbuffer_checker cbuffer_checker; + struct amd_cmd_module cmd_module; /* abstract asic specific structures */ struct radeon_ms_rom rom; struct radeon_ms_properties properties; @@ -426,10 +426,6 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags); int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv); int radeon_ms_driver_unload(struct drm_device *dev); -/* radeon_ms_exec.c */ -int radeon_ms_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file_priv); - /* radeon_ms_family.c */ int radeon_ms_family_init(struct drm_device *dev); diff --git a/shared-core/radeon_ms_bo.c b/shared-core/radeon_ms_bo.c index 015595a4..b366ae5a 100644 --- a/shared-core/radeon_ms_bo.c +++ b/shared-core/radeon_ms_bo.c @@ -134,8 +134,9 @@ static int radeon_ms_bo_move_blit(struct drm_buffer_object *bo, ret = drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, DRM_FENCE_TYPE_EXE | - DRM_RADEON_FENCE_TYPE_RW, - DRM_RADEON_FENCE_FLAG_FLUSHED, + DRM_AMD_FENCE_TYPE_R | + DRM_AMD_FENCE_TYPE_W, + DRM_AMD_FENCE_FLAG_FLUSH, new_mem); return ret; } diff --git a/shared-core/radeon_ms_cp.c b/shared-core/radeon_ms_cp.c index f551000a..3ddeea47 100644 --- a/shared-core/radeon_ms_cp.c +++ b/shared-core/radeon_ms_cp.c @@ -332,7 +332,7 @@ int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count) dev_priv->ring_free -= count; for (i = 0; i < count; i++) { dev_priv->ring_buffer[dev_priv->ring_wptr] = cmd[i]; - DRM_INFO("ring[%d]=0x%08X\n", dev_priv->ring_wptr, cmd[i]); + DRM_DEBUG("ring[%d]=0x%08X\n", dev_priv->ring_wptr, cmd[i]); dev_priv->ring_wptr++; dev_priv->ring_wptr &= dev_priv->ring_mask; } diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c index 83dd0777..3586e019 100644 --- a/shared-core/radeon_ms_crtc.c +++ b/shared-core/radeon_ms_crtc.c @@ -551,6 +551,7 @@ static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc, format = 4; } break; + case 24: case 32: format = 6; break; @@ -648,7 +649,7 @@ static void radeon_ms_crtc1_mode_set_base(struct drm_crtc *crtc, int x, int y) struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_state *state = &dev_priv->driver_state; - DRM_INFO("[radeon_ms] mode_set_base\n"); + DRM_INFO("mode_set_base 0x%lX\n", crtc->fb->bo->offset); state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->bo->offset); radeon_ms_crtc1_restore(dev, state); } diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c index 0d327925..9238de24 100644 --- a/shared-core/radeon_ms_drm.c +++ b/shared-core/radeon_ms_drm.c @@ -59,8 +59,8 @@ struct drm_bo_driver radeon_ms_bo_driver = { }; struct drm_ioctl_desc radeon_ms_ioctls[] = { - DRM_IOCTL_DEF(DRM_RADEON_EXECBUFFER, radeon_ms_execbuffer, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_RESETCP, radeon_ms_resetcp, DRM_AUTH), + DRM_IOCTL_DEF(DRM_AMD_CMD, amd_ioctl_cmd, DRM_AUTH), + DRM_IOCTL_DEF(DRM_AMD_RESETCP, radeon_ms_resetcp, DRM_AUTH), }; int radeon_ms_num_ioctls = DRM_ARRAY_SIZE(radeon_ms_ioctls); @@ -247,7 +247,7 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags) } /* initialze driver specific */ - ret = amd_legacy_cbuffer_initialize(dev); + ret = amd_legacy_cmd_module_initialize(dev); if (ret != 0) { radeon_ms_driver_unload(dev); return ret; @@ -286,7 +286,7 @@ int radeon_ms_driver_unload(struct drm_device *dev) radeon_ms_outputs_destroy(dev); /* shutdown specific driver */ - amd_legacy_cbuffer_destroy(dev); + amd_legacy_cmd_module_destroy(dev); /* shutdown cp engine */ radeon_ms_cp_finish(dev); diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h index e1b4c18c..d7fe6fab 100644 --- a/shared-core/radeon_ms_drm.h +++ b/shared-core/radeon_ms_drm.h @@ -27,42 +27,54 @@ * Authors: * Jérôme Glisse */ -#ifndef __RADEON_MS_DRM_H__ -#define __RADEON_MS_DRM_H__ +#ifndef __AMD_DRM_H__ +#define __AMD_DRM_H__ /* Fence - * We have only one fence class as we submit command through th - * same fifo so there is no need to synchronize buffer btw different - * cmd stream. * - * Set DRM_RADEON_FENCE_FLAG_FLUSHED if you want a flush with + * Set DRM_AND_FENCE_FLAG_FLUSH if you want a flush with * emission of the fence * - * For fence type we have the native DRM EXE type and the radeon RW - * type. + * For fence type we have the native DRM EXE type and the amd R & W type. */ -#define DRM_RADEON_FENCE_CLASS_ACCEL 0 -#define DRM_RADEON_FENCE_TYPE_RW 2 -#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000 +#define DRM_AMD_FENCE_CLASS_2D 0 +#define DRM_AMD_FENCE_TYPE_R (1 << 1) +#define DRM_AMD_FENCE_TYPE_W (1 << 2) +#define DRM_AMD_FENCE_FLAG_FLUSH 0x01000000 -/* radeon ms ioctl */ -#define DRM_RADEON_EXECBUFFER 0x00 -#define DRM_RADEON_RESETCP 0x01 +/* ioctl */ +#define DRM_AMD_CMD 0x00 +#define DRM_AMD_RESETCP 0x01 -struct drm_radeon_execbuffer_arg { - uint64_t next; - uint32_t reloc_offset; - union { - struct drm_bo_op_req req; - struct drm_bo_arg_rep rep; - } d; +/* cmd ioctl */ + +#define DRM_AMD_CMD_BO_TYPE_INVALID 0 +#define DRM_AMD_CMD_BO_TYPE_CMD_RING (1 << 0) +#define DRM_AMD_CMD_BO_TYPE_CMD_INDIRECT (1 << 1) +#define DRM_AMD_CMD_BO_TYPE_DATA (1 << 2) + +struct drm_amd_cmd_bo_offset +{ + uint64_t next; + uint64_t offset; + uint32_t cs_id; +}; + +struct drm_amd_cmd_bo +{ + uint32_t type; + uint64_t next; + uint64_t offset; + struct drm_bo_op_req op_req; + struct drm_bo_arg_rep op_rep; }; -struct drm_radeon_execbuffer { - uint32_t args_count; - uint64_t args; - uint32_t cmd_size; - struct drm_fence_arg fence_arg; +struct drm_amd_cmd +{ + uint32_t cdw_count; + uint32_t bo_count; + uint64_t bo; + struct drm_fence_arg fence_arg; }; #endif diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c index 28fcc180..fc359d45 100644 --- a/shared-core/radeon_ms_exec.c +++ b/shared-core/radeon_ms_exec.c @@ -27,173 +27,233 @@ #include "radeon_ms.h" #include "amd.h" -static void radeon_ms_execbuffer_args_clean(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - uint32_t args_count) +static inline void amd_cmd_bo_cleanup(struct drm_device *dev, + struct amd_cmd *cmd) { + struct amd_cmd_bo *bo; + mutex_lock(&dev->struct_mutex); - while (args_count--) { - drm_bo_usage_deref_locked(&cbuffer->args[args_count].buffer); + list_for_each_entry(bo, &cmd->bo_unused.list, list) { + drm_bo_usage_deref_locked(&bo->bo); + } + list_for_each_entry(bo, &cmd->bo_used.list, list) { + drm_bo_usage_deref_locked(&bo->bo); } mutex_unlock(&dev->struct_mutex); } -static int radeon_ms_execbuffer_args(struct drm_device *dev, - struct drm_file *file_priv, - struct drm_radeon_execbuffer *execbuffer, - struct amd_cbuffer *cbuffer) +static inline int amd_cmd_bo_validate(struct drm_device *dev, + struct drm_file *file, + struct amd_cmd_bo *cmd_bo, + struct drm_amd_cmd_bo *bo, + uint64_t data) +{ + int ret; + + /* validate only cmd indirect or data bo */ + switch (bo->type) { + case DRM_AMD_CMD_BO_TYPE_CMD_INDIRECT: + case DRM_AMD_CMD_BO_TYPE_DATA: + case DRM_AMD_CMD_BO_TYPE_CMD_RING: + /* FIXME: make sure userspace can no longer map the bo */ + break; + default: + return 0; + } + /* check that buffer operation is validate */ + if (bo->op_req.op != drm_bo_validate) { + DRM_ERROR("buffer 0x%x object operation is not validate.\n", + cmd_bo->handle); + return -EINVAL; + } + /* validate buffer */ + memset(&bo->op_rep, 0, sizeof(struct drm_bo_arg_rep)); + ret = drm_bo_handle_validate(file, + bo->op_req.bo_req.handle, + bo->op_req.bo_req.flags, + bo->op_req.bo_req.mask, + bo->op_req.bo_req.hint, + bo->op_req.bo_req.fence_class, + 0, + &bo->op_rep.bo_info, + &cmd_bo->bo); + if (ret) { + DRM_ERROR("validate error %d for 0x%08x\n", + ret, cmd_bo->handle); + return ret; + } + if (copy_to_user((void __user *)((unsigned)data), bo, + sizeof(struct drm_amd_cmd_bo))) { + DRM_ERROR("failed to copy to user validate result of 0x%08x\n", + cmd_bo->handle); + return -EFAULT; + } + return 0; +} + +static int amd_cmd_parse_cmd_bo(struct drm_device *dev, + struct drm_file *file, + struct drm_amd_cmd *drm_amd_cmd, + struct amd_cmd *cmd) { - struct drm_radeon_execbuffer_arg arg; - struct drm_bo_arg_rep rep; - uint32_t args_count = 0; - uint64_t next = 0; - uint64_t data = execbuffer->args; + struct drm_amd_cmd_bo drm_amd_cmd_bo; + struct amd_cmd_bo *cmd_bo; + uint32_t bo_count = 0; + uint64_t data = drm_amd_cmd->bo; int ret = 0; do { - if (args_count >= execbuffer->args_count) { - DRM_ERROR("[radeon_ms] buffer count exceeded %d\n.", - execbuffer->args_count); - ret = -EINVAL; - goto out_err; + /* check we don't have more buffer than announced */ + if (bo_count >= drm_amd_cmd->bo_count) { + DRM_ERROR("cmd bo count exceeded got %d waited %d\n.", + bo_count, drm_amd_cmd->bo_count); + return -EINVAL; } - INIT_LIST_HEAD(&cbuffer->args[args_count].list); - cbuffer->args[args_count].buffer = NULL; - if (copy_from_user(&arg, (void __user *)((unsigned)data), - sizeof(struct drm_radeon_execbuffer_arg))) { - ret = -EFAULT; - goto out_err; + /* initialize amd_cmd_bo */ + cmd_bo = &cmd->bo[bo_count]; + INIT_LIST_HEAD(&cmd_bo->list); + cmd_bo->bo = NULL; + /* copy from userspace */ + if (copy_from_user(&drm_amd_cmd_bo, + (void __user *)((unsigned)data), + sizeof(struct drm_amd_cmd_bo))) { + return -EFAULT; } + /* collect informations */ + cmd_bo->type = drm_amd_cmd_bo.type; + cmd_bo->mask = drm_amd_cmd_bo.op_req.bo_req.mask; + cmd_bo->flags = drm_amd_cmd_bo.op_req.bo_req.flags; + cmd_bo->handle = drm_amd_cmd_bo.op_req.arg_handle; + /* get bo objects */ mutex_lock(&dev->struct_mutex); - cbuffer->args[args_count].buffer = - drm_lookup_buffer_object(file_priv, - arg.d.req.arg_handle, 1); - cbuffer->args[args_count].dw_id = arg.reloc_offset; + cmd_bo->bo = drm_lookup_buffer_object(file, cmd_bo->handle, 1); mutex_unlock(&dev->struct_mutex); - if (arg.d.req.op != drm_bo_validate) { - DRM_ERROR("[radeon_ms] buffer object operation wasn't " - "validate.\n"); - ret = -EINVAL; - goto out_err; + if (cmd_bo->bo == NULL) { + DRM_ERROR("unknown bo handle 0x%x\n", cmd_bo->handle); + return -EINVAL; } - memset(&rep, 0, sizeof(struct drm_bo_arg_rep)); - ret = drm_bo_handle_validate(file_priv, - arg.d.req.bo_req.handle, - arg.d.req.bo_req.flags, - arg.d.req.bo_req.mask, - arg.d.req.bo_req.hint, - arg.d.req.bo_req.fence_class, - 0, - &rep.bo_info, - &cbuffer->args[args_count].buffer); + /* validate buffer if necessary */ + ret = amd_cmd_bo_validate(dev, file, cmd_bo, + &drm_amd_cmd_bo, data); if (ret) { - DRM_ERROR("[radeon_ms] error on handle validate %d\n", - ret); - rep.ret = ret; - goto out_err; + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&cmd_bo->bo); + mutex_unlock(&dev->struct_mutex); + return ret; } - next = arg.next; - arg.d.rep = rep; - if (copy_to_user((void __user *)((unsigned)data), &arg, - sizeof(struct drm_radeon_execbuffer_arg))) { - ret = -EFAULT; - goto out_err; + /* inspect bo type */ + switch (cmd_bo->type) { + case DRM_AMD_CMD_BO_TYPE_CMD_INDIRECT: + /* add it so we properly unreference in case of error */ + list_add_tail(&cmd_bo->list, &cmd->bo_used.list); + return -EINVAL; + case DRM_AMD_CMD_BO_TYPE_DATA: + /* add to unused list */ + list_add_tail(&cmd_bo->list, &cmd->bo_unused.list); + break; + case DRM_AMD_CMD_BO_TYPE_CMD_RING: + /* set cdw_bo */ + list_add_tail(&cmd_bo->list, &cmd->bo_used.list); + cmd->cdw_bo = cmd_bo; + break; + default: + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked(&cmd_bo->bo); + mutex_unlock(&dev->struct_mutex); + DRM_ERROR("unknow bo 0x%x unknown type 0x%x in cmd\n", + cmd_bo->handle, cmd_bo->type); + return -EINVAL; } - data = next; - - list_add_tail(&cbuffer->args[args_count].list, - &cbuffer->arg_unused.list); - - args_count++; - } while (next != 0); - if (args_count != execbuffer->args_count) { - DRM_ERROR("[radeon_ms] not enought buffer got %d waited %d\n.", - args_count, execbuffer->args_count); - ret = -EINVAL; - goto out_err; + /* ok next bo */ + data = drm_amd_cmd_bo.next; + bo_count++; + } while (data != 0); + if (bo_count != drm_amd_cmd->bo_count) { + DRM_ERROR("not enought buffer got %d expected %d\n.", + bo_count, drm_amd_cmd->bo_count); + return -EINVAL; } return 0; -out_err: - radeon_ms_execbuffer_args_clean(dev, cbuffer, args_count); - return ret; } -static int cbuffer_packet0_check(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - int dw_id) +static int amd_cmd_packet0_check(struct drm_device *dev, + struct amd_cmd *cmd, + int *cdw_id) { struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t reg, count, r, i; int ret; - reg = cbuffer->cbuffer[dw_id] & PACKET0_REG_MASK; - count = (cbuffer->cbuffer[dw_id] & PACKET0_COUNT_MASK) >> - PACKET0_COUNT_SHIFT; - if (reg + count > dev_priv->cbuffer_checker.numof_p0_checkers) { + reg = cmd->cdw[*cdw_id] & PACKET0_REG_MASK; + count = (cmd->cdw[*cdw_id] & PACKET0_COUNT_MASK) >> PACKET0_COUNT_SHIFT; + if (reg + count > dev_priv->cmd_module.numof_p0_checkers) { + DRM_ERROR("0x%08X registers is above last accepted registers\n", + reg << 2); return -EINVAL; } for (r = reg, i = 0; i <= count; i++, r++) { - if (dev_priv->cbuffer_checker.check_p0[r] == NULL) { + if (dev_priv->cmd_module.check_p0[r] == NULL) { continue; } - if (dev_priv->cbuffer_checker.check_p0[r] == (void *)-1) { - DRM_INFO("[radeon_ms] check_f: %d %d -1 checker\n", - r, r << 2); + if (dev_priv->cmd_module.check_p0[r] == (void *)-1) { + DRM_ERROR("register 0x%08X (at %d) is forbidden\n", + r << 2, (*cdw_id) + i + 1); return -EINVAL; } - ret = dev_priv->cbuffer_checker.check_p0[r](dev, cbuffer, - dw_id + i + 1, reg); + ret = dev_priv->cmd_module.check_p0[r](dev, cmd, + (*cdw_id) + i + 1, r); if (ret) { - DRM_INFO("[radeon_ms] check_f: %d %d checker ret=%d\n", - r, r << 2, ret); - return -EINVAL; + return ret; } } /* header + N + 1 dword passed test */ - return count + 2; + (*cdw_id) += count + 2; + return 0; } -static int cbuffer_packet3_check(struct drm_device *dev, - struct amd_cbuffer *cbuffer, - int dw_id) +static int amd_cmd_packet3_check(struct drm_device *dev, + struct amd_cmd *cmd, + int *cdw_id) { struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t opcode, count; int ret; - opcode = (cbuffer->cbuffer[dw_id] & PACKET3_OPCODE_MASK) >> + opcode = (cmd->cdw[*cdw_id] & PACKET3_OPCODE_MASK) >> PACKET3_OPCODE_SHIFT; - if (opcode > dev_priv->cbuffer_checker.numof_p3_checkers) { + if (opcode > dev_priv->cmd_module.numof_p3_checkers) { + DRM_ERROR("0x%08X opcode is above last accepted opcodes\n", + opcode); return -EINVAL; } - count = (cbuffer->cbuffer[dw_id] & PACKET3_COUNT_MASK) >> - PACKET3_COUNT_SHIFT; - if (dev_priv->cbuffer_checker.check_p3[opcode] == NULL) { + count = (cmd->cdw[*cdw_id] & PACKET3_COUNT_MASK) >> PACKET3_COUNT_SHIFT; + if (dev_priv->cmd_module.check_p3[opcode] == NULL) { + DRM_ERROR("0x%08X opcode is forbidden\n", opcode); return -EINVAL; } - ret = dev_priv->cbuffer_checker.check_p3[opcode](dev, cbuffer, - dw_id + 1, opcode, - count); + ret = dev_priv->cmd_module.check_p3[opcode](dev, cmd, + (*cdw_id) + 1, opcode, + count); if (ret) { - return -EINVAL; + return ret; } - return count + 2; + /* header + N + 1 dword passed test */ + (*cdw_id) += count + 2; + return 0; } -int amd_cbuffer_check(struct drm_device *dev, struct amd_cbuffer *cbuffer) +int amd_cmd_check(struct drm_device *dev, struct amd_cmd *cmd) { uint32_t i; int ret; - for (i = 0; i < cbuffer->cbuffer_dw_count;) { - switch (PACKET_HEADER_GET(cbuffer->cbuffer[i])) { + for (i = 0; i < cmd->cdw_count;) { + switch (PACKET_HEADER_GET(cmd->cdw[i])) { case 0: - ret = cbuffer_packet0_check(dev, cbuffer, i); - if (ret <= 0) { + ret = amd_cmd_packet0_check(dev, cmd, &i); + if (ret) { return ret; } - /* advance to next packet */ - i += ret; break; case 1: /* we don't accept packet 1 */ @@ -202,122 +262,122 @@ int amd_cbuffer_check(struct drm_device *dev, struct amd_cbuffer *cbuffer) /* FIXME: accept packet 2 */ return -EINVAL; case 3: - ret = cbuffer_packet3_check(dev, cbuffer, i); - if (ret <= 0) { + ret = amd_cmd_packet3_check(dev, cmd, &i); + if (ret) { return ret; } - /* advance to next packet */ - i += ret; break; } } return 0; } -struct amd_cbuffer_arg * -amd_cbuffer_arg_from_dw_id(struct amd_cbuffer_arg *head, uint32_t dw_id) +static int amd_ioctl_cmd_cleanup(struct drm_device *dev, + struct drm_file *file, + struct amd_cmd *cmd, + int r) { - struct amd_cbuffer_arg *arg; - - list_for_each_entry(arg, &head->list, list) { - if (arg->dw_id == dw_id) { - return arg; - } + /* check if we need to unfence object */ + if (r && (!list_empty(&cmd->bo_unused.list) || + !list_empty(&cmd->bo_unused.list))) { + drm_putback_buffer_objects(dev); + } + if (cmd->cdw) { + drm_bo_kunmap(&cmd->cdw_kmap); + cmd->cdw = NULL; } - /* no buffer at this dw index */ - return NULL; + /* derefence buffer as lookup reference them */ + amd_cmd_bo_cleanup(dev, cmd); + if (cmd->bo) { + drm_free(cmd->bo, + cmd->bo_count * sizeof(struct amd_cmd_bo), + DRM_MEM_DRIVER); + cmd->bo = NULL; + } + drm_bo_read_unlock(&dev->bm.bm_lock); + return r; } - -int radeon_ms_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int amd_ioctl_cmd(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_radeon_private *dev_priv = dev->dev_private; - struct drm_radeon_execbuffer *execbuffer = data; - struct drm_fence_arg *fence_arg = &execbuffer->fence_arg; - struct drm_bo_kmap_obj cmd_kmap; + struct drm_amd_cmd *drm_amd_cmd = data; + struct drm_fence_arg *fence_arg = &drm_amd_cmd->fence_arg; struct drm_fence_object *fence; - int cmd_is_iomem; - int ret = 0; - struct amd_cbuffer cbuffer; + struct amd_cmd cmd; + int tmp; + int ret; - /* command buffer dword count must be >= 0 */ - if (execbuffer->cmd_size < 0) { + /* check that we have a command checker */ + if (dev_priv->cmd_module.check == NULL) { + DRM_ERROR("invalid command checker module.\n"); + return -EFAULT; + } + /* command dword count must be >= 0 */ + if (drm_amd_cmd->cdw_count == 0) { + DRM_ERROR("command dword count is 0.\n"); return -EINVAL; } - - /* FIXME: Lock buffer manager, is this really needed ? - */ + /* FIXME: Lock buffer manager, is this really needed ? */ ret = drm_bo_read_lock(&dev->bm.bm_lock); if (ret) { + DRM_ERROR("bo read locking failed.\n"); return ret; } - - cbuffer.args = drm_calloc(execbuffer->args_count, - sizeof(struct amd_cbuffer_arg), - DRM_MEM_DRIVER); - if (cbuffer.args == NULL) { - ret = -ENOMEM; - goto out_free; + /* cleanup & initialize amd cmd structure */ + memset(&cmd, 0, sizeof(struct amd_cmd)); + cmd.bo_count = drm_amd_cmd->bo_count; + INIT_LIST_HEAD(&cmd.bo_unused.list); + INIT_LIST_HEAD(&cmd.bo_used.list); + /* allocate structure for bo parsing */ + cmd.bo = drm_calloc(cmd.bo_count, sizeof(struct amd_cmd_bo), + DRM_MEM_DRIVER); + if (cmd.bo == NULL) { + return amd_ioctl_cmd_cleanup(dev, file, &cmd, -ENOMEM); } - - INIT_LIST_HEAD(&cbuffer.arg_unused.list); - INIT_LIST_HEAD(&cbuffer.arg_used.list); - - /* process arguments */ - ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer, &cbuffer); + /* parse cmd bo */ + ret = amd_cmd_parse_cmd_bo(dev, file, drm_amd_cmd, &cmd); if (ret) { - DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n"); - goto out_free; + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); + } + /* check that a command buffer have been found */ + if (cmd.cdw_bo == NULL) { + DRM_ERROR("no command buffer submited in cmd ioctl\n"); + return amd_ioctl_cmd_cleanup(dev, file, &cmd, -EINVAL); } - /* map command buffer */ - cbuffer.cbuffer_dw_count = (cbuffer.args[0].buffer->mem.num_pages * - PAGE_SIZE) >> 2; - if (execbuffer->cmd_size > cbuffer.cbuffer_dw_count) { - ret = -EINVAL; - goto out_free_release; + cmd.cdw_count = drm_amd_cmd->cdw_count; + cmd.cdw_size = (cmd.cdw_bo->bo->mem.num_pages * PAGE_SIZE) >> 2; + if (cmd.cdw_size < cmd.cdw_count) { + DRM_ERROR("command buffer (%d) is smaller than expected (%d)\n", + cmd.cdw_size, cmd.cdw_count); + return amd_ioctl_cmd_cleanup(dev, file, &cmd, -EINVAL); } - cbuffer.cbuffer_dw_count = execbuffer->cmd_size; - memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj)); - ret = drm_bo_kmap(cbuffer.args[0].buffer, 0, - cbuffer.args[0].buffer->mem.num_pages, &cmd_kmap); + memset(&cmd.cdw_kmap, 0, sizeof(struct drm_bo_kmap_obj)); + ret = drm_bo_kmap(cmd.cdw_bo->bo, 0, + cmd.cdw_bo->bo->mem.num_pages, &cmd.cdw_kmap); if (ret) { - DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret); - goto out_free_release; + DRM_ERROR("error mapping command buffer\n"); + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); } - cbuffer.cbuffer = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem); - list_del(&cbuffer.args[0].list); - list_add_tail(&cbuffer.args[0].list , &cbuffer.arg_used.list); - - /* do cmd checking & relocations */ - if (dev_priv->cbuffer_checker.check) { - ret = dev_priv->cbuffer_checker.check(dev, &cbuffer); - if (ret) { - drm_putback_buffer_objects(dev); - goto out_free_release; - } - } else { - drm_putback_buffer_objects(dev); - goto out_free_release; + cmd.cdw = drm_bmo_virtual(&cmd.cdw_kmap, &tmp); + /* do command checking */ + ret = dev_priv->cmd_module.check(dev, &cmd); + if (ret) { + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); } - - ret = radeon_ms_ring_emit(dev, cbuffer.cbuffer, - cbuffer.cbuffer_dw_count); + /* copy command to ring */ + ret = radeon_ms_ring_emit(dev, cmd.cdw, cmd.cdw_count); if (ret) { - drm_putback_buffer_objects(dev); - goto out_free_release; + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); } - /* fence */ ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); if (ret) { - drm_putback_buffer_objects(dev); - DRM_ERROR("[radeon_ms] fence buffer objects failed\n"); - goto out_free_release; + return amd_ioctl_cmd_cleanup(dev, file, &cmd, ret); } if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) { - ret = drm_fence_add_user_object(file_priv, fence, + ret = drm_fence_add_user_object(file, fence, fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE); if (!ret) { @@ -326,16 +386,10 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data, fence_arg->type = fence->type; fence_arg->signaled = fence->signaled_types; fence_arg->sequence = fence->sequence; + } else { + DRM_ERROR("error add object fence, expect oddity !\n"); } } drm_fence_usage_deref_unlocked(&fence); -out_free_release: - drm_bo_kunmap(&cmd_kmap); - radeon_ms_execbuffer_args_clean(dev, &cbuffer, execbuffer->args_count); -out_free: - drm_free(cbuffer.args, - (execbuffer->args_count * sizeof(struct amd_cbuffer_arg)), - DRM_MEM_DRIVER); - drm_bo_read_unlock(&dev->bm.bm_lock); - return ret; + return amd_ioctl_cmd_cleanup(dev, file, &cmd, 0); } diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c index 994c3e48..08e53bd2 100644 --- a/shared-core/radeon_ms_fence.c +++ b/shared-core/radeon_ms_fence.c @@ -44,7 +44,10 @@ static inline int r3xx_fence_emit_sequence(struct drm_device *dev, sequence & ~R3XX_FENCE_SEQUENCE_RW_FLUSH; /* Ask flush for VERTEX & FRAGPROG pipeline * have 3D idle */ + /* FIXME: proper flush */ +#if 0 dev_priv->flush_cache(dev); +#endif } cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0); cmd[1] = sequence; @@ -78,18 +81,17 @@ static inline void r3xx_fence_report(struct drm_device *dev, return; } sequence = mmio_read(dev_priv, dev_priv->fence_reg); +DRM_INFO("%s pass fence 0x%08x\n", __func__, sequence); if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) { sequence &= ~R3XX_FENCE_SEQUENCE_RW_FLUSH; - fence_types |= DRM_RADEON_FENCE_TYPE_RW; + fence_types |= DRM_AMD_FENCE_TYPE_R; + fence_types |= DRM_AMD_FENCE_TYPE_W; if (sequence == r3xx_fence->sequence_last_flush) { r3xx_fence->sequence_last_flush = 0; } } - /* avoid to report already reported sequence */ - if (sequence != r3xx_fence->sequence_last_reported) { - drm_fence_handler(dev, 0, sequence, fence_types, 0); - r3xx_fence->sequence_last_reported = sequence; - } + drm_fence_handler(dev, 0, sequence, fence_types, 0); + r3xx_fence->sequence_last_reported = sequence; } static void r3xx_fence_flush(struct drm_device *dev, uint32_t class) @@ -116,9 +118,10 @@ static void r3xx_fence_poll(struct drm_device *dev, uint32_t fence_class, } /* if there is a RW flush pending then submit new sequence * preceded by flush cmds */ - if (fc->pending_flush & DRM_RADEON_FENCE_TYPE_RW) { + if (fc->pending_flush & (DRM_AMD_FENCE_TYPE_R | DRM_AMD_FENCE_TYPE_W)) { r3xx_fence_flush(dev, 0); - fc->pending_flush &= ~DRM_RADEON_FENCE_TYPE_RW; + fc->pending_flush &= ~DRM_AMD_FENCE_TYPE_R; + fc->pending_flush &= ~DRM_AMD_FENCE_TYPE_W; } r3xx_fence_report(dev, dev_priv, r3xx_fence); return; @@ -137,10 +140,12 @@ static int r3xx_fence_emit(struct drm_device *dev, uint32_t class, } *sequence = tmp = r3xx_fence_sequence(r3xx_fence); *native_type = DRM_FENCE_TYPE_EXE; - if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) { - *native_type |= DRM_RADEON_FENCE_TYPE_RW; + if (flags & DRM_AMD_FENCE_FLAG_FLUSH) { + *native_type |= DRM_AMD_FENCE_TYPE_R; + *native_type |= DRM_AMD_FENCE_TYPE_W; tmp |= R3XX_FENCE_SEQUENCE_RW_FLUSH; } +DRM_INFO("%s emit fence 0x%08x\n", __func__, tmp); return r3xx_fence_emit_sequence(dev, dev_priv, tmp); } @@ -148,7 +153,8 @@ static int r3xx_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t type) { const uint32_t type_irq_mask = DRM_FENCE_TYPE_EXE | - DRM_RADEON_FENCE_TYPE_RW; + DRM_AMD_FENCE_TYPE_R | + DRM_AMD_FENCE_TYPE_W; /* * We have an irq for EXE & RW fence. */ @@ -243,7 +249,9 @@ int r3xx_fence_types(struct drm_buffer_object *bo, { *class = 0; if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) { - *type = DRM_FENCE_TYPE_EXE | DRM_RADEON_FENCE_TYPE_RW; + *type = DRM_FENCE_TYPE_EXE | + DRM_AMD_FENCE_TYPE_R | + DRM_AMD_FENCE_TYPE_W; } else { *type = DRM_FENCE_TYPE_EXE; } -- cgit v1.2.3 From 21a93915d8a21518c5da76a739f9459ed7f99d6a Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Thu, 17 Apr 2008 16:51:00 +0800 Subject: Porting DVO stuff Ported from Xorg intel 2d driver. Changed interfaces definitions, which needed to be changed later if other device wants to use these DVO stuff. --- linux-core/Makefile.kernel | 3 +- linux-core/dvo.h | 159 +++++++++++++++ linux-core/dvo_ch7017.c | 454 +++++++++++++++++++++++++++++++++++++++++ linux-core/dvo_ch7xxx.c | 368 +++++++++++++++++++++++++++++++++ linux-core/dvo_ivch.c | 459 +++++++++++++++++++++++++++++++++++++++++ linux-core/dvo_sil164.c | 302 +++++++++++++++++++++++++++ linux-core/dvo_tfp410.c | 335 ++++++++++++++++++++++++++++++ linux-core/intel_display.c | 3 +- linux-core/intel_drv.h | 1 + linux-core/intel_dvo.c | 493 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_drv.h | 34 +++- 11 files changed, 2606 insertions(+), 5 deletions(-) create mode 100644 linux-core/dvo.h create mode 100644 linux-core/dvo_ch7017.c create mode 100644 linux-core/dvo_ch7xxx.c create mode 100644 linux-core/dvo_ivch.c create mode 100644 linux-core/dvo_sil164.c create mode 100644 linux-core/dvo_tfp410.c create mode 100644 linux-core/intel_dvo.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 91decfc8..28f6ec06 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -22,7 +22,8 @@ i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \ intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o \ - intel_tv.o i915_compat.o + intel_tv.o i915_compat.o intel_dvo.o dvo_ch7xxx.o \ + dvo_ch7017.o dvo_ivch.o dvo_tfp410.o dvo_sil164.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o nouveau_notifier.o nouveau_swmthd.o \ nouveau_sgdma.o nouveau_dma.o nouveau_buffer.o nouveau_fence.o \ diff --git a/linux-core/dvo.h b/linux-core/dvo.h new file mode 100644 index 00000000..c6c1dbdb --- /dev/null +++ b/linux-core/dvo.h @@ -0,0 +1,159 @@ +/* + * Copyright © 2006 Eric Anholt + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef _INTEL_DVO_H +#define _INTEL_DVO_H + +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" + +struct intel_dvo_device { + char *name; + int type; + /* DVOA/B/C output register */ + u32 dvo_reg; + /* GPIO register used for i2c bus to control this device */ + u32 gpio; + int slave_addr; + struct intel_i2c_chan *i2c_bus; + + const struct intel_dvo_dev_ops *dev_ops; + void *dev_priv; + + struct drm_display_mode *panel_fixed_mode; + bool panel_wants_dither; +}; + +struct intel_dvo_dev_ops { + /* + * Initialize the device at startup time. + * Returns NULL if the device does not exist. + */ + bool (*init)(struct intel_dvo_device *dvo, + struct intel_i2c_chan *i2cbus); + + /* + * Called to allow the output a chance to create properties after the + * RandR objects have been created. + */ + void (*create_resources)(struct intel_dvo_device *dvo); + + /* + * Turn on/off output or set intermediate power levels if available. + * + * Unsupported intermediate modes drop to the lower power setting. + * If the mode is DPMSModeOff, the output must be disabled, + * as the DPLL may be disabled afterwards. + */ + void (*dpms)(struct intel_dvo_device *dvo, int mode); + + /* + * Saves the output's state for restoration on VT switch. + */ + void (*save)(struct intel_dvo_device *dvo); + + /* + * Restore's the output's state at VT switch. + */ + void (*restore)(struct intel_dvo_device *dvo); + + /* + * Callback for testing a video mode for a given output. + * + * This function should only check for cases where a mode can't + * be supported on the output specifically, and not represent + * generic CRTC limitations. + * + * \return MODE_OK if the mode is valid, or another MODE_* otherwise. + */ + int (*mode_valid)(struct intel_dvo_device *dvo, + struct drm_display_mode *mode); + + /* + * Callback to adjust the mode to be set in the CRTC. + * + * This allows an output to adjust the clock or even the entire set of + * timings, which is used for panels with fixed timings or for + * buses with clock limitations. + */ + bool (*mode_fixup)(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + /* + * Callback for preparing mode changes on an output + */ + void (*prepare)(struct intel_dvo_device *dvo); + + /* + * Callback for committing mode changes on an output + */ + void (*commit)(struct intel_dvo_device *dvo); + + /* + * Callback for setting up a video mode after fixups have been made. + * + * This is only called while the output is disabled. The dpms callback + * must be all that's necessary for the output, to turn the output on + * after this function is called. + */ + void (*mode_set)(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + + /* + * Probe for a connected output, and return detect_status. + */ + enum drm_output_status (*detect)(struct intel_dvo_device *dvo); + + /** + * Query the device for the modes it provides. + * + * This function may also update MonInfo, mm_width, and mm_height. + * + * \return singly-linked list of modes or NULL if no modes found. + */ + struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo); + +#ifdef RANDR_12_INTERFACE + /** + * Callback when an output's property has changed. + */ + bool (*set_property)(struct intel_dvo_device *dvo, + struct drm_property *property, uint64_t val); +#endif + + /** + * Clean up driver-specific bits of the output + */ + void (*destroy) (struct intel_dvo_device *dvo); + + /** + * Debugging hook to dump device registers to log file + */ + void (*dump_regs)(struct intel_dvo_device *dvo); +}; + +#endif /* _INTEL_DVO_H */ diff --git a/linux-core/dvo_ch7017.c b/linux-core/dvo_ch7017.c new file mode 100644 index 00000000..8349da1b --- /dev/null +++ b/linux-core/dvo_ch7017.c @@ -0,0 +1,454 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include "dvo.h" + +#define CH7017_TV_DISPLAY_MODE 0x00 +#define CH7017_FLICKER_FILTER 0x01 +#define CH7017_VIDEO_BANDWIDTH 0x02 +#define CH7017_TEXT_ENHANCEMENT 0x03 +#define CH7017_START_ACTIVE_VIDEO 0x04 +#define CH7017_HORIZONTAL_POSITION 0x05 +#define CH7017_VERTICAL_POSITION 0x06 +#define CH7017_BLACK_LEVEL 0x07 +#define CH7017_CONTRAST_ENHANCEMENT 0x08 +#define CH7017_TV_PLL 0x09 +#define CH7017_TV_PLL_M 0x0a +#define CH7017_TV_PLL_N 0x0b +#define CH7017_SUB_CARRIER_0 0x0c +#define CH7017_CIV_CONTROL 0x10 +#define CH7017_CIV_0 0x11 +#define CH7017_CHROMA_BOOST 0x14 +#define CH7017_CLOCK_MODE 0x1c +#define CH7017_INPUT_CLOCK 0x1d +#define CH7017_GPIO_CONTROL 0x1e +#define CH7017_INPUT_DATA_FORMAT 0x1f +#define CH7017_CONNECTION_DETECT 0x20 +#define CH7017_DAC_CONTROL 0x21 +#define CH7017_BUFFERED_CLOCK_OUTPUT 0x22 +#define CH7017_DEFEAT_VSYNC 0x47 +#define CH7017_TEST_PATTERN 0x48 + +#define CH7017_POWER_MANAGEMENT 0x49 +/** Enables the TV output path. */ +#define CH7017_TV_EN (1 << 0) +#define CH7017_DAC0_POWER_DOWN (1 << 1) +#define CH7017_DAC1_POWER_DOWN (1 << 2) +#define CH7017_DAC2_POWER_DOWN (1 << 3) +#define CH7017_DAC3_POWER_DOWN (1 << 4) +/** Powers down the TV out block, and DAC0-3 */ +#define CH7017_TV_POWER_DOWN_EN (1 << 5) + +#define CH7017_VERSION_ID 0x4a + +#define CH7017_DEVICE_ID 0x4b +#define CH7017_DEVICE_ID_VALUE 0x1b +#define CH7018_DEVICE_ID_VALUE 0x1a +#define CH7019_DEVICE_ID_VALUE 0x19 + +#define CH7017_XCLK_D2_ADJUST 0x53 +#define CH7017_UP_SCALER_COEFF_0 0x55 +#define CH7017_UP_SCALER_COEFF_1 0x56 +#define CH7017_UP_SCALER_COEFF_2 0x57 +#define CH7017_UP_SCALER_COEFF_3 0x58 +#define CH7017_UP_SCALER_COEFF_4 0x59 +#define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a +#define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b +#define CH7017_GPIO_INVERT 0x5c +#define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d +#define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e + +#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f +/**< Low bits of horizontal active pixel input */ + +#define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60 +/** High bits of horizontal active pixel input */ +#define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0) +/** High bits of vertical active line output */ +#define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3) + +#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61 +/**< Low bits of vertical active line output */ + +#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62 +/**< Low bits of horizontal active pixel output */ + +#define CH7017_LVDS_POWER_DOWN 0x63 +/** High bits of horizontal active pixel output */ +#define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0) +/** Enables the LVDS power down state transition */ +#define CH7017_LVDS_POWER_DOWN_EN (1 << 6) +/** Enables the LVDS upscaler */ +#define CH7017_LVDS_UPSCALER_EN (1 << 7) +#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 + +#define CH7017_LVDS_ENCODING 0x64 +#define CH7017_LVDS_DITHER_2D (1 << 2) +#define CH7017_LVDS_DITHER_DIS (1 << 3) +#define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4) +#define CH7017_LVDS_24_BIT (1 << 5) + +#define CH7017_LVDS_ENCODING_2 0x65 + +#define CH7017_LVDS_PLL_CONTROL 0x66 +/** Enables the LVDS panel output path */ +#define CH7017_LVDS_PANEN (1 << 0) +/** Enables the LVDS panel backlight */ +#define CH7017_LVDS_BKLEN (1 << 3) + +#define CH7017_POWER_SEQUENCING_T1 0x67 +#define CH7017_POWER_SEQUENCING_T2 0x68 +#define CH7017_POWER_SEQUENCING_T3 0x69 +#define CH7017_POWER_SEQUENCING_T4 0x6a +#define CH7017_POWER_SEQUENCING_T5 0x6b +#define CH7017_GPIO_DRIVER_TYPE 0x6c +#define CH7017_GPIO_DATA 0x6d +#define CH7017_GPIO_DIRECTION_CONTROL 0x6e + +#define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71 +# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 +# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 +# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 + +#define CH7017_LVDS_PLL_VCO_CONTROL 0x72 +# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 +# define CH7017_LVDS_PLL_VCO_SHIFT 4 +# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 + +#define CH7017_OUTPUTS_ENABLE 0x73 +# define CH7017_CHARGE_PUMP_LOW 0x0 +# define CH7017_CHARGE_PUMP_HIGH 0x3 +# define CH7017_LVDS_CHANNEL_A (1 << 3) +# define CH7017_LVDS_CHANNEL_B (1 << 4) +# define CH7017_TV_DAC_A (1 << 5) +# define CH7017_TV_DAC_B (1 << 6) +# define CH7017_DDC_SELECT_DC2 (1 << 7) + +#define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74 +#define CH7017_LVDS_PLL_EMI_REDUCTION 0x75 +#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76 + +#define CH7017_LVDS_CONTROL_2 0x78 +# define CH7017_LOOP_FILTER_SHIFT 5 +# define CH7017_PHASE_DETECTOR_SHIFT 0 + +#define CH7017_BANG_LIMIT_CONTROL 0x7f + +struct ch7017_priv { + uint8_t save_hapi; + uint8_t save_vali; + uint8_t save_valo; + uint8_t save_ailo; + uint8_t save_lvds_pll_vco; + uint8_t save_feedback_div; + uint8_t save_lvds_control_2; + uint8_t save_outputs_enable; + uint8_t save_lvds_power_down; + uint8_t save_power_management; +}; + +static void ch7017_dump_regs(struct intel_dvo_device *dvo); +static void ch7017_dpms(struct intel_dvo_device *dvo, int mode); + +static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) +{ + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + u8 out_buf[2]; + u8 in_buf[2]; + + struct i2c_msg msgs[] = { + { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = i2cbus->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = in_buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = 0; + + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + *val= in_buf[0]; + return true; + }; + + return false; +} + +static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) +{ + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + uint8_t out_buf[2]; + struct i2c_msg msg = { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 2, + .buf = out_buf, + }; + + out_buf[0] = addr; + out_buf[1] = val; + + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + return true; + + return false; +} + +/** Probes for a CH7017 on the given bus and slave address. */ +static bool ch7017_init(struct intel_dvo_device *dvo, + struct intel_i2c_chan *i2cbus) +{ + struct ch7017_priv *priv; + uint8_t val; + + priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL); + if (priv == NULL) + return false; + + dvo->i2c_bus = i2cbus; + dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->dev_priv = priv; + + if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) + goto fail; + + if (val != CH7017_DEVICE_ID_VALUE && + val != CH7018_DEVICE_ID_VALUE && + val != CH7019_DEVICE_ID_VALUE) { + DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n", + val, i2cbus->adapter.name,i2cbus->slave_addr); + goto fail; + } + + return true; +fail: + kfree(priv); + return false; +} + +static enum drm_output_status ch7017_detect(struct intel_dvo_device *dvo) +{ + return output_status_unknown; +} + +static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + if (mode->clock > 160000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void ch7017_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; + uint8_t outputs_enable, lvds_control_2, lvds_power_down; + uint8_t horizontal_active_pixel_input; + uint8_t horizontal_active_pixel_output, vertical_active_line_output; + uint8_t active_input_line_output; + + DRM_DEBUG("Registers before mode setting\n"); + ch7017_dump_regs(dvo); + + /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ + if (mode->clock < 100000) { + outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; + lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | + (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_VCO_SHIFT) | + (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | + (0 << CH7017_PHASE_DETECTOR_SHIFT); + } else { + outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; + lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | + (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); + lvds_pll_feedback_div = 35; + lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | + (0 << CH7017_PHASE_DETECTOR_SHIFT); + if (1) { /* XXX: dual channel panel detection. Assume yes for now. */ + outputs_enable |= CH7017_LVDS_CHANNEL_B; + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (2 << CH7017_LVDS_PLL_VCO_SHIFT) | + (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + } else { + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | + (1 << CH7017_LVDS_PLL_VCO_SHIFT) | + (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); + } + } + + horizontal_active_pixel_input = mode->hdisplay & 0x00ff; + + vertical_active_line_output = mode->vdisplay & 0x00ff; + horizontal_active_pixel_output = mode->hdisplay & 0x00ff; + + active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) | + (((mode->vdisplay & 0x0700) >> 8) << 3); + + lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | + (mode->hdisplay & 0x0700) >> 8; + + ch7017_dpms(dvo, DPMSModeOff); + ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, + horizontal_active_pixel_input); + ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, + horizontal_active_pixel_output); + ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, + vertical_active_line_output); + ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, + active_input_line_output); + ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control); + ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div); + ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2); + ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable); + + /* Turn the LVDS back on with new settings. */ + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down); + + DRM_DEBUG("Registers after mode setting\n"); + ch7017_dump_regs(dvo); +} + +/* set the CH7017 power state */ +static void ch7017_dpms(struct intel_dvo_device *dvo, int mode) +{ + uint8_t val; + + ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); + + /* Turn off TV/VGA, and never turn it on since we don't support it. */ + ch7017_write(dvo, CH7017_POWER_MANAGEMENT, + CH7017_DAC0_POWER_DOWN | + CH7017_DAC1_POWER_DOWN | + CH7017_DAC2_POWER_DOWN | + CH7017_DAC3_POWER_DOWN | + CH7017_TV_POWER_DOWN_EN); + + if (mode == DPMSModeOn) { + /* Turn on the LVDS */ + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, + val & ~CH7017_LVDS_POWER_DOWN_EN); + } else { + /* Turn off the LVDS */ + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, + val | CH7017_LVDS_POWER_DOWN_EN); + } + + /* XXX: Should actually wait for update power status somehow */ + udelay(20000); +} + +static void ch7017_dump_regs(struct intel_dvo_device *dvo) +{ + uint8_t val; + +#define DUMP(reg) \ +do { \ + ch7017_read(dvo, reg, &val); \ + DRM_DEBUG(#reg ": %02x\n", val); \ +} while (0) + + DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); + DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); + DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); + DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); + DUMP(CH7017_LVDS_PLL_VCO_CONTROL); + DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); + DUMP(CH7017_LVDS_CONTROL_2); + DUMP(CH7017_OUTPUTS_ENABLE); + DUMP(CH7017_LVDS_POWER_DOWN); +} + +static void ch7017_save(struct intel_dvo_device *dvo) +{ + struct ch7017_priv *priv = dvo->dev_priv; + + ch7017_read(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi); + ch7017_read(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo); + ch7017_read(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, &priv->save_ailo); + ch7017_read(dvo, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco); + ch7017_read(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div); + ch7017_read(dvo, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2); + ch7017_read(dvo, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable); + ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down); + ch7017_read(dvo, CH7017_POWER_MANAGEMENT, &priv->save_power_management); +} + +static void ch7017_restore(struct intel_dvo_device *dvo) +{ + struct ch7017_priv *priv = dvo->dev_priv; + + /* Power down before changing mode */ + ch7017_dpms(dvo, DPMSModeOff); + + ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi); + ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo); + ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, priv->save_ailo); + ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco); + ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div); + ch7017_write(dvo, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2); + ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable); + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down); + ch7017_write(dvo, CH7017_POWER_MANAGEMENT, priv->save_power_management); +} + +static void ch7017_destroy(struct intel_dvo_device *dvo) +{ + struct ch7017_priv *priv = dvo->dev_priv; + + if (priv) { + kfree(priv); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops ch7017_ops = { + .init = ch7017_init, + .detect = ch7017_detect, + .mode_valid = ch7017_mode_valid, + .mode_set = ch7017_mode_set, + .dpms = ch7017_dpms, + .dump_regs = ch7017_dump_regs, + .save = ch7017_save, + .restore = ch7017_restore, + .destroy = ch7017_destroy, +}; diff --git a/linux-core/dvo_ch7xxx.c b/linux-core/dvo_ch7xxx.c new file mode 100644 index 00000000..69827a7d --- /dev/null +++ b/linux-core/dvo_ch7xxx.c @@ -0,0 +1,368 @@ +/************************************************************************** + +Copyright © 2006 Dave Airlie + +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 AUTHOR BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#include "dvo.h" + +#define CH7xxx_REG_VID 0x4a +#define CH7xxx_REG_DID 0x4b + +#define CH7011_VID 0x83 /* 7010 as well */ +#define CH7009A_VID 0x84 +#define CH7009B_VID 0x85 +#define CH7301_VID 0x95 + +#define CH7xxx_VID 0x84 +#define CH7xxx_DID 0x17 + +#define CH7xxx_NUM_REGS 0x4c + +#define CH7xxx_CM 0x1c +#define CH7xxx_CM_XCM (1<<0) +#define CH7xxx_CM_MCP (1<<2) +#define CH7xxx_INPUT_CLOCK 0x1d +#define CH7xxx_GPIO 0x1e +#define CH7xxx_GPIO_HPIR (1<<3) +#define CH7xxx_IDF 0x1f + +#define CH7xxx_IDF_HSP (1<<3) +#define CH7xxx_IDF_VSP (1<<4) + +#define CH7xxx_CONNECTION_DETECT 0x20 +#define CH7xxx_CDET_DVI (1<<5) + +#define CH7301_DAC_CNTL 0x21 +#define CH7301_HOTPLUG 0x23 +#define CH7xxx_TCTL 0x31 +#define CH7xxx_TVCO 0x32 +#define CH7xxx_TPCP 0x33 +#define CH7xxx_TPD 0x34 +#define CH7xxx_TPVT 0x35 +#define CH7xxx_TLPF 0x36 +#define CH7xxx_TCT 0x37 +#define CH7301_TEST_PATTERN 0x48 + +#define CH7xxx_PM 0x49 +#define CH7xxx_PM_FPD (1<<0) +#define CH7301_PM_DACPD0 (1<<1) +#define CH7301_PM_DACPD1 (1<<2) +#define CH7301_PM_DACPD2 (1<<3) +#define CH7xxx_PM_DVIL (1<<6) +#define CH7xxx_PM_DVIP (1<<7) + +#define CH7301_SYNC_POLARITY 0x56 +#define CH7301_SYNC_RGB_YUV (1<<0) +#define CH7301_SYNC_POL_DVI (1<<5) + +/** @file + * driver for the Chrontel 7xxx DVI chip over DVO. + */ + +static struct ch7xxx_id_struct { + uint8_t vid; + char *name; +} ch7xxx_ids[] = { + { CH7011_VID, "CH7011" }, + { CH7009A_VID, "CH7009A" }, + { CH7009B_VID, "CH7009B" }, + { CH7301_VID, "CH7301" }, +}; + +struct ch7xxx_reg_state { + uint8_t regs[CH7xxx_NUM_REGS]; +}; + +struct ch7xxx_priv { + bool quiet; + + struct ch7xxx_reg_state save_reg; + struct ch7xxx_reg_state mode_reg; + uint8_t save_TCTL, save_TPCP, save_TPD, save_TPVT; + uint8_t save_TLPF, save_TCT, save_PM, save_IDF; +}; + +static void ch7xxx_save(struct intel_dvo_device *dvo); + +static char *ch7xxx_get_id(uint8_t vid) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) { + if (ch7xxx_ids[i].vid == vid) + return ch7xxx_ids[i].name; + } + + return NULL; +} + +/** Reads an 8 bit register */ +static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) +{ + struct ch7xxx_priv *ch7xxx= dvo->dev_priv; + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + u8 out_buf[2]; + u8 in_buf[2]; + + struct i2c_msg msgs[] = { + { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = i2cbus->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = in_buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = 0; + + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + *ch = in_buf[0]; + return true; + }; + + if (!ch7xxx->quiet) { + DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", + addr, i2cbus->adapter.name, i2cbus->slave_addr); + } + return false; +} + +/** Writes an 8 bit register */ +static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +{ + struct ch7xxx_priv *ch7xxx = dvo->dev_priv; + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + uint8_t out_buf[2]; + struct i2c_msg msg = { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 2, + .buf = out_buf, + }; + + out_buf[0] = addr; + out_buf[1] = ch; + + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + return true; + + if (!ch7xxx->quiet) { + DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", + addr, i2cbus->adapter.name, i2cbus->slave_addr); + } + + return false; +} + +static bool ch7xxx_init(struct intel_dvo_device *dvo, + struct intel_i2c_chan *i2cbus) +{ + /* this will detect the CH7xxx chip on the specified i2c bus */ + struct ch7xxx_priv *ch7xxx; + uint8_t vendor, device; + char *name; + + ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL); + if (ch7xxx == NULL) + return false; + + dvo->i2c_bus = i2cbus; + dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->dev_priv = ch7xxx; + ch7xxx->quiet = true; + + if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor)) + goto out; + + name = ch7xxx_get_id(vendor); + if (!name) { + DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n", + vendor, i2cbus->adapter.name, i2cbus->slave_addr); + goto out; + } + + + if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device)) + goto out; + + if (device != CH7xxx_DID) { + DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n", + vendor, i2cbus->adapter.name, i2cbus->slave_addr); + goto out; + } + + ch7xxx->quiet = FALSE; + DRM_DEBUG("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n", + name, vendor, device); + return true; +out: + kfree(ch7xxx); + return false; +} + +static enum drm_output_status ch7xxx_detect(struct intel_dvo_device *dvo) +{ + uint8_t cdet, orig_pm, pm; + + ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm); + + pm = orig_pm; + pm &= ~CH7xxx_PM_FPD; + pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP; + + ch7xxx_writeb(dvo, CH7xxx_PM, pm); + + ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet); + + ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm); + + if (cdet & CH7xxx_CDET_DVI) + return output_status_connected; + return output_status_disconnected; +} + +static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void ch7xxx_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + uint8_t tvco, tpcp, tpd, tlpf, idf; + + if (mode->clock <= 65000) { + tvco = 0x23; + tpcp = 0x08; + tpd = 0x16; + tlpf = 0x60; + } else { + tvco = 0x2d; + tpcp = 0x06; + tpd = 0x26; + tlpf = 0xa0; + } + + ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00); + ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco); + ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp); + ch7xxx_writeb(dvo, CH7xxx_TPD, tpd); + ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30); + ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf); + ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00); + + ch7xxx_readb(dvo, CH7xxx_IDF, &idf); + + idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP); + if (mode->flags & V_PHSYNC) + idf |= CH7xxx_IDF_HSP; + + if (mode->flags & V_PVSYNC) + idf |= CH7xxx_IDF_HSP; + + ch7xxx_writeb(dvo, CH7xxx_IDF, idf); +} + +/* set the CH7xxx power state */ +static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode) +{ + if (mode == DPMSModeOn) + ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP); + else + ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD); +} + +static void ch7xxx_dump_regs(struct intel_dvo_device *dvo) +{ + struct ch7xxx_priv *ch7xxx = dvo->dev_priv; + int i; + + for (i = 0; i < CH7xxx_NUM_REGS; i++) { + if ((i % 8) == 0 ) + DRM_DEBUG("\n %02X: ", i); + DRM_DEBUG("%02X ", ch7xxx->mode_reg.regs[i]); + } +} + +static void ch7xxx_save(struct intel_dvo_device *dvo) +{ + struct ch7xxx_priv *ch7xxx= dvo->dev_priv; + + ch7xxx_readb(dvo, CH7xxx_TCTL, &ch7xxx->save_TCTL); + ch7xxx_readb(dvo, CH7xxx_TPCP, &ch7xxx->save_TPCP); + ch7xxx_readb(dvo, CH7xxx_TPD, &ch7xxx->save_TPD); + ch7xxx_readb(dvo, CH7xxx_TPVT, &ch7xxx->save_TPVT); + ch7xxx_readb(dvo, CH7xxx_TLPF, &ch7xxx->save_TLPF); + ch7xxx_readb(dvo, CH7xxx_PM, &ch7xxx->save_PM); + ch7xxx_readb(dvo, CH7xxx_IDF, &ch7xxx->save_IDF); +} + +static void ch7xxx_restore(struct intel_dvo_device *dvo) +{ + struct ch7xxx_priv *ch7xxx = dvo->dev_priv; + + ch7xxx_writeb(dvo, CH7xxx_TCTL, ch7xxx->save_TCTL); + ch7xxx_writeb(dvo, CH7xxx_TPCP, ch7xxx->save_TPCP); + ch7xxx_writeb(dvo, CH7xxx_TPD, ch7xxx->save_TPD); + ch7xxx_writeb(dvo, CH7xxx_TPVT, ch7xxx->save_TPVT); + ch7xxx_writeb(dvo, CH7xxx_TLPF, ch7xxx->save_TLPF); + ch7xxx_writeb(dvo, CH7xxx_IDF, ch7xxx->save_IDF); + ch7xxx_writeb(dvo, CH7xxx_PM, ch7xxx->save_PM); +} + +static void ch7xxx_destroy(struct intel_dvo_device *dvo) +{ + struct ch7xxx_priv *ch7xxx = dvo->dev_priv; + + if (ch7xxx) { + kfree(ch7xxx); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops ch7xxx_ops = { + .init = ch7xxx_init, + .detect = ch7xxx_detect, + .mode_valid = ch7xxx_mode_valid, + .mode_set = ch7xxx_mode_set, + .dpms = ch7xxx_dpms, + .dump_regs = ch7xxx_dump_regs, + .save = ch7xxx_save, + .restore = ch7xxx_restore, + .destroy = ch7xxx_destroy, +}; diff --git a/linux-core/dvo_ivch.c b/linux-core/dvo_ivch.c new file mode 100644 index 00000000..5fce2462 --- /dev/null +++ b/linux-core/dvo_ivch.c @@ -0,0 +1,459 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include "dvo.h" + +/* + * register definitions for the i82807aa. + * + * Documentation on this chipset can be found in datasheet #29069001 at + * intel.com. + */ + +/* + * VCH Revision & GMBus Base Addr + */ +#define VR00 0x00 +# define VR00_BASE_ADDRESS_MASK 0x007f + +/* + * Functionality Enable + */ +#define VR01 0x01 + +/* + * Enable the panel fitter + */ +# define VR01_PANEL_FIT_ENABLE (1 << 3) +/* + * Enables the LCD display. + * + * This must not be set while VR01_DVO_BYPASS_ENABLE is set. + */ +# define VR01_LCD_ENABLE (1 << 2) +/** Enables the DVO repeater. */ +# define VR01_DVO_BYPASS_ENABLE (1 << 1) +/** Enables the DVO clock */ +# define VR01_DVO_ENABLE (1 << 0) + +/* + * LCD Interface Format + */ +#define VR10 0x10 +/** Enables LVDS output instead of CMOS */ +# define VR10_LVDS_ENABLE (1 << 4) +/** Enables 18-bit LVDS output. */ +# define VR10_INTERFACE_1X18 (0 << 2) +/** Enables 24-bit LVDS or CMOS output */ +# define VR10_INTERFACE_1X24 (1 << 2) +/** Enables 2x18-bit LVDS or CMOS output. */ +# define VR10_INTERFACE_2X18 (2 << 2) +/** Enables 2x24-bit LVDS output */ +# define VR10_INTERFACE_2X24 (3 << 2) + +/* + * VR20 LCD Horizontal Display Size + */ +#define VR20 0x20 + +/* + * LCD Vertical Display Size + */ +#define VR21 0x20 + +/* + * Panel power down status + */ +#define VR30 0x30 +/** Read only bit indicating that the panel is not in a safe poweroff state. */ +# define VR30_PANEL_ON (1 << 15) + +#define VR40 0x40 +# define VR40_STALL_ENABLE (1 << 13) +# define VR40_VERTICAL_INTERP_ENABLE (1 << 12) +# define VR40_ENHANCED_PANEL_FITTING (1 << 11) +# define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10) +# define VR40_AUTO_RATIO_ENABLE (1 << 9) +# define VR40_CLOCK_GATING_ENABLE (1 << 8) + +/* + * Panel Fitting Vertical Ratio + * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2 + */ +#define VR41 0x41 + +/* + * Panel Fitting Horizontal Ratio + * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2 + */ +#define VR42 0x42 + +/* + * Horizontal Image Size + */ +#define VR43 0x43 + +/* VR80 GPIO 0 + */ +#define VR80 0x80 +#define VR81 0x81 +#define VR82 0x82 +#define VR83 0x83 +#define VR84 0x84 +#define VR85 0x85 +#define VR86 0x86 +#define VR87 0x87 + +/* VR88 GPIO 8 + */ +#define VR88 0x88 + +/* Graphics BIOS scratch 0 + */ +#define VR8E 0x8E +# define VR8E_PANEL_TYPE_MASK (0xf << 0) +# define VR8E_PANEL_INTERFACE_CMOS (0 << 4) +# define VR8E_PANEL_INTERFACE_LVDS (1 << 4) +# define VR8E_FORCE_DEFAULT_PANEL (1 << 5) + +/* Graphics BIOS scratch 1 + */ +#define VR8F 0x8F +# define VR8F_VCH_PRESENT (1 << 0) +# define VR8F_DISPLAY_CONN (1 << 1) +# define VR8F_POWER_MASK (0x3c) +# define VR8F_POWER_POS (2) + + +struct ivch_priv { + bool quiet; + + uint16_t width, height; + + uint16_t save_VR01; + uint16_t save_VR40; +}; + +#if 0 +struct vch_capabilities { + struct aimdb_block aimdb_block; + uint8_t panel_type; + uint8_t set_panel_type; + uint8_t slave_address; + uint8_t capabilities; +#define VCH_PANEL_FITTING_SUPPORT (0x3 << 0) +#define VCH_PANEL_FITTING_TEXT (1 << 2) +#define VCH_PANEL_FITTING_GRAPHICS (1 << 3) +#define VCH_PANEL_FITTING_RATIO (1 << 4) +#define VCH_DITHERING (1 << 5) + uint8_t backlight_gpio; + uint8_t set_panel_type_us_gpios; +} __attribute__ ((packed)); +#endif + +static void ivch_dump_regs(struct intel_dvo_device *dvo); + +/** + * Reads a register on the ivch. + * + * Each of the 256 registers are 16 bits long. + */ +static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) +{ + struct ivch_priv *priv = dvo->dev_priv; + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + u8 out_buf[2]; + u8 in_buf[2]; + + struct i2c_msg msgs[] = { + { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = i2cbus->slave_addr, + .flags = I2C_M_RD, + .len = 2, + .buf = in_buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = 0; + + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + *data = (in_buf[1] << 8) | in_buf[0]; + return true; + }; + + if (!priv->quiet) { + DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", + addr, i2cbus->adapter.name, i2cbus->slave_addr); + } + return false; +} + +/** Writes a 16-bit register on the ivch */ +static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) +{ + struct ivch_priv *priv = dvo->dev_priv; + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + u8 out_buf[3]; + struct i2c_msg msg = { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 3, + .buf = out_buf, + }; + + out_buf[0] = addr; + out_buf[1] = data & 0xff; + out_buf[2] = data >> 8; + + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + return true; + + if (!priv->quiet) { + DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", + addr, i2cbus->adapter.name, i2cbus->slave_addr); + } + + return false; +} + +/** Probes the given bus and slave address for an ivch */ +static bool ivch_init(struct intel_dvo_device *dvo, + struct intel_i2c_chan *i2cbus) +{ + struct ivch_priv *priv; + uint16_t temp; + + priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); + if (priv == NULL) + return false; + + dvo->i2c_bus = i2cbus; + dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->dev_priv = priv; + priv->quiet = TRUE; + + if (!ivch_read(dvo, VR00, &temp)) + goto out; + priv->quiet = false; + + /* Since the identification bits are probably zeroes, which doesn't seem + * very unique, check that the value in the base address field matches + * the address it's responding on. + */ + if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) { + DRM_DEBUG("ivch detect failed due to address mismatch " + "(%d vs %d)\n", + (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr); + goto out; + } + +#if 0 + if (!xf86I2CDevInit(&priv->d)) { + goto out; + } +#endif + ivch_read(dvo, VR20, &priv->width); + ivch_read(dvo, VR21, &priv->height); + + return true; + +out: + kfree(priv); + return false; +} + +static enum drm_output_status ivch_detect(struct intel_dvo_device *dvo) +{ + return output_status_connected; +} + +static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + if (mode->clock > 112000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +/** Sets the power state of the panel connected to the ivch */ +static void ivch_dpms(struct intel_dvo_device *dvo, int mode) +{ + int i; + uint16_t vr01, vr30, backlight; + + /* Set the new power state of the panel. */ + if (!ivch_read(dvo, VR01, &vr01)) + return; + + if (mode == DPMSModeOn) + backlight = 1; + else + backlight = 0; + ivch_write(dvo, VR80, backlight); + + if (mode == DPMSModeOn) + vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; + else + vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); + + ivch_write(dvo, VR01, vr01); + + /* Wait for the panel to make its state transition */ + for (i = 0; i < 100; i++) { + if (!ivch_read(dvo, VR30, &vr30)) + break; + + if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DPMSModeOn)) + break; + udelay(1000); + } + /* wait some more; vch may fail to resync sometimes without this */ + udelay(16 * 1000); +} + +static void ivch_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + uint16_t vr40 = 0; + uint16_t vr01; + + vr01 = 0; + vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | + VR40_HORIZONTAL_INTERP_ENABLE); + + if (mode->hdisplay != adjusted_mode->hdisplay || + mode->vdisplay != adjusted_mode->vdisplay) { + uint16_t x_ratio, y_ratio; + + vr01 |= VR01_PANEL_FIT_ENABLE; + vr40 |= VR40_CLOCK_GATING_ENABLE; + x_ratio = (((mode->hdisplay - 1) << 16) / + (adjusted_mode->hdisplay - 1)) >> 2; + y_ratio = (((mode->vdisplay - 1) << 16) / + (adjusted_mode->vdisplay - 1)) >> 2; + ivch_write (dvo, VR42, x_ratio); + ivch_write (dvo, VR41, y_ratio); + } else { + vr01 &= ~VR01_PANEL_FIT_ENABLE; + vr40 &= ~VR40_CLOCK_GATING_ENABLE; + } + vr40 &= ~VR40_AUTO_RATIO_ENABLE; + + ivch_write(dvo, VR01, vr01); + ivch_write(dvo, VR40, vr40); + + ivch_dump_regs(dvo); +} + +static void ivch_dump_regs(struct intel_dvo_device *dvo) +{ + uint16_t val; + + ivch_read(dvo, VR00, &val); + DRM_DEBUG("VR00: 0x%04x\n", val); + ivch_read(dvo, VR01, &val); + DRM_DEBUG("VR01: 0x%04x\n", val); + ivch_read(dvo, VR30, &val); + DRM_DEBUG("VR30: 0x%04x\n", val); + ivch_read(dvo, VR40, &val); + DRM_DEBUG("VR40: 0x%04x\n", val); + + /* GPIO registers */ + ivch_read(dvo, VR80, &val); + DRM_DEBUG("VR80: 0x%04x\n", val); + ivch_read(dvo, VR81, &val); + DRM_DEBUG("VR81: 0x%04x\n", val); + ivch_read(dvo, VR82, &val); + DRM_DEBUG("VR82: 0x%04x\n", val); + ivch_read(dvo, VR83, &val); + DRM_DEBUG("VR83: 0x%04x\n", val); + ivch_read(dvo, VR84, &val); + DRM_DEBUG("VR84: 0x%04x\n", val); + ivch_read(dvo, VR85, &val); + DRM_DEBUG("VR85: 0x%04x\n", val); + ivch_read(dvo, VR86, &val); + DRM_DEBUG("VR86: 0x%04x\n", val); + ivch_read(dvo, VR87, &val); + DRM_DEBUG("VR87: 0x%04x\n", val); + ivch_read(dvo, VR88, &val); + DRM_DEBUG("VR88: 0x%04x\n", val); + + /* Scratch register 0 - AIM Panel type */ + ivch_read(dvo, VR8E, &val); + DRM_DEBUG("VR8E: 0x%04x\n", val); + + /* Scratch register 1 - Status register */ + ivch_read(dvo, VR8F, &val); + DRM_DEBUG("VR8F: 0x%04x\n", val); +} + +static void ivch_save(struct intel_dvo_device *dvo) +{ + struct ivch_priv *priv = dvo->dev_priv; + + ivch_read(dvo, VR01, &priv->save_VR01); + ivch_read(dvo, VR40, &priv->save_VR40); +} + +static void ivch_restore(struct intel_dvo_device *dvo) +{ + struct ivch_priv *priv = dvo->dev_priv; + + ivch_write(dvo, VR01, priv->save_VR01); + ivch_write(dvo, VR40, priv->save_VR40); +} + +static void ivch_destroy(struct intel_dvo_device *dvo) +{ + struct ivch_priv *priv = dvo->dev_priv; + + if (priv) { + kfree(priv); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops ivch_ops= { + .init = ivch_init, + .dpms = ivch_dpms, + .save = ivch_save, + .restore = ivch_restore, + .mode_valid = ivch_mode_valid, + .mode_set = ivch_mode_set, + .detect = ivch_detect, + .dump_regs = ivch_dump_regs, + .destroy = ivch_destroy, +}; diff --git a/linux-core/dvo_sil164.c b/linux-core/dvo_sil164.c new file mode 100644 index 00000000..0cee59b1 --- /dev/null +++ b/linux-core/dvo_sil164.c @@ -0,0 +1,302 @@ +/************************************************************************** + +Copyright © 2006 Dave Airlie + +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 AUTHOR BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#include "dvo.h" + +#define SIL164_VID 0x0001 +#define SIL164_DID 0x0006 + +#define SIL164_VID_LO 0x00 +#define SIL164_VID_HI 0x01 +#define SIL164_DID_LO 0x02 +#define SIL164_DID_HI 0x03 +#define SIL164_REV 0x04 +#define SIL164_RSVD 0x05 +#define SIL164_FREQ_LO 0x06 +#define SIL164_FREQ_HI 0x07 + +#define SIL164_REG8 0x08 +#define SIL164_8_VEN (1<<5) +#define SIL164_8_HEN (1<<4) +#define SIL164_8_DSEL (1<<3) +#define SIL164_8_BSEL (1<<2) +#define SIL164_8_EDGE (1<<1) +#define SIL164_8_PD (1<<0) + +#define SIL164_REG9 0x09 +#define SIL164_9_VLOW (1<<7) +#define SIL164_9_MSEL_MASK (0x7<<4) +#define SIL164_9_TSEL (1<<3) +#define SIL164_9_RSEN (1<<2) +#define SIL164_9_HTPLG (1<<1) +#define SIL164_9_MDI (1<<0) + +#define SIL164_REGC 0x0c + +struct sil164_save_rec { + uint8_t reg8; + uint8_t reg9; + uint8_t regc; +}; + +struct sil164_priv { + //I2CDevRec d; + bool quiet; + struct sil164_save_rec save_regs; + struct sil164_save_rec mode_regs; +}; + +#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr)) + +static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) +{ + struct sil164_priv *sil = dvo->dev_priv; + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + u8 out_buf[2]; + u8 in_buf[2]; + + struct i2c_msg msgs[] = { + { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = i2cbus->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = in_buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = 0; + + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + *ch = in_buf[0]; + return true; + }; + + if (!sil->quiet) { + DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", + addr, i2cbus->adapter.name, i2cbus->slave_addr); + } + return false; +} + +static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +{ + struct sil164_priv *sil= dvo->dev_priv; + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + uint8_t out_buf[2]; + struct i2c_msg msg = { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 2, + .buf = out_buf, + }; + + out_buf[0] = addr; + out_buf[1] = ch; + + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + return true; + + if (!sil->quiet) { + DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", + addr, i2cbus->adapter.name, i2cbus->slave_addr); + } + + return false; +} + +/* Silicon Image 164 driver for chip on i2c bus */ +static bool sil164_init(struct intel_dvo_device *dvo, + struct intel_i2c_chan *i2cbus) +{ + /* this will detect the SIL164 chip on the specified i2c bus */ + struct sil164_priv *sil; + unsigned char ch; + + sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL); + if (sil == NULL) + return false; + + dvo->i2c_bus = i2cbus; + dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->dev_priv = sil; + sil->quiet = true; + + if (!sil164_readb(dvo, SIL164_VID_LO, &ch)) + goto out; + + if (ch != (SIL164_VID & 0xff)) { + DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n", + ch, i2cbus->adapter.name, i2cbus->slave_addr); + goto out; + } + + if (!sil164_readb(dvo, SIL164_DID_LO, &ch)) + goto out; + + if (ch != (SIL164_DID & 0xff)) { + DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n", + ch, i2cbus->adapter.name, i2cbus->slave_addr); + goto out; + } + sil->quiet = false; + + DRM_DEBUG("init sil164 dvo controller successfully!\n"); + return true; + +out: + kfree(sil); + return false; +} + +static enum drm_output_status sil164_detect(struct intel_dvo_device *dvo) +{ + uint8_t reg9; + + sil164_readb(dvo, SIL164_REG9, ®9); + + if (reg9 & SIL164_9_HTPLG) + return output_status_connected; + else + return output_status_disconnected; +} + +static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static void sil164_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* As long as the basics are set up, since we don't have clock + * dependencies in the mode setup, we can just leave the + * registers alone and everything will work fine. + */ + /* recommended programming sequence from doc */ + /*sil164_writeb(sil, 0x08, 0x30); + sil164_writeb(sil, 0x09, 0x00); + sil164_writeb(sil, 0x0a, 0x90); + sil164_writeb(sil, 0x0c, 0x89); + sil164_writeb(sil, 0x08, 0x31);*/ + /* don't do much */ + return; +} + +/* set the SIL164 power state */ +static void sil164_dpms(struct intel_dvo_device *dvo, int mode) +{ + int ret; + unsigned char ch; + + ret = sil164_readb(dvo, SIL164_REG8, &ch); + if (ret == false) + return; + + if (mode == DPMSModeOn) + ch |= SIL164_8_PD; + else + ch &= ~SIL164_8_PD; + + sil164_writeb(dvo, SIL164_REG8, ch); + return; +} + +static void sil164_dump_regs(struct intel_dvo_device *dvo) +{ + uint8_t val; + + sil164_readb(dvo, SIL164_FREQ_LO, &val); + DRM_DEBUG("SIL164_FREQ_LO: 0x%02x\n", val); + sil164_readb(dvo, SIL164_FREQ_HI, &val); + DRM_DEBUG("SIL164_FREQ_HI: 0x%02x\n", val); + sil164_readb(dvo, SIL164_REG8, &val); + DRM_DEBUG("SIL164_REG8: 0x%02x\n", val); + sil164_readb(dvo, SIL164_REG9, &val); + DRM_DEBUG("SIL164_REG9: 0x%02x\n", val); + sil164_readb(dvo, SIL164_REGC, &val); + DRM_DEBUG("SIL164_REGC: 0x%02x\n", val); +} + +static void sil164_save(struct intel_dvo_device *dvo) +{ + struct sil164_priv *sil= dvo->dev_priv; + + if (!sil164_readb(dvo, SIL164_REG8, &sil->save_regs.reg8)) + return; + + if (!sil164_readb(dvo, SIL164_REG9, &sil->save_regs.reg9)) + return; + + if (!sil164_readb(dvo, SIL164_REGC, &sil->save_regs.regc)) + return; + + return; +} + +static void sil164_restore(struct intel_dvo_device *dvo) +{ + struct sil164_priv *sil = dvo->dev_priv; + + /* Restore it powered down initially */ + sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8 & ~0x1); + + sil164_writeb(dvo, SIL164_REG9, sil->save_regs.reg9); + sil164_writeb(dvo, SIL164_REGC, sil->save_regs.regc); + sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8); +} + +static void sil164_destroy(struct intel_dvo_device *dvo) +{ + struct sil164_priv *sil = dvo->dev_priv; + + if (sil) { + kfree(sil); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops sil164_ops = { + .init = sil164_init, + .detect = sil164_detect, + .mode_valid = sil164_mode_valid, + .mode_set = sil164_mode_set, + .dpms = sil164_dpms, + .dump_regs = sil164_dump_regs, + .save = sil164_save, + .restore = sil164_restore, + .destroy = sil164_destroy, +}; diff --git a/linux-core/dvo_tfp410.c b/linux-core/dvo_tfp410.c new file mode 100644 index 00000000..64448509 --- /dev/null +++ b/linux-core/dvo_tfp410.c @@ -0,0 +1,335 @@ +/* + * Copyright © 2007 Dave Mueller + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Dave Mueller + * + */ + +#include "dvo.h" + +/* register definitions according to the TFP410 data sheet */ +#define TFP410_VID 0x014C +#define TFP410_DID 0x0410 + +#define TFP410_VID_LO 0x00 +#define TFP410_VID_HI 0x01 +#define TFP410_DID_LO 0x02 +#define TFP410_DID_HI 0x03 +#define TFP410_REV 0x04 + +#define TFP410_CTL_1 0x08 +#define TFP410_CTL_1_TDIS (1<<6) +#define TFP410_CTL_1_VEN (1<<5) +#define TFP410_CTL_1_HEN (1<<4) +#define TFP410_CTL_1_DSEL (1<<3) +#define TFP410_CTL_1_BSEL (1<<2) +#define TFP410_CTL_1_EDGE (1<<1) +#define TFP410_CTL_1_PD (1<<0) + +#define TFP410_CTL_2 0x09 +#define TFP410_CTL_2_VLOW (1<<7) +#define TFP410_CTL_2_MSEL_MASK (0x7<<4) +#define TFP410_CTL_2_MSEL (1<<4) +#define TFP410_CTL_2_TSEL (1<<3) +#define TFP410_CTL_2_RSEN (1<<2) +#define TFP410_CTL_2_HTPLG (1<<1) +#define TFP410_CTL_2_MDI (1<<0) + +#define TFP410_CTL_3 0x0A +#define TFP410_CTL_3_DK_MASK (0x7<<5) +#define TFP410_CTL_3_DK (1<<5) +#define TFP410_CTL_3_DKEN (1<<4) +#define TFP410_CTL_3_CTL_MASK (0x7<<1) +#define TFP410_CTL_3_CTL (1<<1) + +#define TFP410_USERCFG 0x0B + +#define TFP410_DE_DLY 0x32 + +#define TFP410_DE_CTL 0x33 +#define TFP410_DE_CTL_DEGEN (1<<6) +#define TFP410_DE_CTL_VSPOL (1<<5) +#define TFP410_DE_CTL_HSPOL (1<<4) +#define TFP410_DE_CTL_DEDLY8 (1<<0) + +#define TFP410_DE_TOP 0x34 + +#define TFP410_DE_CNT_LO 0x36 +#define TFP410_DE_CNT_HI 0x37 + +#define TFP410_DE_LIN_LO 0x38 +#define TFP410_DE_LIN_HI 0x39 + +#define TFP410_H_RES_LO 0x3A +#define TFP410_H_RES_HI 0x3B + +#define TFP410_V_RES_LO 0x3C +#define TFP410_V_RES_HI 0x3D + +struct tfp410_save_rec { + uint8_t ctl1; + uint8_t ctl2; +}; + +struct tfp410_priv { + bool quiet; + + struct tfp410_save_rec saved_reg; + struct tfp410_save_rec mode_reg; +}; + +static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) +{ + struct tfp410_priv *tfp = dvo->dev_priv; + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + u8 out_buf[2]; + u8 in_buf[2]; + + struct i2c_msg msgs[] = { + { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = i2cbus->slave_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = in_buf, + } + }; + + out_buf[0] = addr; + out_buf[1] = 0; + + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + *ch = in_buf[0]; + return true; + }; + + if (!tfp->quiet) { + DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", + addr, i2cbus->adapter.name, i2cbus->slave_addr); + } + return false; +} + +static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) +{ + struct tfp410_priv *tfp = dvo->dev_priv; + struct intel_i2c_chan *i2cbus = dvo->i2c_bus; + uint8_t out_buf[2]; + struct i2c_msg msg = { + .addr = i2cbus->slave_addr, + .flags = 0, + .len = 2, + .buf = out_buf, + }; + + out_buf[0] = addr; + out_buf[1] = ch; + + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) + return true; + + if (!tfp->quiet) { + DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", + addr, i2cbus->adapter.name, i2cbus->slave_addr); + } + + return false; +} + +static int tfp410_getid(struct intel_dvo_device *dvo, int addr) +{ + uint8_t ch1, ch2; + + if (tfp410_readb(dvo, addr+0, &ch1) && + tfp410_readb(dvo, addr+1, &ch2)) + return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF); + + return -1; +} + +/* Ti TFP410 driver for chip on i2c bus */ +static bool tfp410_init(struct intel_dvo_device *dvo, + struct intel_i2c_chan *i2cbus) +{ + /* this will detect the tfp410 chip on the specified i2c bus */ + struct tfp410_priv *tfp; + int id; + + tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL); + if (tfp == NULL) + return false; + + dvo->i2c_bus = i2cbus; + dvo->i2c_bus->slave_addr = dvo->slave_addr; + dvo->dev_priv = tfp; + tfp->quiet = TRUE; + + if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) { + DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n", + id, i2cbus->adapter.name, i2cbus->slave_addr); + goto out; + } + + if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) { + DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n", + id, i2cbus->adapter.name, i2cbus->slave_addr); + goto out; + } + tfp->quiet = FALSE; + return true; +out: + kfree(tfp); + return false; +} + +static enum drm_output_status tfp410_detect(struct intel_dvo_device *dvo) +{ + enum drm_output_status ret = output_status_disconnected; + uint8_t ctl2; + + if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) { + if (ctl2 & TFP410_CTL_2_HTPLG) + ret = output_status_connected; + else + ret = output_status_disconnected; + } + + return ret; +} + +static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static void tfp410_mode_set(struct intel_dvo_device *dvo, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* As long as the basics are set up, since we don't have clock dependencies + * in the mode setup, we can just leave the registers alone and everything + * will work fine. + */ + /* don't do much */ + return; +} + +/* set the tfp410 power state */ +static void tfp410_dpms(struct intel_dvo_device *dvo, int mode) +{ + uint8_t ctl1; + + if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1)) + return; + + if (mode == DPMSModeOn) + ctl1 |= TFP410_CTL_1_PD; + else + ctl1 &= ~TFP410_CTL_1_PD; + + tfp410_writeb(dvo, TFP410_CTL_1, ctl1); +} + +static void tfp410_dump_regs(struct intel_dvo_device *dvo) +{ + uint8_t val, val2; + + tfp410_readb(dvo, TFP410_REV, &val); + DRM_DEBUG("TFP410_REV: 0x%02X\n", val); + tfp410_readb(dvo, TFP410_CTL_1, &val); + DRM_DEBUG("TFP410_CTL1: 0x%02X\n", val); + tfp410_readb(dvo, TFP410_CTL_2, &val); + DRM_DEBUG("TFP410_CTL2: 0x%02X\n", val); + tfp410_readb(dvo, TFP410_CTL_3, &val); + DRM_DEBUG("TFP410_CTL3: 0x%02X\n", val); + tfp410_readb(dvo, TFP410_USERCFG, &val); + DRM_DEBUG("TFP410_USERCFG: 0x%02X\n", val); + tfp410_readb(dvo, TFP410_DE_DLY, &val); + DRM_DEBUG("TFP410_DE_DLY: 0x%02X\n", val); + tfp410_readb(dvo, TFP410_DE_CTL, &val); + DRM_DEBUG("TFP410_DE_CTL: 0x%02X\n", val); + tfp410_readb(dvo, TFP410_DE_TOP, &val); + DRM_DEBUG("TFP410_DE_TOP: 0x%02X\n", val); + tfp410_readb(dvo, TFP410_DE_CNT_LO, &val); + tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2); + DRM_DEBUG("TFP410_DE_CNT: 0x%02X%02X\n", val2, val); + tfp410_readb(dvo, TFP410_DE_LIN_LO, &val); + tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2); + DRM_DEBUG("TFP410_DE_LIN: 0x%02X%02X\n", val2, val); + tfp410_readb(dvo, TFP410_H_RES_LO, &val); + tfp410_readb(dvo, TFP410_H_RES_HI, &val2); + DRM_DEBUG("TFP410_H_RES: 0x%02X%02X\n", val2, val); + tfp410_readb(dvo, TFP410_V_RES_LO, &val); + tfp410_readb(dvo, TFP410_V_RES_HI, &val2); + DRM_DEBUG("TFP410_V_RES: 0x%02X%02X\n", val2, val); +} + +static void tfp410_save(struct intel_dvo_device *dvo) +{ + struct tfp410_priv *tfp = dvo->dev_priv; + + if (!tfp410_readb(dvo, TFP410_CTL_1, &tfp->saved_reg.ctl1)) + return; + + if (!tfp410_readb(dvo, TFP410_CTL_2, &tfp->saved_reg.ctl2)) + return; +} + +static void tfp410_restore(struct intel_dvo_device *dvo) +{ + struct tfp410_priv *tfp = dvo->dev_priv; + + /* Restore it powered down initially */ + tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1 & ~0x1); + + tfp410_writeb(dvo, TFP410_CTL_2, tfp->saved_reg.ctl2); + tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1); +} + +static void tfp410_destroy(struct intel_dvo_device *dvo) +{ + struct tfp410_priv *tfp = dvo->dev_priv; + + if (tfp) { + kfree(tfp); + dvo->dev_priv = NULL; + } +} + +struct intel_dvo_dev_ops tfp410_ops = { + .init = tfp410_init, + .detect = tfp410_detect, + .mode_valid = tfp410_mode_valid, + .mode_set = tfp410_mode_set, + .dpms = tfp410_dpms, + .dump_regs = tfp410_dump_regs, + .save = tfp410_save, + .restore = tfp410_restore, + .destroy = tfp410_destroy, +}; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 6aa61256..46abb90c 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1396,7 +1396,8 @@ static void intel_setup_outputs(struct drm_device *dev) if (IS_I9XX(dev)) { intel_sdvo_init(dev, SDVOB); intel_sdvo_init(dev, SDVOC); - } + } else + intel_dvo_init(dev); if (IS_I9XX(dev) && !IS_I915G(dev)) intel_tv_init(dev); diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 51c52c84..e0e6b797 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -69,6 +69,7 @@ extern bool intel_ddc_probe(struct drm_output *output); extern void intel_crt_init(struct drm_device *dev); extern void intel_sdvo_init(struct drm_device *dev, int output_device); +extern void intel_dvo_init(struct drm_device *dev); extern void intel_tv_init(struct drm_device *dev); extern void intel_lvds_init(struct drm_device *dev); diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c new file mode 100644 index 00000000..423b7514 --- /dev/null +++ b/linux-core/intel_dvo.c @@ -0,0 +1,493 @@ +/* + * Copyright © 2006-2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + */ +/* + * Copyright 2006 Dave Airlie + */ + +#include +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "intel_drv.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "dvo.h" + +#define SIL164_ADDR 0x38 +#define CH7xxx_ADDR 0x76 +#define TFP410_ADDR 0x38 + +extern struct intel_dvo_dev_ops sil164_ops; +extern struct intel_dvo_dev_ops ch7xxx_ops; +extern struct intel_dvo_dev_ops ivch_ops; +extern struct intel_dvo_dev_ops tfp410_ops; +extern struct intel_dvo_dev_ops ch7017_ops; + +struct intel_dvo_device intel_dvo_devices[] = { + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "sil164", + .dvo_reg = DVOC, + .slave_addr = SIL164_ADDR, + .dev_ops = &sil164_ops, + }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "ch7xxx", + .dvo_reg = DVOC, + .slave_addr = CH7xxx_ADDR, + .dev_ops = &ch7xxx_ops, + }, + { + .type = INTEL_DVO_CHIP_LVDS, + .name = "ivch", + .dvo_reg = DVOA, + .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */ + .dev_ops = &ivch_ops, + }, + { + .type = INTEL_DVO_CHIP_TMDS, + .name = "tfp410", + .dvo_reg = DVOC, + .slave_addr = TFP410_ADDR, + .dev_ops = &tfp410_ops, + }, + { + .type = INTEL_DVO_CHIP_LVDS, + .name = "ch7017", + .dvo_reg = DVOC, + .slave_addr = 0x75, + .gpio = GPIOE, + .dev_ops = &ch7017_ops, + } +}; + +static void intel_dvo_dpms(struct drm_output *output, int mode) +{ + struct drm_i915_private *dev_priv = output->dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + u32 dvo_reg = dvo->dvo_reg; + u32 temp = I915_READ(dvo_reg); + + if (mode == DPMSModeOn) { + I915_WRITE(dvo_reg, temp | DVO_ENABLE); + I915_READ(dvo_reg); + dvo->dev_ops->dpms(dvo, mode); + } else { + dvo->dev_ops->dpms(dvo, mode); + I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); + I915_READ(dvo_reg); + } +} + +static void intel_dvo_save(struct drm_output *output) +{ + struct drm_i915_private *dev_priv = output->dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + + /* Each output should probably just save the registers it touches, + * but for now, use more overkill. + */ + dev_priv->saveDVOA = I915_READ(DVOA); + dev_priv->saveDVOB = I915_READ(DVOB); + dev_priv->saveDVOC = I915_READ(DVOC); + + dvo->dev_ops->save(dvo); +} + +static void intel_dvo_restore(struct drm_output *output) +{ + struct drm_i915_private *dev_priv = output->dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + + dvo->dev_ops->restore(dvo); + + I915_WRITE(DVOA, dev_priv->saveDVOA); + I915_WRITE(DVOB, dev_priv->saveDVOB); + I915_WRITE(DVOC, dev_priv->saveDVOC); +} + +static int intel_dvo_mode_valid(struct drm_output *output, + struct drm_display_mode *mode) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + + if (mode->flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + /* XXX: Validate clock range */ + + if (dvo->panel_fixed_mode) { + if (mode->hdisplay > dvo->panel_fixed_mode->hdisplay) + return MODE_PANEL; + if (mode->vdisplay > dvo->panel_fixed_mode->vdisplay) + return MODE_PANEL; + } + + return dvo->dev_ops->mode_valid(dvo, mode); +} + +static bool intel_dvo_mode_fixup(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + + /* If we have timings from the BIOS for the panel, put them in + * to the adjusted mode. The CRTC will be set up for this mode, + * with the panel scaling set up to source from the H/VDisplay + * of the original mode. + */ + if (dvo->panel_fixed_mode != NULL) { +#define C(x) adjusted_mode->x = dvo->panel_fixed_mode->x + C(hdisplay); + C(hsync_start); + C(hsync_end); + C(htotal); + C(vdisplay); + C(vsync_start); + C(vsync_end); + C(vtotal); + C(clock); + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); +#undef C + } + + if (dvo->dev_ops->mode_fixup) + return dvo->dev_ops->mode_fixup(dvo, mode, adjusted_mode); + + return true; +} + +static void intel_dvo_mode_set(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = output->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = output->crtc->driver_private; + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + int pipe = intel_crtc->pipe; + u32 dvo_val; + u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg; + int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + + switch (dvo_reg) { + case DVOA: + default: + dvo_srcdim_reg = DVOA_SRCDIM; + break; + case DVOB: + dvo_srcdim_reg = DVOB_SRCDIM; + break; + case DVOC: + dvo_srcdim_reg = DVOC_SRCDIM; + break; + } + + dvo->dev_ops->mode_set(dvo, mode, adjusted_mode); + + /* Save the data order, since I don't know what it should be set to. */ + dvo_val = I915_READ(dvo_reg) & + (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG); + dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | + DVO_BLANK_ACTIVE_HIGH; + + if (pipe == 1) + dvo_val |= DVO_PIPE_B_SELECT; + dvo_val |= DVO_PIPE_STALL; + if (adjusted_mode->flags & V_PHSYNC) + dvo_val |= DVO_HSYNC_ACTIVE_HIGH; + if (adjusted_mode->flags & V_PVSYNC) + dvo_val |= DVO_VSYNC_ACTIVE_HIGH; + + I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED); + + /*I915_WRITE(DVOB_SRCDIM, + (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | + (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ + I915_WRITE(dvo_srcdim_reg, + (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | + (adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT)); + /*I915_WRITE(DVOB, dvo_val);*/ + I915_WRITE(dvo_reg, dvo_val); +} + +/** + * Detect the output connection on our DVO device. + * + * Unimplemented. + */ +static enum drm_output_status intel_dvo_detect(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + + return dvo->dev_ops->detect(dvo); +} + +static int intel_dvo_get_modes(struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + + /* We should probably have an i2c driver get_modes function for those + * devices which will have a fixed set of modes determined by the chip + * (TV-out, for example), but for now with just TMDS and LVDS, + * that's not the case. + */ + intel_ddc_get_modes(output); + if (!list_empty(&output->probed_modes)) + return 1; + +#if 0 + if (intel_output->i2c_drv->vid_rec->get_modes) + { + modes = intel_output->i2c_drv->vid_rec->get_modes (intel_output->i2c_drv->dev_priv); + if (modes != NULL) + return modes; + } +#endif + + if (dvo->panel_fixed_mode != NULL) { + struct drm_display_mode *mode; + mode = drm_mode_duplicate(output->dev, dvo->panel_fixed_mode); + if (mode) { + drm_mode_probed_add(output, mode); + return 1; + } + } + return 0; +} + +static void intel_dvo_destroy (struct drm_output *output) +{ + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + + if (dvo) { + if (dvo->dev_ops->destroy) + dvo->dev_ops->destroy(dvo); + if (dvo->panel_fixed_mode) + kfree(dvo->panel_fixed_mode); + /* no need, in i830_dvoices[] now */ + //kfree(dvo); + } + if (intel_output) { + if (intel_output->i2c_bus) + intel_i2c_destroy(intel_output->i2c_bus); + if (intel_output->ddc_bus) + intel_i2c_destroy(intel_output->ddc_bus); + kfree(intel_output); + output->driver_private = NULL; + } +} + +#ifdef RANDR_GET_CRTC_INTERFACE +static struct drm_crtc *intel_dvo_get_crtc(struct drm_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT); + + return intel_pipe_to_crtc(pScrn, pipe); +} +#endif + + +static const struct drm_output_funcs intel_dvo_output_funcs = { + .dpms = intel_dvo_dpms, + .save = intel_dvo_save, + .restore = intel_dvo_restore, + .mode_valid = intel_dvo_mode_valid, + .mode_fixup = intel_dvo_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_dvo_mode_set, + .commit = intel_output_commit, + .detect = intel_dvo_detect, + .get_modes = intel_dvo_get_modes, + .cleanup = intel_dvo_destroy +}; + +/** + * Attempts to get a fixed panel timing for LVDS (currently only the i830). + * + * Other chips with DVO LVDS will need to extend this to deal with the LVDS + * chip being on DVOB/C and having multiple pipes. + */ +static struct drm_display_mode * +intel_dvo_get_current_mode (struct drm_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_output *intel_output = output->driver_private; + struct intel_dvo_device *dvo = intel_output->dev_priv; + uint32_t dvo_reg = dvo->dvo_reg; + uint32_t dvo_val = I915_READ(dvo_reg); + struct drm_display_mode *mode = NULL; + + /* If the DVO port is active, that'll be the LVDS, so we can pull out + * its timings to get how the BIOS set up the panel. + */ + if (dvo_val & DVO_ENABLE) { + struct drm_crtc *crtc; + int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0; + + crtc = intel_get_crtc_from_pipe(dev, pipe); + if (crtc) { + mode = intel_crtc_mode_get(dev, crtc); + + if (mode) { + mode->type |= DRM_MODE_TYPE_PREFERRED; + if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) + mode->flags |= V_PHSYNC; + if (dvo_val & DVO_VSYNC_ACTIVE_HIGH) + mode->flags |= V_PVSYNC; + } + } + } + return mode; +} + +void intel_dvo_init(struct drm_device *dev) +{ + struct intel_output *intel_output; + struct intel_dvo_device *dvo; + struct intel_i2c_chan *i2cbus = NULL; + int ret = 0; + int i; + int gpio_inited = 0; + int connector = ConnectorUnknown; + + intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL); + if (!intel_output) + return; + + /* Set up the DDC bus */ + intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); + if (!intel_output->ddc_bus) + goto free_intel; + + /* Now, try to find a controller */ + for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { + struct drm_output *output = NULL; + int gpio; + + dvo = &intel_dvo_devices[i]; + + /* Allow the I2C driver info to specify the GPIO to be used in + * special cases, but otherwise default to what's defined + * in the spec. + */ + if (dvo->gpio != 0) + gpio = dvo->gpio; + else if (dvo->type == INTEL_DVO_CHIP_LVDS) + gpio = GPIOB; + else + gpio = GPIOE; + + /* Set up the I2C bus necessary for the chip we're probing. + * It appears that everything is on GPIOE except for panels + * on i830 laptops, which are on GPIOB (DVOA). + */ + if (gpio_inited != gpio) { + if (i2cbus != NULL) + intel_i2c_destroy(i2cbus); + if (!(i2cbus = intel_i2c_create(dev, gpio, + gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) { + continue; + } + gpio_inited = gpio; + } + + if (dvo->dev_ops!= NULL) + ret = dvo->dev_ops->init(dvo, i2cbus); + else + ret = false; + + if (!ret) + continue; + + intel_output->type = INTEL_OUTPUT_DVO; + switch (dvo->type) { + case INTEL_DVO_CHIP_TMDS: + connector = ConnectorDVID; + output = drm_output_create(dev, &intel_dvo_output_funcs, + DRM_MODE_OUTPUT_TMDS); + break; + case INTEL_DVO_CHIP_LVDS: + connector = ConnectorLVDS; + output = drm_output_create(dev, &intel_dvo_output_funcs, + DRM_MODE_OUTPUT_LVDS); + break; + } + if (output == NULL) { + dvo->dev_ops->destroy(dvo); + goto free_i2c; + } + + output->driver_private = intel_output; + output->display_info.subpixel_order = SubPixelHorizontalRGB; + output->interlace_allowed = false; + output->doublescan_allowed = false; + + intel_output->dev_priv = dvo; + intel_output->i2c_bus = i2cbus; + + if (dvo->type == INTEL_DVO_CHIP_LVDS) { + /* For our LVDS chipsets, we should hopefully be able + * to dig the fixed panel mode out of the BIOS data. + * However, it's in a different format from the BIOS + * data on chipsets with integrated LVDS (stored in AIM + * headers, likely), so for now, just get the current + * mode being output through DVO. + */ + dvo->panel_fixed_mode = intel_dvo_get_current_mode(output); + dvo->panel_wants_dither = true; + } + + drm_output_attach_property(output, + dev->mode_config.connector_type_property, + connector); + return; + } + +free_i2c: + intel_i2c_destroy(intel_output->ddc_bus); + /* Didn't find a chip, so tear down. */ + if (i2cbus != NULL) + intel_i2c_destroy(i2cbus); +free_intel: + kfree(intel_output); +} diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index e32c36f1..80d8d462 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -685,11 +685,39 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define PPCR_ON (1<<0) #define DVOA 0x61120 -#define DVOA_ON (1<<31) #define DVOB 0x61140 -#define DVOB_ON (1<<31) #define DVOC 0x61160 -#define DVOC_ON (1<<31) +#define DVO_ENABLE (1 << 31) +#define DVO_PIPE_B_SELECT (1 << 30) +#define DVO_PIPE_STALL_UNUSED (0 << 28) +#define DVO_PIPE_STALL (1 << 28) +#define DVO_PIPE_STALL_TV (2 << 28) +#define DVO_PIPE_STALL_MASK (3 << 28) +#define DVO_USE_VGA_SYNC (1 << 15) +#define DVO_DATA_ORDER_I740 (0 << 14) +#define DVO_DATA_ORDER_FP (1 << 14) +#define DVO_VSYNC_DISABLE (1 << 11) +#define DVO_HSYNC_DISABLE (1 << 10) +#define DVO_VSYNC_TRISTATE (1 << 9) +#define DVO_HSYNC_TRISTATE (1 << 8) +#define DVO_BORDER_ENABLE (1 << 7) +#define DVO_DATA_ORDER_GBRG (1 << 6) +#define DVO_DATA_ORDER_RGGB (0 << 6) +#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6) +#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6) +#define DVO_VSYNC_ACTIVE_HIGH (1 << 4) +#define DVO_HSYNC_ACTIVE_HIGH (1 << 3) +#define DVO_BLANK_ACTIVE_HIGH (1 << 2) +#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */ +#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */ +#define DVO_PRESERVE_MASK (0x7<<24) + +#define DVOA_SRCDIM 0x61124 +#define DVOB_SRCDIM 0x61144 +#define DVOC_SRCDIM 0x61164 +#define DVO_SRCDIM_HORIZONTAL_SHIFT 12 +#define DVO_SRCDIM_VERTICAL_SHIFT 0 + #define LVDS 0x61180 #define LVDS_ON (1<<31) -- cgit v1.2.3 From c250104c8f81026b4191ec8b2a709ff7ab5baedb Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 18 Apr 2008 16:26:41 +0800 Subject: fix removing output_attrs fix a typo in removing output sysfs. Signed-off-by: Hong Liu --- linux-core/drm_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index ef73cc83..8691d156 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -302,7 +302,7 @@ void drm_sysfs_output_remove(struct drm_output *output) int i; DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_output_name(output)); - for (i = 0; i < i; i++) + for (i = 0; i < ARRAY_SIZE(output_attrs); i++) device_remove_file(&output->kdev, &output_attrs[i]); sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); device_unregister(&output->kdev); -- cgit v1.2.3 From 8a390e058fcea70b0c3a912543816bdf4c3e7c4c Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 18 Apr 2008 16:49:23 +0800 Subject: clear interrupt status before install irq On my 865G machine, it seems the CPU will receive interrupt before irq_postinstall is called. This will cause kernel oops because vblank is not inited at that time. Clear interrupt status before install seems fixing this problem. Signed-off-by: Hong Liu --- shared-core/i915_irq.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 8f136c8f..422e81ed 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -1217,14 +1217,25 @@ int i915_vblank_swap(struct drm_device *dev, void *data, void i915_driver_irq_preinstall(struct drm_device * dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + u32 tmp; + + tmp = I915_READ(I915REG_PIPEASTAT); + I915_WRITE(I915REG_PIPEASTAT, tmp); + tmp = I915_READ(I915REG_PIPEBSTAT); + I915_WRITE(I915REG_PIPEBSTAT, tmp); + I915_WRITE16(I915REG_HWSTAM, 0xeffe); if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { I915_WRITE(I915REG_INT_MASK_R, 0x0); I915_WRITE(I915REG_INT_ENABLE_R, 0x0); + tmp = I915_READ(I915REG_INT_IDENTITY_R); + I915_WRITE(I915REG_INT_IDENTITY_R, tmp); } else { I915_WRITE16(I915REG_INT_MASK_R, 0x0); I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + tmp = I915_READ16(I915REG_INT_IDENTITY_R); + I915_WRITE16(I915REG_INT_IDENTITY_R, tmp); } } -- cgit v1.2.3 From b57e1f7efd6e27efbf960ab11323981e016ea86e Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 18 Apr 2008 16:52:04 +0800 Subject: add sysfs entry for DVO output forget to add it in the previous DVO porting patch. Signed-off-by: Hong Liu --- linux-core/intel_dvo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index 423b7514..6f319107 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -477,6 +477,7 @@ void intel_dvo_init(struct drm_device *dev) dvo->panel_wants_dither = true; } + drm_sysfs_output_add(output); drm_output_attach_property(output, dev->mode_config.connector_type_property, connector); -- cgit v1.2.3 From 8dc4d4fa1f1394c2faed89760e1183287577fed3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 22 Apr 2008 18:41:28 -0700 Subject: i915: allocate devname at init time Since it'll be freed at unload time, we should alloc devname rather than pointing to the DRIVER_NAME string. --- shared-core/i915_init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index ce6f1656..53574eb7 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -265,7 +265,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); - dev->devname = DRIVER_NAME; + dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); + if (!dev->devname) + return -ENOMEM; + drm_irq_install(dev); } -- cgit v1.2.3 From 33fa02f2d850da252d5ddd9ef7428b02de7bd6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 23 Apr 2008 12:42:26 -0400 Subject: Make radeon_ms compile. Remove lock functions and use pci_map_rom() instead of pci_map_rom_copy(). --- linux-core/radeon_ms_drv.h | 1 + shared-core/radeon_ms_crtc.c | 11 ----------- shared-core/radeon_ms_rom.c | 4 ++-- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/linux-core/radeon_ms_drv.h b/linux-core/radeon_ms_drv.h index 529f9c42..b80ed442 100644 --- a/linux-core/radeon_ms_drv.h +++ b/linux-core/radeon_ms_drv.h @@ -39,6 +39,7 @@ #include #include #include +#include #include "drm.h" #include "drmP.h" diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c index 3586e019..d73275bb 100644 --- a/shared-core/radeon_ms_crtc.c +++ b/shared-core/radeon_ms_crtc.c @@ -715,21 +715,10 @@ static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc) } } -static bool radeon_ms_crtc_lock(struct drm_crtc *crtc) -{ - return true; -} - -static void radeon_ms_crtc_unlock(struct drm_crtc *crtc) -{ -} - static const struct drm_crtc_funcs radeon_ms_crtc1_funcs= { .dpms = radeon_ms_crtc1_dpms, .save = NULL, /* XXX */ .restore = NULL, /* XXX */ - .lock = radeon_ms_crtc_lock, - .unlock = radeon_ms_crtc_unlock, .prepare = radeon_ms_crtc_mode_prepare, .commit = radeon_ms_crtc_mode_commit, .mode_fixup = radeon_ms_crtc_mode_fixup, diff --git a/shared-core/radeon_ms_rom.c b/shared-core/radeon_ms_rom.c index 5054a390..b4db02be 100644 --- a/shared-core/radeon_ms_rom.c +++ b/shared-core/radeon_ms_rom.c @@ -48,8 +48,8 @@ int radeon_ms_rom_init(struct drm_device *dev) dev_priv->rom.type = ROM_UNKNOWN; /* copy rom if any */ - rom_mapped = pci_map_rom_copy(dev->pdev, &rom->rom_size); - if (rom->rom_size) { + rom_mapped = pci_map_rom(dev->pdev, &rom->rom_size); + if (rom_mapped && rom->rom_size) { rom->rom_image = drm_alloc(rom->rom_size, DRM_MEM_DRIVER); if (rom->rom_image == NULL) { return -1; -- cgit v1.2.3 From 55a9941977953d16b36bbf3e1dcad392ac70e1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Wed, 23 Apr 2008 12:43:52 -0400 Subject: Make via compile. Chase the lock to it's new location. --- linux-core/via_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/via_fence.c b/linux-core/via_fence.c index 20df4779..6473e701 100644 --- a/linux-core/via_fence.c +++ b/linux-core/via_fence.c @@ -89,7 +89,7 @@ static void via_fence_poll(struct drm_device *dev, uint32_t class, if (signaled_flush_types) { waiting_types &= ~signaled_flush_types; if (!waiting_types && dev_priv->have_idlelock) { - drm_idlelock_release(&dev->lock); + drm_idlelock_release(&dev->primary->master->lock); dev_priv->have_idlelock = 0; } drm_fence_handler(dev, 0, dev_priv->emit_0_sequence, -- cgit v1.2.3 From 9d1db4ced1cd8e9e23f9ae945625a54d4f7f3721 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 10:26:37 +1000 Subject: cursor: pass handle not BO. --- libdrm/xf86drmMode.c | 7 ++----- libdrm/xf86drmMode.h | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index f86cc48f..605377dd 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -308,7 +308,7 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, * Cursor manipulation */ -int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height) +int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height) { struct drm_mode_cursor arg; @@ -316,10 +316,7 @@ int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_ arg.crtc = crtcId; arg.width = width; arg.height = height; - if (bo) - arg.handle = bo->handle; - else - arg.handle = 0; + arg.handle = bo_handle; return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); } diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index edf9efee..e5a6ee92 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -208,7 +208,7 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, /** * Set the cursor on crtc */ -int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height); +int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height); /** * Move the cursor on crtc -- cgit v1.2.3 From df46e0691bdd62da8ccc6b3811f57731dd5a2a4b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 10:45:18 +1000 Subject: drm: fix typo from previous merge --- linux-core/Makefile.kernel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index a805859b..6480d51a 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -15,7 +15,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ drm_edid.o drm_modes.o drm_bo_lock.o drm_regman.o \ - drm_vm_nopage-compat.o + drm_vm_nopage_compat.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o -- cgit v1.2.3 From ed072ed075ec431b0746ac1aa8bad5f687d75d8c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 14:01:24 +1000 Subject: drm_mode: initial replacefb implemenation --- libdrm/xf86drmMode.c | 21 ++++++++++++++++++++ libdrm/xf86drmMode.h | 6 ++++++ linux-core/drm_crtc.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 3 ++- linux-core/drm_drv.c | 2 ++ shared-core/drm.h | 1 + 6 files changed, 85 insertions(+), 3 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 605377dd..ae15fd65 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -608,3 +608,24 @@ int drmCheckModesettingSupported(const char *busid) return -ENOSYS; } + +int drmModeReplaceFB(int fd, uint32_t buffer_id, + uint32_t width, uint32_t height, uint8_t depth, + uint8_t bpp, uint32_t pitch, uint32_t bo_handle) +{ + struct drm_mode_fb_cmd f; + int ret; + + f.width = width; + f.height = height; + f.pitch = pitch; + f.bpp = bpp; + f.depth = depth; + f.handle = bo_handle; + f.buffer_id = buffer_id; + + if ((ret = ioctl(fd, DRM_IOCTL_MODE_REPLACEFB, &f))) + return ret; + + return 0; +} diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index e5a6ee92..5171b592 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -184,6 +184,12 @@ extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, */ extern int drmModeRmFB(int fd, uint32_t bufferId); +/** + * Replace a framebuffer object with a new one - for resizing the screen. + */ +extern int drmModeReplaceFB(int fd, uint32_t buffer_id, + uint32_t width, uint32_t height, uint8_t depth, + uint8_t bpp, uint32_t pitch, uint32_t bo_handle); /* * Crtc functions diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1e5195db..60255f54 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1879,8 +1879,8 @@ out: int drm_mode_rmfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_framebuffer *fb = 0; - struct drm_framebuffer *fbl = 0; + struct drm_framebuffer *fb = NULL; + struct drm_framebuffer *fbl = NULL; uint32_t *id = data; int ret = 0; int found = 0; @@ -2513,3 +2513,54 @@ out: return ret; } + +int drm_mode_replacefb(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_fb_cmd *r = data; + struct drm_framebuffer *fb; + struct drm_crtc *crtc; + struct drm_buffer_object *bo; + int found = 0; + struct drm_framebuffer *fbl = NULL; + int ret = 0; + /* right replace the current bo attached to this fb with a new bo */ + mutex_lock(&dev->mode_config.mutex); + ret = drm_get_buffer_object(dev, &bo, r->handle); + if (ret || !bo) { + ret = -EINVAL; + goto out; + } + + fb = idr_find(&dev->mode_config.crtc_idr, r->buffer_id); + if (!fb || (r->buffer_id != fb->id)) { + ret = -EINVAL; + goto out; + } + + list_for_each_entry(fbl, &file_priv->fbs, filp_head) + if (fb == fbl) + found = 1; + + if (!found) { + DRM_ERROR("tried to replace an fb we didn't own\n"); + ret = -EINVAL; + goto out; + } + + if (fb->bo->type == drm_bo_type_kernel) + DRM_ERROR("the bo should not be a kernel bo\n"); + + fb->bo = bo; + + /* find all crtcs connected to this fb */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->fb->id == r->buffer_id) { + crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); + } + } +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; + +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 20b1ea06..64e7e519 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -649,6 +649,7 @@ extern int drm_mode_output_property_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_hotplug_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); - +extern int drm_mode_replacefb(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 649d4cae..82a9c19d 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -141,6 +141,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_HOTPLUG, drm_mode_hotplug_ioctl, DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_HOTPLUG, drm_wait_hotplug, 0), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_REPLACEFB, drm_mode_replacefb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl, diff --git a/shared-core/drm.h b/shared-core/drm.h index c847b4ef..eb2033c7 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1276,6 +1276,7 @@ struct drm_mode_hotplug { #define DRM_IOCTL_MODE_HOTPLUG DRM_IOWR(0xAD, struct drm_mode_hotplug) #define DRM_IOCTL_WAIT_HOTPLUG DRM_IOWR(0xAE, union drm_wait_hotplug) +#define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xAF, struct drm_mode_fb_cmd) /*@}*/ /** -- cgit v1.2.3 From 576cba86b704c0de484ba852b8dce5b24d683f7e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 16:09:45 +1000 Subject: drm: fix replacefb to change fb properties --- linux-core/drm_crtc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 60255f54..2d1c8064 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2551,6 +2551,11 @@ int drm_mode_replacefb(struct drm_device *dev, if (fb->bo->type == drm_bo_type_kernel) DRM_ERROR("the bo should not be a kernel bo\n"); + fb->width = r->width; + fb->height = r->height; + fb->pitch = r->pitch; + fb->bits_per_pixel = r->bpp; + fb->depth = r->depth; fb->bo = bo; /* find all crtcs connected to this fb */ -- cgit v1.2.3 From 74a49aea6104ebea7525a04760ef21646a3ffaf4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 16:10:06 +1000 Subject: intel: set correct limits on screen width/height from DDX --- linux-core/intel_display.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 46abb90c..f66570c2 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1448,8 +1448,13 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; - dev->mode_config.max_width = 4096; - dev->mode_config.max_height = 4096; + if (IS_I965G(dev)) { + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; + } else { + dev->mode_config.max_width = 2048; + dev->mode_config.max_height = 2048; + } /* set memory base */ if (IS_I9XX(dev)) -- cgit v1.2.3 From 19abd5c1ac3456e67241fbd2d8cd08148d6de9f9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 16:10:26 +1000 Subject: drm: set crtc->fb to NULL --- linux-core/intel_fb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 7c4b0632..63491b61 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -763,6 +763,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) drm_framebuffer_destroy(fb); framebuffer_release(info); } + crtc->fb = NULL; return 0; } EXPORT_SYMBOL(intelfb_remove); -- cgit v1.2.3 From 442e12412396280eb5164d7b8f6792969c2cf6a0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 16:11:25 +1000 Subject: drm: check for NULL fb here, shouldn't happen but avoid oops for now --- linux-core/intel_fb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 63491b61..7df1525a 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -754,7 +754,12 @@ EXPORT_SYMBOL(intelfb_probe); int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_framebuffer *fb = crtc->fb; - struct fb_info *info = fb->fbdev; + struct fb_info *info; + + if (!fb) + return -EINVAL; + + info = fb->fbdev; if (info) { unregister_framebuffer(info); -- cgit v1.2.3 From 2a78ad22647933aa8842d534bce6495ff93fbf76 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 16:14:33 +1000 Subject: i915: fix vbl swap for multi-master patch from F9 tree --- shared-core/i915_irq.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 0ee0c444..ea2c88a1 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -198,9 +198,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) continue; - master_priv = vbl_swap->minor->master->driver_priv; - sarea_priv = master_priv->sarea_priv; - list_del(list); dev_priv->swaps_pending--; drm_vblank_put(dev, pipe); @@ -249,16 +246,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) i915_kernel_lost_context(dev); - upper[0] = upper[1] = 0; - slice[0] = max(sarea_priv->planeA_h / nhits, 1); - slice[1] = max(sarea_priv->planeB_h / nhits, 1); - lower[0] = sarea_priv->planeA_y + slice[0]; - lower[1] = sarea_priv->planeB_y + slice[0]; - - offsets[0] = sarea_priv->front_offset; - offsets[1] = sarea_priv->back_offset; - offsets[2] = sarea_priv->third_offset; - num_pages = sarea_priv->third_handle ? 3 : 2; DRM_SPINLOCK(&dev->drw_lock); @@ -272,8 +259,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) upper[1] = lower[1], lower[1] += slice[1]) { int init_drawrect = 1; - if (i == nhits) - lower[0] = lower[1] = sarea_priv->height; list_for_each(hit, &hits) { struct drm_i915_vbl_swap *swap_hit = @@ -282,6 +267,24 @@ static void i915_vblank_tasklet(struct drm_device *dev) int num_rects, plane, front, back; unsigned short top, bottom; + sarea_priv = master_priv->sarea_priv; + + upper[0] = upper[1] = 0; + slice[0] = max(sarea_priv->planeA_h / nhits, 1); + slice[1] = max(sarea_priv->planeB_h / nhits, 1); + lower[0] = sarea_priv->planeA_y + slice[0]; + lower[1] = sarea_priv->planeB_y + slice[0]; + + offsets[0] = sarea_priv->front_offset; + offsets[1] = sarea_priv->back_offset; + offsets[2] = sarea_priv->third_offset; + num_pages = sarea_priv->third_handle ? 3 : 2; + if (i == nhits) + lower[0] = lower[1] = sarea_priv->height; + + pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | + (cpp << 23) | (1 << 24); + drw = drm_get_drawable_info(dev, swap_hit->drw_id); if (!drw) @@ -294,6 +297,8 @@ static void i915_vblank_tasklet(struct drm_device *dev) continue; } + master_priv = swap_hit->minor->master->driver_priv; + if (init_drawrect) { int width = sarea_priv->width; int height = sarea_priv->height; @@ -332,6 +337,8 @@ static void i915_vblank_tasklet(struct drm_device *dev) (2 * plane)) & 0x3; back = (front + 1) % num_pages; + + for (num_rects = drw->num_rects; num_rects--; rect++) { int y1 = max(rect->y1, top); int y2 = min(rect->y2, bottom); -- cgit v1.2.3 From 4466fea7bab2af5c1e25947af474d0ae69df1ffd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 8 May 2008 17:12:16 +1000 Subject: Revert "i915: fix vbl swap for multi-master" This reverts commit 2a78ad22647933aa8842d534bce6495ff93fbf76. --- shared-core/i915_irq.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index ea2c88a1..0ee0c444 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -198,6 +198,9 @@ static void i915_vblank_tasklet(struct drm_device *dev) if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) continue; + master_priv = vbl_swap->minor->master->driver_priv; + sarea_priv = master_priv->sarea_priv; + list_del(list); dev_priv->swaps_pending--; drm_vblank_put(dev, pipe); @@ -246,6 +249,16 @@ static void i915_vblank_tasklet(struct drm_device *dev) i915_kernel_lost_context(dev); + upper[0] = upper[1] = 0; + slice[0] = max(sarea_priv->planeA_h / nhits, 1); + slice[1] = max(sarea_priv->planeB_h / nhits, 1); + lower[0] = sarea_priv->planeA_y + slice[0]; + lower[1] = sarea_priv->planeB_y + slice[0]; + + offsets[0] = sarea_priv->front_offset; + offsets[1] = sarea_priv->back_offset; + offsets[2] = sarea_priv->third_offset; + num_pages = sarea_priv->third_handle ? 3 : 2; DRM_SPINLOCK(&dev->drw_lock); @@ -259,6 +272,8 @@ static void i915_vblank_tasklet(struct drm_device *dev) upper[1] = lower[1], lower[1] += slice[1]) { int init_drawrect = 1; + if (i == nhits) + lower[0] = lower[1] = sarea_priv->height; list_for_each(hit, &hits) { struct drm_i915_vbl_swap *swap_hit = @@ -267,24 +282,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) int num_rects, plane, front, back; unsigned short top, bottom; - sarea_priv = master_priv->sarea_priv; - - upper[0] = upper[1] = 0; - slice[0] = max(sarea_priv->planeA_h / nhits, 1); - slice[1] = max(sarea_priv->planeB_h / nhits, 1); - lower[0] = sarea_priv->planeA_y + slice[0]; - lower[1] = sarea_priv->planeB_y + slice[0]; - - offsets[0] = sarea_priv->front_offset; - offsets[1] = sarea_priv->back_offset; - offsets[2] = sarea_priv->third_offset; - num_pages = sarea_priv->third_handle ? 3 : 2; - if (i == nhits) - lower[0] = lower[1] = sarea_priv->height; - - pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) | - (cpp << 23) | (1 << 24); - drw = drm_get_drawable_info(dev, swap_hit->drw_id); if (!drw) @@ -297,8 +294,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) continue; } - master_priv = swap_hit->minor->master->driver_priv; - if (init_drawrect) { int width = sarea_priv->width; int height = sarea_priv->height; @@ -337,8 +332,6 @@ static void i915_vblank_tasklet(struct drm_device *dev) (2 * plane)) & 0x3; back = (front + 1) % num_pages; - - for (num_rects = drw->num_rects; num_rects--; rect++) { int y1 = max(rect->y1, top); int y2 = min(rect->y2, bottom); -- cgit v1.2.3 From ba36d54ad4a3ea52b338d55ca19a864283e7c9ce Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 8 May 2008 15:00:18 +0200 Subject: drm: Made set_config use drm_mode_set as a argument --- linux-core/drm_crtc.c | 74 ++++++++++++++++++++++++++++++++------------------- linux-core/drm_crtc.h | 6 +++++ 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 2d1c8064..bdcf5f9b 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1130,16 +1130,27 @@ EXPORT_SYMBOL(drm_mode_config_cleanup); * RETURNS: * Zero. (FIXME) */ -int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set, struct drm_framebuffer *fb) +int drm_crtc_set_config(struct drm_mode_set *set) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev; struct drm_crtc **save_crtcs, *new_crtc; - bool save_enabled = crtc->enabled; + bool save_enabled; bool changed = false; bool flip_or_move = false; struct drm_output *output; int count = 0, ro; + if (!set) + return -EINVAL; + + if (!set->crtc) + return -EINVAL; + + dev = set->crtc->dev; + + /* save previous config */ + save_enabled = set->crtc->enabled; + /* this is meant to be num_output not num_crtc */ save_crtcs = kzalloc(dev->mode_config.num_output * sizeof(struct drm_crtc *), GFP_KERNEL); if (!save_crtcs) @@ -1147,30 +1158,30 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ - if (crtc->fb != fb) + if (set->crtc->fb != set->fb) flip_or_move = true; - if (crtc_info->x != crtc->x || crtc_info->y != crtc->y) + if (set->x != set->crtc->x || set->y != set->crtc->y) flip_or_move = true; - if (new_mode && !drm_mode_equal(new_mode, &crtc->mode)) { + if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { DRM_DEBUG("modes are different\n"); - drm_mode_debug_printmodeline(dev, &crtc->mode); - drm_mode_debug_printmodeline(dev, new_mode); + drm_mode_debug_printmodeline(dev, &set->crtc->mode); + drm_mode_debug_printmodeline(dev, set->mode); changed = true; } list_for_each_entry(output, &dev->mode_config.output_list, head) { save_crtcs[count++] = output->crtc; - if (output->crtc == crtc) + if (output->crtc == set->crtc) new_crtc = NULL; else new_crtc = output->crtc; - for (ro = 0; ro < crtc_info->count_outputs; ro++) { - if (output_set[ro] == output) - new_crtc = crtc; + for (ro = 0; ro < set->num_outputs; ro++) { + if (set->outputs[ro] == output) + new_crtc = set->crtc; } if (new_crtc != output->crtc) { changed = true; @@ -1179,33 +1190,34 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, } /* mode_set_base is not a required function */ - if (flip_or_move && !crtc->funcs->mode_set_base) + if (flip_or_move && !set->crtc->funcs->mode_set_base) changed = true; if (changed) { - crtc->fb = fb; - crtc->enabled = (new_mode != NULL); - if (new_mode != NULL) { + set->crtc->fb = set->fb; + set->crtc->enabled = (set->mode != NULL); + if (set->mode != NULL) { DRM_DEBUG("attempting to set mode from userspace\n"); - drm_mode_debug_printmodeline(dev, new_mode); - if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x, - crtc_info->y)) { - crtc->enabled = save_enabled; + drm_mode_debug_printmodeline(dev, set->mode); + if (!drm_crtc_set_mode(set->crtc, set->mode, set->x, + set->y)) { + set->crtc->enabled = save_enabled; count = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) output->crtc = save_crtcs[count++]; kfree(save_crtcs); return -EINVAL; } - crtc->desired_x = crtc_info->x; - crtc->desired_y = crtc_info->y; - crtc->desired_mode = new_mode; + /* TODO are these needed? */ + set->crtc->desired_x = set->x; + set->crtc->desired_y = set->y; + set->crtc->desired_mode = set->mode; } drm_disable_unused_functions(dev); } else if (flip_or_move) { - if (crtc->fb != fb) - crtc->fb = fb; - crtc->funcs->mode_set_base(crtc, crtc_info->x, crtc_info->y); + if (set->crtc->fb != set->fb) + set->crtc->fb = set->fb; + set->crtc->funcs->mode_set_base(set->crtc, set->x, set->y); } kfree(save_crtcs); @@ -1648,6 +1660,7 @@ int drm_mode_setcrtc(struct drm_device *dev, struct drm_output **output_set = NULL, *output; struct drm_framebuffer *fb = NULL; struct drm_display_mode *mode = NULL; + struct drm_mode_set set; uint32_t __user *set_outputs_ptr; int ret = 0; int i; @@ -1724,7 +1737,14 @@ int drm_mode_setcrtc(struct drm_device *dev, } } - ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb); + set.crtc = crtc; + set.x = crtc_req->x; + set.y = crtc_req->y; + set.mode = mode; + set.outputs = output_set; + set.num_outputs = crtc_req->count_outputs; + set.fb =fb; + ret = drm_crtc_set_config(&set); out: kfree(output_set); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 64e7e519..abe8f3f3 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -475,11 +475,17 @@ struct drm_output { * * Represents a single crtc the outputs that it drives with what mode * and from which framebuffer it scans out from. + * + * This is used to set modes. */ struct drm_mode_set { struct drm_framebuffer *fb; struct drm_crtc *crtc; + struct drm_display_mode *mode; + + uint32_t x; + uint32_t y; struct drm_output **outputs; size_t num_outputs; -- cgit v1.2.3 From 9d9104ad5fcd2d284a0a87385e9eb1a77adc869e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 8 May 2008 15:25:37 +0200 Subject: i915: Fixed indent in intel_fb.c --- linux-core/intel_fb.c | 438 +++++++++++++++++++++++++------------------------- 1 file changed, 221 insertions(+), 217 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 7df1525a..73ad35c7 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -47,24 +47,25 @@ struct intelfb_par { struct drm_device *dev; struct drm_crtc *crtc; - struct drm_display_mode *fb_mode; + struct drm_display_mode *fb_mode; struct drm_framebuffer *fb; + struct drm_mode_set set; }; /* static int var_to_refresh(const struct fb_var_screeninfo *var) { int xtot = var->xres + var->left_margin + var->right_margin + - var->hsync_len; + var->hsync_len; int ytot = var->yres + var->upper_margin + var->lower_margin + - var->vsync_len; + var->vsync_len; return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; }*/ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) + unsigned blue, unsigned transp, + struct fb_info *info) { struct intelfb_par *par = info->par; struct drm_framebuffer *fb = par->fb; @@ -82,9 +83,9 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno < 16) { switch (fb->depth) { case 15: - fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); + ((blue & 0xf800) >> 11); break; case 16: fb->pseudo_palette[regno] = (red & 0xf800) | @@ -94,7 +95,7 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, case 24: case 32: fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | - (green & 0xff00) | + (green & 0xff00) | ((blue & 0xff00) >> 8); break; } @@ -104,114 +105,114 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, } static int intelfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) + struct fb_info *info) { - struct intelfb_par *par = info->par; - /*struct drm_device *dev = par->dev;*/ + struct intelfb_par *par = info->par; + /*struct drm_device *dev = par->dev;*/ struct drm_framebuffer *fb = par->fb; - /*struct drm_output *output;*/ - int depth/*, found = 0*/; - - if (!var->pixclock) - return -EINVAL; - - /* Need to resize the fb object !!! */ - if (var->xres > fb->width || var->yres > fb->height) { - DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); - DRM_ERROR("Need resizing code.\n"); - return -EINVAL; - } - - switch (var->bits_per_pixel) { - case 16: - depth = (var->green.length == 6) ? 16 : 15; - break; - case 32: - depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - depth = var->bits_per_pixel; - break; - } - - switch (depth) { - case 8: - var->red.offset = 0; - var->green.offset = 0; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 0; - var->transp.offset = 0; - break; - case 15: - var->red.offset = 10; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 5; - var->blue.length = 5; - var->transp.length = 1; - var->transp.offset = 15; - break; - case 16: - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; - var->transp.length = 0; - var->transp.offset = 0; - break; - case 24: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 0; - var->transp.offset = 0; - break; - case 32: - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - var->transp.length = 8; - var->transp.offset = 24; - break; - default: - return -EINVAL; - } + /*struct drm_output *output;*/ + int depth/*, found = 0*/; + + if (!var->pixclock) + return -EINVAL; + + /* Need to resize the fb object !!! */ + if (var->xres > fb->width || var->yres > fb->height) { + DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); + DRM_ERROR("Need resizing code.\n"); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + depth = var->bits_per_pixel; + break; + } + + switch (depth) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 15: + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.length = 1; + var->transp.offset = 15; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 24; + break; + default: + return -EINVAL; + } #if 0 - /* Here we walk the output mode list and look for modes. If we haven't - * got it, then bail. Not very nice, so this is disabled. - * In the set_par code, we create our mode based on the incoming - * parameters. Nicer, but may not be desired by some. - */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc) - break; - } - - list_for_each_entry(drm_mode, &output->modes, head) { - if (drm_mode->hdisplay == var->xres && - drm_mode->vdisplay == var->yres && - (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && - (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { + /* Here we walk the output mode list and look for modes. If we haven't + * got it, then bail. Not very nice, so this is disabled. + * In the set_par code, we create our mode based on the incoming + * parameters. Nicer, but may not be desired by some. + */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc) + break; + } + + list_for_each_entry(drm_mode, &output->modes, head) { + if (drm_mode->hdisplay == var->xres && + drm_mode->vdisplay == var->yres && + (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && + (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { found = 1; break; } } - if (!found) - return -EINVAL; + if (!found) + return -EINVAL; #endif return 0; @@ -224,68 +225,68 @@ static int intelfb_set_par(struct fb_info *info) struct intelfb_par *par = info->par; struct drm_framebuffer *fb = par->fb; struct drm_device *dev = par->dev; - struct drm_display_mode *drm_mode, *search_mode; - struct drm_output *output = NULL; - struct fb_var_screeninfo *var = &info->var; + struct drm_display_mode *drm_mode, *search_mode; + struct drm_output *output = NULL; + struct fb_var_screeninfo *var = &info->var; int found = 0; int changed = 0; DRM_DEBUG("\n"); - switch (var->bits_per_pixel) { - case 16: - fb->depth = (var->green.length == 6) ? 16 : 15; - break; - case 32: - fb->depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - fb->depth = var->bits_per_pixel; - break; - } + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + fb->depth = var->bits_per_pixel; + break; + } - fb->bits_per_pixel = var->bits_per_pixel; + fb->bits_per_pixel = var->bits_per_pixel; - info->fix.line_length = fb->pitch; - info->fix.smem_len = info->fix.line_length * fb->height; - info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + info->fix.line_length = fb->pitch; + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->screen_size = info->fix.smem_len; /* ??? */ + info->screen_size = info->fix.smem_len; /* ??? */ /* create a drm mode */ - drm_mode = drm_mode_create(dev); - drm_mode->hdisplay = var->xres; - drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; - drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; - drm_mode->htotal = drm_mode->hsync_end + var->left_margin; - drm_mode->vdisplay = var->yres; - drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; - drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; - drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; - drm_mode->clock = PICOS2KHZ(var->pixclock); - drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode->flags = 0; drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; - drm_mode_set_name(drm_mode); + drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); found = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc){ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + if (output->crtc == par->crtc){ found = 1; - break; + break; } - } + } /* no output bound, bail */ if (!found) return -EINVAL; found = 0; - drm_mode_debug_printmodeline(dev, drm_mode); - list_for_each_entry(search_mode, &output->modes, head) { + drm_mode_debug_printmodeline(dev, drm_mode); + list_for_each_entry(search_mode, &output->modes, head) { drm_mode_debug_printmodeline(dev, search_mode); if (drm_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); @@ -296,8 +297,8 @@ static int intelfb_set_par(struct fb_info *info) } /* If we didn't find a matching mode that exists on our output, - * create a new attachment for the incoming user specified mode - */ + * create a new attachment for the incoming user specified mode + */ if (!found) { if (par->fb_mode) { /* this also destroys the mode */ @@ -318,7 +319,7 @@ static int intelfb_set_par(struct fb_info *info) if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) changed = 1; - + drm_mode_debug_printmodeline(dev, drm_mode); drm_mode_debug_printmodeline(dev, &par->crtc->mode); if (!drm_mode_equal(drm_mode, &par->crtc->mode)) @@ -333,9 +334,9 @@ static int intelfb_set_par(struct fb_info *info) #if 0 static void intelfb_copyarea(struct fb_info *info, - const struct fb_copyarea *region) + const struct fb_copyarea *region) { - struct intelfb_par *par = info->par; + struct intelfb_par *par = info->par; struct drm_device *dev = par->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset; @@ -380,7 +381,7 @@ static void intelfb_copyarea(struct fb_info *info, void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) { - struct intelfb_par *par = info->par; + struct intelfb_par *par = info->par; struct drm_device *dev = par->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 cmd, rop_pitch_depth, tmp; @@ -397,9 +398,9 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) nbytes *= image->height; /* - * Check if the glyph data exceeds the immediate mode limit. - * It would take a large font (1K pixels) to hit this limit. - */ + * Check if the glyph data exceeds the immediate mode limit. + * It would take a large font (1K pixels) to hit this limit. + */ if (nbytes > 128 || image->depth != 1) return cfb_imageblit(info, image); @@ -407,13 +408,13 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) ndwords = ROUND_UP_TO(nbytes, 4) / 4; /* - * Ring has to be padded to a quad word. But because the command starts - with 7 bytes, pad only if there is an even number of ndwords - */ + * Ring has to be padded to a quad word. But because the command starts + with 7 bytes, pad only if there is an even number of ndwords + */ pad = !(ndwords % 2); DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width, - image->height, image->depth, image->dx, image->dy); + image->height, image->depth, image->dx, image->dy); DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad); tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords; @@ -477,7 +478,7 @@ void intelfb_imageblit(struct fb_info *info, const struct fb_image *image) } #endif static int intelfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) + struct fb_info *info) { struct intelfb_par *par = info->par; struct drm_crtc *crtc = par->crtc; @@ -505,11 +506,11 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, - // .fb_open = intelfb_open, - // .fb_read = intelfb_read, - // .fb_write = intelfb_write, - // .fb_release = intelfb_release, - // .fb_ioctl = intelfb_ioctl, + //.fb_open = intelfb_open, + //.fb_read = intelfb_read, + //.fb_write = intelfb_write, + //.fb_release = intelfb_release, + //.fb_ioctl = intelfb_ioctl, .fb_check_var = intelfb_check_var, .fb_set_par = intelfb_set_par, .fb_setcolreg = intelfb_setcolreg, @@ -590,14 +591,14 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); fb->depth = 24; ret = drm_buffer_object_create(dev, fb->pitch * fb->height, - drm_bo_type_kernel, - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0, 0, - &fbo); + drm_bo_type_kernel, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0, 0, + &fbo); if (ret || !fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); drm_framebuffer_destroy(fb); @@ -607,7 +608,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) fb->bo = fbo; printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, - fb->height, fbo->offset, fbo); + fb->height, fbo->offset, fbo); fb->fbdev = info; @@ -645,9 +646,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->flags = FBINFO_DEFAULT; ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap); - if (ret) - DRM_ERROR("error mapping fb: %d\n", ret); - + if (ret) + DRM_ERROR("error mapping fb: %d\n", ret); + info->screen_base = fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; @@ -660,13 +661,13 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) info->var.height = -1; info->var.width = -1; - info->var.xres = mode->hdisplay; - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.yres = mode->vdisplay; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; info->var.upper_margin = mode->vtotal - mode->vsync_end; info->var.pixclock = KHZ2PICOS(mode->clock); @@ -693,48 +694,51 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) DRM_DEBUG(" pitch is %d\n", fb->pitch); switch(fb->depth) { case 8: - info->var.red.offset = 0; - info->var.green.offset = 0; - info->var.blue.offset = 0; - info->var.red.length = 8; /* 8bit DAC */ - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; + info->var.red.offset = 0; + info->var.green.offset = 0; + info->var.blue.offset = 0; + info->var.red.length = 8; /* 8bit DAC */ + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; case 15: - info->var.red.offset = 10; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = info->var.green.length = - info->var.blue.length = 5; - info->var.transp.offset = 15; - info->var.transp.length = 1; - break; + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 5; + info->var.blue.length = 5; + info->var.transp.offset = 15; + info->var.transp.length = 1; + break; case 16: - info->var.red.offset = 11; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = 5; - info->var.green.length = 6; - info->var.blue.length = 5; - info->var.transp.offset = 0; + info->var.red.offset = 11; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 6; + info->var.blue.length = 5; + info->var.transp.offset = 0; break; case 24: - info->var.red.offset = 16; - info->var.green.offset = 8; - info->var.blue.offset = 0; - info->var.red.length = info->var.green.length = - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; case 32: info->var.red.offset = 16; info->var.green.offset = 8; info->var.blue.offset = 0; - info->var.red.length = info->var.green.length = - info->var.blue.length = 8; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; info->var.transp.offset = 24; info->var.transp.length = 8; break; @@ -746,7 +750,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, - info->fix.id); + info->fix.id); return 0; } EXPORT_SYMBOL(intelfb_probe); -- cgit v1.2.3 From 7bcbc443f4f5161ab1e1a11cb6694e6d6269377c Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 8 May 2008 20:10:18 +0200 Subject: i915: Changed intel_fb to use the new drm_crtc_set_config interface --- linux-core/drmP.h | 2 +- linux-core/drm_crtc.c | 22 ++++++--------- linux-core/drm_crtc.h | 1 + linux-core/intel_drv.h | 2 +- linux-core/intel_fb.c | 70 +++++++++++++++++++++++++++-------------------- linux-core/radeon_ms_fb.c | 2 +- shared-core/radeon_ms.h | 2 +- 7 files changed, 55 insertions(+), 46 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f5e794e5..52d2782a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -743,7 +743,7 @@ struct drm_driver { struct drm_set_version *sv); /* FB routines, if present */ - int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc); + int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc); int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bdcf5f9b..2bc1c4e3 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -540,8 +540,8 @@ done: crtc->mode = saved_mode; crtc->x = saved_x; crtc->y = saved_y; - } - + } + return ret; } EXPORT_SYMBOL(drm_crtc_set_mode); @@ -1036,16 +1036,6 @@ bool drm_initial_config(struct drm_device *dev, bool can_grow) drm_pick_crtcs(dev); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - - /* can't setup the crtc if there's no assigned mode */ - if (!crtc->desired_mode) - continue; - - /* Now setup the fbdev for attached crtcs */ - dev->driver->fb_probe(dev, crtc); - } - /* This is a little screwy, as we've already walked the outputs * above, but it's a little bit of magic too. There's the potential * for things not to get setup above if an existing device gets @@ -1058,6 +1048,8 @@ bool drm_initial_config(struct drm_device *dev, bool can_grow) if (!output->crtc || !output->crtc->desired_mode) continue; + dev->driver->fb_probe(dev, output->crtc, output); + /* and needs an attached fb */ if (output->crtc->fb) drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); @@ -1140,12 +1132,15 @@ int drm_crtc_set_config(struct drm_mode_set *set) struct drm_output *output; int count = 0, ro; + DRM_DEBUG("\n"); + if (!set) return -EINVAL; if (!set->crtc) return -EINVAL; + DRM_DEBUG("crtc: %p fb: %p outputs: %p num_outputs: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->outputs, set->num_outputs, set->x, set->y); dev = set->crtc->dev; /* save previous config */ @@ -1223,6 +1218,7 @@ int drm_crtc_set_config(struct drm_mode_set *set) kfree(save_crtcs); return 0; } +EXPORT_SYMBOL(drm_crtc_set_config); /** * drm_hotplug_stage_two @@ -1267,7 +1263,7 @@ int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, /* We should really check if there is a fb using this crtc */ if (!has_config) - dev->driver->fb_probe(dev, output->crtc); + dev->driver->fb_probe(dev, output->crtc, output); else { dev->driver->fb_resize(dev, output->crtc); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index abe8f3f3..1d36dcd4 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -605,6 +605,7 @@ extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); +extern int drm_crtc_set_config(struct drm_mode_set *set); extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); extern bool drm_crtc_in_use(struct drm_crtc *crtc); diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index e0e6b797..6b89c000 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -90,7 +90,7 @@ extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern int intel_sdvo_supports_hotplug(struct drm_output *output); extern void intel_sdvo_set_hotplug(struct drm_output *output, int enable); -extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc); +extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); extern int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 73ad35c7..50c24a75 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -46,10 +46,14 @@ struct intelfb_par { struct drm_device *dev; +/* struct drm_crtc *crtc; struct drm_display_mode *fb_mode; struct drm_framebuffer *fb; +*/ + struct drm_display_mode *our_mode; struct drm_mode_set set; + struct drm_output *hack; }; /* static int @@ -68,8 +72,8 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->fb; - struct drm_crtc *crtc = par->crtc; + struct drm_framebuffer *fb = par->set.fb; + struct drm_crtc *crtc = par->set.crtc; if (regno > 255) return 1; @@ -109,7 +113,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, { struct intelfb_par *par = info->par; /*struct drm_device *dev = par->dev;*/ - struct drm_framebuffer *fb = par->fb; + struct drm_framebuffer *fb = par->set.fb; /*struct drm_output *output;*/ int depth/*, found = 0*/; @@ -223,13 +227,12 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->fb; + struct drm_framebuffer *fb = par->set.fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; struct drm_output *output = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; - int changed = 0; DRM_DEBUG("\n"); @@ -274,7 +277,7 @@ static int intelfb_set_par(struct fb_info *info) found = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc){ + if (output->crtc == par->set.crtc){ found = 1; break; } @@ -300,17 +303,24 @@ static int intelfb_set_par(struct fb_info *info) * create a new attachment for the incoming user specified mode */ if (!found) { - if (par->fb_mode) { + if (par->our_mode) { /* this also destroys the mode */ - drm_mode_detachmode_crtc(dev, par->fb_mode); + drm_mode_detachmode_crtc(dev, par->our_mode); } - par->fb_mode = drm_mode; + par->set.mode = drm_mode; + par->our_mode = drm_mode; drm_mode_debug_printmodeline(dev, drm_mode); /* attach mode */ - drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); + drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + } else { + par->set.mode = drm_mode; + if (par->our_mode) + drm_mode_detachmode_crtc(dev, par->our_mode); + par->our_mode = NULL; } +#if 0 /* re-attach fb */ if (!par->crtc->fb) { par->crtc->fb = par->fb; @@ -330,6 +340,9 @@ static int intelfb_set_par(struct fb_info *info) return -EINVAL; return 0; +#else + return drm_crtc_set_config(&par->set); +#endif } #if 0 @@ -481,27 +494,20 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_crtc *crtc = par->crtc; - int changed = 0; + int ret; DRM_DEBUG("\n"); - /* TODO add check size and pos*/ - if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) - changed = 1; - - /* re-attach fb */ - if (!crtc->fb) { - crtc->fb = par->fb; - changed = 1; - } + par->set.x = var->xoffset; + par->set.y = var->yoffset; - if (changed) - drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset); + ret = drm_crtc_set_config(&par->set); - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; + if (!ret) { + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + } - return 0; + return ret; } static struct fb_ops intelfb_ops = { @@ -560,7 +566,7 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) +int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output) { struct fb_info *info; struct intelfb_par *par; @@ -575,6 +581,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) return -EINVAL; } + if (!output) + return -EINVAL; + fb = drm_framebuffer_create(dev); if (!fb) { framebuffer_release(info); @@ -616,8 +625,11 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) par = info->par; par->dev = dev; - par->crtc = crtc; - par->fb = fb; + par->set.crtc = crtc; + par->set.fb = fb; + par->hack = output; + par->set.outputs = &par->hack; + par->set.num_outputs = 1; info->fbops = &intelfb_ops; diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index dbbddaf4..ae4f2da5 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -270,7 +270,7 @@ static struct fb_ops radeonfb_ops = { .fb_imageblit = cfb_imageblit, }; -int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc) +int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output) { struct drm_radeon_private *dev_priv = dev->dev_private; struct fb_info *info; diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index dd34683e..1fdcd0a1 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -435,7 +435,7 @@ int r3xx_fence_types(struct drm_buffer_object *bo, uint32_t * class, uint32_t * type); /* radeon_ms_fb.c */ -int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc); +int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc); /* radeon_ms_gpu.c */ -- cgit v1.2.3 From 7317e774b5cddb7218c1416fa4d9ee98756e4890 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 9 May 2008 09:26:17 +0100 Subject: Fix test applications for recent DRM changes --- tests/mode/modetest.c | 2 +- tests/modedemo/demo.c | 4 ++-- tests/modefb/demo.c | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index a50b0cc5..1fab0406 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -291,7 +291,7 @@ int testFrameBufferAdd(int fd, drmModeResPtr res) goto err; printf("\tAdding FB\n"); - ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, bo->handle, &fb); + ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, bo.handle, &fb); if (ret) goto err_bo; diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c index 3fad984d..72d69405 100644 --- a/tests/modedemo/demo.c +++ b/tests/modedemo/demo.c @@ -603,7 +603,7 @@ void testCursor(int fd, uint32_t crtc) prettyCursor(fd, bo.handle, 0xFFFF00FF); printf("set cursor\n"); - drmModeSetCursor(fd, crtc, &bo, 64, 64); + drmModeSetCursor(fd, crtc, bo.handle, 64, 64); printf("move cursor 0, 0\n"); drmModeMoveCursor(fd, crtc, 0, 0); sleep(1); @@ -614,7 +614,7 @@ void testCursor(int fd, uint32_t crtc) printf("move cursor 100, 100\n"); drmModeMoveCursor(fd, crtc, 100, 100); sleep(1); - drmModeSetCursor(fd, crtc, NULL, 0, 0); + drmModeSetCursor(fd, crtc, 0, 0, 0); } void prettyCursor(int fd, unsigned int handle, unsigned int color) diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c index b6d1f65b..ead53334 100644 --- a/tests/modefb/demo.c +++ b/tests/modefb/demo.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -16,8 +17,6 @@ void cursor(int fd, int drmfd); void prettyColors(int fd); void prettyCursor(int fd, unsigned int handle, unsigned int color); -extern void sleep(int); - struct fb_var_screeninfo var; struct fb_fix_screeninfo fix; @@ -152,7 +151,7 @@ void cursor(int fd, int drmfd) } prettyCursor(drmfd, bo.handle, 0xFFFF00FF); - drmModeSetCursor(drmfd, crtc, &bo, 64, 64); + drmModeSetCursor(drmfd, crtc, bo.handle, 64, 64); drmModeMoveCursor(drmfd, crtc, 0, 0); sleep(1); prettyCursor(drmfd, bo.handle, 0xFFFF0000); @@ -160,7 +159,7 @@ void cursor(int fd, int drmfd) sleep(1); drmModeMoveCursor(drmfd, crtc, 100, 100); sleep(1); - drmModeSetCursor(drmfd, crtc, NULL, 0, 0); + drmModeSetCursor(drmfd, crtc, 0, 0, 0); drmBOUnreference(drmfd, &bo); } -- cgit v1.2.3 From eeff906aa0f64da12a0154c66d99e8492dd95107 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Fri, 9 May 2008 16:36:28 +0100 Subject: Fix build problems --- linux-core/drm_compat.c | 2 +- tests/mode/modetest.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 2a761963..dbb31578 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -217,7 +217,7 @@ static struct page *drm_bo_vm_fault(struct vm_area_struct *vma, mutex_lock(&bo->mutex); - err = drm_bo_wait(bo, 0, 1, 0); + err = drm_bo_wait(bo, 0, 1, 0, 1); if (err) { data->type = (err == -EAGAIN) ? VM_FAULT_MINOR : VM_FAULT_SIGBUS; diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 1fab0406..99238d5a 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -351,7 +351,7 @@ int main(int argc, char **argv) printf("Starting test\n"); - fd = drmOpenControl(0); + fd = drmOpen("i915", NULL); if (fd < 0) { printf("Failed to open the card fb (%d)\n",fd); -- cgit v1.2.3 From 12725a37af691345e74fe22d53300abec2581852 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 9 May 2008 14:19:00 -0700 Subject: i915: add basic VBT support Map the VBIOS (and therefore VBT) at init time for use by various output initialization routines. --- linux-core/Makefile.kernel | 2 +- linux-core/intel_bios.c | 244 +++++++++++++++++++++++++++++++++++++++++++++ linux-core/intel_bios.h | 187 ++++++++++++++++++++++++++++++++++ shared-core/i915_drv.h | 6 ++ shared-core/i915_init.c | 7 ++ 5 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 linux-core/intel_bios.c create mode 100644 linux-core/intel_bios.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 6480d51a..f77f8642 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -22,7 +22,7 @@ mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ i915_buffer.o i915_execbuf.o \ - intel_display.o intel_crt.o intel_lvds.o \ + intel_display.o intel_crt.o intel_lvds.o intel_bios.o \ intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o \ intel_tv.o i915_compat.o intel_dvo.o dvo_ch7xxx.o \ dvo_ch7017.o dvo_ivch.o dvo_tfp410.o dvo_sil164.o diff --git a/linux-core/intel_bios.c b/linux-core/intel_bios.c new file mode 100644 index 00000000..7f8e8513 --- /dev/null +++ b/linux-core/intel_bios.c @@ -0,0 +1,244 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" +#include "intel_bios.h" + +#define VBT_OFFSET 0x1a + +/** + * intel_find_vbt - find the VBT + * @dev: DRM device + * + * Loads the Video BIOS and checks that the VBT exists. + * + * VBT existence is a sanity check that is relied on by other i830_bios.c code. + * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may + * feed an updated VBT back through that, compared to what we'll fetch using + * this method of groping around in the BIOS data. + * + * Returns 0 on success, nonzero on failure. + */ +bool +intel_find_bios(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct pci_dev *pdev = dev->pdev; + void __iomem *bios; + size_t size; + + bios = pci_map_rom(pdev, &size); + if (!bios) + return NULL; + + dev_priv->vbt = (struct vbt_header *)((u8 *)bios + VBT_OFFSET); + dev_priv->bdb = (struct bdb_header *)((u8 *)bios + VBT_OFFSET + + dev_priv->vbt->bdb_offset); + + if (memcmp(dev_priv->vbt->signature, "$VBT", 4) != 0) { + DRM_ERROR("Bad VBT signature\n"); + pci_unmap_rom(pdev, bios); + return NULL; + } + + return bios; +} + +#if 0 +/** + * Returns the BIOS's fixed panel mode. + * + * Note that many BIOSes will have the appropriate tables for a panel even when + * a panel is not attached. Additionally, many BIOSes adjust table sizes or + * offsets, such that this parsing fails. Thus, almost any other method for + * detecting the panel mode is preferable. + */ +struct drm_display_mode * +i830_bios_get_panel_mode(struct drm_device *dev, bool *wants_dither) +{ + I830Ptr pI830 = I830PTR(pScrn); + struct vbt_header *vbt; + struct bdb_header *bdb; + int vbt_off, bdb_off, bdb_block_off, block_size; + int panel_type = -1; + unsigned char *bios; + + bios = i830_bios_get (pScrn); + + if (bios == NULL) + return NULL; + + vbt_off = INTEL_BIOS_16(0x1a); + vbt = (struct vbt_header *)(bios + vbt_off); + bdb_off = vbt_off + vbt->bdb_offset; + bdb = (struct bdb_header *)(bios + bdb_off); + + if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad BDB signature\n"); + xfree(bios); + return NULL; + } + + *wants_dither = FALSE; + for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size; + bdb_block_off += block_size) + { + int start = bdb_off + bdb_block_off; + int id; + struct lvds_bdb_1 *lvds1; + struct lvds_bdb_2 *lvds2; + struct lvds_bdb_2_fp_params *fpparam; + struct lvds_bdb_2_fp_edid_dtd *fptiming; + DisplayModePtr fixed_mode; + CARD8 *timing_ptr; + + id = INTEL_BIOS_8(start); + block_size = INTEL_BIOS_16(start + 1) + 3; + switch (id) { + case 40: + lvds1 = (struct lvds_bdb_1 *)(bios + start); + panel_type = lvds1->panel_type; + if (lvds1->caps & LVDS_CAP_DITHER) + *wants_dither = TRUE; + break; + case 41: + if (panel_type == -1) + break; + + lvds2 = (struct lvds_bdb_2 *)(bios + start); + fpparam = (struct lvds_bdb_2_fp_params *)(bios + + bdb_off + lvds2->panels[panel_type].fp_params_offset); + fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios + + bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset); + timing_ptr = bios + bdb_off + + lvds2->panels[panel_type].fp_edid_dtd_offset; + + if (fpparam->terminator != 0xffff) { + /* Apparently the offsets are wrong for some BIOSes, so we + * try the other offsets if we find a bad terminator. + */ + fpparam = (struct lvds_bdb_2_fp_params *)(bios + + bdb_off + lvds2->panels[panel_type].fp_params_offset + 8); + fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios + + bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset + 8); + timing_ptr = bios + bdb_off + + lvds2->panels[panel_type].fp_edid_dtd_offset + 8; + + if (fpparam->terminator != 0xffff) + continue; + } + + fixed_mode = xnfalloc(sizeof(DisplayModeRec)); + memset(fixed_mode, 0, sizeof(*fixed_mode)); + + /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing + * block, pull the contents out using EDID macros. + */ + fixed_mode->HDisplay = _H_ACTIVE(timing_ptr); + fixed_mode->VDisplay = _V_ACTIVE(timing_ptr); + fixed_mode->HSyncStart = fixed_mode->HDisplay + + _H_SYNC_OFF(timing_ptr); + fixed_mode->HSyncEnd = fixed_mode->HSyncStart + + _H_SYNC_WIDTH(timing_ptr); + fixed_mode->HTotal = fixed_mode->HDisplay + + _H_BLANK(timing_ptr); + fixed_mode->VSyncStart = fixed_mode->VDisplay + + _V_SYNC_OFF(timing_ptr); + fixed_mode->VSyncEnd = fixed_mode->VSyncStart + + _V_SYNC_WIDTH(timing_ptr); + fixed_mode->VTotal = fixed_mode->VDisplay + + _V_BLANK(timing_ptr); + fixed_mode->Clock = _PIXEL_CLOCK(timing_ptr) / 1000; + fixed_mode->type = M_T_PREFERRED; + + xf86SetModeDefaultName(fixed_mode); + + if (pI830->debug_modes) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Found panel mode in BIOS VBT tables:\n"); + xf86PrintModeline(pScrn->scrnIndex, fixed_mode); + } + + xfree(bios); + return fixed_mode; + } + } + + xfree(bios); + return NULL; +} + +unsigned char * +i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block) +{ + unsigned char *bios; + int bdb_off; + int vbt_off; + int aim_off; + struct vbt_header *vbt; + struct aimdb_header *aimdb; + struct aimdb_block *aimdb_block; + + bios = i830_bios_get (pScrn); + if (!bios) + return NULL; + + vbt_off = INTEL_BIOS_16(0x1a); + vbt = (struct vbt_header *)(bios + vbt_off); + + aim_off = vbt->aim_offset[aim]; + if (!aim_off) + { + free (bios); + return NULL; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "aim_off %d\n", aim_off); + aimdb = (struct aimdb_header *) (bios + vbt_off + aim_off); + bdb_off = aimdb->aimdb_header_size; + while (bdb_off < aimdb->aimdb_size) + { + aimdb_block = (struct aimdb_block *) (bios + vbt_off + aim_off + bdb_off); + if (aimdb_block->aimdb_id == data_block) + { + unsigned char *aim = malloc (aimdb_block->aimdb_size + sizeof (struct aimdb_block)); + if (!aim) + { + free (bios); + return NULL; + } + memcpy (aim, aimdb_block, aimdb_block->aimdb_size + sizeof (struct aimdb_block)); + free (bios); + return aim; + } + bdb_off += aimdb_block->aimdb_size + sizeof (struct aimdb_block); + } + free (bios); + return NULL; +} +#endif diff --git a/linux-core/intel_bios.h b/linux-core/intel_bios.h new file mode 100644 index 00000000..b17856de --- /dev/null +++ b/linux-core/intel_bios.h @@ -0,0 +1,187 @@ +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#ifndef _I830_BIOS_H_ +#define _I830_BIOS_H_ + +#include "drmP.h" + +struct vbt_header { + u8 signature[20]; /**< Always starts with 'VBT$' */ + u16 version; /**< decimal */ + u16 header_size; /**< in bytes */ + u16 vbt_size; /**< in bytes */ + u8 vbt_checksum; + u8 reserved0; + u32 bdb_offset; /**< from beginning of VBT */ + u32 aim_offset[4]; /**< from beginning of VBT */ +} __attribute__((packed)); + +struct bdb_header { + u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ + u16 version; /**< decimal */ + u16 header_size; /**< in bytes */ + u16 bdb_size; /**< in bytes */ + u8 type; /* 0 == desktop, 1 == mobile */ + u8 relstage; + u8 chipset; + u8 lvds_present:1; + u8 tv_present:1; + u8 rsvd2:6; /* finish byte */ + u8 rsvd3[4]; + u8 signon[155]; + u8 copyright[61]; + u16 code_segment; + u8 dos_boot_mode; + u8 bandwidth_percent; + u8 rsvd4; + u8 resize_pci_bios; + u8 rsvd5; + u8 rsvd6[3]; + u8 panel_fitting:2; + u8 flexaim:1; + u8 msg_enable:1; + u8 clear_screen:1; + u8 color_flip:1; + u8 rsvd7:2; /* finish byte */ + u8 download_ext_vbt:1; + u8 enable_ssc:1; + u8 ssc_freq:1; + u8 enable_lfp_on_override:1; + u8 disable_ssc_ddt:1; + u8 rsvd8:3; /* finish byte */ + u8 disable_smooth_vision:1; + u8 single_dvi:1; + u8 rsvd9:6; /* finish byte */ + u8 legacy_monitor_detect:1; + u8 rsvd10:7; /* finish byte */ + u8 int_crt_support:1; + u8 int_tv_support:1; + u8 rsvd11:6; /* finish byte */ +} __attribute__((packed)); + +#define LVDS_CAP_EDID (1 << 6) +#define LVDS_CAP_DITHER (1 << 5) +#define LVDS_CAP_PFIT_AUTO_RATIO (1 << 4) +#define LVDS_CAP_PFIT_GRAPHICS_MODE (1 << 3) +#define LVDS_CAP_PFIT_TEXT_MODE (1 << 2) +#define LVDS_CAP_PFIT_GRAPHICS (1 << 1) +#define LVDS_CAP_PFIT_TEXT (1 << 0) +struct lvds_bdb_1 { + u8 id; /**< 40 */ + u16 size; + u8 panel_type; + u8 reserved0; + u16 caps; +} __attribute__((packed)); + +struct lvds_bdb_2_fp_params { + u16 x_res; + u16 y_res; + u32 lvds_reg; + u32 lvds_reg_val; + u32 pp_on_reg; + u32 pp_on_reg_val; + u32 pp_off_reg; + u32 pp_off_reg_val; + u32 pp_cycle_reg; + u32 pp_cycle_reg_val; + u32 pfit_reg; + u32 pfit_reg_val; + u16 terminator; +} __attribute__((packed)); + +struct lvds_bdb_2_fp_edid_dtd { + u16 dclk; /**< In 10khz */ + u8 hactive; + u8 hblank; + u8 high_h; /**< 7:4 = hactive 11:8, 3:0 = hblank 11:8 */ + u8 vactive; + u8 vblank; + u8 high_v; /**< 7:4 = vactive 11:8, 3:0 = vblank 11:8 */ + u8 hsync_off; + u8 hsync_pulse_width; + u8 vsync_off; + u8 high_hsync_off; /**< 7:6 = hsync off 9:8 */ + u8 h_image; + u8 v_image; + u8 max_hv; + u8 h_border; + u8 v_border; + u8 flags; +#define FP_EDID_FLAG_VSYNC_POSITIVE (1 << 2) +#define FP_EDID_FLAG_HSYNC_POSITIVE (1 << 1) +} __attribute__((packed)); + +struct lvds_bdb_2_entry { + u16 fp_params_offset; /**< From beginning of BDB */ + u8 fp_params_size; + u16 fp_edid_dtd_offset; + u8 fp_edid_dtd_size; + u16 fp_edid_pid_offset; + u8 fp_edid_pid_size; +} __attribute__((packed)); + +struct lvds_bdb_2 { + u8 id; /**< 41 */ + u16 size; + u8 table_size; /* not sure on this one */ + struct lvds_bdb_2_entry panels[16]; +} __attribute__((packed)); + +struct aimdb_header { + char signature[16]; + char oem_device[20]; + u16 aimdb_version; + u16 aimdb_header_size; + u16 aimdb_size; +} __attribute__((packed)); + +struct aimdb_block { + u8 aimdb_id; + u16 aimdb_size; +} __attribute__((packed)); + +struct vch_panel_data { + u16 fp_timing_offset; + u8 fp_timing_size; + u16 dvo_timing_offset; + u8 dvo_timing_size; + u16 text_fitting_offset; + u8 text_fitting_size; + u16 graphics_fitting_offset; + u8 graphics_fitting_size; +} __attribute__((packed)); + +struct vch_bdb_22 { + struct aimdb_block aimdb_block; + struct vch_panel_data panels[16]; +} __attribute__((packed)); + +bool intel_find_bios(struct drm_device *dev); + +#endif /* _I830_BIOS_H_ */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a7040f5b..2e7b6bd2 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -33,6 +33,8 @@ /* General customization: */ +#include "intel_bios.h" + #define DRIVER_AUTHOR "Tungsten Graphics, Inc." #define DRIVER_NAME "i915" @@ -171,6 +173,10 @@ struct drm_i915_private { struct drm_buffer_object *sarea_bo; struct drm_bo_kmap_obj sarea_kmap; + /* BIOS data */ + struct vbt_header *vbt; + struct bdb_header *bdb; + /* Register state */ u8 saveLBB; u32 saveDSPACNTR; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 53574eb7..8824b959 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -12,6 +12,7 @@ #include "drm_sarea.h" #include "i915_drm.h" #include "i915_drv.h" +#include "intel_bios.h" /** * i915_probe_agp - get AGP bootup configuration @@ -259,6 +260,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) DRM_DEBUG("Error\n"); } + ret = intel_find_bios(dev); + if (ret) { + DRM_ERROR("failed to find VBT\n"); + return -ENODEV; + } + intel_modeset_init(dev); drm_initial_config(dev, false); -- cgit v1.2.3 From 6ee0c09b0e2746022c25962cbfe655f2f1d5c53e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 9 May 2008 14:19:39 -0700 Subject: i915: use BDB TV flag for TV detection Even if the TV encoder hasn't been fused off, we may not have a TV connector on the platform. The BDB in the BIOS should give us this info in some cases. --- linux-core/intel_tv.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 89bdda1c..ba134d62 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1597,14 +1597,13 @@ intel_tv_init(struct drm_device *dev) char **tv_format_names; int i, initial_mode = 0; - /* FIXME: better TV detection and/or quirks */ -#if 0 - if (tv_priv->quirk_flag & QUIRK_IGNORE_TV) - return; -#endif if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) return; + /* Even if we have an encoder we may not have a connector */ + if (!dev_priv->bdb->int_tv_support) + return; + /* * Sanity check the TV output by checking to see if the * DAC register holds a value -- cgit v1.2.3 From dce34421947d1828ff76c001281107e937e307d4 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 9 May 2008 10:08:36 +0800 Subject: fixup i915 workqueue handling when modeset=1 Fixup workqueue creation error handling and make sure we destroy the queue on unload. --- shared-core/i915_init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 8824b959..b9e7e17b 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -256,7 +256,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) DRM_DEBUG("Enabled hardware status page\n"); dev_priv->wq = create_singlethread_workqueue("i915"); - if (dev_priv == 0) { + if (dev_priv->wq == 0) { DRM_DEBUG("Error\n"); } @@ -291,6 +291,7 @@ int i915_driver_unload(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) { drm_irq_uninstall(dev); intel_modeset_cleanup(dev); + destroy_workqueue(dev_priv->wq); } #if 0 -- cgit v1.2.3 From 8f7fc880e8bbe9e59521df707f2ddd3e80e06e6f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 12 May 2008 16:28:40 +1000 Subject: drm: fix oops on reading proc file with no master --- linux-core/drm_proc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index b6748b9b..7f185209 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -175,6 +175,9 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, return 0; } + if (!master) + return 0; + *start = &buf[offset]; *eof = 0; -- cgit v1.2.3 From 1eedeed09192738334570e13acab381441f3d817 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 12 May 2008 16:28:58 +1000 Subject: drm: masters are always authenticated --- linux-core/drm_fops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index a9f39ac5..03881ee6 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -281,6 +281,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->is_master = 1; priv->master = priv->minor->master; + priv->authenticated = 1; mutex_unlock(&dev->struct_mutex); if (dev->driver->master_create) { ret = dev->driver->master_create(dev, priv->master); -- cgit v1.2.3 From 3f66a0005c1273b0fc935b9bd62a6fabaf99c2be Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 12 May 2008 16:29:13 +1000 Subject: drm: remove root only from a lot of drm ioctls to get stuff running as non-root --- linux-core/drm_bufs.c | 2 +- linux-core/drm_drv.c | 46 +++++++++++++++++++++++----------------------- shared-core/i915_dma.c | 4 ++-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index f6ff75ab..e9052570 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -345,7 +345,7 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data, struct drm_map_list *maplist; int err; - if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP)) + if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP || map->type == _DRM_SHM)) return -EPERM; err = drm_addmap_core(dev, map->offset, map->size, map->type, diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 82a9c19d..d96b14b6 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -59,18 +59,18 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), - DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0), - DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), - DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER), - DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -103,7 +103,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ DRM_IOCTL_DEF(DRM_IOCTL_DMA, NULL, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER), #if __OS_HAS_AGP DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -124,20 +124,20 @@ 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_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - - DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_property_set_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY | DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW), + + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_HOTPLUG, drm_mode_hotplug_ioctl, DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_HOTPLUG, drm_wait_hotplug, 0), @@ -651,7 +651,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (cmd & IOC_IN) { if (copy_from_user(kdata, (void __user *)arg, _IOC_SIZE(cmd)) != 0) { - retcode = -EACCES; + retcode = -EFAULT; goto err_i1; } } @@ -671,13 +671,13 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if ((retcode == 0) && (cmd & IOC_OUT)) { if (copy_to_user((void __user *)arg, kdata, _IOC_SIZE(cmd)) != 0) - retcode = -EACCES; + retcode = -EFAULT; } err_i1: atomic_dec(&dev->ioctl_count); if (retcode) - DRM_DEBUG("ret = %d\n", retcode); + DRM_ERROR("ret = %x %d\n", nr, retcode); return retcode; } EXPORT_SYMBOL(drm_unlocked_ioctl); diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index f3a963b1..fc9e0e49 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1026,14 +1026,14 @@ static int i915_set_status_page(struct drm_device *dev, void *data, } struct drm_ioctl_desc i915_ioctls[] = { - DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -- cgit v1.2.3 From af60d87869303d7f17352c82d2fb1cebb9a8f7ff Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Mon, 12 May 2008 14:38:49 +0800 Subject: fix G33 hardware status page in modeset We need to alloc a hw status page bo for G33 if modeset is enabled since the 2D driver can't alloc gfx memory when working in drm modeset. --- shared-core/i915_dma.c | 4 ++++ shared-core/i915_drv.h | 1 + shared-core/i915_init.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index fc9e0e49..9bec85a1 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -997,6 +997,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data, DRM_ERROR("called with no initialization\n"); return -EINVAL; } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr); dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 2e7b6bd2..10e08c55 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -124,6 +124,7 @@ struct drm_i915_private { uint32_t counter; unsigned int status_gfx_addr; drm_local_map_t hws_map; + struct drm_buffer_object *hws_bo; unsigned int cpp; int use_mi_batchbuffer_start; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index b9e7e17b..7183f81f 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -252,6 +252,38 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) memset(dev_priv->hw_status_page, 0, PAGE_SIZE); I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); + } else { + size = 4 * 1024; + ret = drm_buffer_object_create(dev, size, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0x1, 0, + &dev_priv->hws_bo); + if (ret < 0) { + DRM_ERROR("Unable to allocate or pin ring buffer\n"); + return -EINVAL; + } + dev_priv->status_gfx_addr = + dev_priv->hws_bo->offset & (0x1ffff << 12); + dev_priv->hws_map.offset = dev->agp->base + + dev_priv->hws_bo->offset; + dev_priv->hws_map.size = size; + dev_priv->hws_map.type = 0; + dev_priv->hws_map.flags = 0; + dev_priv->hws_map.mtrr = 0; + + drm_core_ioremap(&dev_priv->hws_map, dev); + if (dev_priv->hws_map.handle == NULL) { + dev_priv->status_gfx_addr = 0; + DRM_ERROR("can not ioremap virtual addr" + " for G33 hw status page\n"); + return -ENOMEM; + } + dev_priv->hw_status_page = dev_priv->hws_map.handle; + memset(dev_priv->hw_status_page, 0, size); + I915_WRITE(I915REG_HWS_PGA, dev_priv->status_gfx_addr); } DRM_DEBUG("Enabled hardware status page\n"); @@ -324,6 +356,7 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->status_gfx_addr) { dev_priv->status_gfx_addr = 0; drm_core_ioremapfree(&dev_priv->hws_map, dev); + drm_bo_usage_deref_unlocked(&dev_priv->hws_bo); I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); } -- cgit v1.2.3 From f1b9bbe2b8f2339359afa39bf27702eca6f6c975 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Mon, 12 May 2008 16:14:38 +0800 Subject: modeset init code cleanup moving modeset init code into one function and correct error handling druing i915 init --- shared-core/i915_init.c | 331 ++++++++++++++++++++++++++++-------------------- 1 file changed, 197 insertions(+), 134 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 7183f81f..22577c7f 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -99,6 +99,181 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, return 0; } +int i915_load_modeset_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long agp_size, prealloc_size; + int size, ret = 0; + + i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); + printk("setting up %ld bytes of VRAM space\n", prealloc_size); + printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); + + drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1); + drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, + (agp_size - prealloc_size) >> PAGE_SHIFT, 1); + I915_WRITE(LP_RING + RING_LEN, 0); + I915_WRITE(LP_RING + RING_HEAD, 0); + I915_WRITE(LP_RING + RING_TAIL, 0); + + size = PRIMARY_RINGBUFFER_SIZE; + ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0x1, 0, + &dev_priv->ring_buffer); + if (ret < 0) { + DRM_ERROR("Unable to allocate or pin ring buffer\n"); + goto clean_mm; + } + + /* remap the buffer object properly */ + dev_priv->ring.Start = dev_priv->ring_buffer->offset; + dev_priv->ring.End = dev_priv->ring.Start + size; + dev_priv->ring.Size = size; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; + + /* FIXME: need wrapper with PCI mem checks */ + ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, + (void **) &dev_priv->ring.virtual_start); + if (ret) { + DRM_ERROR("error mapping ring buffer: %d\n", ret); + goto destroy_ringbuffer; + } + + DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start, + dev_priv->ring.virtual_start, dev_priv->ring.Size); + + memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); + I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); + I915_WRITE(LP_RING + RING_LEN, + ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | + (RING_NO_REPORT | RING_VALID)); + + /* We are using separate values as placeholders for mechanisms for + * private backbuffer/depthbuffer usage. + */ + dev_priv->use_mi_batchbuffer_start = 0; + + /* Allow hardware batchbuffers unless told otherwise. + */ + dev_priv->allow_batchbuffer = 1; + + /* Program Hardware Status Page */ + if (!IS_G33(dev)) { + dev_priv->status_page_dmah = + drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); + + if (!dev_priv->status_page_dmah) { + DRM_ERROR("Can not allocate hardware status page\n"); + ret = -ENOMEM; + goto destroy_ringbuffer; + } + dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + + I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); + } else { + size = 4 * 1024; + ret = drm_buffer_object_create(dev, size, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0x1, 0, + &dev_priv->hws_bo); + if (ret < 0) { + DRM_ERROR("Unable to allocate or pin hw status page\n"); + ret = -EINVAL; + goto destroy_ringbuffer; + } + + dev_priv->status_gfx_addr = + dev_priv->hws_bo->offset & (0x1ffff << 12); + dev_priv->hws_map.offset = dev->agp->base + + dev_priv->hws_bo->offset; + dev_priv->hws_map.size = size; + dev_priv->hws_map.type= 0; + dev_priv->hws_map.flags= 0; + dev_priv->hws_map.mtrr = 0; + + drm_core_ioremap(&dev_priv->hws_map, dev); + if (dev_priv->hws_map.handle == NULL) { + dev_priv->status_gfx_addr = 0; + DRM_ERROR("can not ioremap virtual addr for" + "G33 hw status page\n"); + ret = -ENOMEM; + goto destroy_hws; + } + dev_priv->hw_status_page = dev_priv->hws_map.handle; + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + I915_WRITE(I915REG_HWS_PGA, dev_priv->status_gfx_addr); + } + DRM_DEBUG("Enabled hardware status page\n"); + + dev_priv->wq = create_singlethread_workqueue("i915"); + if (dev_priv->wq == 0) { + DRM_DEBUG("Error\n"); + ret = -EINVAL; + goto destroy_hws; + } + + ret = intel_find_bios(dev); + if (ret) { + DRM_ERROR("failed to find VBT\n"); + ret = -ENODEV; + goto destroy_wq; + } + + intel_modeset_init(dev); + drm_initial_config(dev, false); + + drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); + drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); + + dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); + if (!dev->devname) { + ret = -ENOMEM; + goto modeset_cleanup; + } + + ret = drm_irq_install(dev); + if (ret) { + kfree(dev->devname); + goto modeset_cleanup; + } + return 0; + +modeset_cleanup: + intel_modeset_cleanup(dev); +destroy_wq: + destroy_workqueue(dev_priv->wq); +destroy_hws: + if (!IS_G33(dev)) { + if (dev_priv->status_page_dmah) + drm_pci_free(dev, dev_priv->status_page_dmah); + } else { + if (dev_priv->hws_map.handle) + drm_core_ioremapfree(&dev_priv->hws_map, dev); + if (dev_priv->hws_bo) + drm_bo_usage_deref_unlocked(&dev_priv->hws_bo); + } + I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); +destroy_ringbuffer: + if (dev_priv->ring.virtual_start) + drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, + dev_priv->ring.virtual_start); + if (dev_priv->ring_buffer) + drm_bo_usage_deref_unlocked(&dev_priv->ring_buffer); +clean_mm: + drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1); + drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1); + return ret; +} + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -113,8 +288,7 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv; - unsigned long agp_size, prealloc_size; - int size, ret; + int ret = 0; dev_priv = drm_alloc(sizeof(struct drm_i915_private), DRM_MEM_DRIVER); if (dev_priv == NULL) @@ -156,16 +330,18 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) drm_get_resource_start(dev, 0) & 0xff000000; } else { DRM_ERROR("Unable to find MMIO registers\n"); - return -ENODEV; + ret = -ENODEV; + goto free_priv; } DRM_DEBUG("fb_base: 0x%08lx\n", dev->mode_config.fb_base); ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen, - _DRM_REGISTERS, _DRM_KERNEL|_DRM_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map); + _DRM_REGISTERS, _DRM_KERNEL|_DRM_READ_ONLY|_DRM_DRIVER, + &dev_priv->mmio_map); if (ret != 0) { DRM_ERROR("Cannot add mapping for MMIO registers\n"); - return ret; + goto free_priv; } #ifdef __linux__ @@ -177,141 +353,28 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* * Initialize the memory manager for local and AGP space */ - drm_bo_driver_init(dev); + ret = drm_bo_driver_init(dev); + if (ret) { + DRM_ERROR("fail to init memory manager for local & AGP space\n"); + goto out_rmmap; + } if (drm_core_check_feature(dev, DRIVER_MODESET)) { - i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); - printk("setting up %ld bytes of VRAM space\n", prealloc_size); - printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); - drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1); - drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT, 1); - - I915_WRITE(LP_RING + RING_LEN, 0); - I915_WRITE(LP_RING + RING_HEAD, 0); - I915_WRITE(LP_RING + RING_TAIL, 0); - - size = PRIMARY_RINGBUFFER_SIZE; - ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, - DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0x1, 0, - &dev_priv->ring_buffer); + ret = i915_load_modeset_init(dev); if (ret < 0) { - DRM_ERROR("Unable to allocate or pin ring buffer\n"); - return -EINVAL; + DRM_ERROR("failed to init modeset\n"); + goto driver_fini; } - - /* remap the buffer object properly */ - dev_priv->ring.Start = dev_priv->ring_buffer->offset; - dev_priv->ring.End = dev_priv->ring.Start + size; - dev_priv->ring.Size = size; - dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; - - /* FIXME: need wrapper with PCI mem checks */ - ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem, - (void **) &dev_priv->ring.virtual_start); - if (ret) - DRM_ERROR("error mapping ring buffer: %d\n", ret); - - DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start, - dev_priv->ring.virtual_start, dev_priv->ring.Size); - - // - - memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); - - I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); - I915_WRITE(LP_RING + RING_LEN, - ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | - (RING_NO_REPORT | RING_VALID)); - - /* We are using separate values as placeholders for mechanisms for - * private backbuffer/depthbuffer usage. - */ - dev_priv->use_mi_batchbuffer_start = 0; - - /* Allow hardware batchbuffers unless told otherwise. - */ - dev_priv->allow_batchbuffer = 1; - - /* Program Hardware Status Page */ - if (!IS_G33(dev)) { - dev_priv->status_page_dmah = - drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); - - if (!dev_priv->status_page_dmah) { - dev->dev_private = (void *)dev_priv; - i915_dma_cleanup(dev); - DRM_ERROR("Can not allocate hardware status page\n"); - return -ENOMEM; - } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - - I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); - } else { - size = 4 * 1024; - ret = drm_buffer_object_create(dev, size, - drm_bo_type_kernel, - DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0x1, 0, - &dev_priv->hws_bo); - if (ret < 0) { - DRM_ERROR("Unable to allocate or pin ring buffer\n"); - return -EINVAL; - } - dev_priv->status_gfx_addr = - dev_priv->hws_bo->offset & (0x1ffff << 12); - dev_priv->hws_map.offset = dev->agp->base + - dev_priv->hws_bo->offset; - dev_priv->hws_map.size = size; - dev_priv->hws_map.type = 0; - dev_priv->hws_map.flags = 0; - dev_priv->hws_map.mtrr = 0; - - drm_core_ioremap(&dev_priv->hws_map, dev); - if (dev_priv->hws_map.handle == NULL) { - dev_priv->status_gfx_addr = 0; - DRM_ERROR("can not ioremap virtual addr" - " for G33 hw status page\n"); - return -ENOMEM; - } - dev_priv->hw_status_page = dev_priv->hws_map.handle; - memset(dev_priv->hw_status_page, 0, size); - I915_WRITE(I915REG_HWS_PGA, dev_priv->status_gfx_addr); - } - DRM_DEBUG("Enabled hardware status page\n"); - - dev_priv->wq = create_singlethread_workqueue("i915"); - if (dev_priv->wq == 0) { - DRM_DEBUG("Error\n"); - } - - ret = intel_find_bios(dev); - if (ret) { - DRM_ERROR("failed to find VBT\n"); - return -ENODEV; - } - - intel_modeset_init(dev); - drm_initial_config(dev, false); - - drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); - drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); - - dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); - if (!dev->devname) - return -ENOMEM; - - drm_irq_install(dev); } - return 0; + +driver_fini: + drm_bo_driver_finish(dev); +out_rmmap: + drm_rmmap(dev, dev_priv->mmio_map); +free_priv: + drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER); + return ret; } int i915_driver_unload(struct drm_device *dev) -- cgit v1.2.3 From b2dee13f5d7209b62c5e9ba8cd059717a8302fec Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 9 May 2008 10:15:17 +0800 Subject: free dummy read page if fail to init mm Since drm_bo_driver_init will be called in driver_load, we need to free what it alloced when error to avoid memory leak. --- linux-core/drm_bo.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 301f946f..0470825b 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2406,8 +2406,14 @@ int drm_bo_driver_init(struct drm_device *dev) * Other types need to be driver / IOCTL initialized. */ ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0, 1); - if (ret) + if (ret) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + ClearPageReserved(bm->dummy_read_page); +#endif + __free_page(bm->dummy_read_page); + bm->dummy_read_page = NULL; goto out_unlock; + } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); -- cgit v1.2.3 From a51e38548cfdece2978e9b5f0d6f0467ba7a7272 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 9 May 2008 10:06:17 +0800 Subject: fix kernel oops when removing fb drm_crtc->fb may point to NULL, f.e X server will allocate a new fb and assign it to the CRTC at startup, when X server exits, it will destroy the allocated fb, making drm_crtc->fb points to NULL. --- linux-core/drmP.h | 2 +- linux-core/drm_crtc.c | 2 +- linux-core/intel_drv.h | 2 +- linux-core/intel_fb.c | 4 +--- linux-core/radeon_ms_fb.c | 2 +- shared-core/radeon_ms.h | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 52d2782a..60ae018e 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -744,7 +744,7 @@ struct drm_driver { /* FB routines, if present */ int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); - int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc); + int (*fb_remove)(struct drm_device *dev, struct drm_framebuffer *fb); int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); /* Master routines */ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 2bc1c4e3..c011db30 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1095,7 +1095,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) if (fb->bo->type != drm_bo_type_kernel) drm_framebuffer_destroy(fb); else - dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); + dev->driver->fb_remove(dev, fb); } list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 6b89c000..e97117de 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -91,7 +91,7 @@ extern int intel_sdvo_supports_hotplug(struct drm_output *output); extern void intel_sdvo_set_hotplug(struct drm_output *output, int enable); extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); -extern int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc); +extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 50c24a75..9934e3af 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -767,9 +767,8 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_outp } EXPORT_SYMBOL(intelfb_probe); -int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) +int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) { - struct drm_framebuffer *fb = crtc->fb; struct fb_info *info; if (!fb) @@ -784,7 +783,6 @@ int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc) drm_framebuffer_destroy(fb); framebuffer_release(info); } - crtc->fb = NULL; return 0; } EXPORT_SYMBOL(intelfb_remove); diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index ae4f2da5..082279ec 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -438,7 +438,7 @@ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_out } EXPORT_SYMBOL(radeonfb_probe); -int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc) +int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *kern_fb) { struct drm_radeon_private *dev_priv = dev->dev_private; struct amd_fb *fb = dev_priv->fb; diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h index 1fdcd0a1..f3bbc9a3 100644 --- a/shared-core/radeon_ms.h +++ b/shared-core/radeon_ms.h @@ -436,7 +436,7 @@ int r3xx_fence_types(struct drm_buffer_object *bo, /* radeon_ms_fb.c */ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); -int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc); +int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); /* radeon_ms_gpu.c */ int radeon_ms_gpu_initialize(struct drm_device *dev); -- cgit v1.2.3 From d32ce7f621c0d8e42cdf88ce6f1d15638a3d34b7 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 12 May 2008 15:47:19 -0700 Subject: i915: TV hotplug fixes In order to avoid recursive ->detect->interrupt->detect->interrupt->... we need to disable TV hotplug interrupts in intel_tv.c:intel_tv_detect_type. We also need to enable the TV interrupt detection and hotplug sequence properly in i915_irq.c. --- linux-core/intel_tv.c | 27 +++++++++++++++++++++++---- shared-core/i915_irq.c | 17 +++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index ba134d62..865e27b9 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1360,11 +1360,21 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_output *intel_output = output->driver_private; + u32 pipeastat, pipeastat_save; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; int type = ConnectorUnknown; tv_dac = I915_READ(TV_DAC); + + /* Disable TV interrupts around load detect or we'll recurse */ + pipeastat = I915_READ(I915REG_PIPEASTAT); + pipeastat_save = pipeastat; + pipeastat &= ~I915_HOTPLUG_INTERRUPT_ENABLE; + pipeastat &= ~I915_HOTPLUG_TV_INTERRUPT_ENABLE; + I915_WRITE(I915REG_PIPEASTAT, pipeastat | I915_HOTPLUG_TV_CLEAR | + I915_HOTPLUG_CLEAR); + /* * Detect TV by polling) */ @@ -1412,6 +1422,10 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) type = -1; } + /* Restore interrupt config */ + I915_WRITE(I915REG_PIPEASTAT, pipeastat_save | I915_HOTPLUG_TV_CLEAR | + I915_HOTPLUG_CLEAR); + return type; } @@ -1434,10 +1448,15 @@ intel_tv_detect(struct drm_output *output) mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); - crtc = intel_get_load_detect_pipe(output, &mode, &dpms_mode); - if (crtc) { - type = intel_tv_detect_type(crtc, output); - intel_release_load_detect_pipe(output, dpms_mode); + if (output->crtc) { + type = intel_tv_detect_type(output->crtc, output); + } else { + crtc = intel_get_load_detect_pipe(output, &mode, &dpms_mode); + if (crtc) { + type = intel_tv_detect_type(crtc, output); + intel_release_load_detect_pipe(output, dpms_mode); + } else + type = -1; } if (type != tv_priv->type) { diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 0ee0c444..4aef568e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -471,7 +471,6 @@ static void i915_hotplug_tv(struct drm_device *dev) if (iout == 0) goto unlock; - /* may need to I915_WRITE(TVDAC, 1<<31) to ack the interrupt */ status = output->funcs->detect(output); drm_hotplug_stage_two(dev, output, status == output_status_connected ? 1 : 0); @@ -631,7 +630,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; u32 iir; - u32 pipea_stats, pipeb_stats; + u32 pipea_stats = 0, pipeb_stats, tvdac; int hotplug = 0; int vblank = 0; @@ -672,10 +671,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } /* This is a global event, and not a pipe A event */ - if ((pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) || - (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS)) + if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) hotplug = 1; + if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS) { + hotplug = 1; + /* Toggle hotplug detection to clear hotplug status */ + tvdac = I915_READ(TV_DAC); + I915_WRITE(TV_DAC, tvdac & ~TVDAC_STATE_CHG_EN); + I915_WRITE(TV_DAC, tvdac | TVDAC_STATE_CHG_EN); + } + I915_WRITE(I915REG_PIPEASTAT, pipea_stats); } @@ -1001,6 +1007,9 @@ void i915_enable_interrupt (struct drm_device *dev) I915_WRITE(SDVOB, I915_READ(SDVOB) | SDVO_INTERRUPT_ENABLE); I915_WRITE(SDVOC, I915_READ(SDVOC) | SDVO_INTERRUPT_ENABLE); + + /* TV */ + I915_WRITE(TV_DAC, I915_READ(TV_DAC) | TVDAC_STATE_CHG_EN); } else { /* DVO ???? */ } -- cgit v1.2.3 From 5be53a0881c5248146c585015bf60bb2958773af Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 13 May 2008 09:24:47 +0200 Subject: i915: execbuf now works without i915_dma_init being called --- shared-core/i915_dma.c | 9 +++++++-- shared-core/i915_init.c | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 9bec85a1..498620f5 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -197,7 +197,9 @@ static int i915_initialize(struct drm_device * dev, #ifdef I915_HAVE_BUFFER - dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; + } #endif if (!dev_priv->ring.Size) { @@ -260,8 +262,11 @@ static int i915_initialize(struct drm_device * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); } DRM_DEBUG("Enabled hardware status page\n"); + #ifdef I915_HAVE_BUFFER - mutex_init(&dev_priv->cmdbuf_mutex); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + mutex_init(&dev_priv->cmdbuf_mutex); + } #endif if (init->func == I915_INIT_DMA2) { diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 22577c7f..c0ca226a 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -155,10 +155,14 @@ int i915_load_modeset_init(struct drm_device *dev) * private backbuffer/depthbuffer usage. */ dev_priv->use_mi_batchbuffer_start = 0; + if (IS_I965G(dev)) /* 965 doesn't support older method */ + dev_priv->use_mi_batchbuffer_start = 1; /* Allow hardware batchbuffers unless told otherwise. */ dev_priv->allow_batchbuffer = 1; + dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; + mutex_init(&dev_priv->cmdbuf_mutex); /* Program Hardware Status Page */ if (!IS_G33(dev)) { -- cgit v1.2.3 From ee631e1b8604a176b9118396998ce5bfc6475dae Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 13 May 2008 14:44:17 -0700 Subject: i915: register definition & header file cleanup It would be nice if one day the DRM driver was the canonical source for register definitions and core macros. To that end, this patch cleans things up quite a bit, removing redundant definitions (some with different names referring to the same register) and generally tidying up the header file. --- linux-core/i915_drv.c | 59 +- linux-core/i915_fence.c | 2 +- linux-core/intel_display.c | 52 +- linux-core/intel_lvds.c | 12 +- linux-core/intel_tv.c | 18 +- shared-core/i915_dma.c | 14 +- shared-core/i915_drv.h | 1531 ++++++++++++++++++-------------------------- shared-core/i915_init.c | 25 +- shared-core/i915_irq.c | 160 ++--- 9 files changed, 782 insertions(+), 1091 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index ec91fb93..27c239d0 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -67,11 +67,6 @@ static struct drm_bo_driver i915_bo_driver = { }; #endif -enum pipe { - PIPE_A = 0, - PIPE_B, -}; - static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -308,13 +303,13 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE); dev_priv->saveDSPASIZE = I915_READ(DSPASIZE); dev_priv->saveDSPAPOS = I915_READ(DSPAPOS); - dev_priv->saveDSPABASE = I915_READ(DSPABASE); + dev_priv->saveDSPAADDR = I915_READ(DSPAADDR); if (IS_I965G(dev)) { dev_priv->saveDSPASURF = I915_READ(DSPASURF); dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); } i915_save_palette(dev, PIPE_A); - dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT); + dev_priv->savePIPEASTAT = I915_READ(PIPEASTAT); /* Pipe & plane B info */ dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); @@ -336,13 +331,13 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE); dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); - dev_priv->saveDSPBBASE = I915_READ(DSPBBASE); + dev_priv->saveDSPBADDR = I915_READ(DSPBADDR); if (IS_I965GM(dev) || IS_IGD_GM(dev)) { dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); } i915_save_palette(dev, PIPE_B); - dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT); + dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); /* CRT state */ dev_priv->saveADPA = I915_READ(ADPA); @@ -357,9 +352,9 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) dev_priv->saveLVDS = I915_READ(LVDS); if (!IS_I830(dev) && !IS_845G(dev)) dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); - dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON); - dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF); - dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); + dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS); + dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); + dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); /* FIXME: save TV & SDVO state */ @@ -370,19 +365,19 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); /* Interrupt state */ - dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R); - dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R); - dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R); + dev_priv->saveIIR = I915_READ(IIR); + dev_priv->saveIER = I915_READ(IER); + dev_priv->saveIMR = I915_READ(IMR); /* VGA state */ - dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); - dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); - dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); + dev_priv->saveVGA0 = I915_READ(VGA0); + dev_priv->saveVGA1 = I915_READ(VGA1); + dev_priv->saveVGA_PD = I915_READ(VGA_PD); dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); /* Clock gating state */ dev_priv->saveD_STATE = I915_READ(D_STATE); - dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); + dev_priv->saveCG_2D_DIS = I915_READ(CG_2D_DIS); /* Cache mode state */ dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); @@ -419,6 +414,8 @@ static int i915_resume(struct drm_device *dev) if (pci_enable_device(dev->pdev)) return -1; + DRM_INFO("resuming i915\n"); + pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); I915_WRITE(DSPARB, dev_priv->saveDSPARB); @@ -452,7 +449,7 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); - I915_WRITE(DSPABASE, dev_priv->saveDSPABASE); + I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR); I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); if (IS_I965G(dev)) { I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); @@ -464,10 +461,11 @@ static int i915_resume(struct drm_device *dev) i915_restore_palette(dev, PIPE_A); /* Enable the plane */ I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); - I915_WRITE(DSPABASE, I915_READ(DSPABASE)); + I915_WRITE(DSPAADDR, I915_READ(DSPAADDR)); /* Pipe & plane B info */ if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { + DRM_INFO("restoring DPLL_B: 0x%08x\n", dev_priv->saveDPLL_B); I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & ~DPLL_VCO_ENABLE); udelay(150); @@ -476,6 +474,7 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(FPB1, dev_priv->saveFPB1); /* Actually enable it */ I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); + DRM_INFO("restoring DPLL_B: 0x%08x\n", dev_priv->saveDPLL_B); udelay(150); if (IS_I965G(dev)) I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); @@ -494,7 +493,7 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); - I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE); + I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR); I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); if (IS_I965G(dev)) { I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); @@ -506,7 +505,7 @@ static int i915_resume(struct drm_device *dev) i915_restore_palette(dev, PIPE_B); /* Enable the plane */ I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); - I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); + I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); /* CRT state */ I915_WRITE(ADPA, dev_priv->saveADPA); @@ -521,9 +520,9 @@ static int i915_resume(struct drm_device *dev) I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); - I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON); - I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF); - I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); + I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS); + I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); + I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); /* FIXME: restore TV & SDVO state */ @@ -536,14 +535,14 @@ static int i915_resume(struct drm_device *dev) /* VGA state */ I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); - I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0); - I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1); - I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); + I915_WRITE(VGA0, dev_priv->saveVGA0); + I915_WRITE(VGA1, dev_priv->saveVGA1); + I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); udelay(150); /* Clock gating state */ I915_WRITE (D_STATE, dev_priv->saveD_STATE); - I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); + I915_WRITE (CG_2D_DIS, dev_priv->saveCG_2D_DIS); /* Cache mode state */ I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 3ca8403f..436b7e1f 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -46,7 +46,7 @@ static inline void i915_initiate_rwflush(struct drm_i915_private *dev_priv, dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fc->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); - I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); + I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); dev_priv->flush_pending = 1; fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW; } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index f66570c2..273f76d0 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -367,7 +367,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) struct intel_crtc *intel_crtc = crtc->driver_private; int pipe = intel_crtc->pipe; unsigned long Start, Offset; - int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE); + int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; @@ -456,7 +456,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) int pipe = intel_crtc->pipe; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; - int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE; + int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR; int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; u32 temp; bool enabled; @@ -617,16 +617,16 @@ static int intel_get_core_clock_speed(struct drm_device *dev) else if (IS_I915GM(dev)) { u16 gcfgc = 0; - pci_read_config_word(dev->pdev, I915_GCFGC, &gcfgc); + pci_read_config_word(dev->pdev, GCFGC, &gcfgc); - if (gcfgc & I915_LOW_FREQUENCY_ENABLE) + if (gcfgc & GC_LOW_FREQUENCY_ENABLE) return 133000; else { - switch (gcfgc & I915_DISPLAY_CLOCK_MASK) { - case I915_DISPLAY_CLOCK_333_MHZ: + switch (gcfgc & GC_DISPLAY_CLOCK_MASK) { + case GC_DISPLAY_CLOCK_333_MHZ: return 333000; default: - case I915_DISPLAY_CLOCK_190_200_MHZ: + case GC_DISPLAY_CLOCK_190_200_MHZ: return 190000; } } @@ -635,20 +635,20 @@ static int intel_get_core_clock_speed(struct drm_device *dev) else if (IS_I855(dev)) { #if 0 PCITAG bridge = pciTag(0, 0, 0); /* This is always the host bridge */ - u16 hpllcc = pciReadWord(bridge, I855_HPLLCC); + u16 hpllcc = pciReadWord(bridge, HPLLCC); #endif u16 hpllcc = 0; /* Assume that the hardware is in the high speed state. This * should be the default. */ - switch (hpllcc & I855_CLOCK_CONTROL_MASK) { - case I855_CLOCK_133_200: - case I855_CLOCK_100_200: + switch (hpllcc & GC_CLOCK_CONTROL_MASK) { + case GC_CLOCK_133_200: + case GC_CLOCK_100_200: return 200000; - case I855_CLOCK_166_250: + case GC_CLOCK_166_250: return 250000; - case I855_CLOCK_100_133: + case GC_CLOCK_100_133: return 133000; } } else /* 852, 830 */ @@ -961,24 +961,6 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } } -#define CURSOR_A_CONTROL 0x70080 -#define CURSOR_A_BASE 0x70084 -#define CURSOR_A_POSITION 0x70088 - -#define CURSOR_B_CONTROL 0x700C0 -#define CURSOR_B_BASE 0x700C4 -#define CURSOR_B_POSITION 0x700C8 - -#define CURSOR_MODE_DISABLE 0x00 -#define CURSOR_MODE_64_32B_AX 0x07 -#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) -#define MCURSOR_GAMMA_ENABLE (1 << 26) - -#define CURSOR_POS_MASK 0x007FF -#define CURSOR_POS_SIGN 0x8000 -#define CURSOR_X_SHIFT 0 -#define CURSOR_Y_SHIFT 16 - static int intel_crtc_cursor_set(struct drm_crtc *crtc, struct drm_buffer_object *bo, uint32_t width, uint32_t height) @@ -987,8 +969,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = crtc->driver_private; int pipe = intel_crtc->pipe; - uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL; - uint32_t base = (pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE; + uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; + uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; uint32_t temp; size_t addr; @@ -1063,8 +1045,8 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); adder = intel_crtc->cursor_addr; - I915_WRITE((pipe == 0) ? CURSOR_A_POSITION : CURSOR_B_POSITION, temp); - I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder); + I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); + I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder); return 0; } diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 92a1d600..1da95e18 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -106,10 +106,10 @@ static void intel_lvds_save(struct drm_output *output) struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->savePP_ON = I915_READ(LVDSPP_ON); - dev_priv->savePP_OFF = I915_READ(LVDSPP_OFF); + dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS); + dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS); dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); - dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); + dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & BACKLIGHT_DUTY_CYCLE_MASK); @@ -128,9 +128,9 @@ static void intel_lvds_restore(struct drm_output *output) struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); - I915_WRITE(LVDSPP_ON, dev_priv->savePP_ON); - I915_WRITE(LVDSPP_OFF, dev_priv->savePP_OFF); - I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); + I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON); + I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF); + I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) intel_lvds_set_power(dev, true); diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 865e27b9..42f4b10b 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1012,7 +1012,7 @@ intel_tv_restore(struct drm_output *output) int pipeconf = I915_READ(pipeconf_reg); int dspcntr = I915_READ(dspcntr_reg); int dspbase_reg = (intel_crtc->plane == 0) ? - DSPABASE : DSPBBASE; + DSPAADDR : DSPBADDR; /* Pipe must be off here */ I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); /* Flush the plane changes */ @@ -1277,7 +1277,7 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, int pipeconf = I915_READ(pipeconf_reg); int dspcntr = I915_READ(dspcntr_reg); int dspbase_reg = (intel_crtc->plane == 0) ? - DSPABASE : DSPBBASE; + DSPAADDR : DSPBADDR; int xpos = 0x0, ypos = 0x0; unsigned int xsize, ysize; /* Pipe must be off here */ @@ -1368,12 +1368,12 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) tv_dac = I915_READ(TV_DAC); /* Disable TV interrupts around load detect or we'll recurse */ - pipeastat = I915_READ(I915REG_PIPEASTAT); + pipeastat = I915_READ(PIPEASTAT); pipeastat_save = pipeastat; - pipeastat &= ~I915_HOTPLUG_INTERRUPT_ENABLE; - pipeastat &= ~I915_HOTPLUG_TV_INTERRUPT_ENABLE; - I915_WRITE(I915REG_PIPEASTAT, pipeastat | I915_HOTPLUG_TV_CLEAR | - I915_HOTPLUG_CLEAR); + pipeastat &= ~PIPE_HOTPLUG_INTERRUPT_ENABLE; + pipeastat &= ~PIPE_HOTPLUG_TV_INTERRUPT_ENABLE; + I915_WRITE(PIPEASTAT, pipeastat | PIPE_HOTPLUG_TV_INTERRUPT_STATUS | + PIPE_HOTPLUG_INTERRUPT_STATUS); /* * Detect TV by polling) @@ -1423,8 +1423,8 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) } /* Restore interrupt config */ - I915_WRITE(I915REG_PIPEASTAT, pipeastat_save | I915_HOTPLUG_TV_CLEAR | - I915_HOTPLUG_CLEAR); + I915_WRITE(PIPEASTAT, pipeastat_save | PIPE_HOTPLUG_TV_INTERRUPT_STATUS | + PIPE_HOTPLUG_INTERRUPT_STATUS); return type; } diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 9bec85a1..e1417388 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -40,11 +40,11 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_ring_buffer *ring = &(dev_priv->ring); - u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; int i; for (i = 0; i < 10000; i++) { - ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->Size; @@ -71,8 +71,8 @@ void i915_kernel_lost_context(struct drm_device * dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) return; - ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR; + ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->Size; @@ -510,7 +510,7 @@ void i915_emit_breadcrumb(struct drm_device *dev) master_priv->sarea_priv->last_enqueue = dev_priv->counter; BEGIN_LP_RING(4); - OUT_RING(CMD_STORE_DWORD_IDX); + OUT_RING(MI_STORE_DWORD_INDEX); OUT_RING(20); OUT_RING(dev_priv->counter); OUT_RING(0); @@ -521,7 +521,7 @@ void i915_emit_breadcrumb(struct drm_device *dev) int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t flush_cmd = CMD_MI_FLUSH; + uint32_t flush_cmd = MI_FLUSH; RING_LOCALS; flush_cmd |= flush; @@ -1022,7 +1022,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, dev_priv->hw_status_page = dev_priv->hws_map.handle; memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(I915REG_HWS_PGA, dev_priv->status_gfx_addr); + I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n", dev_priv->status_gfx_addr); DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 10e08c55..84cc60f3 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -69,6 +69,11 @@ #endif #define DRIVER_PATCHLEVEL 0 +enum pipe { + PIPE_A = 0, + PIPE_B, +}; + #ifdef I915_HAVE_BUFFER #define I915_MAX_VALIDATE_BUFFERS 4096 struct drm_i915_validate_buffer; @@ -202,7 +207,7 @@ struct drm_i915_private { u32 saveDSPASTRIDE; u32 saveDSPASIZE; u32 saveDSPAPOS; - u32 saveDSPABASE; + u32 saveDSPAADDR; u32 saveDSPASURF; u32 saveDSPATILEOFF; u32 savePFIT_PGM_RATIOS; @@ -223,24 +228,24 @@ struct drm_i915_private { u32 saveDSPBSTRIDE; u32 saveDSPBSIZE; u32 saveDSPBPOS; - u32 saveDSPBBASE; + u32 saveDSPBADDR; u32 saveDSPBSURF; u32 saveDSPBTILEOFF; - u32 saveVCLK_DIVISOR_VGA0; - u32 saveVCLK_DIVISOR_VGA1; - u32 saveVCLK_POST_DIV; + u32 saveVGA0; + u32 saveVGA1; + u32 saveVGA_PD; u32 saveVGACNTRL; u32 saveADPA; u32 saveLVDS; - u32 saveLVDSPP_ON; - u32 saveLVDSPP_OFF; + u32 savePP_ON_DELAYS; + u32 savePP_OFF_DELAYS; u32 saveDVOA; u32 saveDVOB; u32 saveDVOC; u32 savePP_ON; u32 savePP_OFF; u32 savePP_CONTROL; - u32 savePP_CYCLE; + u32 savePP_DIVISOR; u32 savePFIT_CONTROL; u32 save_palette_a[256]; u32 save_palette_b[256]; @@ -253,7 +258,7 @@ struct drm_i915_private { u32 saveIMR; u32 saveCACHE_MODE_0; u32 saveD_STATE; - u32 saveDSPCLK_GATE_D; + u32 saveCG_2D_DIS; u32 saveMI_ARB_STATE; u32 saveSWF0[16]; u32 saveSWF1[16]; @@ -382,6 +387,8 @@ extern void intel_modeset_cleanup(struct drm_device *dev); #define I915_VERBOSE 0 +#define PRIMARY_RINGBUFFER_SIZE (128*1024) + #define RING_LOCALS unsigned int outring, ringmask, outcount; \ volatile char *virt; @@ -409,10 +416,14 @@ extern void intel_modeset_cleanup(struct drm_device *dev); if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \ dev_priv->ring.tail = outring; \ dev_priv->ring.space -= outcount * 4; \ - I915_WRITE(LP_RING + RING_TAIL, outring); \ + I915_WRITE(PRB0_TAIL, outring); \ } while(0) -#define MI_NOOP (0x00 << 23) +#define BREADCRUMB_BITS 31 +#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) + +#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) +#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); @@ -437,8 +448,20 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4) #define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4) -/* Extended config space */ -#define LBB 0xf4 +/* PCI config space */ + +#define HPLLCC 0xc0 /* 855 only */ +#define GC_CLOCK_CONTROL_MASK (3 << 0) +#define GC_CLOCK_133_200 (0 << 0) +#define GC_CLOCK_100_200 (1 << 0) +#define GC_CLOCK_100_133 (2 << 0) +#define GC_CLOCK_166_250 (3 << 0) +#define GCFGC 0xf0 /* 915+ only */ +#define GC_LOW_FREQUENCY_ENABLE (1 << 7) +#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) +#define GC_DISPLAY_CLOCK_333_MHZ (4 << 4) +#define GC_DISPLAY_CLOCK_MASK (7 << 4) +#define LBB 0xf4 /* VGA stuff */ @@ -481,32 +504,146 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define VGA_CR_INDEX_CGA 0x3d4 #define VGA_CR_DATA_CGA 0x3d5 -#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) -#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) -#define CMD_REPORT_HEAD (7<<23) -#define CMD_STORE_DWORD_IMM ((0x20<<23) | (0x1 << 22) | 0x1) -#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) -#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) - -#define CMD_MI_FLUSH (0x04 << 23) -#define MI_NO_WRITE_FLUSH (1 << 2) -#define MI_READ_FLUSH (1 << 0) -#define MI_EXE_FLUSH (1 << 1) -#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ -#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ - -/* Packet to load a register value from the ring/batch command stream: +/* + * Memory interface instructions used by the kernel + */ +#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags)) + +#define MI_NOOP MI_INSTR(0, 0) +#define MI_USER_INTERRUPT MI_INSTR(0x02, 0) +#define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0) +#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) +#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) +#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) +#define MI_FLUSH MI_INSTR(0x04, 0) +#define MI_READ_FLUSH (1 << 0) +#define MI_EXE_FLUSH (1 << 1) +#define MI_NO_WRITE_FLUSH (1 << 2) +#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ +#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ +#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) +#define MI_REPORT_HEAD MI_INSTR(0x07, 0) +#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0) +#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) /* used to have 1<<22? */ +#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) +#define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1) +#define MI_BATCH_BUFFER MI_INSTR(0x30, 1) +#define MI_BATCH_NON_SECURE (1) +#define MI_BATCH_NON_SECURE_I965 (1<<8) +#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) + +/* + * 3D instructions used by the kernel */ -#define CMD_MI_LOAD_REGISTER_IMM ((0x22 << 23)|0x1) +#define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags)) -#define BB1_START_ADDR_MASK (~0x7) -#define BB1_PROTECTED (1<<0) -#define BB1_UNPROTECTED (0<<0) -#define BB2_END_ADDR_MASK (~0x7) +#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) +#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16)) +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) +#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) +#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) +#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) +#define BLT_DEPTH_8 (0<<24) +#define BLT_DEPTH_16_565 (1<<24) +#define BLT_DEPTH_16_1555 (2<<24) +#define BLT_DEPTH_32 (3<<24) +#define BLT_ROP_GXCOPY (0xcc<<16) +#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) +#define XY_SRC_COPY_BLT_DST_TILED (1<<11) +#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) +#define ASYNC_FLIP (1<<22) +#define DISPLAY_PLANE_A (0<<20) +#define DISPLAY_PLANE_B (1<<20) -#define I915REG_HWS_PGA 0x02080 +/* + * Instruction and interrupt control regs + */ + +#define PRB0_TAIL 0x02030 +#define PRB0_HEAD 0x02034 +#define PRB0_START 0x02038 +#define PRB0_CTL 0x0203c +#define TAIL_ADDR 0x001FFFF8 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define START_ADDR 0x0xFFFFF000 +#define RING_NR_PAGES 0x001FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 +#define PRB1_TAIL 0x02040 /* 915+ only */ +#define PRB1_HEAD 0x02044 /* 915+ only */ +#define PRB1_START 0x02048 /* 915+ only */ +#define PRB1_CTL 0x0204c /* 915+ only */ +#define HWS_PGA 0x02080 +#define IPEIR 0x02088 +#define NOPID 0x02094 +#define HWSTAM 0x02098 +#define SCPD0 0x0209c /* 915+ only */ +#define IER 0x020a0 +#define IIR 0x020a4 +#define IMR 0x020a8 +#define ISR 0x020ac +#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) +#define I915_DISPLAY_PORT_INTERRUPT (1<<17) +#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) +#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) +#define I915_HWB_OOM_INTERRUPT (1<<13) +#define I915_SYNC_STATUS_INTERRUPT (1<<12) +#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) +#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) +#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) +#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) +#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) +#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) +#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) +#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) +#define I915_DEBUG_INTERRUPT (1<<2) +#define I915_USER_INTERRUPT (1<<1) +#define EIR 0x020b0 +#define EMR 0x020b4 +#define ESR 0x020b8 +#define INSTPM 0x020c0 +#define FW_BLC 0x020d8 +#define FW_BLC_SELF 0x020e0 /* 915+ only */ +#define MI_ARB_STATE 0x020e4 /* 915+ only */ +#define CACHE_MODE_0 0x02120 /* 915+ only */ +#define CM0_MASK_SHIFT 16 +#define CM0_IZ_OPT_DISABLE (1<<6) +#define CM0_ZR_OPT_DISABLE (1<<5) +#define CM0_DEPTH_EVICT_DISABLE (1<<4) +#define CM0_COLOR_EVICT_DISABLE (1<<3) +#define CM0_DEPTH_WRITE_DISABLE (1<<1) +#define CM0_RC_OP_FLUSH_DISABLE (1<<0) +#define GFX_FLSH_CNTL 0x02170 /* 915+ only */ + +/* + * Framebuffer compression (915+ only) + */ -/* Framebuffer compression */ #define FBC_CFB_BASE 0x03200 /* 4k page aligned */ #define FBC_LL_BASE 0x03204 /* 4k page aligned */ #define FBC_CONTROL 0x03208 @@ -535,77 +672,10 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define FBC_FENCE_OFF 0x0321b #define FBC_LL_SIZE (1536) -#define FBC_LL_PAD (32) - -/* Interrupt bits: - */ -#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) -#define I915_DISPLAY_PORT_INTERRUPT (1<<17) -#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) -#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) -#define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */ -#define I915_SYNC_STATUS_INTERRUPT (1<<12) -#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) -#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) -#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) -#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) -#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) -#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) -#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) -#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) -#define I915_DEBUG_INTERRUPT (1<<2) -#define I915_USER_INTERRUPT (1<<1) - - -#define I915REG_HWSTAM 0x02098 -#define I915REG_INT_IDENTITY_R 0x020a4 -#define I915REG_INT_MASK_R 0x020a8 -#define I915REG_INT_ENABLE_R 0x020a0 -#define I915REG_INSTPM 0x020c0 - -#define PIPEADSL 0x70000 -#define PIPEBDSL 0x71000 - -#define I915REG_PIPEASTAT 0x70024 -#define I915REG_PIPEBSTAT 0x71024 - -#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) -#define I915_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) -#define I915_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) -#define I915_HOTPLUG_CLEAR (1UL<<10) -#define I915_HOTPLUG_TV_CLEAR (1UL<<2) -#define I915_VBLANK_CLEAR (1UL<<1) - -/* - * The two pipe frame counter registers are not synchronized, so - * reading a stable value is somewhat tricky. The following code - * should work: - * - * do { - * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> - * PIPE_FRAME_HIGH_SHIFT; - * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> - * PIPE_FRAME_LOW_SHIFT); - * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> - * PIPE_FRAME_HIGH_SHIFT); - * } while (high1 != high2); - * frame = (high1 << 8) | low1; - */ -#define PIPEAFRAMEHIGH 0x70040 -#define PIPEBFRAMEHIGH 0x71040 -#define PIPE_FRAME_HIGH_MASK 0x0000ffff -#define PIPE_FRAME_HIGH_SHIFT 0 -#define PIPEAFRAMEPIXEL 0x70044 -#define PIPEBFRAMEPIXEL 0x71044 -#define PIPE_FRAME_LOW_MASK 0xff000000 -#define PIPE_FRAME_LOW_SHIFT 24 /* - * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register - * and is 24 bits wide. + * GPIO regs */ -#define PIPE_PIXEL_MASK 0x00ffffff -#define PIPE_PIXEL_SHIFT 0 #define GPIOA 0x5010 #define GPIOB 0x5014 @@ -630,520 +700,82 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); # define GPIO_DATA_VAL_IN (1 << 12) # define GPIO_DATA_PULLUP_DISABLE (1 << 13) -/* p317, 319 - */ -#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */ -#define VCLK2_VCO_N 0x600a -#define VCLK2_VCO_DIV_SEL 0x6012 - -#define VCLK_DIVISOR_VGA0 0x6000 -#define VCLK_DIVISOR_VGA1 0x6004 -#define VCLK_POST_DIV 0x6010 -/** Selects a post divisor of 4 instead of 2. */ -# define VGA1_PD_P2_DIV_4 (1 << 15) -/** Overrides the p2 post divisor field */ -# define VGA1_PD_P1_DIV_2 (1 << 13) -# define VGA1_PD_P1_SHIFT 8 -/** P1 value is 2 greater than this field */ -# define VGA1_PD_P1_MASK (0x1f << 8) -/** Selects a post divisor of 4 instead of 2. */ -# define VGA0_PD_P2_DIV_4 (1 << 7) -/** Overrides the p2 post divisor field */ -# define VGA0_PD_P1_DIV_2 (1 << 5) -# define VGA0_PD_P1_SHIFT 0 -/** P1 value is 2 greater than this field */ -# define VGA0_PD_P1_MASK (0x1f << 0) - -#define POST_DIV_SELECT 0x70 -#define POST_DIV_1 0x00 -#define POST_DIV_2 0x10 -#define POST_DIV_4 0x20 -#define POST_DIV_8 0x30 -#define POST_DIV_16 0x40 -#define POST_DIV_32 0x50 -#define VCO_LOOP_DIV_BY_4M 0x00 -#define VCO_LOOP_DIV_BY_16M 0x04 - -#define I915_FIFO_UNDERRUN_STATUS (1UL<<31) -#define I915_CRC_ERROR_ENABLE (1UL<<29) -#define I915_CRC_DONE_ENABLE (1UL<<28) -#define I915_GMBUS_EVENT_ENABLE (1UL<<27) -#define I915_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) -#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25) -#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) -#define I915_DPST_EVENT_ENABLE (1UL<<23) -#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22) -#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) -#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) -#define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ -#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) -#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16) -#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) -#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12) -#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11) -#define I915_HOTPLUG_INTERRUPT_STATUS (1UL<<10) -#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9) -#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) -#define I915_DPST_EVENT_STATUS (1UL<<7) -#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6) -#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) -#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) -#define I915_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) -#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ -#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1) -#define I915_OVERLAY_UPDATED_STATUS (1UL<<0) - -#define SRX_INDEX 0x3c4 -#define SRX_DATA 0x3c5 -#define SR01 1 -#define SR01_SCREEN_OFF (1<<5) - -#define PPCR 0x61204 -#define PPCR_ON (1<<0) - -#define DVOA 0x61120 -#define DVOB 0x61140 -#define DVOC 0x61160 -#define DVO_ENABLE (1 << 31) -#define DVO_PIPE_B_SELECT (1 << 30) -#define DVO_PIPE_STALL_UNUSED (0 << 28) -#define DVO_PIPE_STALL (1 << 28) -#define DVO_PIPE_STALL_TV (2 << 28) -#define DVO_PIPE_STALL_MASK (3 << 28) -#define DVO_USE_VGA_SYNC (1 << 15) -#define DVO_DATA_ORDER_I740 (0 << 14) -#define DVO_DATA_ORDER_FP (1 << 14) -#define DVO_VSYNC_DISABLE (1 << 11) -#define DVO_HSYNC_DISABLE (1 << 10) -#define DVO_VSYNC_TRISTATE (1 << 9) -#define DVO_HSYNC_TRISTATE (1 << 8) -#define DVO_BORDER_ENABLE (1 << 7) -#define DVO_DATA_ORDER_GBRG (1 << 6) -#define DVO_DATA_ORDER_RGGB (0 << 6) -#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6) -#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6) -#define DVO_VSYNC_ACTIVE_HIGH (1 << 4) -#define DVO_HSYNC_ACTIVE_HIGH (1 << 3) -#define DVO_BLANK_ACTIVE_HIGH (1 << 2) -#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */ -#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */ -#define DVO_PRESERVE_MASK (0x7<<24) - -#define DVOA_SRCDIM 0x61124 -#define DVOB_SRCDIM 0x61144 -#define DVOC_SRCDIM 0x61164 -#define DVO_SRCDIM_HORIZONTAL_SHIFT 12 -#define DVO_SRCDIM_VERTICAL_SHIFT 0 - -#define LVDS 0x61180 -#define LVDS_ON (1<<31) - -#define ADPA 0x61100 -#define ADPA_DPMS_MASK (~(3<<10)) -#define ADPA_DPMS_ON (0<<10) -#define ADPA_DPMS_SUSPEND (1<<10) -#define ADPA_DPMS_STANDBY (2<<10) -#define ADPA_DPMS_OFF (3<<10) - -#define NOPID 0x2094 -#define LP_RING 0x2030 -#define HP_RING 0x2040 -/* The binner has its own ring buffer: - */ -#define HWB_RING 0x2400 - -#define RING_TAIL 0x00 -#define TAIL_ADDR 0x001FFFF8 -#define RING_HEAD 0x04 -#define HEAD_WRAP_COUNT 0xFFE00000 -#define HEAD_WRAP_ONE 0x00200000 -#define HEAD_ADDR 0x001FFFFC -#define RING_START 0x08 -#define START_ADDR 0x0xFFFFF000 -#define RING_LEN 0x0C -#define RING_NR_PAGES 0x001FF000 -#define RING_REPORT_MASK 0x00000006 -#define RING_REPORT_64K 0x00000002 -#define RING_REPORT_128K 0x00000004 -#define RING_NO_REPORT 0x00000000 -#define RING_VALID_MASK 0x00000001 -#define RING_VALID 0x00000001 -#define RING_INVALID 0x00000000 - -/* Instruction parser error reg: - */ -#define IPEIR 0x2088 - -/* Scratch pad debug 0 reg: - */ -#define SCPD0 0x209c - -/* Error status reg: - */ -#define ESR 0x20b8 - -/* Secondary DMA fetch address debug reg: - */ -#define DMA_FADD_S 0x20d4 - -/* Memory Interface Arbitration State - */ -#define MI_ARB_STATE 0x20e4 - -/* Cache mode 0 reg. - * - Manipulating render cache behaviour is central - * to the concept of zone rendering, tuning this reg can help avoid - * unnecessary render cache reads and even writes (for z/stencil) - * at beginning and end of scene. - * - * - To change a bit, write to this reg with a mask bit set and the - * bit of interest either set or cleared. EG: (BIT<<16) | BIT to set. - */ -#define Cache_Mode_0 0x2120 -#define CACHE_MODE_0 0x2120 -#define CM0_MASK_SHIFT 16 -#define CM0_IZ_OPT_DISABLE (1<<6) -#define CM0_ZR_OPT_DISABLE (1<<5) -#define CM0_DEPTH_EVICT_DISABLE (1<<4) -#define CM0_COLOR_EVICT_DISABLE (1<<3) -#define CM0_DEPTH_WRITE_DISABLE (1<<1) -#define CM0_RC_OP_FLUSH_DISABLE (1<<0) - - -/* Graphics flush control. A CPU write flushes the GWB of all writes. - * The data is discarded. - */ -#define GFX_FLSH_CNTL 0x2170 - -/* Binner control. Defines the location of the bin pointer list: - */ -#define BINCTL 0x2420 -#define BC_MASK (1 << 9) - -/* Binned scene info. - */ -#define BINSCENE 0x2428 -#define BS_OP_LOAD (1 << 8) -#define BS_MASK (1 << 22) - -/* Bin command parser debug reg: - */ -#define BCPD 0x2480 - -/* Bin memory control debug reg: - */ -#define BMCD 0x2484 - -/* Bin data cache debug reg: - */ -#define BDCD 0x2488 - -/* Binner pointer cache debug reg: - */ -#define BPCD 0x248c - -/* Binner scratch pad debug reg: - */ -#define BINSKPD 0x24f0 - -/* HWB scratch pad debug reg: - */ -#define HWBSKPD 0x24f4 - -/* Binner memory pool reg: - */ -#define BMP_BUFFER 0x2430 -#define BMP_PAGE_SIZE_4K (0 << 10) -#define BMP_BUFFER_SIZE_SHIFT 1 -#define BMP_ENABLE (1 << 0) - -/* Get/put memory from the binner memory pool: - */ -#define BMP_GET 0x2438 -#define BMP_PUT 0x2440 -#define BMP_OFFSET_SHIFT 5 - -/* 3D state packets: - */ -#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) - -#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) -#define SC_UPDATE_SCISSOR (0x1<<1) -#define SC_ENABLE_MASK (0x1<<0) -#define SC_ENABLE (0x1<<0) - -#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16)) - -#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) -#define SCI_YMIN_MASK (0xffff<<16) -#define SCI_XMIN_MASK (0xffff<<0) -#define SCI_YMAX_MASK (0xffff<<16) -#define SCI_XMAX_MASK (0xffff<<0) - -#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) -#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) -#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) -#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) -#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) -#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) -#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) - -#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) - -#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) -#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) -#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5) -#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) -#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) -#define BLT_DEPTH_8 (0<<24) -#define BLT_DEPTH_16_565 (1<<24) -#define BLT_DEPTH_16_1555 (2<<24) -#define BLT_DEPTH_32 (3<<24) -#define BLT_ROP_GXCOPY (0xcc<<16) -#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) -#define XY_SRC_COPY_BLT_DST_TILED (1<<11) - -#define MI_BATCH_BUFFER ((0x30<<23)|1) -#define MI_BATCH_BUFFER_START (0x31<<23) -#define MI_BATCH_BUFFER_END (0xA<<23) -#define MI_BATCH_NON_SECURE (1) - -#define MI_BATCH_NON_SECURE_I965 (1<<8) - -#define MI_WAIT_FOR_EVENT ((0x3<<23)) -#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) -#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) -#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) - -#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23)) - -#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) -#define ASYNC_FLIP (1<<22) -#define DISPLAY_PLANE_A (0<<20) -#define DISPLAY_PLANE_B (1<<20) - -/* Display regs */ -#define DSPACNTR 0x70180 -#define DSPBCNTR 0x71180 -#define DISPPLANE_SEL_PIPE_MASK (1<<24) - -/* Define the region of interest for the binner: - */ -#define CMD_OP_BIN_CONTROL ((0x3<<29)|(0x1d<<24)|(0x84<<16)|4) - -#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) - -#define BREADCRUMB_BITS 31 -#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) - -#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) -#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) - -#define BLC_PWM_CTL 0x61254 -#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) - -#define BLC_PWM_CTL2 0x61250 - -/** - * This is the most significant 15 bits of the number of backlight cycles in a - * complete cycle of the modulated backlight control. - * - * The actual value is this field multiplied by two. - */ -#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) -#define BLM_LEGACY_MODE (1 << 16) -/** - * This is the number of cycles out of the backlight modulation cycle for which - * the backlight is on. - * - * This field must be no greater than the number of cycles in the complete - * backlight modulation cycle. - */ -#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) -#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) - -#define I915_GCFGC 0xf0 -#define I915_LOW_FREQUENCY_ENABLE (1 << 7) -#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4) -#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4) -#define I915_DISPLAY_CLOCK_MASK (7 << 4) - -#define I855_HPLLCC 0xc0 -#define I855_CLOCK_CONTROL_MASK (3 << 0) -#define I855_CLOCK_133_200 (0 << 0) -#define I855_CLOCK_100_200 (1 << 0) -#define I855_CLOCK_100_133 (2 << 0) -#define I855_CLOCK_166_250 (3 << 0) - -/* p317, 319 - */ -#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */ -#define VCLK2_VCO_N 0x600a -#define VCLK2_VCO_DIV_SEL 0x6012 - -#define VCLK_DIVISOR_VGA0 0x6000 -#define VCLK_DIVISOR_VGA1 0x6004 -#define VCLK_POST_DIV 0x6010 -/** Selects a post divisor of 4 instead of 2. */ -# define VGA1_PD_P2_DIV_4 (1 << 15) -/** Overrides the p2 post divisor field */ -# define VGA1_PD_P1_DIV_2 (1 << 13) -# define VGA1_PD_P1_SHIFT 8 -/** P1 value is 2 greater than this field */ -# define VGA1_PD_P1_MASK (0x1f << 8) -/** Selects a post divisor of 4 instead of 2. */ -# define VGA0_PD_P2_DIV_4 (1 << 7) -/** Overrides the p2 post divisor field */ -# define VGA0_PD_P1_DIV_2 (1 << 5) -# define VGA0_PD_P1_SHIFT 0 -/** P1 value is 2 greater than this field */ -# define VGA0_PD_P1_MASK (0x1f << 0) - -/* PCI D state control register */ -#define D_STATE 0x6104 -#define DSPCLK_GATE_D 0x6200 - -/* I830 CRTC registers */ -#define HTOTAL_A 0x60000 -#define HBLANK_A 0x60004 -#define HSYNC_A 0x60008 -#define VTOTAL_A 0x6000c -#define VBLANK_A 0x60010 -#define VSYNC_A 0x60014 -#define PIPEASRC 0x6001c -#define BCLRPAT_A 0x60020 -#define VSYNCSHIFT_A 0x60028 - -#define HTOTAL_B 0x61000 -#define HBLANK_B 0x61004 -#define HSYNC_B 0x61008 -#define VTOTAL_B 0x6100c -#define VBLANK_B 0x61010 -#define VSYNC_B 0x61014 -#define PIPEBSRC 0x6101c -#define BCLRPAT_B 0x61020 -#define VSYNCSHIFT_B 0x61028 - -#define HACTIVE_MASK 0x00000fff -#define VTOTAL_MASK 0x00001fff -#define VTOTAL_SHIFT 16 -#define VACTIVE_MASK 0x00000fff -#define VBLANK_END_MASK 0x00001fff -#define VBLANK_END_SHIFT 16 -#define VBLANK_START_MASK 0x00001fff - -#define PP_STATUS 0x61200 -# define PP_ON (1 << 31) -/** - * Indicates that all dependencies of the panel are on: - * - * - PLL enabled - * - pipe enabled - * - LVDS/DVOB/DVOC on - */ -# define PP_READY (1 << 30) -# define PP_SEQUENCE_NONE (0 << 28) -# define PP_SEQUENCE_ON (1 << 28) -# define PP_SEQUENCE_OFF (2 << 28) -# define PP_SEQUENCE_MASK 0x30000000 -#define PP_CONTROL 0x61204 -# define POWER_TARGET_ON (1 << 0) - -#define LVDSPP_ON 0x61208 -#define LVDSPP_OFF 0x6120c -#define PP_CYCLE 0x61210 - -#define PFIT_CONTROL 0x61230 -# define PFIT_ENABLE (1 << 31) -# define PFIT_PIPE_MASK (3 << 29) -# define PFIT_PIPE_SHIFT 29 -# define VERT_INTERP_DISABLE (0 << 10) -# define VERT_INTERP_BILINEAR (1 << 10) -# define VERT_INTERP_MASK (3 << 10) -# define VERT_AUTO_SCALE (1 << 9) -# define HORIZ_INTERP_DISABLE (0 << 6) -# define HORIZ_INTERP_BILINEAR (1 << 6) -# define HORIZ_INTERP_MASK (3 << 6) -# define HORIZ_AUTO_SCALE (1 << 5) -# define PANEL_8TO6_DITHER_ENABLE (1 << 3) - -#define PFIT_PGM_RATIOS 0x61234 -# define PFIT_VERT_SCALE_MASK 0xfff00000 -# define PFIT_HORIZ_SCALE_MASK 0x0000fff0 - -#define PFIT_AUTO_RATIOS 0x61238 - - -#define DPLL_A 0x06014 -#define DPLL_B 0x06018 -# define DPLL_VCO_ENABLE (1 << 31) -# define DPLL_DVO_HIGH_SPEED (1 << 30) -# define DPLL_SYNCLOCK_ENABLE (1 << 29) -# define DPLL_VGA_MODE_DIS (1 << 28) -# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ -# define DPLLB_MODE_LVDS (2 << 26) /* i915 */ -# define DPLL_MODE_MASK (3 << 26) -# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ -# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ -# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ -# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ -# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ -# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ -/** +/* + * Clock control & power management + */ + +#define VGA0 0x6000 +#define VGA1 0x6004 +#define VGA_PD 0x6010 +#define VGA0_PD_P2_DIV_4 (1 << 7) +#define VGA0_PD_P1_DIV_2 (1 << 5) +#define VGA0_PD_P1_SHIFT 0 +#define VGA0_PD_P1_MASK (0x1f << 0) +#define VGA1_PD_P2_DIV_4 (1 << 15) +#define VGA1_PD_P1_DIV_2 (1 << 13) +#define VGA1_PD_P1_SHIFT 8 +#define VGA1_PD_P1_MASK (0x1f << 8) +#define DPLL_A 0x06014 +#define DPLL_B 0x06018 +#define DPLL_VCO_ENABLE (1 << 31) +#define DPLL_DVO_HIGH_SPEED (1 << 30) +#define DPLL_SYNCLOCK_ENABLE (1 << 29) +#define DPLL_VGA_MODE_DIS (1 << 28) +#define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ +#define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +#define DPLL_MODE_MASK (3 << 26) +#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ +#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ +#define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ +#define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ +#define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ +#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ +/* * The i830 generation, in DAC/serial mode, defines p1 as two plus this * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set. */ -# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 -/** +#define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 +/* * The i830 generation, in LVDS mode, defines P1 as the bit number set within * this field (only one bit may be set). */ -# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 -# define DPLL_FPA01_P1_POST_DIV_SHIFT 16 -# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */ -# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ -# define PLL_REF_INPUT_DREFCLK (0 << 13) -# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ -# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ -# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) -# define PLL_REF_INPUT_MASK (3 << 13) -# define PLL_LOAD_PULSE_PHASE_SHIFT 9 +#define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 +#define DPLL_FPA01_P1_POST_DIV_SHIFT 16 +/* i830, required in DVO non-gang */ +#define PLL_P2_DIVIDE_BY_4 (1 << 23) +#define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ +#define PLL_REF_INPUT_DREFCLK (0 << 13) +#define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ +#define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ +#define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +#define PLL_REF_INPUT_MASK (3 << 13) +#define PLL_LOAD_PULSE_PHASE_SHIFT 9 /* * Parallel to Serial Load Pulse phase selection. * Selects the phase for the 10X DPLL clock for the PCIe * digital display port. The range is 4 to 13; 10 or more * is just a flip delay. The default is 6 */ -# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) -# define DISPLAY_RATE_SELECT_FPA1 (1 << 8) - -/** +#define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) +#define DISPLAY_RATE_SELECT_FPA1 (1 << 8) +/* * SDVO multiplier for 945G/GM. Not used on 965. - * - * \sa DPLL_MD_UDI_MULTIPLIER_MASK - */ -# define SDVO_MULTIPLIER_MASK 0x000000ff -# define SDVO_MULTIPLIER_SHIFT_HIRES 4 -# define SDVO_MULTIPLIER_SHIFT_VGA 0 - -/** @defgroup DPLL_MD - * @{ */ -/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */ -#define DPLL_A_MD 0x0601c -/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */ -#define DPLL_B_MD 0x06020 -/** +#define SDVO_MULTIPLIER_MASK 0x000000ff +#define SDVO_MULTIPLIER_SHIFT_HIRES 4 +#define SDVO_MULTIPLIER_SHIFT_VGA 0 +#define DPLL_A_MD 0x0601c /* 965+ only */ +/* * UDI pixel divider, controlling how many pixels are stuffed into a packet. * * Value is pixels minus 1. Must be set to 1 pixel for SDVO. */ -# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 -# define DPLL_MD_UDI_DIVIDER_SHIFT 24 -/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ -# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 -# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 -/** +#define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +#define DPLL_MD_UDI_DIVIDER_SHIFT 24 +/* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ +#define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +#define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +/* * SDVO/UDI pixel multiplier. * * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus @@ -1160,80 +792,134 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); * This register field has values of multiplication factor minus 1, with * a maximum multiplier of 5 for SDVO. */ -# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 -# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 -/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. +#define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +#define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +/* + * SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. * This best be set to the default value (3) or the CRT won't work. No, * I don't entirely understand what this does... */ -# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f -# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 -/** @} */ - -#define DPLL_TEST 0x606c -# define DPLLB_TEST_SDVO_DIV_1 (0 << 22) -# define DPLLB_TEST_SDVO_DIV_2 (1 << 22) -# define DPLLB_TEST_SDVO_DIV_4 (2 << 22) -# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) -# define DPLLB_TEST_N_BYPASS (1 << 19) -# define DPLLB_TEST_M_BYPASS (1 << 18) -# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) -# define DPLLA_TEST_N_BYPASS (1 << 3) -# define DPLLA_TEST_M_BYPASS (1 << 2) -# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) +#define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +#define DPLL_B_MD 0x06020 /* 965+ only */ +#define FPA0 0x06040 +#define FPA1 0x06044 +#define FPB0 0x06048 +#define FPB1 0x0604c +#define FP_N_DIV_MASK 0x003f0000 +#define FP_N_DIV_SHIFT 16 +#define FP_M1_DIV_MASK 0x00003f00 +#define FP_M1_DIV_SHIFT 8 +#define FP_M2_DIV_MASK 0x0000003f +#define FP_M2_DIV_SHIFT 0 +#define DPLL_TEST 0x606c +#define DPLLB_TEST_SDVO_DIV_1 (0 << 22) +#define DPLLB_TEST_SDVO_DIV_2 (1 << 22) +#define DPLLB_TEST_SDVO_DIV_4 (2 << 22) +#define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) +#define DPLLB_TEST_N_BYPASS (1 << 19) +#define DPLLB_TEST_M_BYPASS (1 << 18) +#define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) +#define DPLLA_TEST_N_BYPASS (1 << 3) +#define DPLLA_TEST_M_BYPASS (1 << 2) +#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) +#define D_STATE 0x6104 +#define CG_2D_DIS 0x6200 +#define CG_3D_DIS 0x6204 -#define ADPA 0x61100 -#define ADPA_DAC_ENABLE (1<<31) -#define ADPA_DAC_DISABLE 0 -#define ADPA_PIPE_SELECT_MASK (1<<30) -#define ADPA_PIPE_A_SELECT 0 -#define ADPA_PIPE_B_SELECT (1<<30) -#define ADPA_USE_VGA_HVPOLARITY (1<<15) -#define ADPA_SETS_HVPOLARITY 0 -#define ADPA_VSYNC_CNTL_DISABLE (1<<11) -#define ADPA_VSYNC_CNTL_ENABLE 0 -#define ADPA_HSYNC_CNTL_DISABLE (1<<10) -#define ADPA_HSYNC_CNTL_ENABLE 0 -#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) -#define ADPA_VSYNC_ACTIVE_LOW 0 -#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) -#define ADPA_HSYNC_ACTIVE_LOW 0 - -#define FPA0 0x06040 -#define FPA1 0x06044 -#define FPB0 0x06048 -#define FPB1 0x0604c -# define FP_N_DIV_MASK 0x003f0000 -# define FP_N_DIV_SHIFT 16 -# define FP_M1_DIV_MASK 0x00003f00 -# define FP_M1_DIV_SHIFT 8 -# define FP_M2_DIV_MASK 0x0000003f -# define FP_M2_DIV_SHIFT 0 +/* + * Palette regs + */ + +#define PALETTE_A 0x0a000 +#define PALETTE_B 0x0a800 + +/* + * Overlay regs + */ + +#define OVADD 0x30000 +#define DOVSTA 0x30008 +#define OC_BUF (0x3<<20) +#define OGAMC5 0x30010 +#define OGAMC4 0x30014 +#define OGAMC3 0x30018 +#define OGAMC2 0x3001c +#define OGAMC1 0x30020 +#define OGAMC0 0x30024 + +/* + * Display engine regs + */ + +/* Pipe A timing regs */ +#define HTOTAL_A 0x60000 +#define HBLANK_A 0x60004 +#define HSYNC_A 0x60008 +#define VTOTAL_A 0x6000c +#define VBLANK_A 0x60010 +#define VSYNC_A 0x60014 +#define PIPEASRC 0x6001c +#define BCLRPAT_A 0x60020 +/* Pipe B timing regs */ +#define HTOTAL_B 0x61000 +#define HBLANK_B 0x61004 +#define HSYNC_B 0x61008 +#define VTOTAL_B 0x6100c +#define VBLANK_B 0x61010 +#define VSYNC_B 0x61014 +#define PIPEBSRC 0x6101c +#define BCLRPAT_B 0x61020 +/* VGA port control */ +#define ADPA 0x61100 +#define ADPA_DAC_ENABLE (1<<31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_MASK (1<<30) +#define ADPA_PIPE_A_SELECT 0 +#define ADPA_PIPE_B_SELECT (1<<30) +#define ADPA_USE_VGA_HVPOLARITY (1<<15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_VSYNC_CNTL_DISABLE (1<<11) +#define ADPA_VSYNC_CNTL_ENABLE 0 +#define ADPA_HSYNC_CNTL_DISABLE (1<<10) +#define ADPA_HSYNC_CNTL_ENABLE 0 +#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) +#define ADPA_VSYNC_ACTIVE_LOW 0 +#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) +#define ADPA_HSYNC_ACTIVE_LOW 0 +#define ADPA_DPMS_MASK (~(3<<10)) +#define ADPA_DPMS_ON (0<<10) +#define ADPA_DPMS_SUSPEND (1<<10) +#define ADPA_DPMS_STANDBY (2<<10) +#define ADPA_DPMS_OFF (3<<10) + +/* Hotplug control (945+ only) */ #define PORT_HOTPLUG_EN 0x61110 -# define SDVOB_HOTPLUG_INT_EN (1 << 26) -# define SDVOC_HOTPLUG_INT_EN (1 << 25) -# define TV_HOTPLUG_INT_EN (1 << 18) -# define CRT_HOTPLUG_INT_EN (1 << 9) -# define CRT_HOTPLUG_FORCE_DETECT (1 << 3) +#define SDVOB_HOTPLUG_INT_EN (1 << 26) +#define SDVOC_HOTPLUG_INT_EN (1 << 25) +#define TV_HOTPLUG_INT_EN (1 << 18) +#define CRT_HOTPLUG_INT_EN (1 << 9) +#define CRT_HOTPLUG_FORCE_DETECT (1 << 3) #define PORT_HOTPLUG_STAT 0x61114 -# define CRT_HOTPLUG_INT_STATUS (1 << 11) -# define TV_HOTPLUG_INT_STATUS (1 << 10) -# define CRT_HOTPLUG_MONITOR_MASK (3 << 8) -# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) -# define CRT_HOTPLUG_MONITOR_MONO (2 << 8) -# define CRT_HOTPLUG_MONITOR_NONE (0 << 8) -# define SDVOC_HOTPLUG_INT_STATUS (1 << 7) -# define SDVOB_HOTPLUG_INT_STATUS (1 << 6) - +#define CRT_HOTPLUG_INT_STATUS (1 << 11) +#define TV_HOTPLUG_INT_STATUS (1 << 10) +#define CRT_HOTPLUG_MONITOR_MASK (3 << 8) +#define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) +#define CRT_HOTPLUG_MONITOR_MONO (2 << 8) +#define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +#define SDVOC_HOTPLUG_INT_STATUS (1 << 7) +#define SDVOB_HOTPLUG_INT_STATUS (1 << 6) + +/* SDVO port control */ #define SDVOB 0x61140 #define SDVOC 0x61160 -#define SDVO_ENABLE (1 << 31) -#define SDVO_PIPE_B_SELECT (1 << 30) -#define SDVO_STALL_SELECT (1 << 29) -#define SDVO_INTERRUPT_ENABLE (1 << 26) +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) /** * 915G/GM SDVO pixel multiplier. * @@ -1241,69 +927,156 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); * * \sa DPLL_MD_UDI_MULTIPLIER_MASK */ -#define SDVO_PORT_MULTIPLY_MASK (7 << 23) -#define SDVO_PORT_MULTIPLY_SHIFT 23 -#define SDVO_PHASE_SELECT_MASK (15 << 19) -#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) -#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) -#define SDVOC_GANG_MODE (1 << 16) -#define SDVO_BORDER_ENABLE (1 << 7) -#define SDVOB_PCIE_CONCURRENCY (1 << 3) -#define SDVO_DETECTED (1 << 2) +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_SHIFT 23 +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) +#define SDVO_BORDER_ENABLE (1 << 7) +#define SDVOB_PCIE_CONCURRENCY (1 << 3) +#define SDVO_DETECTED (1 << 2) /* Bits to be preserved when writing */ -#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26)) -#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26)) +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26)) +#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26)) -/** @defgroup LVDS - * @{ - */ -/** - * This register controls the LVDS output enable, pipe selection, and data - * format selection. - * - * All of the clock/data pairs are force powered down by power sequencing. - */ +/* DVO port control */ +#define DVOA 0x61120 +#define DVOB 0x61140 +#define DVOC 0x61160 +#define DVO_ENABLE (1 << 31) +#define DVO_PIPE_B_SELECT (1 << 30) +#define DVO_PIPE_STALL_UNUSED (0 << 28) +#define DVO_PIPE_STALL (1 << 28) +#define DVO_PIPE_STALL_TV (2 << 28) +#define DVO_PIPE_STALL_MASK (3 << 28) +#define DVO_USE_VGA_SYNC (1 << 15) +#define DVO_DATA_ORDER_I740 (0 << 14) +#define DVO_DATA_ORDER_FP (1 << 14) +#define DVO_VSYNC_DISABLE (1 << 11) +#define DVO_HSYNC_DISABLE (1 << 10) +#define DVO_VSYNC_TRISTATE (1 << 9) +#define DVO_HSYNC_TRISTATE (1 << 8) +#define DVO_BORDER_ENABLE (1 << 7) +#define DVO_DATA_ORDER_GBRG (1 << 6) +#define DVO_DATA_ORDER_RGGB (0 << 6) +#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6) +#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6) +#define DVO_VSYNC_ACTIVE_HIGH (1 << 4) +#define DVO_HSYNC_ACTIVE_HIGH (1 << 3) +#define DVO_BLANK_ACTIVE_HIGH (1 << 2) +#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */ +#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */ +#define DVO_PRESERVE_MASK (0x7<<24) +#define DVOA_SRCDIM 0x61124 +#define DVOB_SRCDIM 0x61144 +#define DVOC_SRCDIM 0x61164 +#define DVO_SRCDIM_HORIZONTAL_SHIFT 12 +#define DVO_SRCDIM_VERTICAL_SHIFT 0 + +/* LVDS port control */ #define LVDS 0x61180 -/** +/* * Enables the LVDS port. This bit must be set before DPLLs are enabled, as * the DPLL semantics change when the LVDS is assigned to that pipe. */ -# define LVDS_PORT_EN (1 << 31) -/** Selects pipe B for LVDS data. Must be set on pre-965. */ -# define LVDS_PIPEB_SELECT (1 << 30) - -/** +#define LVDS_PORT_EN (1 << 31) +/* Selects pipe B for LVDS data. Must be set on pre-965. */ +#define LVDS_PIPEB_SELECT (1 << 30) +/* * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per * pixel. */ -# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) -# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) -# define LVDS_A0A2_CLKA_POWER_UP (3 << 8) -/** +#define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) +#define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) +#define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +/* * Controls the A3 data pair, which contains the additional LSBs for 24 bit * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be * on. */ -# define LVDS_A3_POWER_MASK (3 << 6) -# define LVDS_A3_POWER_DOWN (0 << 6) -# define LVDS_A3_POWER_UP (3 << 6) -/** +#define LVDS_A3_POWER_MASK (3 << 6) +#define LVDS_A3_POWER_DOWN (0 << 6) +#define LVDS_A3_POWER_UP (3 << 6) +/* * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP * is set. */ -# define LVDS_CLKB_POWER_MASK (3 << 4) -# define LVDS_CLKB_POWER_DOWN (0 << 4) -# define LVDS_CLKB_POWER_UP (3 << 4) - -/** +#define LVDS_CLKB_POWER_MASK (3 << 4) +#define LVDS_CLKB_POWER_DOWN (0 << 4) +#define LVDS_CLKB_POWER_UP (3 << 4) +/* * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 * setting for whether we are in dual-channel mode. The B3 pair will * additionally only be powered up when LVDS_A3_POWER_UP is set. */ -# define LVDS_B0B3_POWER_MASK (3 << 2) -# define LVDS_B0B3_POWER_DOWN (0 << 2) -# define LVDS_B0B3_POWER_UP (3 << 2) +#define LVDS_B0B3_POWER_MASK (3 << 2) +#define LVDS_B0B3_POWER_DOWN (0 << 2) +#define LVDS_B0B3_POWER_UP (3 << 2) + +/* Panel power sequencing */ +#define PP_STATUS 0x61200 +#define PP_ON (1 << 31) +/* + * Indicates that all dependencies of the panel are on: + * + * - PLL enabled + * - pipe enabled + * - LVDS/DVOB/DVOC on + */ +#define PP_READY (1 << 30) +#define PP_SEQUENCE_NONE (0 << 28) +#define PP_SEQUENCE_ON (1 << 28) +#define PP_SEQUENCE_OFF (2 << 28) +#define PP_SEQUENCE_MASK 0x30000000 +#define PP_CONTROL 0x61204 +#define POWER_TARGET_ON (1 << 0) +#define PP_ON_DELAYS 0x61208 +#define PP_OFF_DELAYS 0x6120c +#define PP_DIVISOR 0x61210 + +/* Panel fitting */ +#define PFIT_CONTROL 0x61230 +#define PFIT_ENABLE (1 << 31) +#define PFIT_PIPE_MASK (3 << 29) +#define PFIT_PIPE_SHIFT 29 +#define VERT_INTERP_DISABLE (0 << 10) +#define VERT_INTERP_BILINEAR (1 << 10) +#define VERT_INTERP_MASK (3 << 10) +#define VERT_AUTO_SCALE (1 << 9) +#define HORIZ_INTERP_DISABLE (0 << 6) +#define HORIZ_INTERP_BILINEAR (1 << 6) +#define HORIZ_INTERP_MASK (3 << 6) +#define HORIZ_AUTO_SCALE (1 << 5) +#define PANEL_8TO6_DITHER_ENABLE (1 << 3) +#define PFIT_PGM_RATIOS 0x61234 +#define PFIT_VERT_SCALE_MASK 0xfff00000 +#define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +#define PFIT_AUTO_RATIOS 0x61238 +/* Backlight control */ +#define BLC_PWM_CTL 0x61254 +#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) +#define BLC_PWM_CTL2 0x61250 /* 965+ only */ +/* + * This is the most significant 15 bits of the number of backlight cycles in a + * complete cycle of the modulated backlight control. + * + * The actual value is this field multiplied by two. + */ +#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) +#define BLM_LEGACY_MODE (1 << 16) +/* + * This is the number of cycles out of the backlight modulation cycle for which + * the backlight is on. + * + * This field must be no greater than the number of cycles in the complete + * backlight modulation cycle. + */ +#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) +#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) + +/* TV port control */ #define TV_CTL 0x68000 /** Enables the TV encoder */ # define TV_ENC_ENABLE (1 << 31) @@ -1370,11 +1143,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_TEST_MODE_MONITOR_DETECT (7 << 0) # define TV_TEST_MODE_MASK (7 << 0) -/** @} */ -/** @defgroup TV_DAC - * @{ - */ #define TV_DAC 0x68004 /** * Reports that DAC state change logic has reported change (RO). @@ -1418,7 +1187,6 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); # define DAC_C_1_1_V (1 << 0) # define DAC_C_0_7_V (2 << 0) # define DAC_C_OFF (3 << 0) -/** @} */ /** * CSC coefficients are stored in a floating point format with 9 bits of @@ -1477,9 +1245,6 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); # define TV_AV_MASK 0x000007ff # define TV_AV_SHIFT 0 -/** @defgroup TV_CSC_KNOBS - * @{ - */ #define TV_CLR_KNOBS 0x68028 /** 2s-complement brightness adjustment */ # define TV_BRIGHTNESS_MASK 0xff000000 @@ -1493,11 +1258,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Hue adjustment, as an integer phase angle in degrees */ # define TV_HUE_MASK 0x000000ff # define TV_HUE_SHIFT 0 -/** @} */ -/** @defgroup TV_CLR_LEVEL - * @{ - */ #define TV_CLR_LEVEL 0x6802c /** Controls the DAC level for black */ # define TV_BLACK_LEVEL_MASK 0x01ff0000 @@ -1505,11 +1266,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Controls the DAC level for blanking */ # define TV_BLANK_LEVEL_MASK 0x000001ff # define TV_BLANK_LEVEL_SHIFT 0 -/* @} */ -/** @defgroup TV_H_CTL_1 - * @{ - */ #define TV_H_CTL_1 0x68030 /** Number of pixels in the hsync. */ # define TV_HSYNC_END_MASK 0x1fff0000 @@ -1517,11 +1274,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Total number of pixels minus one in the line (display and blanking). */ # define TV_HTOTAL_MASK 0x00001fff # define TV_HTOTAL_SHIFT 0 -/** @} */ -/** @defgroup TV_H_CTL_2 - * @{ - */ #define TV_H_CTL_2 0x68034 /** Enables the colorburst (needed for non-component color) */ # define TV_BURST_ENA (1 << 31) @@ -1531,11 +1284,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Length of the colorburst */ # define TV_HBURST_LEN_SHIFT 0 # define TV_HBURST_LEN_MASK 0x0001fff -/** @} */ -/** @defgroup TV_H_CTL_3 - * @{ - */ #define TV_H_CTL_3 0x68038 /** End of hblank, measured in pixels minus one from start of hsync */ # define TV_HBLANK_END_SHIFT 16 @@ -1543,11 +1292,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Start of hblank, measured in pixels minus one from start of hsync */ # define TV_HBLANK_START_SHIFT 0 # define TV_HBLANK_START_MASK 0x0001fff -/** @} */ -/** @defgroup TV_V_CTL_1 - * @{ - */ #define TV_V_CTL_1 0x6803c /** XXX */ # define TV_NBR_END_SHIFT 16 @@ -1558,11 +1303,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** XXX */ # define TV_VI_END_F2_SHIFT 0 # define TV_VI_END_F2_MASK 0x0000003f -/** @} */ -/** @defgroup TV_V_CTL_2 - * @{ - */ #define TV_V_CTL_2 0x68040 /** Length of vsync, in half lines */ # define TV_VSYNC_LEN_MASK 0x07ff0000 @@ -1578,11 +1319,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_VSYNC_START_F2_MASK 0x0000007f # define TV_VSYNC_START_F2_SHIFT 0 -/** @} */ -/** @defgroup TV_V_CTL_3 - * @{ - */ #define TV_V_CTL_3 0x68044 /** Enables generation of the equalization signal */ # define TV_EQUAL_ENA (1 << 31) @@ -1600,11 +1337,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_VEQ_START_F2_MASK 0x000007f # define TV_VEQ_START_F2_SHIFT 0 -/** @} */ -/** @defgroup TV_V_CTL_4 - * @{ - */ #define TV_V_CTL_4 0x68048 /** * Offset to start of vertical colorburst, measured in one less than the @@ -1618,11 +1351,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_VBURST_END_F1_MASK 0x000000ff # define TV_VBURST_END_F1_SHIFT 0 -/** @} */ -/** @defgroup TV_V_CTL_5 - * @{ - */ #define TV_V_CTL_5 0x6804c /** * Offset to start of vertical colorburst, measured in one less than the @@ -1636,11 +1365,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_VBURST_END_F2_MASK 0x000000ff # define TV_VBURST_END_F2_SHIFT 0 -/** @} */ -/** @defgroup TV_V_CTL_6 - * @{ - */ #define TV_V_CTL_6 0x68050 /** * Offset to start of vertical colorburst, measured in one less than the @@ -1654,11 +1379,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_VBURST_END_F3_MASK 0x000000ff # define TV_VBURST_END_F3_SHIFT 0 -/** @} */ -/** @defgroup TV_V_CTL_7 - * @{ - */ #define TV_V_CTL_7 0x68054 /** * Offset to start of vertical colorburst, measured in one less than the @@ -1672,11 +1393,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_VBURST_END_F4_MASK 0x000000ff # define TV_VBURST_END_F4_SHIFT 0 -/** @} */ -/** @defgroup TV_SC_CTL_1 - * @{ - */ #define TV_SC_CTL_1 0x68060 /** Turns on the first subcarrier phase generation DDA */ # define TV_SC_DDA1_EN (1 << 31) @@ -1698,11 +1415,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Sets the increment of the first subcarrier phase generation DDA */ # define TV_SCDDA1_INC_MASK 0x00000fff # define TV_SCDDA1_INC_SHIFT 0 -/** @} */ -/** @defgroup TV_SC_CTL_2 - * @{ - */ #define TV_SC_CTL_2 0x68064 /** Sets the rollover for the second subcarrier phase generation DDA */ # define TV_SCDDA2_SIZE_MASK 0x7fff0000 @@ -1710,11 +1423,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Sets the increent of the second subcarrier phase generation DDA */ # define TV_SCDDA2_INC_MASK 0x00007fff # define TV_SCDDA2_INC_SHIFT 0 -/** @} */ -/** @defgroup TV_SC_CTL_3 - * @{ - */ #define TV_SC_CTL_3 0x68068 /** Sets the rollover for the third subcarrier phase generation DDA */ # define TV_SCDDA3_SIZE_MASK 0x7fff0000 @@ -1722,11 +1431,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Sets the increent of the third subcarrier phase generation DDA */ # define TV_SCDDA3_INC_MASK 0x00007fff # define TV_SCDDA3_INC_SHIFT 0 -/** @} */ -/** @defgroup TV_WIN_POS - * @{ - */ #define TV_WIN_POS 0x68070 /** X coordinate of the display from the start of horizontal active */ # define TV_XPOS_MASK 0x1fff0000 @@ -1734,11 +1439,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Y coordinate of the display from the start of vertical active (NBR) */ # define TV_YPOS_MASK 0x00000fff # define TV_YPOS_SHIFT 0 -/** @} */ -/** @defgroup TV_WIN_SIZE - * @{ - */ #define TV_WIN_SIZE 0x68074 /** Horizontal size of the display window, measured in pixels*/ # define TV_XSIZE_MASK 0x1fff0000 @@ -1750,11 +1451,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_YSIZE_MASK 0x00000fff # define TV_YSIZE_SHIFT 0 -/** @} */ -/** @defgroup TV_FILTER_CTL_1 - * @{ - */ #define TV_FILTER_CTL_1 0x68080 /** * Enables automatic scaling calculation. @@ -1787,11 +1484,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_HSCALE_FRAC_MASK 0x00003fff # define TV_HSCALE_FRAC_SHIFT 0 -/** @} */ -/** @defgroup TV_FILTER_CTL_2 - * @{ - */ #define TV_FILTER_CTL_2 0x68084 /** * Sets the integer part of the 3.15 fixed-point vertical scaling factor. @@ -1807,11 +1500,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_VSCALE_FRAC_MASK 0x00007fff # define TV_VSCALE_FRAC_SHIFT 0 -/** @} */ -/** @defgroup TV_FILTER_CTL_3 - * @{ - */ #define TV_FILTER_CTL_3 0x68088 /** * Sets the integer part of the 3.15 fixed-point vertical scaling factor. @@ -1831,11 +1520,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); */ # define TV_VSCALE_IP_FRAC_MASK 0x00007fff # define TV_VSCALE_IP_FRAC_SHIFT 0 -/** @} */ -/** @defgroup TV_CC_CONTROL - * @{ - */ #define TV_CC_CONTROL 0x68090 # define TV_CC_ENABLE (1 << 31) /** @@ -1851,11 +1536,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** Sets the vertical position of the CC data. Usually 21 */ # define TV_CC_LINE_MASK 0x0000003f # define TV_CC_LINE_SHIFT 0 -/** @} */ -/** @defgroup TV_CC_DATA - * @{ - */ #define TV_CC_DATA 0x68094 # define TV_CC_RDY (1 << 31) /** Second word of CC data to be transmitted. */ @@ -1864,10 +1545,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /** First word of CC data to be transmitted. */ # define TV_CC_DATA_1_MASK 0x0000007f # define TV_CC_DATA_1_SHIFT 0 -/** @} - */ -/** @{ */ #define TV_H_LUMA_0 0x68100 #define TV_H_LUMA_59 0x681ec #define TV_H_CHROMA_0 0x68200 @@ -1877,102 +1555,131 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define TV_V_CHROMA_0 0x68400 #define TV_V_CHROMA_42 0x684a8 -#define PIPEACONF 0x70008 -#define PIPEACONF_ENABLE (1<<31) -#define PIPEACONF_DISABLE 0 -#define PIPEACONF_DOUBLE_WIDE (1<<30) -#define I965_PIPECONF_ACTIVE (1<<30) -#define PIPEACONF_SINGLE_WIDE 0 -#define PIPEACONF_PIPE_UNLOCKED 0 -#define PIPEACONF_PIPE_LOCKED (1<<25) -#define PIPEACONF_PALETTE 0 -#define PIPEACONF_GAMMA (1<<24) -#define PIPECONF_FORCE_BORDER (1<<25) -#define PIPECONF_PROGRESSIVE (0 << 21) -#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) -#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) - -#define DSPARB 0x70030 -#define DSPARB_CSTART_MASK (0x7f << 7) -#define DSPARB_CSTART_SHIFT 7 -#define DSPARB_BSTART_MASK (0x7f) -#define DSPARB_BSTART_SHIFT 0 - -#define PIPEBCONF 0x71008 -#define PIPEBCONF_ENABLE (1<<31) -#define PIPEBCONF_DISABLE 0 -#define PIPEBCONF_DOUBLE_WIDE (1<<30) -#define PIPEBCONF_DISABLE 0 -#define PIPEBCONF_GAMMA (1<<24) -#define PIPEBCONF_PALETTE 0 - -#define PIPEBGCMAXRED 0x71010 -#define PIPEBGCMAXGREEN 0x71014 -#define PIPEBGCMAXBLUE 0x71018 -#define PIPEBSTAT 0x71024 -#define PIPEBFRAMEHIGH 0x71040 -#define PIPEBFRAMEPIXEL 0x71044 +/* Display & cursor control */ -#define DSPACNTR 0x70180 -#define DSPBCNTR 0x71180 -#define DISPLAY_PLANE_ENABLE (1<<31) -#define DISPLAY_PLANE_DISABLE 0 -#define DISPPLANE_GAMMA_ENABLE (1<<30) -#define DISPPLANE_GAMMA_DISABLE 0 -#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) -#define DISPPLANE_8BPP (0x2<<26) -#define DISPPLANE_15_16BPP (0x4<<26) -#define DISPPLANE_16BPP (0x5<<26) -#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) -#define DISPPLANE_32BPP (0x7<<26) -#define DISPPLANE_STEREO_ENABLE (1<<25) -#define DISPPLANE_STEREO_DISABLE 0 -#define DISPPLANE_SEL_PIPE_MASK (1<<24) -#define DISPPLANE_SEL_PIPE_A 0 -#define DISPPLANE_SEL_PIPE_B (1<<24) -#define DISPPLANE_SRC_KEY_ENABLE (1<<22) -#define DISPPLANE_SRC_KEY_DISABLE 0 -#define DISPPLANE_LINE_DOUBLE (1<<20) -#define DISPPLANE_NO_LINE_DOUBLE 0 -#define DISPPLANE_STEREO_POLARITY_FIRST 0 -#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) -/* plane B only */ -#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) -#define DISPPLANE_ALPHA_TRANS_DISABLE 0 -#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 -#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) - -#define DSPABASE 0x70184 +/* Pipe A */ +#define PIPEADSL 0x70000 +#define PIPEACONF 0x70008 +#define PIPEACONF_ENABLE (1<<31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1<<30) +#define I965_PIPECONF_ACTIVE (1<<30) +#define PIPEACONF_SINGLE_WIDE 0 +#define PIPEACONF_PIPE_UNLOCKED 0 +#define PIPEACONF_PIPE_LOCKED (1<<25) +#define PIPEACONF_PALETTE 0 +#define PIPEACONF_GAMMA (1<<24) +#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) +#define PIPEASTAT 0x70024 +#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) +#define PIPE_CRC_ERROR_ENABLE (1UL<<29) +#define PIPE_CRC_DONE_ENABLE (1UL<<28) +#define PIPE_GMBUS_EVENT_ENABLE (1UL<<27) +#define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) +#define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25) +#define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) +#define PIPE_DPST_EVENT_ENABLE (1UL<<23) +#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22) +#define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) +#define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) +#define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) /* pre-965 */ +#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ +#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17) +#define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) +#define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) +#define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) +#define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) +#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10) +#define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9) +#define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) +#define PIPE_DPST_EVENT_STATUS (1UL<<7) +#define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6) +#define PIPE_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) +#define PIPE_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) +#define PIPE_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) /* pre-965 */ +#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ +#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) +#define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0) + +#define DSPARB 0x70030 +#define DSPARB_CSTART_MASK (0x7f << 7) +#define DSPARB_CSTART_SHIFT 7 +#define DSPARB_BSTART_MASK (0x7f) +#define DSPARB_BSTART_SHIFT 0 +/* + * The two pipe frame counter registers are not synchronized, so + * reading a stable value is somewhat tricky. The following code + * should work: + * + * do { + * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> + * PIPE_FRAME_HIGH_SHIFT; + * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> + * PIPE_FRAME_LOW_SHIFT); + * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> + * PIPE_FRAME_HIGH_SHIFT); + * } while (high1 != high2); + * frame = (high1 << 8) | low1; + */ +#define PIPEAFRAMEHIGH 0x70040 +#define PIPE_FRAME_HIGH_MASK 0x0000ffff +#define PIPE_FRAME_HIGH_SHIFT 0 +#define PIPEAFRAMEPIXEL 0x70044 +#define PIPE_FRAME_LOW_MASK 0xff000000 +#define PIPE_FRAME_LOW_SHIFT 24 +#define PIPE_PIXEL_MASK 0x00ffffff +#define PIPE_PIXEL_SHIFT 0 + +/* Cursor A & B regs */ +#define CURACNTR 0x70080 +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_64_32B_AX 0x07 +#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) +#define MCURSOR_GAMMA_ENABLE (1 << 26) +#define CURABASE 0x70084 +#define CURAPOS 0x70088 +#define CURSOR_POS_MASK 0x007FF +#define CURSOR_POS_SIGN 0x8000 +#define CURSOR_X_SHIFT 0 +#define CURSOR_Y_SHIFT 16 +#define CURBCNTR 0x700c0 +#define CURBBASE 0x700c4 +#define CURBPOS 0x700c8 + +/* Display A control */ +#define DSPACNTR 0x70180 +#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_DISABLE 0 +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_15_16BPP (0x4<<26) +#define DISPPLANE_16BPP (0x5<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP (0x7<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_A 0 +#define DISPPLANE_SEL_PIPE_B (1<<24) +#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SRC_KEY_DISABLE 0 +#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_NO_LINE_DOUBLE 0 +#define DISPPLANE_STEREO_POLARITY_FIRST 0 +#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +#define DSPAADDR 0x70184 #define DSPASTRIDE 0x70188 - -#define DSPBBASE 0x71184 -#define DSPBADDR DSPBBASE -#define DSPBSTRIDE 0x71188 - -#define DSPAKEYVAL 0x70194 -#define DSPAKEYMASK 0x70198 - #define DSPAPOS 0x7018C /* reserved */ #define DSPASIZE 0x70190 -#define DSPBPOS 0x7118C -#define DSPBSIZE 0x71190 - -#define DSPASURF 0x7019C -#define DSPATILEOFF 0x701A4 - -#define DSPBSURF 0x7119C -#define DSPBTILEOFF 0x711A4 - -#define VGACNTRL 0x71400 -# define VGA_DISP_DISABLE (1 << 31) -# define VGA_2X_MODE (1 << 30) -# define VGA_PIPE_B_SELECT (1 << 29) - -/* - * Some BIOS scratch area registers. The 845 (and 830?) store the amount - * of video memory available to the BIOS in SWF1. - */ +#define DSPASURF 0x7019C /* 965+ only */ +#define DSPATILEOFF 0x701A4 /* 965+ only */ +/* VBIOS flags */ #define SWF0 0x71410 #define SWF1 0x71414 #define SWF2 0x71418 @@ -1986,27 +1693,33 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define SWF31 0x72418 #define SWF32 0x7241c -/* - * Overlay registers. These are overlay registers accessed via MMIO. - * Those loaded via the overlay register page are defined in i830_video.c. - */ -#define OVADD 0x30000 +/* Pipe B */ +#define PIPEBDSL 0x71000 +#define PIPEBCONF 0x71008 +#define PIPEBSTAT 0x71024 +#define PIPEBFRAMEHIGH 0x71040 +#define PIPEBFRAMEPIXEL 0x71044 -#define DOVSTA 0x30008 -#define OC_BUF (0x3<<20) +/* Display B control */ +#define DSPBCNTR 0x71180 +#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) +#define DISPPLANE_ALPHA_TRANS_DISABLE 0 +#define DISPPLANE_SPRITE_ABOVE_DISPLAY 0 +#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) +#define DSPBADDR 0x71184 +#define DSPBSTRIDE 0x71188 +#define DSPBPOS 0x7118C +#define DSPBSIZE 0x71190 +#define DSPBSURF 0x7119C +#define DSPBTILEOFF 0x711A4 -#define OGAMC5 0x30010 -#define OGAMC4 0x30014 -#define OGAMC3 0x30018 -#define OGAMC2 0x3001c -#define OGAMC1 0x30020 -#define OGAMC0 0x30024 +/* VBIOS regs */ +#define VGACNTRL 0x71400 +# define VGA_DISP_DISABLE (1 << 31) +# define VGA_2X_MODE (1 << 30) +# define VGA_PIPE_B_SELECT (1 << 29) -/* - * Palette registers - */ -#define PALETTE_A 0x0a000 -#define PALETTE_B 0x0a800 +/* Chipset type macros */ #define IS_I830(dev) ((dev)->pci_device == 0x3577) #define IS_845G(dev) ((dev)->pci_device == 0x2562) @@ -2043,6 +1756,4 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev)) -#define PRIMARY_RINGBUFFER_SIZE (128*1024) - #endif diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 22577c7f..0bbad65e 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -112,9 +112,9 @@ int i915_load_modeset_init(struct drm_device *dev) drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1); drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT, 1); - I915_WRITE(LP_RING + RING_LEN, 0); - I915_WRITE(LP_RING + RING_HEAD, 0); - I915_WRITE(LP_RING + RING_TAIL, 0); + I915_WRITE(PRB0_CTL, 0); + I915_WRITE(PRB0_HEAD, 0); + I915_WRITE(PRB0_TAIL, 0); size = PRIMARY_RINGBUFFER_SIZE; ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, @@ -146,10 +146,9 @@ int i915_load_modeset_init(struct drm_device *dev) dev_priv->ring.virtual_start, dev_priv->ring.Size); memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size); - I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start); - I915_WRITE(LP_RING + RING_LEN, - ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | - (RING_NO_REPORT | RING_VALID)); + I915_WRITE(PRB0_START, dev_priv->ring.Start); + I915_WRITE(PRB0_CTL, ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | + (RING_NO_REPORT | RING_VALID)); /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. @@ -175,7 +174,7 @@ int i915_load_modeset_init(struct drm_device *dev) memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page); + I915_WRITE(HWS_PGA, dev_priv->dma_status_page); } else { size = 4 * 1024; ret = drm_buffer_object_create(dev, size, @@ -210,7 +209,7 @@ int i915_load_modeset_init(struct drm_device *dev) } dev_priv->hw_status_page = dev_priv->hws_map.handle; memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(I915REG_HWS_PGA, dev_priv->status_gfx_addr); + I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); } DRM_DEBUG("Enabled hardware status page\n"); @@ -261,7 +260,7 @@ destroy_hws: if (dev_priv->hws_bo) drm_bo_usage_deref_unlocked(&dev_priv->hws_bo); } - I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); + I915_WRITE(HWS_PGA, 0x1ffff000); destroy_ringbuffer: if (dev_priv->ring.virtual_start) drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, @@ -381,7 +380,7 @@ int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - I915_WRITE(LP_RING + RING_LEN, 0); + I915_WRITE(PRB0_CTL, 0); if (drm_core_check_feature(dev, DRIVER_MODESET)) { drm_irq_uninstall(dev); @@ -413,14 +412,14 @@ int i915_driver_unload(struct drm_device *dev) dev_priv->hw_status_page = NULL; dev_priv->dma_status_page = 0; /* Need to rewrite hardware status page */ - I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); + I915_WRITE(HWS_PGA, 0x1ffff000); } if (dev_priv->status_gfx_addr) { dev_priv->status_gfx_addr = 0; drm_core_ioremapfree(&dev_priv->hws_map, dev); drm_bo_usage_deref_unlocked(&dev_priv->hws_bo); - I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); + I915_WRITE(HWS_PGA, 0x1ffff000); } if (drm_core_check_feature(dev, DRIVER_MODESET)) { diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4aef568e..38995421 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -636,9 +636,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) /* On i8xx/i915 hw the IIR and IER are 16bit on i9xx its 32bit */ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - iir = I915_READ(I915REG_INT_IDENTITY_R); + iir = I915_READ(IIR); else - iir = I915_READ16(I915REG_INT_IDENTITY_R); + iir = I915_READ16(IIR); iir &= (dev_priv->irq_enable_reg | I915_USER_INTERRUPT); @@ -649,10 +649,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) #if 0 DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", iir, - I915_READ(I915REG_INT_MASK_R), - I915_READ(I915REG_INT_ENABLE_R), - I915_READ(I915REG_PIPEASTAT), - I915_READ(I915REG_PIPEBSTAT)); + I915_READ(IMR), + I915_READ(IER), + I915_READ(PIPEASTAT), + I915_READ(PIPEBSTAT)); #endif return IRQ_NONE; } @@ -662,19 +662,19 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) * we may get extra interrupts. */ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { - pipea_stats = I915_READ(I915REG_PIPEASTAT); - if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) + pipea_stats = I915_READ(PIPEASTAT); + if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) { vblank++; drm_handle_vblank(dev, i915_get_plane(dev, 0)); } /* This is a global event, and not a pipe A event */ - if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) + if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS) hotplug = 1; - if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS) { + if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS) { hotplug = 1; /* Toggle hotplug detection to clear hotplug status */ tvdac = I915_READ(TV_DAC); @@ -682,27 +682,27 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_WRITE(TV_DAC, tvdac | TVDAC_STATE_CHG_EN); } - I915_WRITE(I915REG_PIPEASTAT, pipea_stats); + I915_WRITE(PIPEASTAT, pipea_stats); } if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { - pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) + pipeb_stats = I915_READ(PIPEBSTAT); + if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) { vblank++; drm_handle_vblank(dev, i915_get_plane(dev, 1)); } - I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); + I915_WRITE(PIPEBSTAT, pipeb_stats); } /* Clear the generated interrupt */ if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - I915_WRITE(I915REG_INT_IDENTITY_R, iir); - (void) I915_READ(I915REG_INT_IDENTITY_R); + I915_WRITE(IIR, iir); + (void) I915_READ(IIR); } else { - I915_WRITE16(I915REG_INT_IDENTITY_R, iir); - (void) I915_READ16(I915REG_INT_IDENTITY_R); + I915_WRITE16(IIR, iir); + (void) I915_READ16(IIR); } if (dev->primary->master) { @@ -728,10 +728,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_INFO("Hotplug event received\n"); if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev)) { - if (pipea_stats & I915_HOTPLUG_INTERRUPT_STATUS) + if (pipea_stats & PIPE_HOTPLUG_INTERRUPT_STATUS) temp2 |= SDVOB_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS; - if (pipea_stats & I915_HOTPLUG_TV_INTERRUPT_STATUS) + if (pipea_stats & PIPE_HOTPLUG_TV_INTERRUPT_STATUS) temp2 |= TV_HOTPLUG_INT_STATUS; } else { temp2 = I915_READ(PORT_HOTPLUG_STAT); @@ -757,7 +757,7 @@ int i915_emit_irq(struct drm_device *dev) BEGIN_LP_RING(2); OUT_RING(0); - OUT_RING(GFX_OP_USER_INTERRUPT); + OUT_RING(MI_USER_INTERRUPT); ADVANCE_LP_RING(); return dev_priv->counter; @@ -771,9 +771,9 @@ void i915_user_irq_on(struct drm_device *dev) if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE(IER, dev_priv->irq_enable_reg); else - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE16(IER, dev_priv->irq_enable_reg); } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); @@ -787,9 +787,9 @@ void i915_user_irq_off(struct drm_device *dev) if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { // dev_priv->irq_enable_reg &= ~I915_USER_INTERRUPT; // if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - // I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + // I915_WRITE(IER, dev_priv->irq_enable_reg); // else - // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + // I915_WRITE16(IER, dev_priv->irq_enable_reg); } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } @@ -876,11 +876,11 @@ int i915_enable_vblank(struct drm_device *dev, int plane) switch (pipe) { case 0: - pipestat_reg = I915REG_PIPEASTAT; + pipestat_reg = PIPEASTAT; dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: - pipestat_reg = I915REG_PIPEBSTAT; + pipestat_reg = PIPEBSTAT; dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: @@ -897,21 +897,21 @@ int i915_enable_vblank(struct drm_device *dev, int plane) * but */ if (IS_I965G (dev)) - pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE; + pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; else - pipestat |= I915_VBLANK_INTERRUPT_ENABLE; + pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; /* * Clear any pending status */ - pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | - I915_VBLANK_INTERRUPT_STATUS); + pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | + PIPE_VBLANK_INTERRUPT_STATUS); I915_WRITE(pipestat_reg, pipestat); } if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE(IER, dev_priv->irq_enable_reg); else - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE16(IER, dev_priv->irq_enable_reg); return 0; @@ -926,11 +926,11 @@ void i915_disable_vblank(struct drm_device *dev, int plane) switch (pipe) { case 0: - pipestat_reg = I915REG_PIPEASTAT; + pipestat_reg = PIPEASTAT; dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: - pipestat_reg = I915REG_PIPEBSTAT; + pipestat_reg = PIPEBSTAT; dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: @@ -940,20 +940,20 @@ void i915_disable_vblank(struct drm_device *dev, int plane) } if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE(IER, dev_priv->irq_enable_reg); else - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE16(IER, dev_priv->irq_enable_reg); if (pipestat_reg) { pipestat = I915_READ (pipestat_reg); - pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE | - I915_VBLANK_INTERRUPT_ENABLE); + pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | + PIPE_VBLANK_INTERRUPT_ENABLE); /* * Clear any pending status */ - pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | - I915_VBLANK_INTERRUPT_STATUS); + pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | + PIPE_VBLANK_INTERRUPT_STATUS); I915_WRITE(pipestat_reg, pipestat); } } @@ -973,11 +973,11 @@ void i915_enable_interrupt (struct drm_device *dev) dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; /* Enable global interrupts for hotplug - not a pipeA event */ - I915_WRITE(I915REG_PIPEASTAT, I915_READ(I915REG_PIPEASTAT) | - I915_HOTPLUG_INTERRUPT_ENABLE | - I915_HOTPLUG_TV_INTERRUPT_ENABLE | - I915_HOTPLUG_TV_CLEAR | - I915_HOTPLUG_CLEAR); + I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) | + PIPE_HOTPLUG_INTERRUPT_ENABLE | + PIPE_HOTPLUG_TV_INTERRUPT_ENABLE | + PIPE_HOTPLUG_TV_INTERRUPT_STATUS | + PIPE_HOTPLUG_INTERRUPT_STATUS); } if (dev_priv->irq_enable_reg & (I915_DISPLAY_PORT_INTERRUPT | I915_DISPLAY_PIPE_A_EVENT_INTERRUPT)) { @@ -1025,9 +1025,9 @@ void i915_enable_interrupt (struct drm_device *dev) } if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE(IER, dev_priv->irq_enable_reg); else - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE16(IER, dev_priv->irq_enable_reg); dev_priv->irq_enabled = 1; } @@ -1068,9 +1068,9 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, } if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) - flag = I915_READ(I915REG_INT_ENABLE_R); + flag = I915_READ(IER); else - flag = I915_READ16(I915REG_INT_ENABLE_R); + flag = I915_READ16(IER); pipe->pipe = 0; if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) @@ -1249,23 +1249,23 @@ void i915_driver_irq_preinstall(struct drm_device * dev) struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; u32 tmp; - tmp = I915_READ(I915REG_PIPEASTAT); - I915_WRITE(I915REG_PIPEASTAT, tmp); - tmp = I915_READ(I915REG_PIPEBSTAT); - I915_WRITE(I915REG_PIPEBSTAT, tmp); + tmp = I915_READ(PIPEASTAT); + I915_WRITE(PIPEASTAT, tmp); + tmp = I915_READ(PIPEBSTAT); + I915_WRITE(PIPEBSTAT, tmp); - I915_WRITE16(I915REG_HWSTAM, 0xeffe); + I915_WRITE16(HWSTAM, 0xeffe); if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - I915_WRITE(I915REG_INT_MASK_R, 0x0); - I915_WRITE(I915REG_INT_ENABLE_R, 0x0); - tmp = I915_READ(I915REG_INT_IDENTITY_R); - I915_WRITE(I915REG_INT_IDENTITY_R, tmp); + I915_WRITE(IMR, 0x0); + I915_WRITE(IER, 0x0); + tmp = I915_READ(IIR); + I915_WRITE(IIR, tmp); } else { - I915_WRITE16(I915REG_INT_MASK_R, 0x0); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); - tmp = I915_READ16(I915REG_INT_IDENTITY_R); - I915_WRITE16(I915REG_INT_IDENTITY_R, tmp); + I915_WRITE16(IMR, 0x0); + I915_WRITE16(IER, 0x0); + tmp = I915_READ16(IIR); + I915_WRITE16(IIR, tmp); } } @@ -1300,7 +1300,7 @@ int i915_driver_irq_postinstall(struct drm_device * dev) * Initialize the hardware status page IRQ location. */ - I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); + I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); return 0; } @@ -1314,23 +1314,23 @@ void i915_driver_irq_uninstall(struct drm_device * dev) dev_priv->irq_enabled = 0; - temp = I915_READ(I915REG_PIPEASTAT); - I915_WRITE(I915REG_PIPEASTAT, temp); - temp = I915_READ(I915REG_PIPEBSTAT); - I915_WRITE(I915REG_PIPEBSTAT, temp); + temp = I915_READ(PIPEASTAT); + I915_WRITE(PIPEASTAT, temp); + temp = I915_READ(PIPEBSTAT); + I915_WRITE(PIPEBSTAT, temp); if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - I915_WRITE(I915REG_HWSTAM, 0xffffffff); - I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); - I915_WRITE(I915REG_INT_ENABLE_R, 0x0); + I915_WRITE(HWSTAM, 0xffffffff); + I915_WRITE(IMR, 0xffffffff); + I915_WRITE(IER, 0x0); - temp = I915_READ(I915REG_INT_IDENTITY_R); - I915_WRITE(I915REG_INT_IDENTITY_R, temp); + temp = I915_READ(IIR); + I915_WRITE(IIR, temp); } else { - I915_WRITE16(I915REG_HWSTAM, 0xffff); - I915_WRITE16(I915REG_INT_MASK_R, 0xffff); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + I915_WRITE16(HWSTAM, 0xffff); + I915_WRITE16(IMR, 0xffff); + I915_WRITE16(IER, 0x0); - temp = I915_READ16(I915REG_INT_IDENTITY_R); - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + temp = I915_READ16(IIR); + I915_WRITE16(IIR, temp); } } -- cgit v1.2.3 From e8320a716d97504d91299d20d640b847c86e4b17 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Mon, 19 May 2008 17:06:38 +0800 Subject: i915: init bo mm at driver init only when modeset=1 To avoid bo memory manager being inited twice, it will be called at firstopen when modeset is not enabled. --- shared-core/i915_init.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 98908a50..f5fe5ba4 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -353,16 +353,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) #endif #endif - /* - * Initialize the memory manager for local and AGP space - */ - ret = drm_bo_driver_init(dev); - if (ret) { - DRM_ERROR("fail to init memory manager for local & AGP space\n"); - goto out_rmmap; - } - if (drm_core_check_feature(dev, DRIVER_MODESET)) { + /* + * Initialize the memory manager for local and AGP space + */ + ret = drm_bo_driver_init(dev); + if (ret) { + DRM_ERROR("fail to init memory manager for " + "local & AGP space\n"); + goto out_rmmap; + } + ret = i915_load_modeset_init(dev); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); -- cgit v1.2.3 From 1cde3cc1ac467eb0527ed55127cf3bb983afde80 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Mon, 19 May 2008 17:06:40 +0800 Subject: i915: check dummy page before freeing The dummy read page will point to NULL if drm_bo_driver_init failed at firstopen (modeset is not enabled), and will cause kernel oops at subsequent drm_lastclose call, so be sure to check it. --- linux-core/drm_bo.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 0470825b..f2d3cebf 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2361,10 +2361,12 @@ int drm_bo_driver_finish(struct drm_device *dev) if (list_empty(&bm->unfenced)) DRM_DEBUG("Unfenced list was clean\n"); + if (bm->dummy_read_page) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) - ClearPageReserved(bm->dummy_read_page); + ClearPageReserved(bm->dummy_read_page); #endif - __free_page(bm->dummy_read_page); + __free_page(bm->dummy_read_page); + } out: mutex_unlock(&dev->struct_mutex); -- cgit v1.2.3 From b4d8cda8e6d6ea319ab7c471d6d68b8af8693cfe Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 23 May 2008 18:41:58 -0700 Subject: drm_mode_debug_printmodeline doesn't need struct drm_device * Makes printing modelines from some routines easier. --- linux-core/drm_crtc.c | 8 ++++---- linux-core/drm_crtc.h | 3 +-- linux-core/drm_modes.c | 5 ++--- linux-core/intel_display.c | 4 +--- linux-core/intel_fb.c | 10 +++++----- linux-core/radeon_ms_fb.c | 6 +++--- 6 files changed, 16 insertions(+), 20 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c011db30..e05466ee 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -404,7 +404,7 @@ void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int mode->vrefresh = drm_mode_vrefresh(mode); drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - drm_mode_debug_printmodeline(dev, mode); + drm_mode_debug_printmodeline(mode); } } @@ -1161,8 +1161,8 @@ int drm_crtc_set_config(struct drm_mode_set *set) if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { DRM_DEBUG("modes are different\n"); - drm_mode_debug_printmodeline(dev, &set->crtc->mode); - drm_mode_debug_printmodeline(dev, set->mode); + drm_mode_debug_printmodeline(&set->crtc->mode); + drm_mode_debug_printmodeline(set->mode); changed = true; } @@ -1193,7 +1193,7 @@ int drm_crtc_set_config(struct drm_mode_set *set) set->crtc->enabled = (set->mode != NULL); if (set->mode != NULL) { DRM_DEBUG("attempting to set mode from userspace\n"); - drm_mode_debug_printmodeline(dev, set->mode); + drm_mode_debug_printmodeline(set->mode); if (!drm_crtc_set_mode(set->crtc, set->mode, set->x, set->y)) { set->crtc->enabled = save_enabled; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 1d36dcd4..ae2dd173 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -561,8 +561,7 @@ extern void drm_mode_probed_add(struct drm_output *output, struct drm_display_mo extern void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode); extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *mode); -extern void drm_mode_debug_printmodeline(struct drm_device *dev, - struct drm_display_mode *mode); +extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode); extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_set_name(struct drm_display_mode *mode); diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 3763ca69..897777d0 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -43,8 +43,7 @@ * * Describe @mode using DRM_DEBUG. */ -void drm_mode_debug_printmodeline(struct drm_device *dev, - struct drm_display_mode *mode) +void drm_mode_debug_printmodeline(struct drm_display_mode *mode) { DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", mode->mode_id, mode->name, mode->vrefresh, mode->clock, @@ -388,7 +387,7 @@ void drm_mode_prune_invalid(struct drm_device *dev, if (mode->status != MODE_OK) { list_del(&mode->head); if (verbose) { - drm_mode_debug_printmodeline(dev, mode); + drm_mode_debug_printmodeline(mode); DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status); } kfree(mode); diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 273f76d0..e7162c2c 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -846,7 +846,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(PFIT_CONTROL, 0); DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); - drm_mode_debug_printmodeline(dev, mode); + drm_mode_debug_printmodeline(mode); #if 0 if (!xf86ModesEqual(mode, adjusted_mode)) { @@ -1015,8 +1015,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, temp |= (pipe << 28); temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; - DRM_DEBUG("cusror base %x\n", addr); - I915_WRITE(control, temp); I915_WRITE(base, addr); diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 9934e3af..4f5a0000 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -288,9 +288,9 @@ static int intelfb_set_par(struct fb_info *info) return -EINVAL; found = 0; - drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(drm_mode); list_for_each_entry(search_mode, &output->modes, head) { - drm_mode_debug_printmodeline(dev, search_mode); + drm_mode_debug_printmodeline(search_mode); if (drm_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); drm_mode = search_mode; @@ -310,7 +310,7 @@ static int intelfb_set_par(struct fb_info *info) par->set.mode = drm_mode; par->our_mode = drm_mode; - drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(drm_mode); /* attach mode */ drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); } else { @@ -330,8 +330,8 @@ static int intelfb_set_par(struct fb_info *info) if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) changed = 1; - drm_mode_debug_printmodeline(dev, drm_mode); - drm_mode_debug_printmodeline(dev, &par->crtc->mode); + drm_mode_debug_printmodeline(drm_mode); + drm_mode_debug_printmodeline(&par->crtc->mode); if (!drm_mode_equal(drm_mode, &par->crtc->mode)) changed = 1; diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index 082279ec..e320144e 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -221,9 +221,9 @@ static int radeonfb_set_par(struct fb_info *info) break; } - drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(drm_mode); list_for_each_entry(search_mode, &output->modes, head) { - drm_mode_debug_printmodeline(dev, search_mode); + drm_mode_debug_printmodeline(search_mode); if (radeonfb_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); drm_mode = search_mode; @@ -237,7 +237,7 @@ static int radeonfb_set_par(struct fb_info *info) drm_mode_detachmode_crtc(dev, par->fb_mode); } par->fb_mode = drm_mode; - drm_mode_debug_printmodeline(dev, drm_mode); + drm_mode_debug_printmodeline(drm_mode); /* attach mode */ drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode); } -- cgit v1.2.3 From 9fc4ea5c00dfb91ebff893fb5092e768155cc2e2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 23 May 2008 18:42:47 -0700 Subject: i915: do a better job of parsing VBIOS data Add code to get panel modes from the VBIOS if present and check whether certain outputs exist. Should make our display detection code a little more robust. --- linux-core/i915_drv.c | 4 +- linux-core/intel_bios.c | 322 ++++++++++++++++++++++++------------------------ linux-core/intel_bios.h | 312 +++++++++++++++++++++++++++++++++++++++------- linux-core/intel_lvds.c | 48 +++----- linux-core/intel_tv.c | 2 +- shared-core/i915_drv.h | 26 ++-- shared-core/i915_init.c | 4 +- 7 files changed, 461 insertions(+), 257 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 27c239d0..51262d79 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -387,7 +387,7 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) /* Scratch space */ for (i = 0; i < 16; i++) { - dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); + dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2)); dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2)); } for (i = 0; i < 3; i++) @@ -551,7 +551,7 @@ static int i915_resume(struct drm_device *dev) I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); for (i = 0; i < 16; i++) { - I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); + I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]); I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); } for (i = 0; i < 3; i++) diff --git a/linux-core/intel_bios.c b/linux-core/intel_bios.c index 7f8e8513..f124fa1a 100644 --- a/linux-core/intel_bios.c +++ b/linux-core/intel_bios.c @@ -30,170 +30,7 @@ #include "i915_drv.h" #include "intel_bios.h" -#define VBT_OFFSET 0x1a - -/** - * intel_find_vbt - find the VBT - * @dev: DRM device - * - * Loads the Video BIOS and checks that the VBT exists. - * - * VBT existence is a sanity check that is relied on by other i830_bios.c code. - * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may - * feed an updated VBT back through that, compared to what we'll fetch using - * this method of groping around in the BIOS data. - * - * Returns 0 on success, nonzero on failure. - */ -bool -intel_find_bios(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct pci_dev *pdev = dev->pdev; - void __iomem *bios; - size_t size; - - bios = pci_map_rom(pdev, &size); - if (!bios) - return NULL; - - dev_priv->vbt = (struct vbt_header *)((u8 *)bios + VBT_OFFSET); - dev_priv->bdb = (struct bdb_header *)((u8 *)bios + VBT_OFFSET + - dev_priv->vbt->bdb_offset); - - if (memcmp(dev_priv->vbt->signature, "$VBT", 4) != 0) { - DRM_ERROR("Bad VBT signature\n"); - pci_unmap_rom(pdev, bios); - return NULL; - } - - return bios; -} - #if 0 -/** - * Returns the BIOS's fixed panel mode. - * - * Note that many BIOSes will have the appropriate tables for a panel even when - * a panel is not attached. Additionally, many BIOSes adjust table sizes or - * offsets, such that this parsing fails. Thus, almost any other method for - * detecting the panel mode is preferable. - */ -struct drm_display_mode * -i830_bios_get_panel_mode(struct drm_device *dev, bool *wants_dither) -{ - I830Ptr pI830 = I830PTR(pScrn); - struct vbt_header *vbt; - struct bdb_header *bdb; - int vbt_off, bdb_off, bdb_block_off, block_size; - int panel_type = -1; - unsigned char *bios; - - bios = i830_bios_get (pScrn); - - if (bios == NULL) - return NULL; - - vbt_off = INTEL_BIOS_16(0x1a); - vbt = (struct vbt_header *)(bios + vbt_off); - bdb_off = vbt_off + vbt->bdb_offset; - bdb = (struct bdb_header *)(bios + bdb_off); - - if (memcmp(bdb->signature, "BIOS_DATA_BLOCK ", 16) != 0) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Bad BDB signature\n"); - xfree(bios); - return NULL; - } - - *wants_dither = FALSE; - for (bdb_block_off = bdb->header_size; bdb_block_off < bdb->bdb_size; - bdb_block_off += block_size) - { - int start = bdb_off + bdb_block_off; - int id; - struct lvds_bdb_1 *lvds1; - struct lvds_bdb_2 *lvds2; - struct lvds_bdb_2_fp_params *fpparam; - struct lvds_bdb_2_fp_edid_dtd *fptiming; - DisplayModePtr fixed_mode; - CARD8 *timing_ptr; - - id = INTEL_BIOS_8(start); - block_size = INTEL_BIOS_16(start + 1) + 3; - switch (id) { - case 40: - lvds1 = (struct lvds_bdb_1 *)(bios + start); - panel_type = lvds1->panel_type; - if (lvds1->caps & LVDS_CAP_DITHER) - *wants_dither = TRUE; - break; - case 41: - if (panel_type == -1) - break; - - lvds2 = (struct lvds_bdb_2 *)(bios + start); - fpparam = (struct lvds_bdb_2_fp_params *)(bios + - bdb_off + lvds2->panels[panel_type].fp_params_offset); - fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios + - bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset); - timing_ptr = bios + bdb_off + - lvds2->panels[panel_type].fp_edid_dtd_offset; - - if (fpparam->terminator != 0xffff) { - /* Apparently the offsets are wrong for some BIOSes, so we - * try the other offsets if we find a bad terminator. - */ - fpparam = (struct lvds_bdb_2_fp_params *)(bios + - bdb_off + lvds2->panels[panel_type].fp_params_offset + 8); - fptiming = (struct lvds_bdb_2_fp_edid_dtd *)(bios + - bdb_off + lvds2->panels[panel_type].fp_edid_dtd_offset + 8); - timing_ptr = bios + bdb_off + - lvds2->panels[panel_type].fp_edid_dtd_offset + 8; - - if (fpparam->terminator != 0xffff) - continue; - } - - fixed_mode = xnfalloc(sizeof(DisplayModeRec)); - memset(fixed_mode, 0, sizeof(*fixed_mode)); - - /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing - * block, pull the contents out using EDID macros. - */ - fixed_mode->HDisplay = _H_ACTIVE(timing_ptr); - fixed_mode->VDisplay = _V_ACTIVE(timing_ptr); - fixed_mode->HSyncStart = fixed_mode->HDisplay + - _H_SYNC_OFF(timing_ptr); - fixed_mode->HSyncEnd = fixed_mode->HSyncStart + - _H_SYNC_WIDTH(timing_ptr); - fixed_mode->HTotal = fixed_mode->HDisplay + - _H_BLANK(timing_ptr); - fixed_mode->VSyncStart = fixed_mode->VDisplay + - _V_SYNC_OFF(timing_ptr); - fixed_mode->VSyncEnd = fixed_mode->VSyncStart + - _V_SYNC_WIDTH(timing_ptr); - fixed_mode->VTotal = fixed_mode->VDisplay + - _V_BLANK(timing_ptr); - fixed_mode->Clock = _PIXEL_CLOCK(timing_ptr) / 1000; - fixed_mode->type = M_T_PREFERRED; - - xf86SetModeDefaultName(fixed_mode); - - if (pI830->debug_modes) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Found panel mode in BIOS VBT tables:\n"); - xf86PrintModeline(pScrn->scrnIndex, fixed_mode); - } - - xfree(bios); - return fixed_mode; - } - } - - xfree(bios); - return NULL; -} - unsigned char * i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block) { @@ -242,3 +79,162 @@ i830_bios_get_aim_data_block (ScrnInfoPtr pScrn, int aim, int data_block) return NULL; } #endif + +static void * +find_section(struct bdb_header *bdb, int section_id) +{ + u8 *base = (u8 *)bdb; + int index = 0; + u16 total, current_size; + u8 current_id; + + /* skip to first section */ + index += bdb->header_size; + total = bdb->bdb_size; + + /* walk the sections looking for section_id */ + while (index < total) { + current_id = *(base + index); + index++; + current_size = *((u16 *)(base + index)); + index += 2; + if (current_id == section_id) + return base + index; + index += current_size; + } + + return NULL; +} + +/* Try to find panel data */ +static void +parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) +{ + struct bdb_lvds_options *lvds_options; + struct bdb_lvds_lfp_data *lvds_lfp_data; + struct bdb_lvds_lfp_data_entry *entry; + struct lvds_dvo_timing *dvo_timing; + struct drm_display_mode *panel_fixed_mode; + + /* Defaults if we can't find VBT info */ + dev_priv->lvds_dither = 0; + dev_priv->lvds_vbt = 0; + + lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); + if (!lvds_options) + return; + + dev_priv->lvds_dither = lvds_options->pixel_dither; + if (lvds_options->panel_type == 0xff) + return; + + lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); + if (!lvds_lfp_data) + return; + + dev_priv->lvds_vbt = 1; + + entry = &lvds_lfp_data->data[lvds_options->panel_type]; + dvo_timing = &entry->dvo_timing; + + panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), + DRM_MEM_DRIVER); + + panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | + dvo_timing->hactive_lo; + panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + + ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); + panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + + dvo_timing->hsync_pulse_width; + panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + + ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); + + panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | + dvo_timing->vactive_lo; + panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + + dvo_timing->vsync_off; + panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + + dvo_timing->vsync_pulse_width; + panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + + ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); + panel_fixed_mode->clock = dvo_timing->clock * 10; + panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; + + drm_mode_set_name(panel_fixed_mode); + + dev_priv->vbt_mode = panel_fixed_mode; + + DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); + drm_mode_debug_printmodeline(panel_fixed_mode); + + return; +} + +static void +parse_general_features(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct bdb_general_features *general; + + /* Set sensible defaults in case we can't find the general block */ + dev_priv->int_tv_support = 1; + dev_priv->int_crt_support = 1; + + general = find_section(bdb, BDB_GENERAL_FEATURES); + if (general) { + dev_priv->int_tv_support = general->int_tv_support; + dev_priv->int_crt_support = general->int_crt_support; + } +} + +/** + * intel_init_bios - initialize VBIOS settings & find VBT + * @dev: DRM device + * + * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers + * to appropriate values. + * + * VBT existence is a sanity check that is relied on by other i830_bios.c code. + * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may + * feed an updated VBT back through that, compared to what we'll fetch using + * this method of groping around in the BIOS data. + * + * Returns 0 on success, nonzero on failure. + */ +bool +intel_init_bios(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct pci_dev *pdev = dev->pdev; + struct vbt_header *vbt = NULL; + struct bdb_header *bdb; + u8 __iomem *bios; + size_t size; + int i; + + bios = pci_map_rom(pdev, &size); + if (!bios) + return -1; + + /* Scour memory looking for the VBT signature */ + for (i = 0; i + 4 < size; i++) { + if (!memcmp(bios + i, "$VBT", 4)) { + vbt = (struct vbt_header *)(bios + i); + break; + } + } + + if (!vbt) { + DRM_ERROR("VBT signature missing\n"); + pci_unmap_rom(pdev, bios); + return -1; + } + + bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); + + /* Grab useful general definitions */ + parse_general_features(dev_priv, bdb); + parse_panel_data(dev_priv, bdb); + + return 0; +} diff --git a/linux-core/intel_bios.h b/linux-core/intel_bios.h index b17856de..5ea715ac 100644 --- a/linux-core/intel_bios.h +++ b/linux-core/intel_bios.h @@ -46,6 +46,10 @@ struct bdb_header { u16 version; /**< decimal */ u16 header_size; /**< in bytes */ u16 bdb_size; /**< in bytes */ +}; + +/* strictly speaking, this is a "skip" block, but it has interesting info */ +struct vbios_data { u8 type; /* 0 == desktop, 1 == mobile */ u8 relstage; u8 chipset; @@ -58,48 +62,133 @@ struct bdb_header { u16 code_segment; u8 dos_boot_mode; u8 bandwidth_percent; - u8 rsvd4; + u8 rsvd4; /* popup memory size */ u8 resize_pci_bios; - u8 rsvd5; - u8 rsvd6[3]; + u8 rsvd5; /* is crt already on ddc2 */ +} __attribute__((packed)); + +/* + * There are several types of BIOS data blocks (BDBs), each block has + * an ID and size in the first 3 bytes (ID in first, size in next 2). + * Known types are listed below. + */ +#define BDB_GENERAL_FEATURES 1 +#define BDB_GENERAL_DEFINITIONS 2 +#define BDB_OLD_TOGGLE_LIST 3 +#define BDB_MODE_SUPPORT_LIST 4 +#define BDB_GENERIC_MODE_TABLE 5 +#define BDB_EXT_MMIO_REGS 6 +#define BDB_SWF_IO 7 +#define BDB_SWF_MMIO 8 +#define BDB_DOT_CLOCK_TABLE 9 +#define BDB_MODE_REMOVAL_TABLE 10 +#define BDB_CHILD_DEVICE_TABLE 11 +#define BDB_DRIVER_FEATURES 12 +#define BDB_DRIVER_PERSISTENCE 13 +#define BDB_EXT_TABLE_PTRS 14 +#define BDB_DOT_CLOCK_OVERRIDE 15 +#define BDB_DISPLAY_SELECT 16 +/* 17 rsvd */ +#define BDB_DRIVER_ROTATION 18 +#define BDB_DISPLAY_REMOVE 19 +#define BDB_OEM_CUSTOM 20 +#define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ +#define BDB_SDVO_LVDS_OPTIONS 22 +#define BDB_SDVO_PANEL_DTDS 23 +#define BDB_SDVO_LVDS_PNP_IDS 24 +#define BDB_SDVO_LVDS_POWER_SEQ 25 +#define BDB_TV_OPTIONS 26 +#define BDB_LVDS_OPTIONS 40 +#define BDB_LVDS_LFP_DATA_PTRS 41 +#define BDB_LVDS_LFP_DATA 42 +#define BDB_LVDS_BACKLIGHT 43 +#define BDB_LVDS_POWER 44 +#define BDB_SKIP 254 /* VBIOS private block, ignore */ + +struct bdb_general_features { + /* bits 1 */ u8 panel_fitting:2; u8 flexaim:1; u8 msg_enable:1; - u8 clear_screen:1; + u8 clear_screen:3; u8 color_flip:1; - u8 rsvd7:2; /* finish byte */ + + /* bits 2 */ u8 download_ext_vbt:1; u8 enable_ssc:1; u8 ssc_freq:1; u8 enable_lfp_on_override:1; u8 disable_ssc_ddt:1; u8 rsvd8:3; /* finish byte */ + + /* bits 3 */ u8 disable_smooth_vision:1; u8 single_dvi:1; u8 rsvd9:6; /* finish byte */ - u8 legacy_monitor_detect:1; - u8 rsvd10:7; /* finish byte */ + + /* bits 4 */ + u8 legacy_monitor_detect; + + /* bits 5 */ u8 int_crt_support:1; u8 int_tv_support:1; u8 rsvd11:6; /* finish byte */ } __attribute__((packed)); -#define LVDS_CAP_EDID (1 << 6) -#define LVDS_CAP_DITHER (1 << 5) -#define LVDS_CAP_PFIT_AUTO_RATIO (1 << 4) -#define LVDS_CAP_PFIT_GRAPHICS_MODE (1 << 3) -#define LVDS_CAP_PFIT_TEXT_MODE (1 << 2) -#define LVDS_CAP_PFIT_GRAPHICS (1 << 1) -#define LVDS_CAP_PFIT_TEXT (1 << 0) -struct lvds_bdb_1 { - u8 id; /**< 40 */ - u16 size; +struct bdb_general_definitions { + /* DDC GPIO */ + u8 crt_ddc_gmbus_pin; + + /* DPMS bits */ + u8 dpms_acpi:1; + u8 skip_boot_crt_detect:1; + u8 dpms_aim:1; + u8 rsvd1:5; /* finish byte */ + + /* boot device bits */ + u8 boot_display[2]; + u8 child_dev_size; + + /* device info */ + u8 tv_or_lvds_info[33]; + u8 dev1[33]; + u8 dev2[33]; + u8 dev3[33]; + u8 dev4[33]; + /* may be another device block here on some platforms */ +}; + +struct bdb_lvds_options { u8 panel_type; - u8 reserved0; - u16 caps; + u8 rsvd1; + /* LVDS capabilities, stored in a dword */ + u8 rsvd2:1; + u8 lvds_edid:1; + u8 pixel_dither:1; + u8 pfit_ratio_auto:1; + u8 pfit_gfx_mode_enhanced:1; + u8 pfit_text_mode_enhanced:1; + u8 pfit_mode:2; + u8 rsvd4; } __attribute__((packed)); -struct lvds_bdb_2_fp_params { +/* LFP pointer table contains entries to the struct below */ +struct bdb_lvds_lfp_data_ptr { + u16 fp_timing_offset; /* offsets are from start of bdb */ + u8 fp_table_size; + u16 dvo_timing_offset; + u8 dvo_table_size; + u16 panel_pnp_id_offset; + u8 pnp_table_size; +} __attribute__((packed)); + +struct bdb_lvds_lfp_data_ptrs { + u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ + struct bdb_lvds_lfp_data_ptr ptr[16]; +} __attribute__((packed)); + +/* LFP data has 3 blocks per entry */ +struct lvds_fp_timing { u16 x_res; u16 y_res; u32 lvds_reg; @@ -115,42 +204,50 @@ struct lvds_bdb_2_fp_params { u16 terminator; } __attribute__((packed)); -struct lvds_bdb_2_fp_edid_dtd { - u16 dclk; /**< In 10khz */ - u8 hactive; - u8 hblank; - u8 high_h; /**< 7:4 = hactive 11:8, 3:0 = hblank 11:8 */ - u8 vactive; - u8 vblank; - u8 high_v; /**< 7:4 = vactive 11:8, 3:0 = vblank 11:8 */ - u8 hsync_off; +struct lvds_dvo_timing { + u16 clock; /**< In 10khz */ + u8 hactive_lo; + u8 hblank_lo; + u8 hblank_hi:4; + u8 hactive_hi:4; + u8 vactive_lo; + u8 vblank_lo; + u8 vblank_hi:4; + u8 vactive_hi:4; + u8 hsync_off_lo; u8 hsync_pulse_width; - u8 vsync_off; - u8 high_hsync_off; /**< 7:6 = hsync off 9:8 */ + u8 vsync_pulse_width:4; + u8 vsync_off:4; + u8 rsvd0:6; + u8 hsync_off_hi:2; u8 h_image; u8 v_image; u8 max_hv; u8 h_border; u8 v_border; - u8 flags; -#define FP_EDID_FLAG_VSYNC_POSITIVE (1 << 2) -#define FP_EDID_FLAG_HSYNC_POSITIVE (1 << 1) + u8 rsvd1:3; + u8 digital:2; + u8 vsync_positive:1; + u8 hsync_positive:1; + u8 rsvd2:1; +} __attribute__((packed)); + +struct lvds_pnp_id { + u16 mfg_name; + u16 product_code; + u32 serial; + u8 mfg_week; + u8 mfg_year; } __attribute__((packed)); -struct lvds_bdb_2_entry { - u16 fp_params_offset; /**< From beginning of BDB */ - u8 fp_params_size; - u16 fp_edid_dtd_offset; - u8 fp_edid_dtd_size; - u16 fp_edid_pid_offset; - u8 fp_edid_pid_size; +struct bdb_lvds_lfp_data_entry { + struct lvds_fp_timing fp_timing; + struct lvds_dvo_timing dvo_timing; + struct lvds_pnp_id pnp_id; } __attribute__((packed)); -struct lvds_bdb_2 { - u8 id; /**< 41 */ - u16 size; - u8 table_size; /* not sure on this one */ - struct lvds_bdb_2_entry panels[16]; +struct bdb_lvds_lfp_data { + struct bdb_lvds_lfp_data_entry data[16]; } __attribute__((packed)); struct aimdb_header { @@ -182,6 +279,127 @@ struct vch_bdb_22 { struct vch_panel_data panels[16]; } __attribute__((packed)); -bool intel_find_bios(struct drm_device *dev); +bool intel_init_bios(struct drm_device *dev); + +/* + * Driver<->VBIOS interaction occurs through scratch bits in + * GR18 & SWF*. + */ + +/* GR18 bits are set on display switch and hotkey events */ +#define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ +#define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ +#define GR18_HK_NONE (0x0<<3) +#define GR18_HK_LFP_STRETCH (0x1<<3) +#define GR18_HK_TOGGLE_DISP (0x2<<3) +#define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ +#define GR18_HK_POPUP_DISABLED (0x6<<3) +#define GR18_HK_POPUP_ENABLED (0x7<<3) +#define GR18_HK_PFIT (0x8<<3) +#define GR18_HK_APM_CHANGE (0xa<<3) +#define GR18_HK_MULTIPLE (0xc<<3) +#define GR18_USER_INT_EN (1<<2) +#define GR18_A0000_FLUSH_EN (1<<1) +#define GR18_SMM_EN (1<<0) + +/* Set by driver, cleared by VBIOS */ +#define SWF00_YRES_SHIFT 16 +#define SWF00_XRES_SHIFT 0 +#define SWF00_RES_MASK 0xffff + +/* Set by VBIOS at boot time and driver at runtime */ +#define SWF01_TV2_FORMAT_SHIFT 8 +#define SWF01_TV1_FORMAT_SHIFT 0 +#define SWF01_TV_FORMAT_MASK 0xffff + +#define SWF10_VBIOS_BLC_I2C_EN (1<<29) +#define SWF10_GTT_OVERRIDE_EN (1<<28) +#define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ +#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) +#define SWF10_OLD_TOGGLE 0x0 +#define SWF10_TOGGLE_LIST_1 0x1 +#define SWF10_TOGGLE_LIST_2 0x2 +#define SWF10_TOGGLE_LIST_3 0x3 +#define SWF10_TOGGLE_LIST_4 0x4 +#define SWF10_PANNING_EN (1<<23) +#define SWF10_DRIVER_LOADED (1<<22) +#define SWF10_EXTENDED_DESKTOP (1<<21) +#define SWF10_EXCLUSIVE_MODE (1<<20) +#define SWF10_OVERLAY_EN (1<<19) +#define SWF10_PLANEB_HOLDOFF (1<<18) +#define SWF10_PLANEA_HOLDOFF (1<<17) +#define SWF10_VGA_HOLDOFF (1<<16) +#define SWF10_ACTIVE_DISP_MASK 0xffff +#define SWF10_PIPEB_LFP2 (1<<15) +#define SWF10_PIPEB_EFP2 (1<<14) +#define SWF10_PIPEB_TV2 (1<<13) +#define SWF10_PIPEB_CRT2 (1<<12) +#define SWF10_PIPEB_LFP (1<<11) +#define SWF10_PIPEB_EFP (1<<10) +#define SWF10_PIPEB_TV (1<<9) +#define SWF10_PIPEB_CRT (1<<8) +#define SWF10_PIPEA_LFP2 (1<<7) +#define SWF10_PIPEA_EFP2 (1<<6) +#define SWF10_PIPEA_TV2 (1<<5) +#define SWF10_PIPEA_CRT2 (1<<4) +#define SWF10_PIPEA_LFP (1<<3) +#define SWF10_PIPEA_EFP (1<<2) +#define SWF10_PIPEA_TV (1<<1) +#define SWF10_PIPEA_CRT (1<<0) + +#define SWF11_MEMORY_SIZE_SHIFT 16 +#define SWF11_SV_TEST_EN (1<<15) +#define SWF11_IS_AGP (1<<14) +#define SWF11_DISPLAY_HOLDOFF (1<<13) +#define SWF11_DPMS_REDUCED (1<<12) +#define SWF11_IS_VBE_MODE (1<<11) +#define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ +#define SWF11_DPMS_MASK 0x07 +#define SWF11_DPMS_OFF (1<<2) +#define SWF11_DPMS_SUSPEND (1<<1) +#define SWF11_DPMS_STANDBY (1<<0) +#define SWF11_DPMS_ON 0 + +#define SWF14_GFX_PFIT_EN (1<<31) +#define SWF14_TEXT_PFIT_EN (1<<30) +#define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */ +#define SWF14_POPUP_EN (1<<28) +#define SWF14_DISPLAY_HOLDOFF (1<<27) +#define SWF14_DISP_DETECT_EN (1<<26) +#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ +#define SWF14_DRIVER_STATUS (1<<24) +#define SWF14_OS_TYPE_WIN9X (1<<23) +#define SWF14_OS_TYPE_WINNT (1<<22) +/* 21:19 rsvd */ +#define SWF14_PM_TYPE_MASK 0x00070000 +#define SWF14_PM_ACPI_VIDEO (0x4 << 16) +#define SWF14_PM_ACPI (0x3 << 16) +#define SWF14_PM_APM_12 (0x2 << 16) +#define SWF14_PM_APM_11 (0x1 << 16) +#define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ + /* if GR18 indicates a display switch */ +#define SWF14_DS_PIPEB_LFP2_EN (1<<15) +#define SWF14_DS_PIPEB_EFP2_EN (1<<14) +#define SWF14_DS_PIPEB_TV2_EN (1<<13) +#define SWF14_DS_PIPEB_CRT2_EN (1<<12) +#define SWF14_DS_PIPEB_LFP_EN (1<<11) +#define SWF14_DS_PIPEB_EFP_EN (1<<10) +#define SWF14_DS_PIPEB_TV_EN (1<<9) +#define SWF14_DS_PIPEB_CRT_EN (1<<8) +#define SWF14_DS_PIPEA_LFP2_EN (1<<7) +#define SWF14_DS_PIPEA_EFP2_EN (1<<6) +#define SWF14_DS_PIPEA_TV2_EN (1<<5) +#define SWF14_DS_PIPEA_CRT2_EN (1<<4) +#define SWF14_DS_PIPEA_LFP_EN (1<<3) +#define SWF14_DS_PIPEA_EFP_EN (1<<2) +#define SWF14_DS_PIPEA_TV_EN (1<<1) +#define SWF14_DS_PIPEA_CRT_EN (1<<0) + /* if GR18 indicates a panel fitting request */ +#define SWF14_PFIT_EN (1<<0) /* 0 means disable */ + /* if GR18 indicates an APM change request */ +#define SWF14_APM_HIBERNATE 0x4 +#define SWF14_APM_SUSPEND 0x3 +#define SWF14_APM_STANDBY 0x1 +#define SWF14_APM_RESTORE 0x0 #endif /* _I830_BIOS_H_ */ diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 1da95e18..6b6d3162 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -380,6 +380,17 @@ void intel_lvds_init(struct drm_device *dev) output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; + + /* + * LVDS discovery: + * 1) check for EDID on DDC + * 2) check for VBT data + * 3) check to see if LVDS is already on + * if none of the above, no panel + * 4) make sure lid is open + * if closed, act like it's not there for now + */ + /* Set up the DDC bus. */ intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); if (!intel_output->ddc_bus) { @@ -402,6 +413,11 @@ void intel_lvds_init(struct drm_device *dev) } } + /* Failed to get EDID, what about VBT? */ + if (dev_priv->vbt_mode) + dev_priv->panel_fixed_mode = + drm_mode_duplicate(dev, dev_priv->vbt_mode); + /* * If we didn't get EDID, try checking if the panel is already turned * on. If so, assume that whatever is currently programmed is the @@ -424,38 +440,8 @@ void intel_lvds_init(struct drm_device *dev) if (!dev_priv->panel_fixed_mode) goto failed; - /* FIXME: probe the BIOS for modes and check for LVDS quirks */ #if 0 - /* Get the LVDS fixed mode out of the BIOS. We should support LVDS - * with the BIOS being unavailable or broken, but lack the - * configuration options for now. - */ - bios_mode = intel_bios_get_panel_mode(pScrn); - if (bios_mode != NULL) { - if (dev_priv->panel_fixed_mode != NULL) { - if (dev_priv->debug_modes && - !xf86ModesEqual(dev_priv->panel_fixed_mode, - bios_mode)) - { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "BIOS panel mode data doesn't match probed data, " - "continuing with probed.\n"); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode:\n"); - xf86PrintModeline(pScrn->scrnIndex, bios_mode); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "probed mode:\n"); - xf86PrintModeline(pScrn->scrnIndex, dev_priv->panel_fixed_mode); - xfree(bios_mode->name); - xfree(bios_mode); - } - } else { - dev_priv->panel_fixed_mode = bios_mode; - } - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Couldn't detect panel mode. Disabling panel\n"); - goto disable_exit; - } - + /* FIXME: detect aopen & mac mini type stuff automatically? */ /* * Blacklist machines with BIOSes that list an LVDS panel without * actually having one. diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 42f4b10b..650c46f7 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1620,7 +1620,7 @@ intel_tv_init(struct drm_device *dev) return; /* Even if we have an encoder we may not have a connector */ - if (!dev_priv->bdb->int_tv_support) + if (!dev_priv->int_tv_support) return; /* diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 84cc60f3..c5e22f7c 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -174,14 +174,17 @@ struct drm_i915_private { int backlight_duty_cycle; /* restore backlight to this value */ bool panel_wants_dither; struct drm_display_mode *panel_fixed_mode; + struct drm_display_mode *vbt_mode; /* if any */ /* DRI2 sarea */ struct drm_buffer_object *sarea_bo; struct drm_bo_kmap_obj sarea_kmap; - /* BIOS data */ - struct vbt_header *vbt; - struct bdb_header *bdb; + /* Feature bits from the VBIOS */ + int int_tv_support:1; + int lvds_dither:1; + int lvds_vbt:1; + int int_crt_support:1; /* Register state */ u8 saveLBB; @@ -1680,15 +1683,16 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define DSPATILEOFF 0x701A4 /* 965+ only */ /* VBIOS flags */ -#define SWF0 0x71410 -#define SWF1 0x71414 -#define SWF2 0x71418 -#define SWF3 0x7141c -#define SWF4 0x71420 -#define SWF5 0x71424 -#define SWF6 0x71428 - +#define SWF00 0x71410 +#define SWF01 0x71414 +#define SWF02 0x71418 +#define SWF03 0x7141c +#define SWF04 0x71420 +#define SWF05 0x71424 +#define SWF06 0x71428 #define SWF10 0x70410 +#define SWF11 0x70414 +#define SWF14 0x71420 #define SWF30 0x72414 #define SWF31 0x72418 #define SWF32 0x7241c diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index f5fe5ba4..bda15e01 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -224,9 +224,9 @@ int i915_load_modeset_init(struct drm_device *dev) goto destroy_hws; } - ret = intel_find_bios(dev); + ret = intel_init_bios(dev); if (ret) { - DRM_ERROR("failed to find VBT\n"); + DRM_ERROR("failed to find VBIOS tables\n"); ret = -ENODEV; goto destroy_wq; } -- cgit v1.2.3 From 070755af3fecefb6b09e8ef98738e4926e4148a7 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 28 May 2008 08:24:42 -0700 Subject: i915: unmap BIOS when we're done with it At the moment, we only read it at startup time, so we can just unmap it there when we're done. --- linux-core/intel_bios.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/intel_bios.c b/linux-core/intel_bios.c index f124fa1a..0cdc915c 100644 --- a/linux-core/intel_bios.c +++ b/linux-core/intel_bios.c @@ -236,5 +236,7 @@ intel_init_bios(struct drm_device *dev) parse_general_features(dev_priv, bdb); parse_panel_data(dev_priv, bdb); + pci_unmap_rom(pdev, bios); + return 0; } -- cgit v1.2.3 From ee5afc63428488c9c39e5ecd7d8cdc646a7b65b7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 29 May 2008 13:58:26 +1000 Subject: modeset: disable radeon ms by default as I'm going to break it. --- linux-core/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/Makefile b/linux-core/Makefile index 4ac083fe..b9405bbb 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -328,7 +328,7 @@ ifneq (,$(findstring xgi,$(DRM_MODULES))) CONFIG_DRM_XGI := m endif ifneq (,$(findstring radeon_ms,$(DRM_MODULES))) -CONFIG_DRM_RADEON_MS := m +#CONFIG_DRM_RADEON_MS := m endif # These require AGP support -- cgit v1.2.3 From df8cd54286fbae5903d8ede390ec4a11cb6c4b6c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 29 May 2008 14:02:14 +1000 Subject: modesetting: reorganise code into core and helper functions. This splits a lot of the core modesetting code out into a file of helper functions, that are only called from themselves and/or the driver. The driver gets called into more often or can call these functions from itself if it is a helper using driver. I've broken framebuffer resize doing this but I didn't like the API for that in any case. --- linux-core/Makefile.kernel | 2 +- linux-core/drm_crtc.c | 471 +-------------------------------------- linux-core/drm_crtc.h | 43 ++-- linux-core/drm_crtc_helper.c | 515 +++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_crtc_helper.h | 69 ++++++ linux-core/intel_crt.c | 17 +- linux-core/intel_display.c | 29 ++- linux-core/intel_drv.h | 1 + linux-core/intel_dvo.c | 15 +- linux-core/intel_fb.c | 6 +- linux-core/intel_lvds.c | 16 +- linux-core/intel_sdvo.c | 16 +- linux-core/intel_tv.c | 12 +- shared-core/i915_init.c | 3 +- shared-core/i915_irq.c | 11 +- 15 files changed, 688 insertions(+), 538 deletions(-) create mode 100644 linux-core/drm_crtc_helper.c create mode 100644 linux-core/drm_crtc_helper.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index f77f8642..ac9baf02 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -15,7 +15,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ drm_edid.o drm_modes.o drm_bo_lock.o drm_regman.o \ - drm_vm_nopage_compat.o + drm_vm_nopage_compat.o drm_crtc_helper.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e05466ee..a4a51080 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -418,133 +418,6 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) } EXPORT_SYMBOL(drm_crtc_probe_output_modes); -/** - * drm_crtc_set_mode - set a mode - * @crtc: CRTC to program - * @mode: mode to use - * @x: width of mode - * @y: height of mode - * - * LOCKING: - * Caller must hold mode config lock. - * - * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance - * to fixup or reject the mode prior to trying to set it. - * - * RETURNS: - * True if the mode was set successfully, or false otherwise. - */ -bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y) -{ - struct drm_device *dev = crtc->dev; - struct drm_display_mode *adjusted_mode, saved_mode; - int saved_x, saved_y; - struct drm_output *output; - bool ret = true; - - adjusted_mode = drm_mode_duplicate(dev, mode); - - crtc->enabled = drm_crtc_in_use(crtc); - - if (!crtc->enabled) - return true; - - saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; - - /* Update crtc values up front so the driver can rely on them for mode - * setting. - */ - crtc->mode = *mode; - crtc->x = x; - crtc->y = y; - - if (drm_mode_equal(&saved_mode, &crtc->mode)) { - if (saved_x != crtc->x || saved_y != crtc->y) { - crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); - goto done; - } - } - - /* Pass our mode to the outputs and the CRTC to give them a chance to - * adjust it according to limitations or output properties, and also - * a chance to reject the mode entirely. - */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - if (output->crtc != crtc) - continue; - - if (!(ret = output->funcs->mode_fixup(output, mode, adjusted_mode))) { - goto done; - } - } - - if (!(ret = crtc->funcs->mode_fixup(crtc, mode, adjusted_mode))) { - goto done; - } - - /* Prepare the outputs and CRTCs before setting the mode. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - if (output->crtc != crtc) - continue; - - /* Disable the output as the first thing we do. */ - output->funcs->prepare(output); - } - - crtc->funcs->prepare(crtc); - - /* Set up the DPLL and any output state that needs to adjust or depend - * on the DPLL. - */ - crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - if (output->crtc != crtc) - continue; - - DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id); - - output->funcs->mode_set(output, mode, adjusted_mode); - } - - /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ - crtc->funcs->commit(crtc); - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - if (output->crtc != crtc) - continue; - - output->funcs->commit(output); - -#if 0 // TODO def RANDR_12_INTERFACE - if (output->randr_output) - RRPostPendingProperties (output->randr_output); -#endif - } - - /* XXX free adjustedmode */ - drm_mode_destroy(dev, adjusted_mode); - /* TODO */ -// if (scrn->pScreen) -// drm_crtc_set_screen_sub_pixel_order(dev); - -done: - if (!ret) { - crtc->mode = saved_mode; - crtc->x = saved_x; - crtc->y = saved_y; - } - - return ret; -} -EXPORT_SYMBOL(drm_crtc_set_mode); /** * drm_disable_unused_functions - disable unused objects @@ -896,171 +769,8 @@ out_err: return ret; } -/** - * drm_pick_crtcs - pick crtcs for output devices - * @dev: DRM device - * - * LOCKING: - * Caller must hold mode config lock. - */ -static void drm_pick_crtcs (struct drm_device *dev) -{ - int c, o, assigned; - struct drm_output *output, *output_equal; - struct drm_crtc *crtc; - struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; - int found; - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - output->crtc = NULL; - - /* Don't hook up outputs that are disconnected ?? - * - * This is debateable. Do we want fixed /dev/fbX or - * dynamic on hotplug (need mode code for that though) ? - * - * If we don't hook up outputs now, then we only create - * /dev/fbX for the output that's enabled, that's good as - * the users console will be on that output. - * - * If we do hook up outputs that are disconnected now, then - * the user may end up having to muck about with the fbcon - * map flags to assign his console to the enabled output. Ugh. - */ - if (output->status != output_status_connected) - continue; - - if (list_empty(&output->modes)) - continue; - - des_mode = NULL; - found = 0; - list_for_each_entry(des_mode, &output->modes, head) { - if (des_mode->type & DRM_MODE_TYPE_PREFERRED) { - found = 1; - break; - } - } - - /* No preferred mode, let's just select the first available */ - if (!found) { - des_mode = NULL; - list_for_each_entry(des_mode, &output->modes, head) { - break; - } - } - - c = -1; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - assigned = 0; - c++; - if ((output->possible_crtcs & (1 << c)) == 0) - continue; - - list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { - if (output->id == output_equal->id) - continue; - - /* Find out if crtc has been assigned before */ - if (output_equal->crtc == crtc) - assigned = 1; - } - -#if 1 /* continue for now */ - if (assigned) - continue; -#endif - - o = -1; - list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { - o++; - if (output->id == output_equal->id) - continue; - - list_for_each_entry(modes, &output->modes, head) { - list_for_each_entry(modes_equal, &output_equal->modes, head) { - if (drm_mode_equal (modes, modes_equal)) { - if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) { - printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones); - des_mode = modes; - assigned = 0; - goto clone; - } - } - } - } - } -clone: - /* crtc has been assigned skip it */ - if (assigned) - continue; - - /* Found a CRTC to attach to, do it ! */ - output->crtc = crtc; - output->crtc->desired_mode = des_mode; - output->initial_x = 0; - output->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); - break; - } - } -} -EXPORT_SYMBOL(drm_pick_crtcs); - -/** - * drm_initial_config - setup a sane initial output configuration - * @dev: DRM device - * @can_grow: this configuration is growable - * - * LOCKING: - * Called at init time, must take mode config lock. - * - * Scan the CRTCs and outputs and try to put together an initial setup. - * At the moment, this is a cloned configuration across all heads with - * a new framebuffer object as the backing store. - * - * RETURNS: - * Zero if everything went ok, nonzero otherwise. - */ -bool drm_initial_config(struct drm_device *dev, bool can_grow) -{ - struct drm_output *output; - struct drm_crtc *crtc; - int ret = false; - - mutex_lock(&dev->mode_config.mutex); - - drm_crtc_probe_output_modes(dev, 2048, 2048); - - drm_pick_crtcs(dev); - - /* This is a little screwy, as we've already walked the outputs - * above, but it's a little bit of magic too. There's the potential - * for things not to get setup above if an existing device gets - * re-assigned thus confusing the hardware. By walking the outputs - * this fixes up their crtc's. - */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - /* can't setup the output if there's no assigned mode */ - if (!output->crtc || !output->crtc->desired_mode) - continue; - - dev->driver->fb_probe(dev, output->crtc, output); - - /* and needs an attached fb */ - if (output->crtc->fb) - drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); - } - - drm_disable_unused_functions(dev); - - mutex_unlock(&dev->mode_config.mutex); - return ret; -} -EXPORT_SYMBOL(drm_initial_config); /** * drm_mode_config_cleanup - free up DRM mode_config info @@ -1105,179 +815,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_cleanup); -/** - * drm_crtc_set_config - set a new config from userspace - * @crtc: CRTC to setup - * @crtc_info: user provided configuration - * @new_mode: new mode to set - * @output_set: set of outputs for the new config - * @fb: new framebuffer - * - * LOCKING: - * Caller must hold mode config lock. - * - * Setup a new configuration, provided by the user in @crtc_info, and enable - * it. - * - * RETURNS: - * Zero. (FIXME) - */ -int drm_crtc_set_config(struct drm_mode_set *set) -{ - struct drm_device *dev; - struct drm_crtc **save_crtcs, *new_crtc; - bool save_enabled; - bool changed = false; - bool flip_or_move = false; - struct drm_output *output; - int count = 0, ro; - - DRM_DEBUG("\n"); - - if (!set) - return -EINVAL; - - if (!set->crtc) - return -EINVAL; - - DRM_DEBUG("crtc: %p fb: %p outputs: %p num_outputs: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->outputs, set->num_outputs, set->x, set->y); - dev = set->crtc->dev; - - /* save previous config */ - save_enabled = set->crtc->enabled; - - /* this is meant to be num_output not num_crtc */ - save_crtcs = kzalloc(dev->mode_config.num_output * sizeof(struct drm_crtc *), GFP_KERNEL); - if (!save_crtcs) - return -ENOMEM; - - /* We should be able to check here if the fb has the same properties - * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) - flip_or_move = true; - if (set->x != set->crtc->x || set->y != set->crtc->y) - flip_or_move = true; - - if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { - DRM_DEBUG("modes are different\n"); - drm_mode_debug_printmodeline(&set->crtc->mode); - drm_mode_debug_printmodeline(set->mode); - changed = true; - } - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - save_crtcs[count++] = output->crtc; - - if (output->crtc == set->crtc) - new_crtc = NULL; - else - new_crtc = output->crtc; - - for (ro = 0; ro < set->num_outputs; ro++) { - if (set->outputs[ro] == output) - new_crtc = set->crtc; - } - if (new_crtc != output->crtc) { - changed = true; - output->crtc = new_crtc; - } - } - - /* mode_set_base is not a required function */ - if (flip_or_move && !set->crtc->funcs->mode_set_base) - changed = true; - - if (changed) { - set->crtc->fb = set->fb; - set->crtc->enabled = (set->mode != NULL); - if (set->mode != NULL) { - DRM_DEBUG("attempting to set mode from userspace\n"); - drm_mode_debug_printmodeline(set->mode); - if (!drm_crtc_set_mode(set->crtc, set->mode, set->x, - set->y)) { - set->crtc->enabled = save_enabled; - count = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) - output->crtc = save_crtcs[count++]; - kfree(save_crtcs); - return -EINVAL; - } - /* TODO are these needed? */ - set->crtc->desired_x = set->x; - set->crtc->desired_y = set->y; - set->crtc->desired_mode = set->mode; - } - drm_disable_unused_functions(dev); - } else if (flip_or_move) { - if (set->crtc->fb != set->fb) - set->crtc->fb = set->fb; - set->crtc->funcs->mode_set_base(set->crtc, set->x, set->y); - } - - kfree(save_crtcs); - return 0; -} -EXPORT_SYMBOL(drm_crtc_set_config); - -/** - * drm_hotplug_stage_two - * @dev DRM device - * @output hotpluged output - * - * LOCKING. - * Caller must hold mode config lock, function might grab struct lock. - * - * Stage two of a hotplug. - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, - bool connected) -{ - int has_config = 0; - - dev->mode_config.hotplug_counter++; - - /* We might want to do something more here */ - if (!connected) { - DRM_DEBUG("not connected\n"); - return 0; - } - - if (output->crtc && output->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the output already has a config\n"); - has_config = 1; - } - - drm_crtc_probe_output_modes(dev, 2048, 2048); - - if (!has_config) - drm_pick_crtcs(dev); - - if (!output->crtc || !output->crtc->desired_mode) { - DRM_DEBUG("could not find a desired mode or crtc for output\n"); - return 1; - } - - /* We should really check if there is a fb using this crtc */ - if (!has_config) - dev->driver->fb_probe(dev, output->crtc, output); - else { - dev->driver->fb_resize(dev, output->crtc); - - if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) - DRM_ERROR("failed to set mode after hotplug\n"); - } - - drm_sysfs_hotplug_event(dev); - - drm_disable_unused_functions(dev); - - return 0; -} -EXPORT_SYMBOL(drm_hotplug_stage_two); int drm_mode_hotplug_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -1740,7 +1278,7 @@ int drm_mode_setcrtc(struct drm_device *dev, set.outputs = output_set; set.num_outputs = crtc_req->count_outputs; set.fb =fb; - ret = drm_crtc_set_config(&set); + ret = crtc->funcs->set_config(&set); out: kfree(output_set); @@ -2535,7 +2073,6 @@ int drm_mode_replacefb(struct drm_device *dev, { struct drm_mode_fb_cmd *r = data; struct drm_framebuffer *fb; - struct drm_crtc *crtc; struct drm_buffer_object *bo; int found = 0; struct drm_framebuffer *fbl = NULL; @@ -2574,12 +2111,18 @@ int drm_mode_replacefb(struct drm_device *dev, fb->depth = r->depth; fb->bo = bo; + if (dev->mode_config.funcs->resize_fb) + dev->mode_config.funcs->resize_fb(dev, fb); + else + ret = -EINVAL; +#if 0 /* find all crtcs connected to this fb */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb->id == r->buffer_id) { crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); } } +#endif out: mutex_unlock(&dev->mode_config.mutex); return ret; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index ae2dd173..957ecc2c 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -14,6 +14,7 @@ #include struct drm_device; +struct drm_mode_set; /* * Note on terminology: here, for brevity and convenience, we refer to output @@ -313,20 +314,6 @@ struct drm_crtc_funcs { /* Restore CRTC state */ void (*restore)(struct drm_crtc *crtc); /* resume? */ - void (*prepare)(struct drm_crtc *crtc); - void (*commit)(struct drm_crtc *crtc); - - /* Provider can fixup or change mode timings before modeset occurs */ - bool (*mode_fixup)(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - /* Actually set the mode */ - void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y); - - /* Move the crtc on the current fb to the given position *optional* */ - void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); - /* cursor controls */ int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo, uint32_t width, uint32_t height); @@ -337,6 +324,8 @@ struct drm_crtc_funcs { int regno); /* Driver cleanup routine */ void (*cleanup)(struct drm_crtc *crtc); + + int (*set_config)(struct drm_mode_set *set); }; /** @@ -371,6 +360,9 @@ struct drm_crtc { int desired_x, desired_y; const struct drm_crtc_funcs *funcs; void *driver_private; + + /* if you are using the helper */ + void *helper_private; }; extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, @@ -399,21 +391,14 @@ struct drm_output_funcs { void (*dpms)(struct drm_output *output, int mode); void (*save)(struct drm_output *output); void (*restore)(struct drm_output *output); - int (*mode_valid)(struct drm_output *output, - struct drm_display_mode *mode); - bool (*mode_fixup)(struct drm_output *output, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - void (*prepare)(struct drm_output *output); - void (*commit)(struct drm_output *output); - void (*mode_set)(struct drm_output *output, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); enum drm_output_status (*detect)(struct drm_output *output); int (*get_modes)(struct drm_output *output); bool (*set_property)(struct drm_output *output, struct drm_property *property, uint64_t val); void (*cleanup)(struct drm_output *output); + int (*mode_valid)(struct drm_output *output, + struct drm_display_mode *mode); + }; #define DRM_OUTPUT_MAX_UMODES 16 @@ -468,6 +453,8 @@ struct drm_output { struct drm_property_blob *edid_blob_ptr; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; + + void *helper_private; }; /** @@ -501,7 +488,7 @@ struct drm_mode_set * the CRTC<->output mappings as needed and update its view of the screen. */ struct drm_mode_config_funcs { - bool (*resize)(struct drm_device *dev, int width, int height); + bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); }; /** @@ -597,18 +584,14 @@ extern int drm_output_property_get_value(struct drm_output *output, struct drm_property *property, uint64_t *value); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); -extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); -extern int drm_crtc_set_config(struct drm_mode_set *set); -extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y); +extern void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY); extern bool drm_crtc_in_use(struct drm_crtc *crtc); -extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected); extern int drm_output_attach_property(struct drm_output *output, struct drm_property *property, uint64_t init_val); diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c new file mode 100644 index 00000000..f776dbed --- /dev/null +++ b/linux-core/drm_crtc_helper.c @@ -0,0 +1,515 @@ + +/* + * Copyright (c) 2006-2007 Intel Corporation + * Copyright (c) 2007 Dave Airlie + * + * DRM core CRTC related functions + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Authors: + * Keith Packard + * Eric Anholt + * Dave Airlie + * Jesse Barnes + */ + +#include "drmP.h" +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + + +/** + * drm_pick_crtcs - pick crtcs for output devices + * @dev: DRM device + * + * LOCKING: + * Caller must hold mode config lock. + */ +static void drm_pick_crtcs (struct drm_device *dev) +{ + int c, o, assigned; + struct drm_output *output, *output_equal; + struct drm_crtc *crtc; + struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; + int found; + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + output->crtc = NULL; + + /* Don't hook up outputs that are disconnected ?? + * + * This is debateable. Do we want fixed /dev/fbX or + * dynamic on hotplug (need mode code for that though) ? + * + * If we don't hook up outputs now, then we only create + * /dev/fbX for the output that's enabled, that's good as + * the users console will be on that output. + * + * If we do hook up outputs that are disconnected now, then + * the user may end up having to muck about with the fbcon + * map flags to assign his console to the enabled output. Ugh. + */ + if (output->status != output_status_connected) + continue; + + if (list_empty(&output->modes)) + continue; + + des_mode = NULL; + found = 0; + list_for_each_entry(des_mode, &output->modes, head) { + if (des_mode->type & DRM_MODE_TYPE_PREFERRED) { + found = 1; + break; + } + } + + /* No preferred mode, let's just select the first available */ + if (!found) { + des_mode = NULL; + list_for_each_entry(des_mode, &output->modes, head) { + break; + } + } + + c = -1; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + assigned = 0; + + c++; + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + + list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { + if (output->id == output_equal->id) + continue; + + /* Find out if crtc has been assigned before */ + if (output_equal->crtc == crtc) + assigned = 1; + } + +#if 1 /* continue for now */ + if (assigned) + continue; +#endif + + o = -1; + list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { + o++; + if (output->id == output_equal->id) + continue; + + list_for_each_entry(modes, &output->modes, head) { + list_for_each_entry(modes_equal, &output_equal->modes, head) { + if (drm_mode_equal (modes, modes_equal)) { + if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) { + printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones); + des_mode = modes; + assigned = 0; + goto clone; + } + } + } + } + } + +clone: + /* crtc has been assigned skip it */ + if (assigned) + continue; + + /* Found a CRTC to attach to, do it ! */ + output->crtc = crtc; + output->crtc->desired_mode = des_mode; + output->initial_x = 0; + output->initial_y = 0; + DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); + break; + } + } +} +EXPORT_SYMBOL(drm_pick_crtcs); + +/** + * drm_crtc_set_mode - set a mode + * @crtc: CRTC to program + * @mode: mode to use + * @x: width of mode + * @y: height of mode + * + * LOCKING: + * Caller must hold mode config lock. + * + * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance + * to fixup or reject the mode prior to trying to set it. + * + * RETURNS: + * True if the mode was set successfully, or false otherwise. + */ +bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_display_mode *adjusted_mode, saved_mode; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + struct drm_output_helper_funcs *output_funcs; + int saved_x, saved_y; + struct drm_output *output; + bool ret = true; + + adjusted_mode = drm_mode_duplicate(dev, mode); + + crtc->enabled = drm_crtc_in_use(crtc); + + if (!crtc->enabled) + return true; + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + + /* Update crtc values up front so the driver can rely on them for mode + * setting. + */ + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + + if (drm_mode_equal(&saved_mode, &crtc->mode)) { + if (saved_x != crtc->x || saved_y != crtc->y) { + crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y); + goto done; + } + } + + /* Pass our mode to the outputs and the CRTC to give them a chance to + * adjust it according to limitations or output properties, and also + * a chance to reject the mode entirely. + */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + + if (output->crtc != crtc) + continue; + output_funcs = output->helper_private; + if (!(ret = output_funcs->mode_fixup(output, mode, adjusted_mode))) { + goto done; + } + } + + if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { + goto done; + } + + /* Prepare the outputs and CRTCs before setting the mode. */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + + if (output->crtc != crtc) + continue; + output_funcs = output->helper_private; + /* Disable the output as the first thing we do. */ + output_funcs->prepare(output); + } + + crtc_funcs->prepare(crtc); + + /* Set up the DPLL and any output state that needs to adjust or depend + * on the DPLL. + */ + crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y); + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + + if (output->crtc != crtc) + continue; + + DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id); + output_funcs = output->helper_private; + output_funcs->mode_set(output, mode, adjusted_mode); + } + + /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ + crtc_funcs->commit(crtc); + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + + if (output->crtc != crtc) + continue; + + output_funcs = output->helper_private; + output_funcs->commit(output); + +#if 0 // TODO def RANDR_12_INTERFACE + if (output->randr_output) + RRPostPendingProperties (output->randr_output); +#endif + } + + /* XXX free adjustedmode */ + drm_mode_destroy(dev, adjusted_mode); + /* TODO */ +// if (scrn->pScreen) +// drm_crtc_set_screen_sub_pixel_order(dev); + +done: + if (!ret) { + crtc->mode = saved_mode; + crtc->x = saved_x; + crtc->y = saved_y; + } + + return ret; +} +EXPORT_SYMBOL(drm_crtc_helper_set_mode); + + +/** + * drm_crtc_helper_set_config - set a new config from userspace + * @crtc: CRTC to setup + * @crtc_info: user provided configuration + * @new_mode: new mode to set + * @output_set: set of outputs for the new config + * @fb: new framebuffer + * + * LOCKING: + * Caller must hold mode config lock. + * + * Setup a new configuration, provided by the user in @crtc_info, and enable + * it. + * + * RETURNS: + * Zero. (FIXME) + */ +int drm_crtc_helper_set_config(struct drm_mode_set *set) +{ + struct drm_device *dev; + struct drm_crtc **save_crtcs, *new_crtc; + bool save_enabled; + bool changed = false; + bool flip_or_move = false; + struct drm_output *output; + int count = 0, ro; + struct drm_crtc_helper_funcs *crtc_funcs; + + DRM_DEBUG("\n"); + + if (!set) + return -EINVAL; + + if (!set->crtc) + return -EINVAL; + + if (!set->crtc->helper_private) + return -EINVAL; + + crtc_funcs = set->crtc->helper_private; + + DRM_DEBUG("crtc: %p fb: %p outputs: %p num_outputs: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->outputs, set->num_outputs, set->x, set->y); + dev = set->crtc->dev; + + /* save previous config */ + save_enabled = set->crtc->enabled; + + /* this is meant to be num_output not num_crtc */ + save_crtcs = kzalloc(dev->mode_config.num_output * sizeof(struct drm_crtc *), GFP_KERNEL); + if (!save_crtcs) + return -ENOMEM; + + /* We should be able to check here if the fb has the same properties + * and then just flip_or_move it */ + if (set->crtc->fb != set->fb) + flip_or_move = true; + + if (set->x != set->crtc->x || set->y != set->crtc->y) + flip_or_move = true; + + if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { + DRM_DEBUG("modes are different\n"); + drm_mode_debug_printmodeline(&set->crtc->mode); + drm_mode_debug_printmodeline(set->mode); + changed = true; + } + + list_for_each_entry(output, &dev->mode_config.output_list, head) { + save_crtcs[count++] = output->crtc; + + if (output->crtc == set->crtc) + new_crtc = NULL; + else + new_crtc = output->crtc; + + for (ro = 0; ro < set->num_outputs; ro++) { + if (set->outputs[ro] == output) + new_crtc = set->crtc; + } + if (new_crtc != output->crtc) { + changed = true; + output->crtc = new_crtc; + } + } + + /* mode_set_base is not a required function */ + if (flip_or_move && !crtc_funcs->mode_set_base) + changed = true; + + if (changed) { + set->crtc->fb = set->fb; + set->crtc->enabled = (set->mode != NULL); + if (set->mode != NULL) { + DRM_DEBUG("attempting to set mode from userspace\n"); + drm_mode_debug_printmodeline(set->mode); + if (!drm_crtc_helper_set_mode(set->crtc, set->mode, set->x, + set->y)) { + set->crtc->enabled = save_enabled; + count = 0; + list_for_each_entry(output, &dev->mode_config.output_list, head) + output->crtc = save_crtcs[count++]; + kfree(save_crtcs); + return -EINVAL; + } + /* TODO are these needed? */ + set->crtc->desired_x = set->x; + set->crtc->desired_y = set->y; + set->crtc->desired_mode = set->mode; + } + drm_disable_unused_functions(dev); + } else if (flip_or_move) { + if (set->crtc->fb != set->fb) + set->crtc->fb = set->fb; + crtc_funcs->mode_set_base(set->crtc, set->x, set->y); + } + + kfree(save_crtcs); + return 0; +} +EXPORT_SYMBOL(drm_crtc_helper_set_config); + +/** + * drm_initial_config - setup a sane initial output configuration + * @dev: DRM device + * @can_grow: this configuration is growable + * + * LOCKING: + * Called at init time, must take mode config lock. + * + * Scan the CRTCs and outputs and try to put together an initial setup. + * At the moment, this is a cloned configuration across all heads with + * a new framebuffer object as the backing store. + * + * RETURNS: + * Zero if everything went ok, nonzero otherwise. + */ +bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) +{ + struct drm_output *output; + int ret = false; + + mutex_lock(&dev->mode_config.mutex); + + drm_crtc_probe_output_modes(dev, 2048, 2048); + + drm_pick_crtcs(dev); + + /* This is a little screwy, as we've already walked the outputs + * above, but it's a little bit of magic too. There's the potential + * for things not to get setup above if an existing device gets + * re-assigned thus confusing the hardware. By walking the outputs + * this fixes up their crtc's. + */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + + /* can't setup the output if there's no assigned mode */ + if (!output->crtc || !output->crtc->desired_mode) + continue; + + dev->driver->fb_probe(dev, output->crtc, output); + + /* and needs an attached fb */ + if (output->crtc->fb) + drm_crtc_helper_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); + } + + drm_disable_unused_functions(dev); + + mutex_unlock(&dev->mode_config.mutex); + return ret; +} +EXPORT_SYMBOL(drm_helper_initial_config); + +/** + * drm_hotplug_stage_two + * @dev DRM device + * @output hotpluged output + * + * LOCKING. + * Caller must hold mode config lock, function might grab struct lock. + * + * Stage two of a hotplug. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, + bool connected) +{ + int has_config = 0; + + dev->mode_config.hotplug_counter++; + + /* We might want to do something more here */ + if (!connected) { + DRM_DEBUG("not connected\n"); + return 0; + } + + if (output->crtc && output->crtc->desired_mode) { + DRM_DEBUG("drm thinks that the output already has a config\n"); + has_config = 1; + } + + drm_crtc_probe_output_modes(dev, 2048, 2048); + + if (!has_config) + drm_pick_crtcs(dev); + + if (!output->crtc || !output->crtc->desired_mode) { + DRM_DEBUG("could not find a desired mode or crtc for output\n"); + return 1; + } + + /* We should really check if there is a fb using this crtc */ + if (!has_config) + dev->driver->fb_probe(dev, output->crtc, output); + else { + dev->driver->fb_resize(dev, output->crtc); + +#if 0 + if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) + DRM_ERROR("failed to set mode after hotplug\n"); +#endif + } + + drm_sysfs_hotplug_event(dev); + + drm_disable_unused_functions(dev); + + return 0; +} +EXPORT_SYMBOL(drm_helper_hotplug_stage_two); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h new file mode 100644 index 00000000..f56b97c6 --- /dev/null +++ b/linux-core/drm_crtc_helper.h @@ -0,0 +1,69 @@ +/* + * Copyright © 2006 Keith Packard + * Copyright © 2007 Intel Corporation + * Jesse Barnes + */ + +/* + * The DRM mode setting helper functions are common code for drivers to use if they wish. + * Drivers are not forced to use this code in their implementations but it would be useful + * if they code they do use at least provides a consistent interface and operation to userspace + */ + +#ifndef __DRM_CRTC_HELPER_H__ +#define __DRM_CRTC_HELPER_H__ + +#include +#include +#include +#include + +#include + +struct drm_crtc_helper_funcs { + void (*prepare)(struct drm_crtc *crtc); + void (*commit)(struct drm_crtc *crtc); + + /* Provider can fixup or change mode timings before modeset occurs */ + bool (*mode_fixup)(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + /* Actually set the mode */ + void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, int x, int y); + + /* Move the crtc on the current fb to the given position *optional* */ + void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); +}; + +struct drm_output_helper_funcs { + bool (*mode_fixup)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*prepare)(struct drm_output *output); + void (*commit)(struct drm_output *output); + void (*mode_set)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +}; + +extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, + bool connected); +extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); +extern int drm_crtc_helper_set_config(struct drm_mode_set *set); +extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y); + +static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) +{ + crtc->helper_private = (void *)funcs; +} + +static inline void drm_output_helper_add(struct drm_output *output, const struct drm_output_helper_funcs *funcs) +{ + output->helper_private = (void *)funcs; +} + + + +#endif diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index ef40871e..3c5dae1a 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -28,6 +28,7 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" +#include "drm_crtc_helper.h" #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -220,19 +221,24 @@ static bool intel_crt_set_property(struct drm_output *output, /* * Routines for controlling stuff on the analog port */ + +static const struct drm_output_helper_funcs intel_crt_helper_funcs = { + .mode_fixup = intel_crt_mode_fixup, + .prepare = intel_output_prepare, + .commit = intel_output_commit, + .mode_set = intel_crt_mode_set, +}; + static const struct drm_output_funcs intel_crt_output_funcs = { .dpms = intel_crt_dpms, .save = intel_crt_save, .restore = intel_crt_restore, - .mode_valid = intel_crt_mode_valid, - .mode_fixup = intel_crt_mode_fixup, - .prepare = intel_output_prepare, - .mode_set = intel_crt_mode_set, - .commit = intel_output_commit, .detect = intel_crt_detect, .get_modes = intel_crt_get_modes, .cleanup = intel_crt_destroy, .set_property = intel_crt_set_property, + .mode_valid = intel_crt_mode_valid, + }; void intel_crt_init(struct drm_device *dev) @@ -261,6 +267,7 @@ void intel_crt_init(struct drm_device *dev) output->interlace_allowed = 0; output->doublescan_allowed = 0; + drm_output_helper_add(output, &intel_crt_helper_funcs); drm_sysfs_output_add(output); drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA); diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index e7162c2c..a2307a3d 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -30,6 +30,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#include "drm_crtc_helper.h" + bool intel_pipe_has_type (struct drm_crtc *crtc, int type); typedef struct { @@ -1090,6 +1092,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, struct drm_crtc *possible_crtc; struct drm_crtc *supported_crtc =NULL; struct drm_crtc *crtc = NULL; + struct drm_output_helper_funcs *output_funcs; int i = -1; /* @@ -1147,14 +1150,15 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, if (!crtc->enabled) { if (!mode) mode = &load_detect_mode; - drm_crtc_set_mode(crtc, mode, 0, 0); + drm_crtc_helper_set_mode(crtc, mode, 0, 0); } else { if (intel_crtc->dpms_mode != DPMSModeOn) crtc->funcs->dpms(crtc, DPMSModeOn); + output_funcs = output->helper_private; /* Add this output to the crtc */ - output->funcs->mode_set(output, &crtc->mode, &crtc->mode); - output->funcs->commit(output); + output_funcs->mode_set(output, &crtc->mode, &crtc->mode); + output_funcs->commit(output); } /* let the output get through one full cycle before testing */ intel_wait_for_vblank(dev); @@ -1293,16 +1297,20 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, return mode; } -static const struct drm_crtc_funcs intel_crtc_funcs = { - .dpms = intel_crtc_dpms, +static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, + .prepare = intel_crtc_prepare, + .commit = intel_crtc_commit, +}; + +static const struct drm_crtc_funcs intel_crtc_funcs = { + .dpms = intel_crtc_dpms, .cursor_set = intel_crtc_cursor_set, .cursor_move = intel_crtc_cursor_move, .gamma_set = intel_crtc_gamma_set, - .prepare = intel_crtc_prepare, - .commit = intel_crtc_commit, + .set_config = drm_crtc_helper_set_config, }; @@ -1331,6 +1339,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_addr = 0; intel_crtc->dpms_mode = DPMSModeOff; + drm_crtc_helper_add(crtc, &intel_helper_funcs); crtc->driver_private = intel_crtc; } @@ -1418,6 +1427,10 @@ static void intel_setup_outputs(struct drm_device *dev) } } +static const struct drm_mode_config_funcs intel_mode_funcs = { + .resize_fb = NULL, +}; + void intel_modeset_init(struct drm_device *dev) { int num_pipe; @@ -1428,6 +1441,8 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; + dev->mode_config.funcs = (void *)&intel_mode_funcs; + if (IS_I965G(dev)) { dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index e97117de..9f8ca8dd 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -11,6 +11,7 @@ #include #include "drm_crtc.h" +#include "drm_crtc_helper.h" /* * Display related stuff */ diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index 6f319107..5a7da276 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -325,19 +325,21 @@ static struct drm_crtc *intel_dvo_get_crtc(struct drm_output *output) } #endif +static const struct drm_output_helper_funcs intel_dvo_helper_funcs = { + .mode_fixup = intel_dvo_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_dvo_mode_set, + .commit = intel_output_commit, +}; static const struct drm_output_funcs intel_dvo_output_funcs = { .dpms = intel_dvo_dpms, .save = intel_dvo_save, .restore = intel_dvo_restore, - .mode_valid = intel_dvo_mode_valid, - .mode_fixup = intel_dvo_mode_fixup, - .prepare = intel_output_prepare, - .mode_set = intel_dvo_mode_set, - .commit = intel_output_commit, .detect = intel_dvo_detect, .get_modes = intel_dvo_get_modes, - .cleanup = intel_dvo_destroy + .cleanup = intel_dvo_destroy, + .mode_valid = intel_dvo_mode_valid, }; /** @@ -457,6 +459,7 @@ void intel_dvo_init(struct drm_device *dev) goto free_i2c; } + drm_output_helper_add(output, &intel_dvo_helper_funcs); output->driver_private = intel_output; output->display_info.subpixel_order = SubPixelHorizontalRGB; output->interlace_allowed = false; diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 4f5a0000..05fc3b29 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -341,7 +341,7 @@ static int intelfb_set_par(struct fb_info *info) return 0; #else - return drm_crtc_set_config(&par->set); + return par->set.crtc->funcs->set_config(&par->set); #endif } @@ -496,11 +496,11 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; int ret; DRM_DEBUG("\n"); - + par->set.x = var->xoffset; par->set.y = var->yoffset; - ret = drm_crtc_set_config(&par->set); + ret = par->set.crtc->funcs->set_config(&par->set); if (!ret) { info->var.xoffset = var->xoffset; diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 6b6d3162..f71dd436 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -332,18 +332,21 @@ static void intel_lvds_destroy(struct drm_output *output) kfree(output->driver_private); } -static const struct drm_output_funcs intel_lvds_output_funcs = { - .dpms = intel_lvds_dpms, - .save = intel_lvds_save, - .restore = intel_lvds_restore, - .mode_valid = intel_lvds_mode_valid, +static const struct drm_output_helper_funcs intel_lvds_helper_funcs = { .mode_fixup = intel_lvds_mode_fixup, .prepare = intel_lvds_prepare, .mode_set = intel_lvds_mode_set, .commit = intel_lvds_commit, +}; + +static const struct drm_output_funcs intel_lvds_output_funcs = { + .dpms = intel_lvds_dpms, + .save = intel_lvds_save, + .restore = intel_lvds_restore, .detect = intel_lvds_detect, .get_modes = intel_lvds_get_modes, - .cleanup = intel_lvds_destroy + .cleanup = intel_lvds_destroy, + .mode_valid = intel_lvds_mode_valid, }; /** @@ -375,6 +378,7 @@ void intel_lvds_init(struct drm_device *dev) } intel_output->type = INTEL_OUTPUT_LVDS; + drm_output_helper_add(output, &intel_lvds_helper_funcs); output->driver_private = intel_output; output->display_info.subpixel_order = SubPixelHorizontalRGB; output->interlace_allowed = FALSE; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index ba6fe9a8..41da034d 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -972,18 +972,21 @@ static void intel_sdvo_destroy(struct drm_output *output) } } -static const struct drm_output_funcs intel_sdvo_output_funcs = { - .dpms = intel_sdvo_dpms, - .save = intel_sdvo_save, - .restore = intel_sdvo_restore, - .mode_valid = intel_sdvo_mode_valid, +static const struct drm_output_helper_funcs intel_sdvo_helper_funcs = { .mode_fixup = intel_sdvo_mode_fixup, .prepare = intel_output_prepare, .mode_set = intel_sdvo_mode_set, .commit = intel_output_commit, +}; + +static const struct drm_output_funcs intel_sdvo_output_funcs = { + .dpms = intel_sdvo_dpms, + .save = intel_sdvo_save, + .restore = intel_sdvo_restore, .detect = intel_sdvo_detect, .get_modes = intel_sdvo_get_modes, - .cleanup = intel_sdvo_destroy + .cleanup = intel_sdvo_destroy, + .mode_valid = intel_sdvo_mode_valid, }; void intel_sdvo_init(struct drm_device *dev, int output_device) @@ -1010,6 +1013,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_SDVO; + drm_output_helper_add(output, &intel_sdvo_helper_funcs); output->driver_private = intel_output; output->interlace_allowed = 0; output->doublescan_allowed = 0; diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 650c46f7..18fb1f37 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1590,15 +1590,18 @@ out: return ret; } +static const struct drm_output_helper_funcs intel_tv_helper_funcs = { + .mode_fixup = intel_tv_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_tv_mode_set, + .commit = intel_output_commit, +}; + static const struct drm_output_funcs intel_tv_output_funcs = { .dpms = intel_tv_dpms, .save = intel_tv_save, .restore = intel_tv_restore, .mode_valid = intel_tv_mode_valid, - .mode_fixup = intel_tv_mode_fixup, - .prepare = intel_output_prepare, - .mode_set = intel_tv_mode_set, - .commit = intel_output_commit, .detect = intel_tv_detect, .get_modes = intel_tv_get_modes, .cleanup = intel_tv_destroy, @@ -1674,6 +1677,7 @@ intel_tv_init(struct drm_device *dev) tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); + drm_output_helper_add(output, &intel_tv_helper_funcs); output->driver_private = intel_output; output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index bda15e01..f03f8949 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -13,6 +13,7 @@ #include "i915_drm.h" #include "i915_drv.h" #include "intel_bios.h" +#include "intel_drv.h" /** * i915_probe_agp - get AGP bootup configuration @@ -232,7 +233,7 @@ int i915_load_modeset_init(struct drm_device *dev) } intel_modeset_init(dev); - drm_initial_config(dev, false); + drm_helper_initial_config(dev, false); drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 592e881b..ccedc70e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -31,6 +31,7 @@ #include "i915_drm.h" #include "i915_drv.h" #include "intel_drv.h" +#include "drm_crtc_helper.h" #define MAX_NOPID ((u32)~0) @@ -471,8 +472,8 @@ static void i915_hotplug_tv(struct drm_device *dev) goto unlock; status = output->funcs->detect(output); - drm_hotplug_stage_two(dev, output, - status == output_status_connected ? 1 : 0); + drm_helper_hotplug_stage_two(dev, output, + status == output_status_connected ? 1 : 0); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -497,7 +498,7 @@ static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) if (iout == 0) goto unlock; - drm_hotplug_stage_two(dev, output, isconnected); + drm_helper_hotplug_stage_two(dev, output, isconnected); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -518,9 +519,9 @@ static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) status = output->funcs->detect(output); if (status != output_status_connected) - drm_hotplug_stage_two(dev, output, false); + drm_helper_hotplug_stage_two(dev, output, false); else - drm_hotplug_stage_two(dev, output, true); + drm_helper_hotplug_stage_two(dev, output, true); intel_sdvo_set_hotplug(output, 1); -- cgit v1.2.3 From 98c5cf7f6fc51f1a8f5f90b3895009cd38dd8f22 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 11:25:41 +1000 Subject: modesetting: reorganise out crtc/outputs are allocated. Use subclassing from the drivers to allocate the objects. This saves two objects being allocated for each crtc/output and generally makes exit paths cleaner. --- linux-core/drm_crtc.c | 85 +++++++++++++++------------------------------- linux-core/drm_crtc.h | 33 +++++++++--------- linux-core/intel_crt.c | 26 +++++++------- linux-core/intel_display.c | 64 +++++++++++++++++----------------- linux-core/intel_drv.h | 5 +++ linux-core/intel_dvo.c | 52 ++++++++++++---------------- linux-core/intel_lvds.c | 28 +++++++-------- linux-core/intel_modes.c | 4 +-- linux-core/intel_sdvo.c | 54 ++++++++++++++--------------- linux-core/intel_tv.c | 41 +++++++++++----------- shared-core/i915_irq.c | 4 +-- 11 files changed, 181 insertions(+), 215 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index a4a51080..faf70df5 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -232,27 +232,19 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) EXPORT_SYMBOL(drm_framebuffer_destroy); /** - * drm_crtc_create - create a new CRTC object + * drm_crtc_init - Initialise a new CRTC object * @dev: DRM device + * @crtc: CRTC object to init * @funcs: callbacks for the new CRTC * * LOCKING: * Caller must hold mode config lock. * - * Creates a new CRTC object and adds it to @dev's mode_config structure. - * - * RETURNS: - * Pointer to new CRTC object or NULL on error. + * Inits a new object created as base part of an driver crtc object. */ -struct drm_crtc *drm_crtc_create(struct drm_device *dev, - const struct drm_crtc_funcs *funcs) +void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, + const struct drm_crtc_funcs *funcs) { - struct drm_crtc *crtc; - - crtc = kzalloc(sizeof(struct drm_crtc), GFP_KERNEL); - if (!crtc) - return NULL; - crtc->dev = dev; crtc->funcs = funcs; @@ -260,34 +252,28 @@ struct drm_crtc *drm_crtc_create(struct drm_device *dev, list_add_tail(&crtc->head, &dev->mode_config.crtc_list); dev->mode_config.num_crtc++; - - return crtc; } -EXPORT_SYMBOL(drm_crtc_create); +EXPORT_SYMBOL(drm_crtc_init); /** - * drm_crtc_destroy - remove a CRTC object - * @crtc: CRTC to remove + * drm_crtc_cleanup - Cleans up the core crtc usage. + * @crtc: CRTC to cleanup * * LOCKING: * Caller must hold mode config lock. * - * Cleanup @crtc. Calls @crtc's cleanup function, then removes @crtc from - * its associated DRM device's mode_config. Frees it afterwards. + * Cleanup @crtc. Removes from drm modesetting space + * does NOT free object, caller does that. */ -void drm_crtc_destroy(struct drm_crtc *crtc) +void drm_crtc_cleanup(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - if (crtc->funcs->cleanup) - (*crtc->funcs->cleanup)(crtc); - drm_idr_put(dev, crtc->id); list_del(&crtc->head); dev->mode_config.num_crtc--; - kfree(crtc); } -EXPORT_SYMBOL(drm_crtc_destroy); +EXPORT_SYMBOL(drm_crtc_cleanup); /** * drm_crtc_in_use - check if a given CRTC is in a mode_config @@ -481,30 +467,23 @@ void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) EXPORT_SYMBOL(drm_mode_remove); /** - * drm_output_create - create a new output + * drm_output_init - Init a preallocated output * @dev: DRM device + * @output: the output to init * @funcs: callbacks for this output * @name: user visible name of the output * * LOCKING: * Caller must hold @dev's mode_config lock. * - * Creates a new drm_output structure and adds it to @dev's mode_config - * structure. - * - * RETURNS: - * Pointer to the new output or NULL on error. + * Initialises a preallocated output. Outputs should be + * subclassed as part of driver output objects. */ -struct drm_output *drm_output_create(struct drm_device *dev, - const struct drm_output_funcs *funcs, - int output_type) +void drm_output_init(struct drm_device *dev, + struct drm_output *output, + const struct drm_output_funcs *funcs, + int output_type) { - struct drm_output *output = NULL; - - output = kzalloc(sizeof(struct drm_output), GFP_KERNEL); - if (!output) - return NULL; - output->dev = dev; output->funcs = funcs; output->id = drm_idr_get(dev, output); @@ -526,30 +505,23 @@ struct drm_output *drm_output_create(struct drm_device *dev, drm_output_attach_property(output, dev->mode_config.dpms_property, 0); mutex_unlock(&dev->mode_config.mutex); - - return output; - } -EXPORT_SYMBOL(drm_output_create); +EXPORT_SYMBOL(drm_output_init); /** - * drm_output_destroy - remove an output - * @output: output to remove + * drm_output_cleanup - cleans up an initialised output + * @output: output to cleanup * * LOCKING: * Caller must hold @dev's mode_config lock. * - * Call @output's cleanup function, then remove the output from the DRM - * mode_config after freeing @output's modes. + * Cleans up the output but doesn't free the object. */ -void drm_output_destroy(struct drm_output *output) +void drm_output_cleanup(struct drm_output *output) { struct drm_device *dev = output->dev; struct drm_display_mode *mode, *t; - if (*output->funcs->cleanup) - (*output->funcs->cleanup)(output); - list_for_each_entry_safe(mode, t, &output->probed_modes, head) drm_mode_remove(output, mode); @@ -563,9 +535,8 @@ void drm_output_destroy(struct drm_output *output) drm_idr_put(dev, output->id); list_del(&output->head); mutex_unlock(&dev->mode_config.mutex); - kfree(output); } -EXPORT_SYMBOL(drm_output_destroy); +EXPORT_SYMBOL(drm_output_cleanup); /** @@ -793,7 +764,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_sysfs_output_remove(output); - drm_output_destroy(output); + output->funcs->destroy(output); } list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, head) { @@ -809,7 +780,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) } list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { - drm_crtc_destroy(crtc); + crtc->funcs->destroy(crtc); } } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 957ecc2c..b769eb7a 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -291,7 +291,7 @@ struct drm_output; * @mode_fixup: fixup proposed mode * @mode_set: set the desired mode on the CRTC * @gamma_set: specify color ramp for CRTC - * @cleanup: cleanup driver private state prior to close + * @destroy: deinit and free object. * * The drm_crtc_funcs structure is the central CRTC management structure * in the DRM. Each CRTC controls one or more outputs (note that the name @@ -322,8 +322,8 @@ struct drm_crtc_funcs { /* Set gamma on the CRTC */ void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b, int regno); - /* Driver cleanup routine */ - void (*cleanup)(struct drm_crtc *crtc); + /* Object destroy routine */ + void (*destroy)(struct drm_crtc *crtc); int (*set_config)(struct drm_mode_set *set); }; @@ -337,7 +337,6 @@ struct drm_crtc_funcs { * @desired_x: desired x for desired_mode * @desired_y: desired y for desired_mode * @funcs: CRTC control functions - * @driver_private: arbitrary driver data * * Each CRTC may have one or more outputs associated with it. This structure * allows the CRTC to be controlled. @@ -359,15 +358,11 @@ struct drm_crtc { struct drm_display_mode *desired_mode; int desired_x, desired_y; const struct drm_crtc_funcs *funcs; - void *driver_private; /* if you are using the helper */ void *helper_private; }; -extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, - const struct drm_crtc_funcs *funcs); - /** * drm_output_funcs - control outputs on a given device * @init: setup this output @@ -380,7 +375,7 @@ extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, * @detect: is this output active? * @get_modes: get mode list for this output * @set_property: property for this output may need update - * @cleanup: output is going away, cleanup + * @destroy: make object go away * * Each CRTC may have one or more outputs attached to it. The functions * below allow the core DRM code to control outputs, enumerate available modes, @@ -395,7 +390,7 @@ struct drm_output_funcs { int (*get_modes)(struct drm_output *output); bool (*set_property)(struct drm_output *output, struct drm_property *property, uint64_t val); - void (*cleanup)(struct drm_output *output); + void (*destroy)(struct drm_output *output); int (*mode_valid)(struct drm_output *output, struct drm_display_mode *mode); @@ -416,7 +411,6 @@ struct drm_output_funcs { * @initial_y: initial y position for this output * @status: output connected? * @funcs: output control functions - * @driver_private: private driver data * * Each output may be connected to one or more CRTCs, or may be clonable by * another output if they can share a CRTC. Each output also has a specific @@ -447,7 +441,6 @@ struct drm_output { struct drm_display_info display_info; const struct drm_output_funcs *funcs; - void *driver_private; struct list_head user_modes; struct drm_property_blob *edid_blob_ptr; @@ -532,13 +525,21 @@ struct drm_mode_config { uint32_t hotplug_counter; }; -struct drm_output *drm_output_create(struct drm_device *dev, - const struct drm_output_funcs *funcs, - int type); + +extern void drm_crtc_init(struct drm_device *dev, + struct drm_crtc *crtc, + const struct drm_crtc_funcs *funcs); +extern void drm_crtc_cleanup(struct drm_crtc *crtc); + +void drm_output_init(struct drm_device *dev, + struct drm_output *output, + const struct drm_output_funcs *funcs, + int output_type); + +void drm_output_cleanup(struct drm_output *output); extern char *drm_get_output_name(struct drm_output *output); extern char *drm_get_dpms_name(int val); -extern void drm_output_destroy(struct drm_output *output); extern void drm_fb_release(struct file *filp); extern struct edid *drm_get_edid(struct drm_output *output, diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 3c5dae1a..584dea21 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -96,7 +96,7 @@ static void intel_crt_mode_set(struct drm_output *output, { struct drm_device *dev = output->dev; struct drm_crtc *crtc = output->crtc; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_i915_private *dev_priv = dev->dev_private; int dpll_md_reg; u32 adpa, dpll_md; @@ -166,7 +166,7 @@ static bool intel_crt_detect_hotplug(struct drm_output *output) static bool intel_crt_detect_ddc(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); /* CRT should always be at 0, but check anyway */ if (intel_output->type != INTEL_OUTPUT_ANALOG) @@ -195,10 +195,11 @@ static enum drm_output_status intel_crt_detect(struct drm_output *output) static void intel_crt_destroy(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); intel_i2c_destroy(intel_output->ddc_bus); - kfree(output->driver_private); + drm_output_cleanup(output); + kfree(output); } static int intel_crt_get_modes(struct drm_output *output) @@ -235,7 +236,7 @@ static const struct drm_output_funcs intel_crt_output_funcs = { .restore = intel_crt_restore, .detect = intel_crt_detect, .get_modes = intel_crt_get_modes, - .cleanup = intel_crt_destroy, + .destroy = intel_crt_destroy, .set_property = intel_crt_set_property, .mode_valid = intel_crt_mode_valid, @@ -246,24 +247,23 @@ void intel_crt_init(struct drm_device *dev) struct drm_output *output; struct intel_output *intel_output; - output = drm_output_create(dev, &intel_crt_output_funcs, - DRM_MODE_OUTPUT_DAC); - - intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); - if (!intel_output) { - drm_output_destroy(output); + intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); + if (!intel_output) return; - } + + output = &intel_output->base; + drm_output_init(dev, &intel_output->base, &intel_crt_output_funcs, DRM_MODE_OUTPUT_DAC); + /* Set up the DDC bus. */ intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); + intel_crt_destroy(output); return; } intel_output->type = INTEL_OUTPUT_ANALOG; - output->driver_private = intel_output; output->interlace_allowed = 0; output->doublescan_allowed = 0; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index a2307a3d..abcf5f5e 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -229,7 +229,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type) list_for_each_entry(l_entry, &mode_config->output_list, head) { if (l_entry->crtc == crtc) { - struct intel_output *intel_output = l_entry->driver_private; + struct intel_output *intel_output = to_intel_output(l_entry); if (intel_output->type == type) return true; } @@ -344,7 +344,7 @@ intel_set_vblank(struct drm_device *dev) int vbl_pipe = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - intel_crtc = crtc->driver_private; + intel_crtc = to_intel_crtc(crtc); if (crtc->enabled) vbl_pipe |= (1<pipe); @@ -366,7 +366,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; unsigned long Start, Offset; int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); @@ -454,7 +454,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) struct drm_device *dev = crtc->dev; struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; @@ -694,7 +694,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int fp_reg = (pipe == 0) ? FPA0 : FPB0; int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; @@ -719,7 +719,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_output *output; list_for_each_entry(output, &mode_config->output_list, head) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); if (output->crtc != crtc) continue; @@ -947,7 +947,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; int i; @@ -969,7 +969,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; @@ -1027,7 +1027,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; uint32_t temp = 0; uint32_t adder; @@ -1055,8 +1055,8 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { - struct intel_crtc *intel_crtc = crtc->driver_private; - + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + intel_crtc->lut_r[regno] = red >> 8; intel_crtc->lut_g[regno] = green >> 8; intel_crtc->lut_b[regno] = blue >> 8; @@ -1087,7 +1087,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, int *dpms_mode) { struct drm_device *dev = output->dev; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_crtc *intel_crtc; struct drm_crtc *possible_crtc; struct drm_crtc *supported_crtc =NULL; @@ -1109,7 +1109,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, if (output->crtc) { crtc = output->crtc; /* Make sure the crtc and output are running */ - intel_crtc = crtc->driver_private; + intel_crtc = to_intel_crtc(crtc); *dpms_mode = intel_crtc->dpms_mode; if (intel_crtc->dpms_mode != DPMSModeOn) { crtc->funcs->dpms(crtc, DPMSModeOn); @@ -1144,7 +1144,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, output->crtc = crtc; intel_output->load_detect_temp = TRUE; - intel_crtc = crtc->driver_private; + intel_crtc = to_intel_crtc(crtc); *dpms_mode = intel_crtc->dpms_mode; if (!crtc->enabled) { @@ -1169,7 +1169,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, void intel_release_load_detect_pipe(struct drm_output *output, int dpms_mode) { struct drm_device *dev = output->dev; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct drm_crtc *crtc = output->crtc; if (intel_output->load_detect_temp) { @@ -1191,7 +1191,7 @@ void intel_release_load_detect_pipe(struct drm_output *output, int dpms_mode) static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B); u32 fp; @@ -1269,7 +1269,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; struct drm_display_mode *mode; int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); @@ -1297,6 +1297,14 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, return mode; } +static void intel_crtc_destroy(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + drm_crtc_cleanup(crtc); + kfree(intel_crtc); +} + static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, @@ -1311,24 +1319,20 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { .cursor_move = intel_crtc_cursor_move, .gamma_set = intel_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, + .destroy = intel_crtc_destroy, }; void intel_crtc_init(struct drm_device *dev, int pipe) { - struct drm_crtc *crtc; struct intel_crtc *intel_crtc; int i; - crtc = drm_crtc_create(dev, &intel_crtc_funcs); - if (crtc == NULL) - return; - intel_crtc = kzalloc(sizeof(struct intel_crtc), GFP_KERNEL); - if (intel_crtc == NULL) { - kfree(crtc); + if (intel_crtc == NULL) return; - } + + drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); intel_crtc->pipe = pipe; for (i = 0; i < 256; i++) { @@ -1339,9 +1343,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_addr = 0; intel_crtc->dpms_mode = DPMSModeOff; - drm_crtc_helper_add(crtc, &intel_helper_funcs); - - crtc->driver_private = intel_crtc; + drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); } struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) @@ -1349,7 +1351,7 @@ struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) struct drm_crtc *crtc = NULL; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_crtc *intel_crtc = crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); if (intel_crtc->pipe == pipe) break; } @@ -1363,7 +1365,7 @@ int intel_output_clones(struct drm_device *dev, int type_mask) int entry = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); if (type_mask & (1 << intel_output->type)) index_mask |= (1 << entry); entry++; @@ -1392,7 +1394,7 @@ static void intel_setup_outputs(struct drm_device *dev) intel_tv_init(dev); list_for_each_entry(output, &dev->mode_config.output_list, head) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); int crtc_mask = 0, clone_mask = 0; /* valid crtcs */ diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 9f8ca8dd..82d2d703 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -47,6 +47,7 @@ struct intel_i2c_chan { }; struct intel_output { + struct drm_output base; int type; struct intel_i2c_chan *i2c_bus; /* for control functions */ struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ @@ -55,6 +56,7 @@ struct intel_output { }; struct intel_crtc { + struct drm_crtc base; int pipe; int plane; uint32_t cursor_addr; @@ -62,6 +64,9 @@ struct intel_crtc { int dpms_mode; }; +#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) +#define to_intel_output(x) container_of(x, struct intel_output, base) + struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, const char *name); void intel_i2c_destroy(struct intel_i2c_chan *chan); diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index 5a7da276..d9f39af6 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -88,7 +88,7 @@ struct intel_dvo_device intel_dvo_devices[] = { static void intel_dvo_dpms(struct drm_output *output, int mode) { struct drm_i915_private *dev_priv = output->dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; u32 dvo_reg = dvo->dvo_reg; u32 temp = I915_READ(dvo_reg); @@ -107,7 +107,7 @@ static void intel_dvo_dpms(struct drm_output *output, int mode) static void intel_dvo_save(struct drm_output *output) { struct drm_i915_private *dev_priv = output->dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; /* Each output should probably just save the registers it touches, @@ -123,7 +123,7 @@ static void intel_dvo_save(struct drm_output *output) static void intel_dvo_restore(struct drm_output *output) { struct drm_i915_private *dev_priv = output->dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; dvo->dev_ops->restore(dvo); @@ -136,7 +136,7 @@ static void intel_dvo_restore(struct drm_output *output) static int intel_dvo_mode_valid(struct drm_output *output, struct drm_display_mode *mode) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; if (mode->flags & V_DBLSCAN) @@ -158,7 +158,7 @@ static bool intel_dvo_mode_fixup(struct drm_output *output, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; /* If we have timings from the BIOS for the panel, put them in @@ -193,8 +193,8 @@ static void intel_dvo_mode_set(struct drm_output *output, { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = output->crtc->driver_private; - struct intel_output *intel_output = output->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(output->crtc); + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; int pipe = intel_crtc->pipe; u32 dvo_val; @@ -249,7 +249,7 @@ static void intel_dvo_mode_set(struct drm_output *output, */ static enum drm_output_status intel_dvo_detect(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; return dvo->dev_ops->detect(dvo); @@ -257,7 +257,7 @@ static enum drm_output_status intel_dvo_detect(struct drm_output *output) static int intel_dvo_get_modes(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; /* We should probably have an i2c driver get_modes function for those @@ -291,7 +291,7 @@ static int intel_dvo_get_modes(struct drm_output *output) static void intel_dvo_destroy (struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; if (dvo) { @@ -302,14 +302,12 @@ static void intel_dvo_destroy (struct drm_output *output) /* no need, in i830_dvoices[] now */ //kfree(dvo); } - if (intel_output) { - if (intel_output->i2c_bus) - intel_i2c_destroy(intel_output->i2c_bus); - if (intel_output->ddc_bus) - intel_i2c_destroy(intel_output->ddc_bus); - kfree(intel_output); - output->driver_private = NULL; - } + if (intel_output->i2c_bus) + intel_i2c_destroy(intel_output->i2c_bus); + if (intel_output->ddc_bus) + intel_i2c_destroy(intel_output->ddc_bus); + drm_output_cleanup(output); + kfree(output); } #ifdef RANDR_GET_CRTC_INTERFACE @@ -317,7 +315,7 @@ static struct drm_crtc *intel_dvo_get_crtc(struct drm_output *output) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT); @@ -338,7 +336,7 @@ static const struct drm_output_funcs intel_dvo_output_funcs = { .restore = intel_dvo_restore, .detect = intel_dvo_detect, .get_modes = intel_dvo_get_modes, - .cleanup = intel_dvo_destroy, + .destroy = intel_dvo_destroy, .mode_valid = intel_dvo_mode_valid, }; @@ -353,7 +351,7 @@ intel_dvo_get_current_mode (struct drm_output *output) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_dvo_device *dvo = intel_output->dev_priv; uint32_t dvo_reg = dvo->dvo_reg; uint32_t dvo_val = I915_READ(dvo_reg); @@ -403,7 +401,7 @@ void intel_dvo_init(struct drm_device *dev) /* Now, try to find a controller */ for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { - struct drm_output *output = NULL; + struct drm_output *output = &intel_output->base; int gpio; dvo = &intel_dvo_devices[i]; @@ -445,22 +443,17 @@ void intel_dvo_init(struct drm_device *dev) switch (dvo->type) { case INTEL_DVO_CHIP_TMDS: connector = ConnectorDVID; - output = drm_output_create(dev, &intel_dvo_output_funcs, + drm_output_init(dev, output, &intel_dvo_output_funcs, DRM_MODE_OUTPUT_TMDS); break; case INTEL_DVO_CHIP_LVDS: connector = ConnectorLVDS; - output = drm_output_create(dev, &intel_dvo_output_funcs, + drm_output_init(dev, output, &intel_dvo_output_funcs, DRM_MODE_OUTPUT_LVDS); break; } - if (output == NULL) { - dvo->dev_ops->destroy(dvo); - goto free_i2c; - } drm_output_helper_add(output, &intel_dvo_helper_funcs); - output->driver_private = intel_output; output->display_info.subpixel_order = SubPixelHorizontalRGB; output->interlace_allowed = false; output->doublescan_allowed = false; @@ -487,7 +480,6 @@ void intel_dvo_init(struct drm_device *dev) return; } -free_i2c: intel_i2c_destroy(intel_output->ddc_bus); /* Didn't find a chip, so tear down. */ if (i2cbus != NULL) diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index f71dd436..6781a47c 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -161,7 +161,7 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = output->crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(output->crtc); struct drm_output *tmp_output; /* Should never happen!! */ @@ -241,7 +241,7 @@ static void intel_lvds_mode_set(struct drm_output *output, { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = output->crtc->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(output->crtc); u32 pfit_control; /* @@ -326,10 +326,11 @@ static int intel_lvds_get_modes(struct drm_output *output) */ static void intel_lvds_destroy(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); intel_i2c_destroy(intel_output->ddc_bus); - kfree(output->driver_private); + drm_output_cleanup(output); + kfree(output); } static const struct drm_output_helper_funcs intel_lvds_helper_funcs = { @@ -345,7 +346,7 @@ static const struct drm_output_funcs intel_lvds_output_funcs = { .restore = intel_lvds_restore, .detect = intel_lvds_detect, .get_modes = intel_lvds_get_modes, - .cleanup = intel_lvds_destroy, + .destroy = intel_lvds_destroy, .mode_valid = intel_lvds_mode_valid, }; @@ -359,27 +360,25 @@ static const struct drm_output_funcs intel_lvds_output_funcs = { void intel_lvds_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_output *output; struct intel_output *intel_output; + struct drm_output *output; struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; u32 lvds; int pipe; - output = drm_output_create(dev, &intel_lvds_output_funcs, - DRM_MODE_OUTPUT_LVDS); - if (!output) - return; - intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) { - drm_output_destroy(output); return; } + output = &intel_output->base; + drm_output_init(dev, &intel_output->base, &intel_lvds_output_funcs, + DRM_MODE_OUTPUT_LVDS); + intel_output->type = INTEL_OUTPUT_LVDS; + drm_output_helper_add(output, &intel_lvds_helper_funcs); - output->driver_private = intel_output; output->display_info.subpixel_order = SubPixelHorizontalRGB; output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; @@ -400,6 +399,7 @@ void intel_lvds_init(struct drm_device *dev) if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); + intel_lvds_destroy(output); return; } @@ -487,5 +487,5 @@ out: failed: DRM_DEBUG("No LVDS modes found, disabling.\n"); - drm_output_destroy(output); /* calls intel_lvds_destroy above */ + intel_lvds_destroy(output); } diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c index f8bf496c..8e9a506a 100644 --- a/linux-core/intel_modes.c +++ b/linux-core/intel_modes.c @@ -15,7 +15,7 @@ */ bool intel_ddc_probe(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); u8 out_buf[] = { 0x0, 0x0}; u8 buf[2]; int ret; @@ -49,7 +49,7 @@ bool intel_ddc_probe(struct drm_output *output) */ int intel_ddc_get_modes(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct edid *edid; int ret = 0; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 41da034d..f4b1c6ef 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -64,7 +64,7 @@ void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u32 bval = val, cval = val; int i; @@ -91,7 +91,7 @@ void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr, u8 *ch) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u8 out_buf[2]; u8 buf[2]; @@ -129,7 +129,7 @@ static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr, static bool intel_sdvo_write_byte(struct drm_output *output, int addr, u8 ch) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); u8 out_buf[2]; struct i2c_msg msgs[] = { { @@ -201,7 +201,7 @@ const static struct _sdvo_cmd_name { static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd, void *args, int args_len) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; @@ -242,7 +242,7 @@ static const char *cmd_status_names[] = { static u8 intel_sdvo_read_response(struct drm_output *output, void *response, int response_len) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; u8 status; @@ -493,7 +493,7 @@ static bool intel_sdvo_set_output_timing(struct drm_output *output, static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output, struct intel_sdvo_dtd *dtd) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u8 status; @@ -563,8 +563,8 @@ static void intel_sdvo_mode_set(struct drm_output *output, struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = output->crtc; - struct intel_crtc *intel_crtc = crtc->driver_private; - struct intel_output *intel_output = output->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u16 width, height; u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; @@ -693,7 +693,7 @@ static void intel_sdvo_dpms(struct drm_output *output, int mode) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u32 temp; @@ -743,7 +743,7 @@ static void intel_sdvo_save(struct drm_output *output) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int o; @@ -780,7 +780,7 @@ static void intel_sdvo_restore(struct drm_output *output) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int o; int i; @@ -828,7 +828,7 @@ static void intel_sdvo_restore(struct drm_output *output) static int intel_sdvo_mode_valid(struct drm_output *output, struct drm_display_mode *mode) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; if (mode->flags & V_DBLSCAN) @@ -863,7 +863,7 @@ struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB) /* find the sdvo output */ list_for_each_entry(output, &dev->mode_config.output_list, head) { - iout = output->driver_private; + iout = to_intel_output(output); if (iout->type != INTEL_OUTPUT_SDVO) continue; @@ -961,15 +961,13 @@ static int intel_sdvo_get_modes(struct drm_output *output) static void intel_sdvo_destroy(struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); if (intel_output->i2c_bus) intel_i2c_destroy(intel_output->i2c_bus); - if (intel_output) { - kfree(intel_output); - output->driver_private = NULL; - } + drm_output_cleanup(output); + kfree(intel_output); } static const struct drm_output_helper_funcs intel_sdvo_helper_funcs = { @@ -985,7 +983,7 @@ static const struct drm_output_funcs intel_sdvo_output_funcs = { .restore = intel_sdvo_restore, .detect = intel_sdvo_detect, .get_modes = intel_sdvo_get_modes, - .cleanup = intel_sdvo_destroy, + .destroy = intel_sdvo_destroy, .mode_valid = intel_sdvo_mode_valid, }; @@ -1000,21 +998,19 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) int i; int output_type, output_id; - output = drm_output_create(dev, &intel_sdvo_output_funcs, - DRM_MODE_OUTPUT_NONE); - if (!output) - return; - intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); if (!intel_output) { - drm_output_destroy(output); return; } + output = &intel_output->base; + + drm_output_init(dev, output, &intel_sdvo_output_funcs, + DRM_MODE_OUTPUT_NONE); + sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_SDVO; drm_output_helper_add(output, &intel_sdvo_helper_funcs); - output->driver_private = intel_output; output->interlace_allowed = 0; output->doublescan_allowed = 0; @@ -1025,7 +1021,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); if (i2cbus == NULL) { - drm_output_destroy(output); + intel_sdvo_destroy(output); return; } @@ -1049,7 +1045,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) if (!intel_sdvo_read_byte(output, i, &ch[i])) { DRM_DEBUG("No SDVO device found on SDVO%c\n", output_device == SDVOB ? 'B' : 'C'); - drm_output_destroy(output); + intel_sdvo_destroy(output); return; } } @@ -1095,7 +1091,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", SDVO_NAME(sdvo_priv), bytes[0], bytes[1]); - drm_output_destroy(output); + intel_sdvo_destroy(output); return; } diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 18fb1f37..e3e78a9f 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -920,7 +920,7 @@ intel_tv_save(struct drm_output *output) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_tv_priv *tv_priv = intel_output->dev_priv; int i; @@ -970,7 +970,7 @@ intel_tv_restore(struct drm_output *output) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_tv_priv *tv_priv = intel_output->dev_priv; struct drm_crtc *crtc = output->crtc; struct intel_crtc *intel_crtc; @@ -980,7 +980,7 @@ intel_tv_restore(struct drm_output *output) if (!crtc) return; - intel_crtc = crtc->driver_private; + intel_crtc = to_intel_crtc(crtc); I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1); I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2); I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3); @@ -1069,7 +1069,7 @@ intel_tv_mode_lookup (char *tv_format) static const struct tv_mode * intel_tv_mode_find (struct drm_output *output) { - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_tv_priv *tv_priv = intel_output->dev_priv; return intel_tv_mode_lookup(tv_priv->tv_format); @@ -1117,8 +1117,8 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = output->crtc; - struct intel_crtc *intel_crtc = crtc->driver_private; - struct intel_output *intel_output = output->driver_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_output *intel_output = to_intel_output(output); struct intel_tv_priv *tv_priv = intel_output->dev_priv; const struct tv_mode *tv_mode = intel_tv_mode_find(output); u32 tv_ctl; @@ -1359,7 +1359,7 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) { struct drm_device *dev = output->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); u32 pipeastat, pipeastat_save; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; @@ -1440,7 +1440,7 @@ intel_tv_detect(struct drm_output *output) { struct drm_crtc *crtc; struct drm_display_mode mode; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_tv_priv *tv_priv = intel_output->dev_priv; int dpms_mode; int type = tv_priv->type; @@ -1547,17 +1547,20 @@ intel_tv_get_modes(struct drm_output *output) static void intel_tv_destroy (struct drm_output *output) { - if (output->driver_private) - drm_free(output->driver_private, sizeof(struct intel_tv_priv), - DRM_MEM_DRIVER); + struct intel_output *intel_output = to_intel_output(output); + + drm_output_cleanup(output); + drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), + DRM_MEM_DRIVER); } + static bool intel_tv_set_property(struct drm_output *output, struct drm_property *property, uint64_t val) { struct drm_device *dev = output->dev; - struct intel_output *intel_output = output->driver_private; + struct intel_output *intel_output = to_intel_output(output); struct intel_tv_priv *tv_priv = intel_output->dev_priv; int ret = 0; @@ -1604,7 +1607,7 @@ static const struct drm_output_funcs intel_tv_output_funcs = { .mode_valid = intel_tv_mode_valid, .detect = intel_tv_detect, .get_modes = intel_tv_get_modes, - .cleanup = intel_tv_destroy, + .destroy = intel_tv_destroy, .set_property = intel_tv_set_property, }; @@ -1649,18 +1652,15 @@ intel_tv_init(struct drm_device *dev) (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) return; - output = drm_output_create(dev, &intel_tv_output_funcs, - DRM_MODE_OUTPUT_TVDAC); - - if (!output) - return; - intel_output = drm_calloc(1, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); if (!intel_output) { - drm_output_destroy(output); return; } + output = &intel_output->base; + + drm_output_init(dev, output, &intel_tv_output_funcs, + DRM_MODE_OUTPUT_TVDAC); tv_priv = (struct intel_tv_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_TVOUT; @@ -1678,7 +1678,6 @@ intel_tv_init(struct drm_device *dev) tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); drm_output_helper_add(output, &intel_tv_helper_funcs); - output->driver_private = intel_output; output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index ccedc70e..abf916ed 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -461,7 +461,7 @@ static void i915_hotplug_tv(struct drm_device *dev) /* find the crt output */ list_for_each_entry(output, &dev->mode_config.output_list, head) { - iout = output->driver_private; + iout = to_intel_output(output); if (iout->type == INTEL_OUTPUT_TVOUT) break; else @@ -488,7 +488,7 @@ static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) /* find the crt output */ list_for_each_entry(output, &dev->mode_config.output_list, head) { - iout = output->driver_private; + iout = to_intel_output(output); if (iout->type == INTEL_OUTPUT_ANALOG) break; else -- cgit v1.2.3 From 9654c776fda55d6420a14449bf2e274839c444a6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 11:47:57 +1000 Subject: drm/modesetting: add initial encoder structures and setup functions --- linux-core/drm_crtc.c | 25 +++++++++++++++++++++++++ linux-core/drm_crtc.h | 23 +++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index faf70df5..f7e7bfa8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -538,6 +538,31 @@ void drm_output_cleanup(struct drm_output *output) } EXPORT_SYMBOL(drm_output_cleanup); +void drm_encoder_init(struct drm_device *dev, + struct drm_encoder *encoder, + int encoder_type) +{ + encoder->dev = dev; + encoder->id = drm_idr_get(dev, encoder); + encoder->encoder_type = encoder_type; + + mutex_lock(&dev->mode_config.mutex); + list_add_tail(&encoder->head, &dev->mode_config.encoder_list); + dev->mode_config.num_encoder++; + + mutex_unlock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_encoder_init); + +void drm_encoder_cleanup(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + mutex_lock(&dev->mode_config.mutex); + drm_idr_put(dev, encoder->id); + list_del(&encoder->head); + mutex_unlock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_encoder_cleanup); /** * drm_mode_create - create a new display mode diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index b769eb7a..7765afea 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -277,6 +277,7 @@ struct drm_property { struct drm_crtc; struct drm_output; +struct drm_encoder; /** * drm_crtc_funcs - control CRTCs for a given device @@ -396,9 +397,29 @@ struct drm_output_funcs { }; +struct drm_encoder_funcs { + void (*destroy)(struct drm_encoder *encoder); +}; + #define DRM_OUTPUT_MAX_UMODES 16 #define DRM_OUTPUT_MAX_PROPERTY 16 #define DRM_OUTPUT_LEN 32 + +/** + * drm_encoder - central DRM encoder structure + */ +struct drm_encoder { + struct drm_device *dev; + struct list_head head; + + int id; + int encoder_type; + uint32_t possible_crtcs; + uint32_t possible_clones; + + const struct drm_encoder_funcs *funcs; +}; + /** * drm_output - central DRM output control structure * @crtc: CRTC this output is currently connected to, NULL if none @@ -496,6 +517,8 @@ struct drm_mode_config { struct list_head fb_list; int num_output; struct list_head output_list; + int num_encoder; + struct list_head encoder_list; int num_crtc; struct list_head crtc_list; -- cgit v1.2.3 From 6b970f193b69a912183dcbf85b9dc51ec99aeefe Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 11:48:41 +1000 Subject: drm: remove unused init func from outputs --- linux-core/drm_crtc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 7765afea..7bb779ef 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -383,7 +383,6 @@ struct drm_crtc { * etc. */ struct drm_output_funcs { - void (*init)(struct drm_output *output); void (*dpms)(struct drm_output *output, int mode); void (*save)(struct drm_output *output); void (*restore)(struct drm_output *output); -- cgit v1.2.3 From 8ae82f3a2feb8b8fe56214c4c9e806bf1f87cbf8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 12:03:36 +1000 Subject: drm: add encoder / get encoder to the modesetting resources interface --- linux-core/drm_crtc.c | 56 ++++++++++++++++++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 4 +++- linux-core/drm_crtc_helper.h | 9 +++++++ linux-core/drm_drv.c | 1 + 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f7e7bfa8..5d5448c5 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -784,6 +784,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) { struct drm_output *output, *ot; struct drm_crtc *crtc, *ct; + struct drm_encoder *encoder, *enct; struct drm_framebuffer *fb, *fbt; struct drm_property *property, *pt; @@ -804,6 +805,10 @@ void drm_mode_config_cleanup(struct drm_device *dev) dev->driver->fb_remove(dev, fb); } + list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, head) { + encoder->funcs->destroy(encoder); + } + list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { crtc->funcs->destroy(crtc); } @@ -911,14 +916,17 @@ int drm_mode_getresources(struct drm_device *dev, struct drm_framebuffer *fb; struct drm_output *output; struct drm_crtc *crtc; + struct drm_encoder *encoder; int ret = 0; int output_count = 0; int crtc_count = 0; int fb_count = 0; + int encoder_count = 0; int copied = 0; uint32_t __user *fb_id; uint32_t __user *crtc_id; uint32_t __user *output_id; + uint32_t __user *encoder_id; mutex_lock(&dev->mode_config.mutex); @@ -931,6 +939,9 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each(lh, &dev->mode_config.output_list) output_count++; + list_for_each(lh, &dev->mode_config.encoder_list) + encoder_count++; + card_res->max_height = dev->mode_config.max_height; card_res->min_height = dev->mode_config.min_height; card_res->max_width = dev->mode_config.max_width; @@ -982,9 +993,25 @@ int drm_mode_getresources(struct drm_device *dev, } } card_res->count_outputs = output_count; + + /* Encoders */ + if (card_res->count_encoders >= encoder_count) { + copied = 0; + encoder_id = (uint32_t *)(unsigned long)card_res->encoder_id_ptr; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + head) { + DRM_DEBUG("ENCODER ID is %d\n", encoder->id); + if (put_user(encoder->id, encoder_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + card_res->count_encoders = encoder_count; - DRM_DEBUG("Counted %d %d\n", card_res->count_crtcs, - card_res->count_outputs); + DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs, + card_res->count_outputs, card_res->count_encoders); out: mutex_unlock(&dev->mode_config.mutex); @@ -1165,6 +1192,31 @@ out: return ret; } +int drm_mode_getencoder(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_get_encoder *enc_resp = data; + struct drm_encoder *encoder; + int ret = 0; + + mutex_lock(&dev->mode_config.mutex); + encoder = idr_find(&dev->mode_config.crtc_idr, enc_resp->encoder_id); + if (!encoder || (encoder->id != enc_resp->encoder_id)) { + DRM_DEBUG("Unknown encoder ID %d\n", enc_resp->encoder_id); + ret = -EINVAL; + goto out; + } + + enc_resp->encoder_type = encoder->encoder_type; + enc_resp->encoder_id = encoder->id; + enc_resp->crtcs = encoder->possible_crtcs; + enc_resp->clones = encoder->possible_clones; + +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + /** * drm_mode_setcrtc - set CRTC configuration * @inode: inode from the ioctl diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 7bb779ef..adaa49bd 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -366,7 +366,6 @@ struct drm_crtc { /** * drm_output_funcs - control outputs on a given device - * @init: setup this output * @dpms: set power state (see drm_crtc_funcs above) * @save: save output state * @restore: restore output state @@ -417,6 +416,7 @@ struct drm_encoder { uint32_t possible_clones; const struct drm_encoder_funcs *funcs; + void *helper_private; }; /** @@ -663,5 +663,7 @@ extern int drm_mode_hotplug_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_replacefb(struct drm_device *dev, void *data, struct drm_file *file_priv); +int drm_mode_getencoder(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index f56b97c6..9e16861d 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -47,6 +47,15 @@ struct drm_output_helper_funcs { struct drm_display_mode *adjusted_mode); }; +struct drm_encoder_helper_funcs { + void (*prepare)(struct drm_output *output); + void (*commit)(struct drm_output *output); + void (*mode_set)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +}; + + extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected); extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index d96b14b6..6111c850 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -142,6 +142,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_WAIT_HOTPLUG, drm_wait_hotplug, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_REPLACEFB, drm_mode_replacefb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -- cgit v1.2.3 From 16a8f824face8067029ef6f3d10f1723d87b23f6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 12:10:01 +1000 Subject: libdrm: add encoder retrival --- libdrm/xf86drmMode.c | 27 +++++++++++++++++++++++++++ libdrm/xf86drmMode.h | 15 +++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index ae15fd65..e5798f96 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -139,6 +139,8 @@ drmModeResPtr drmModeGetResources(int fd) res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t))); if (res.count_outputs) res.output_id_ptr = VOID2U64(drmMalloc(res.count_outputs*sizeof(uint32_t))); + if (res.count_encoders) + res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t))); if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { r = NULL; @@ -164,11 +166,13 @@ drmModeResPtr drmModeGetResources(int fd) r->fbs = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t)); r->crtcs = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t)); r->outputs = drmAllocCpy(U642VOID(res.output_id_ptr), res.count_outputs, sizeof(uint32_t)); + r->encoders = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t)); err_allocs: drmFree(U642VOID(res.fb_id_ptr)); drmFree(U642VOID(res.crtc_id_ptr)); drmFree(U642VOID(res.output_id_ptr)); + drmFree(U642VOID(res.encoder_id_ptr)); return r; } @@ -333,6 +337,29 @@ int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg); } +/* + * Encoder get + */ +drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) +{ + struct drm_mode_get_encoder enc; + drmModeEncoderPtr r = NULL; + + enc.encoder_id = encoder_id; + enc.encoder_type = 0; + enc.crtcs = 0; + enc.clones = 0; + + if (ioctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc)) + return 0; + + r->encoder_type = enc.encoder_type; + r->crtcs = enc.crtcs; + r->clones = enc.clones; + + return r; +} + /* * Output manipulation */ diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 5171b592..a5ecd099 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -63,6 +63,9 @@ typedef struct _drmModeRes { int count_outputs; uint32_t *outputs; + int count_encoders; + uint32_t *encoders; + uint32_t min_width, max_width; uint32_t min_height, max_height; } drmModeRes, *drmModeResPtr; @@ -106,6 +109,13 @@ typedef struct _drmModeCrtc { } drmModeCrtc, *drmModeCrtcPtr; +typedef struct _drmModeEncoder { + unsigned int encoder_id; + unsigned int encoder_type; + uint32_t crtcs; + uint32_t clones; +} drmModeEncoder, *drmModeEncoderPtr; + typedef enum { DRM_MODE_CONNECTED = 1, DRM_MODE_DISCONNECTED = 2, @@ -221,6 +231,11 @@ int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width */ int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y); +/** + * Encoder functions + */ +drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id); + /* * Output manipulation */ -- cgit v1.2.3 From fae2c17b313e2838652c32ea4a576172b4063639 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 12:14:44 +1000 Subject: drm: add more encoder interfaces --- libdrm/xf86drmMode.c | 8 ++++++++ libdrm/xf86drmMode.h | 2 ++ shared-core/drm.h | 15 +++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index e5798f96..672a5e2a 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -381,6 +381,8 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) out.count_props = 0; out.props_ptr = 0; out.prop_values_ptr = 0; + out.count_encoders = 0; + out.encoders_ptr = 0; if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) return 0; @@ -393,6 +395,9 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) if (out.count_modes) out.modes_ptr = VOID2U64(drmMalloc(out.count_modes*sizeof(struct drm_mode_modeinfo))); + if (out.count_encoders) + out.encoders_ptr = VOID2U64(drmMalloc(out.count_encoders*sizeof(uint32_t))); + if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) goto err_allocs; @@ -416,6 +421,8 @@ drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) r->props = drmAllocCpy(U642VOID(out.props_ptr), out.count_props, sizeof(uint32_t)); r->prop_values = drmAllocCpy(U642VOID(out.prop_values_ptr), out.count_props, sizeof(uint64_t)); r->modes = drmAllocCpy(U642VOID(out.modes_ptr), out.count_modes, sizeof(struct drm_mode_modeinfo)); + r->count_encoders = out.count_encoders; + r->encoders = drmAllocCpy(U642VOID(out.encoders_ptr), out.count_encoders, sizeof(uint32_t)); r->output_type = out.output_type; r->output_type_id = out.output_type_id; @@ -423,6 +430,7 @@ err_allocs: drmFree(U642VOID(out.prop_values_ptr)); drmFree(U642VOID(out.props_ptr)); drmFree(U642VOID(out.modes_ptr)); + drmFree(U642VOID(out.encoders_ptr)); return r; } diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index a5ecd099..601a6460 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -154,6 +154,8 @@ typedef struct _drmModeOutput { uint32_t *props; /**< List of property ids */ uint64_t *prop_values; /**< List of property values */ + int count_encoders; + uint32_t *encoders; /**< List of encoder ids */ } drmModeOutput, *drmModeOutputPtr; diff --git a/shared-core/drm.h b/shared-core/drm.h index eb2033c7..6cb68685 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1026,9 +1026,11 @@ struct drm_mode_card_res { uint64_t fb_id_ptr; uint64_t crtc_id_ptr; uint64_t output_id_ptr; + uint64_t encoder_id_ptr; int count_fbs; int count_crtcs; int count_outputs; + int count_encoders; int min_width, max_width; int min_height, max_height; }; @@ -1051,6 +1053,15 @@ struct drm_mode_crtc { struct drm_mode_modeinfo mode; }; +struct drm_mode_get_encoder { + + uint32_t encoder_type; + uint32_t encoder_id; + + uint32_t crtcs; + uint32_t clones; +}; + #define DRM_MODE_OUTPUT_NONE 0 #define DRM_MODE_OUTPUT_DAC 1 #define DRM_MODE_OUTPUT_TMDS 2 @@ -1059,12 +1070,15 @@ struct drm_mode_crtc { struct drm_mode_get_output { + uint64_t encoders_ptr; uint64_t modes_ptr; uint64_t props_ptr; uint64_t prop_values_ptr; int count_modes; int count_props; + int count_encoders; + unsigned int output; /**< Id */ unsigned int crtc; /**< Id of crtc */ unsigned int output_type; @@ -1277,6 +1291,7 @@ struct drm_mode_hotplug { #define DRM_IOCTL_WAIT_HOTPLUG DRM_IOWR(0xAE, union drm_wait_hotplug) #define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xAF, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xB0, struct drm_mode_get_encoder) /*@}*/ /** -- cgit v1.2.3 From b72419a8f74bfb1d3b6a5ca1d8f6dfa3c6a84e86 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 12:19:13 +1000 Subject: drm: add encoder ids to the output handling --- linux-core/drm_crtc.c | 23 +++++++++++++++++++++++ linux-core/drm_crtc.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 5d5448c5..fc35c1ab 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1104,6 +1104,7 @@ int drm_mode_getoutput(struct drm_device *dev, struct drm_display_mode *mode; int mode_count = 0; int props_count = 0; + int encoders_count = 0; int ret = 0; int copied = 0; int i; @@ -1111,6 +1112,7 @@ int drm_mode_getoutput(struct drm_device *dev, struct drm_mode_modeinfo __user *mode_ptr; uint32_t __user *prop_ptr; uint64_t __user *prop_values; + uint32_t __user *encoder_ptr; memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); @@ -1132,6 +1134,12 @@ int drm_mode_getoutput(struct drm_device *dev, } } + for (i = 0; i < DRM_OUTPUT_MAX_ENCODER; i++) { + if (output->encoder_ids[i] != 0) { + encoders_count++; + } + } + if (out_resp->count_modes == 0) { drm_crtc_probe_single_output_modes(output, dev->mode_config.max_width, dev->mode_config.max_height); } @@ -1187,6 +1195,21 @@ int drm_mode_getoutput(struct drm_device *dev, } out_resp->count_props = props_count; + if ((out_resp->count_encoders >= encoders_count) && encoders_count) { + copied = 0; + encoder_ptr = (uint32_t *)(unsigned long)(out_resp->encoders_ptr); + for (i = 0; i < DRM_OUTPUT_MAX_ENCODER; i++) { + if (output->encoder_ids[i] != 0) { + if (put_user(output->encoder_ids[i], encoder_ptr + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + } + out_resp->count_encoders = encoders_count; + out: mutex_unlock(&dev->mode_config.mutex); return ret; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index adaa49bd..ed8467e3 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -402,6 +402,7 @@ struct drm_encoder_funcs { #define DRM_OUTPUT_MAX_UMODES 16 #define DRM_OUTPUT_MAX_PROPERTY 16 #define DRM_OUTPUT_LEN 32 +#define DRM_OUTPUT_MAX_ENCODER 2 /** * drm_encoder - central DRM encoder structure @@ -468,6 +469,8 @@ struct drm_output { uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; void *helper_private; + + u32 encoder_ids[DRM_OUTPUT_MAX_ENCODER]; }; /** -- cgit v1.2.3 From 6b5592790dcaed503bec8f441eab52d22b76d7c1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 12:20:36 +1000 Subject: drm: add red hat copyright. --- linux-core/drm_crtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fc35c1ab..734850f3 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2006-2007 Intel Corporation * Copyright (c) 2007 Dave Airlie + * Copyright (c) 2008 Red Hat Inc. * * DRM core CRTC related functions * -- cgit v1.2.3 From 1542492b797fbdf4970e0213827e2f9887d6174d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 12:24:19 +1000 Subject: drm: init the encoder list/count --- linux-core/drm_crtc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 734850f3..f6937f44 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -708,6 +708,7 @@ void drm_mode_config_init(struct drm_device *dev) INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.output_list); + INIT_LIST_HEAD(&dev->mode_config.encoder_list); INIT_LIST_HEAD(&dev->mode_config.property_list); INIT_LIST_HEAD(&dev->mode_config.property_blob_list); idr_init(&dev->mode_config.crtc_idr); @@ -718,6 +719,7 @@ void drm_mode_config_init(struct drm_device *dev) dev->mode_config.num_fb = 0; dev->mode_config.num_output = 0; dev->mode_config.num_crtc = 0; + dev->mode_config.num_encoder = 0; dev->mode_config.hotplug_counter = 0; } EXPORT_SYMBOL(drm_mode_config_init); -- cgit v1.2.3 From 514147e3f3180b46d3e9e6e906580fe232d4ad26 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 12:29:45 +1000 Subject: drm: add encoder free function --- libdrm/xf86drmMode.c | 5 +++++ libdrm/xf86drmMode.h | 1 + 2 files changed, 6 insertions(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 672a5e2a..78efe827 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -119,6 +119,11 @@ void drmModeFreeOutput(drmModeOutputPtr ptr) } +void drmModeFreeEncoder(drmModeEncoderPtr ptr) +{ + drmFree(ptr); +} + /* * ModeSetting functions. */ diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 601a6460..85e3d912 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -165,6 +165,7 @@ extern void drmModeFreeResources( drmModeResPtr ptr ); extern void drmModeFreeFB( drmModeFBPtr ptr ); extern void drmModeFreeCrtc( drmModeCrtcPtr ptr ); extern void drmModeFreeOutput( drmModeOutputPtr ptr ); +extern void drmModeFreeEncoder( drmModeEncoderPtr ptr ); /** * Retrives all of the resources associated with a card. -- cgit v1.2.3 From 4403c59b76c55c9c430decac8bc76e4230a253ab Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 13:22:51 +1000 Subject: tests: add basic encoder reading to test --- tests/mode/modetest.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 99238d5a..eba072ee 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -52,6 +52,7 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) int i = 0, j; struct drm_mode_modeinfo *mode = NULL; drmModePropertyPtr props; + drmModeEncoderPtr enc; unsigned char *name = NULL; printf("Output: %d-%d\n", output->output_type, output->output_type_id); @@ -65,6 +66,14 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) printf("\tclones : %i\n", output->clones); printf("\tcount_modes : %i\n", output->count_modes); printf("\tcount_props : %i\n", output->count_props); + printf("\tcount_encs : %i\n", output->count_encoders); + + for (i = 0; i < output->count_encoders; i++) { + enc = drmModeGetEncoder(fd, output->encoders[i]); + if (enc) { + printf("Encoder: %d %d %d %d\n", enc->encoder_id, enc->encoder_type, enc->crtcs, enc->clones); + } + } for (i = 0; i < output->count_props; i++) { props = drmModeGetProperty(fd, output->props[i]); @@ -121,6 +130,16 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) return 0; } +int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t id) +{ + printf("Encoder\n"); + printf("\tid :%i\n", id); + printf("\ttype :%d\n", encoder->encoder_type); + printf("\tcrtcs :%d\n", encoder->crtcs); + printf("\tclones :%d\n", encoder->clones); + return 0; +} + int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) { printf("Crtc\n"); @@ -158,6 +177,7 @@ int printRes(int fd, drmModeResPtr res) drmModeOutputPtr output; drmModeCrtcPtr crtc; drmModeFBPtr fb; + drmModeEncoderPtr encoder; for (i = 0; i < res->count_outputs; i++) { output = drmModeGetOutput(fd, res->outputs[i]); @@ -170,6 +190,18 @@ int printRes(int fd, drmModeResPtr res) } } + for (i = 0; i < res->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, res->encoders[i]); + + if (!encoder) + printf("Could not get encoder %i\n", i); + else { + printEncoder(fd, res, encoder, res->encoders[i]); + drmModeFreeEncoder(encoder); + } + } + + for (i = 0; i < res->count_crtcs; i++) { crtc = drmModeGetCrtc(fd, res->crtcs[i]); -- cgit v1.2.3 From 9239cf511f65a43eb578fbb6a7c5255e05db2101 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 13:31:16 +1000 Subject: drm: add encoder attach/detach --- linux-core/drm_crtc.c | 28 ++++++++++++++++++++++++++++ linux-core/drm_crtc.h | 5 +++++ 2 files changed, 33 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f6937f44..400df98e 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2202,3 +2202,31 @@ out: return ret; } + +int drm_mode_output_attach_encoder(struct drm_output *output, + struct drm_encoder *encoder) +{ + int i; + + for (i = 0; i < DRM_OUTPUT_MAX_ENCODER; i++) { + if (output->encoder_ids[i] == 0) { + output->encoder_ids[i] = encoder->id; + return 0; + } + } + return -ENOMEM; +} +EXPORT_SYMBOL(drm_mode_output_attach_encoder); + +void drm_mode_output_detach_encoder(struct drm_output *output, + struct drm_encoder *encoder) +{ + int i; + for (i = 0; i < DRM_OUTPUT_MAX_ENCODER; i++) { + if (output->encoder_ids[i] == encoder->id) { + output->encoder_ids[i] = 0; + break; + } + } +} +EXPORT_SYMBOL(drm_mode_output_detach_encoder); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index ed8467e3..04e0d033 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -629,6 +629,11 @@ extern int drm_property_add_enum(struct drm_property *property, int index, extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); +extern int drm_mode_output_attach_encoder(struct drm_output *output, + struct drm_encoder *encoder); +extern void drm_mode_output_detach_encoder(struct drm_output *output, + struct drm_encoder *encoder); + /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); -- cgit v1.2.3 From 1c4b25a2b1c31df190eab173128702d1b5871906 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 13:49:39 +1000 Subject: drm: fix a couple of bugs in the encoder return to userspace --- libdrm/xf86drmMode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 78efe827..0824ec3f 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -167,6 +167,7 @@ drmModeResPtr drmModeGetResources(int fd) r->count_fbs = res.count_fbs; r->count_crtcs = res.count_crtcs; r->count_outputs = res.count_outputs; + r->count_encoders = res.count_encoders; /* TODO we realy should test if these allocs fails. */ r->fbs = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t)); r->crtcs = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t)); @@ -358,6 +359,9 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) if (ioctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc)) return 0; + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + r->encoder_type = enc.encoder_type; r->crtcs = enc.crtcs; r->clones = enc.clones; -- cgit v1.2.3 From 6aeef92c0cad784a5019ea90d97ab81f4e51fdd9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 13:57:27 +1000 Subject: drm: attach an encoder. Time to do some renaming on the connectors I think --- linux-core/drm_crtc.c | 12 +++++++----- linux-core/drm_crtc.h | 17 ++++++++++++----- linux-core/intel_crt.c | 18 +++++++++++++++--- linux-core/intel_drv.h | 2 ++ linux-core/intel_sdvo.c | 4 ++-- shared-core/drm.h | 8 +++++++- 6 files changed, 45 insertions(+), 16 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 400df98e..bb527413 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -77,7 +77,7 @@ static struct drm_prop_enum_list drm_conn_enum_list[] = }; static struct drm_prop_enum_list drm_output_enum_list[] = { { DRM_MODE_OUTPUT_NONE, "None" }, - { DRM_MODE_OUTPUT_DAC, "DAC" }, + { DRM_MODE_OUTPUT_VGA, "VGA" }, { DRM_MODE_OUTPUT_TMDS, "TMDS" }, { DRM_MODE_OUTPUT_LVDS, "LVDS" }, { DRM_MODE_OUTPUT_TVDAC, "TV" }, @@ -541,11 +541,13 @@ EXPORT_SYMBOL(drm_output_cleanup); void drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, + const struct drm_encoder_funcs *funcs, int encoder_type) { encoder->dev = dev; encoder->id = drm_idr_get(dev, encoder); encoder->encoder_type = encoder_type; + encoder->funcs = funcs; mutex_lock(&dev->mode_config.mutex); list_add_tail(&encoder->head, &dev->mode_config.encoder_list); @@ -791,6 +793,10 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_framebuffer *fb, *fbt; struct drm_property *property, *pt; + list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, head) { + encoder->funcs->destroy(encoder); + } + list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { drm_sysfs_output_remove(output); output->funcs->destroy(output); @@ -808,10 +814,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) dev->driver->fb_remove(dev, fb); } - list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, head) { - encoder->funcs->destroy(encoder); - } - list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { crtc->funcs->destroy(crtc); } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 04e0d033..03c336e2 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -556,12 +556,19 @@ extern void drm_crtc_init(struct drm_device *dev, const struct drm_crtc_funcs *funcs); extern void drm_crtc_cleanup(struct drm_crtc *crtc); -void drm_output_init(struct drm_device *dev, - struct drm_output *output, - const struct drm_output_funcs *funcs, - int output_type); +extern void drm_output_init(struct drm_device *dev, + struct drm_output *output, + const struct drm_output_funcs *funcs, + int output_type); -void drm_output_cleanup(struct drm_output *output); +extern void drm_output_cleanup(struct drm_output *output); + +extern void drm_encoder_init(struct drm_device *dev, + struct drm_encoder *encoder, + const struct drm_encoder_funcs *funcs, + int encoder_type); + +extern void drm_encoder_cleanup(struct drm_encoder *encoder); extern char *drm_get_output_name(struct drm_output *output); extern char *drm_get_dpms_name(int val); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 584dea21..44035783 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -242,6 +242,15 @@ static const struct drm_output_funcs intel_crt_output_funcs = { }; +void intel_crt_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs intel_crt_enc_funcs = { + .destroy = intel_crt_enc_destroy, +}; + void intel_crt_init(struct drm_device *dev) { struct drm_output *output; @@ -252,7 +261,11 @@ void intel_crt_init(struct drm_device *dev) return; output = &intel_output->base; - drm_output_init(dev, &intel_output->base, &intel_crt_output_funcs, DRM_MODE_OUTPUT_DAC); + drm_output_init(dev, &intel_output->base, &intel_crt_output_funcs, DRM_MODE_OUTPUT_VGA); + + drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); + + drm_mode_output_attach_encoder(&intel_output->base, &intel_output->enc); /* Set up the DDC bus. */ intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); @@ -268,7 +281,6 @@ void intel_crt_init(struct drm_device *dev) output->doublescan_allowed = 0; drm_output_helper_add(output, &intel_crt_helper_funcs); - drm_sysfs_output_add(output); - drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA); + drm_sysfs_output_add(output); } diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 82d2d703..3f0c1664 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -48,6 +48,8 @@ struct intel_i2c_chan { struct intel_output { struct drm_output base; + + struct drm_encoder enc; int type; struct intel_i2c_chan *i2c_bus; /* for control functions */ struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index f4b1c6ef..2b232e9a 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1059,14 +1059,14 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; output->display_info.subpixel_order = SubPixelHorizontalRGB; - output_type = DRM_MODE_OUTPUT_DAC; + output_type = DRM_MODE_OUTPUT_VGA; connector_type = ConnectorVGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; output->display_info.subpixel_order = SubPixelHorizontalRGB; - output_type = DRM_MODE_OUTPUT_DAC; + output_type = DRM_MODE_OUTPUT_VGA; connector_type = ConnectorVGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) diff --git a/shared-core/drm.h b/shared-core/drm.h index 6cb68685..0005bb0b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1062,8 +1062,14 @@ struct drm_mode_get_encoder { uint32_t clones; }; +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 + #define DRM_MODE_OUTPUT_NONE 0 -#define DRM_MODE_OUTPUT_DAC 1 +#define DRM_MODE_OUTPUT_VGA 1 #define DRM_MODE_OUTPUT_TMDS 2 #define DRM_MODE_OUTPUT_LVDS 3 #define DRM_MODE_OUTPUT_TVDAC 4 -- cgit v1.2.3 From 9d38448ed33aaff324cc4bbe1e0878593e97d07d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 15:03:12 +1000 Subject: modesetting: the great renaming. Okay we have crtc, encoder and connectors. No more outputs exposed beyond driver internals I've broken intel tv connector stuff. Really for TV we should have one TV connector, with a sub property for the type of signal been driven over it --- libdrm/xf86drmMode.c | 148 ++++++------ libdrm/xf86drmMode.h | 42 ++-- linux-core/drmP.h | 8 +- linux-core/drm_crtc.c | 540 +++++++++++++++++++++---------------------- linux-core/drm_crtc.h | 200 ++++++++-------- linux-core/drm_crtc_helper.c | 186 +++++++-------- linux-core/drm_crtc_helper.h | 22 +- linux-core/drm_drv.c | 4 +- linux-core/drm_edid.c | 94 ++++---- linux-core/drm_modes.c | 14 +- linux-core/drm_sysfs.c | 92 ++++---- linux-core/dvo.h | 2 +- linux-core/dvo_ch7017.c | 4 +- linux-core/dvo_ch7xxx.c | 6 +- linux-core/dvo_ivch.c | 4 +- linux-core/dvo_sil164.c | 6 +- linux-core/dvo_tfp410.c | 8 +- linux-core/intel_crt.c | 91 ++++---- linux-core/intel_display.c | 98 ++++---- linux-core/intel_drv.h | 22 +- linux-core/intel_dvo.c | 123 +++++----- linux-core/intel_fb.c | 34 +-- linux-core/intel_lvds.c | 127 +++++----- linux-core/intel_modes.c | 16 +- linux-core/intel_sdvo.c | 399 ++++++++++++++++---------------- linux-core/intel_tv.c | 173 +++++++------- shared-core/drm.h | 40 ++-- shared-core/i915_irq.c | 46 ++-- tests/mode/modetest.c | 90 ++++---- 29 files changed, 1326 insertions(+), 1313 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 0824ec3f..a18c4290 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -109,7 +109,7 @@ void drmModeFreeCrtc(drmModeCrtcPtr ptr) } -void drmModeFreeOutput(drmModeOutputPtr ptr) +void drmModeFreeConnector(drmModeConnectorPtr ptr) { if (!ptr) return; @@ -142,8 +142,8 @@ drmModeResPtr drmModeGetResources(int fd) res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t))); if (res.count_crtcs) res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t))); - if (res.count_outputs) - res.output_id_ptr = VOID2U64(drmMalloc(res.count_outputs*sizeof(uint32_t))); + if (res.count_connectors) + res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t))); if (res.count_encoders) res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t))); @@ -166,18 +166,18 @@ drmModeResPtr drmModeGetResources(int fd) r->max_height = res.max_height; r->count_fbs = res.count_fbs; r->count_crtcs = res.count_crtcs; - r->count_outputs = res.count_outputs; + r->count_connectors = res.count_connectors; r->count_encoders = res.count_encoders; /* TODO we realy should test if these allocs fails. */ r->fbs = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t)); r->crtcs = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t)); - r->outputs = drmAllocCpy(U642VOID(res.output_id_ptr), res.count_outputs, sizeof(uint32_t)); + r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t)); r->encoders = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t)); err_allocs: drmFree(U642VOID(res.fb_id_ptr)); drmFree(U642VOID(res.crtc_id_ptr)); - drmFree(U642VOID(res.output_id_ptr)); + drmFree(U642VOID(res.connector_id_ptr)); drmFree(U642VOID(res.encoder_id_ptr)); return r; @@ -254,8 +254,8 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) struct drm_mode_crtc crtc; drmModeCrtcPtr r; - crtc.count_outputs = 0; - crtc.outputs = 0; + crtc.count_connectors = 0; + crtc.connectors = 0; crtc.count_possibles = 0; crtc.possibles = 0; crtc.crtc_id = crtcId; @@ -278,10 +278,10 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo)); r->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; - r->count_outputs = crtc.count_outputs; + r->count_connectors = crtc.count_connectors; r->count_possibles = crtc.count_possibles; /* TODO we realy should test if these alloc & cpy fails. */ - r->outputs = crtc.outputs; + r->connectors = crtc.connectors; r->possibles = crtc.possibles; return r; @@ -289,13 +289,13 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, - uint32_t x, uint32_t y, uint32_t *outputs, int count, + uint32_t x, uint32_t y, uint32_t *connectors, int count, struct drm_mode_modeinfo *mode) { struct drm_mode_crtc crtc; - crtc.count_outputs = 0; - crtc.outputs = 0; + crtc.count_connectors = 0; + crtc.connectors = 0; crtc.count_possibles = 0; crtc.possibles = 0; @@ -303,8 +303,8 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, crtc.y = y; crtc.crtc_id = crtcId; crtc.fb_id = bufferId; - crtc.set_outputs_ptr = VOID2U64(outputs); - crtc.count_outputs = count; + crtc.set_connectors_ptr = VOID2U64(connectors); + crtc.count_connectors = count; if (mode) { memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo)); crtc.mode_valid = 1; @@ -370,96 +370,96 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) } /* - * Output manipulation + * Connector manipulation */ -drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id) +drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) { - struct drm_mode_get_output out; - drmModeOutputPtr r = NULL; - - out.output = output_id; - out.output_type_id = 0; - out.output_type = 0; - out.count_crtcs = 0; - out.crtcs = 0; - out.count_clones = 0; - out.clones = 0; - out.count_modes = 0; - out.modes_ptr = 0; - out.count_props = 0; - out.props_ptr = 0; - out.prop_values_ptr = 0; - out.count_encoders = 0; - out.encoders_ptr = 0; - - if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) + struct drm_mode_get_connector conn; + drmModeConnectorPtr r = NULL; + + conn.connector = connector_id; + conn.connector_type_id = 0; + conn.connector_type = 0; + conn.count_crtcs = 0; + conn.crtcs = 0; + conn.count_clones = 0; + conn.clones = 0; + conn.count_modes = 0; + conn.modes_ptr = 0; + conn.count_props = 0; + conn.props_ptr = 0; + conn.prop_values_ptr = 0; + conn.count_encoders = 0; + conn.encoders_ptr = 0; + + if (ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)) return 0; - if (out.count_props) { - out.props_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint32_t))); - out.prop_values_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint64_t))); + if (conn.count_props) { + conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t))); + conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t))); } - if (out.count_modes) - out.modes_ptr = VOID2U64(drmMalloc(out.count_modes*sizeof(struct drm_mode_modeinfo))); + if (conn.count_modes) + conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo))); - if (out.count_encoders) - out.encoders_ptr = VOID2U64(drmMalloc(out.count_encoders*sizeof(uint32_t))); + if (conn.count_encoders) + conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t))); - if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out)) + if (ioctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)) goto err_allocs; if(!(r = drmMalloc(sizeof(*r)))) { goto err_allocs; } - r->output_id = out.output; - r->crtc = out.crtc; - r->connection = out.connection; - r->mmWidth = out.mm_width; - r->mmHeight = out.mm_height; - r->subpixel = out.subpixel; - r->count_crtcs = out.count_crtcs; - r->count_clones = out.count_clones; - r->count_modes = out.count_modes; + r->connector_id = conn.connector; + r->crtc = conn.crtc; + r->connection = conn.connection; + r->mmWidth = conn.mm_width; + r->mmHeight = conn.mm_height; + r->subpixel = conn.subpixel; + r->count_crtcs = conn.count_crtcs; + r->count_clones = conn.count_clones; + r->count_modes = conn.count_modes; /* TODO we should test if these alloc & cpy fails. */ - r->crtcs = out.crtcs; - r->clones = out.clones; - r->count_props = out.count_props; - r->props = drmAllocCpy(U642VOID(out.props_ptr), out.count_props, sizeof(uint32_t)); - r->prop_values = drmAllocCpy(U642VOID(out.prop_values_ptr), out.count_props, sizeof(uint64_t)); - r->modes = drmAllocCpy(U642VOID(out.modes_ptr), out.count_modes, sizeof(struct drm_mode_modeinfo)); - r->count_encoders = out.count_encoders; - r->encoders = drmAllocCpy(U642VOID(out.encoders_ptr), out.count_encoders, sizeof(uint32_t)); - r->output_type = out.output_type; - r->output_type_id = out.output_type_id; + r->crtcs = conn.crtcs; + r->clones = conn.clones; + r->count_props = conn.count_props; + r->props = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t)); + r->prop_values = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t)); + r->modes = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo)); + r->count_encoders = conn.count_encoders; + r->encoders = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t)); + r->connector_type = conn.connector_type; + r->connector_type_id = conn.connector_type_id; err_allocs: - drmFree(U642VOID(out.prop_values_ptr)); - drmFree(U642VOID(out.props_ptr)); - drmFree(U642VOID(out.modes_ptr)); - drmFree(U642VOID(out.encoders_ptr)); + drmFree(U642VOID(conn.prop_values_ptr)); + drmFree(U642VOID(conn.props_ptr)); + drmFree(U642VOID(conn.modes_ptr)); + drmFree(U642VOID(conn.encoders_ptr)); return r; } -int drmModeAttachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info) +int drmModeAttachMode(int fd, uint32_t connector_id, struct drm_mode_modeinfo *mode_info) { struct drm_mode_mode_cmd res; memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); - res.output_id = output_id; + res.connector_id = connector_id; return ioctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res); } -int drmModeDetachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info) +int drmModeDetachMode(int fd, uint32_t connector_id, struct drm_mode_modeinfo *mode_info) { struct drm_mode_mode_cmd res; memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); - res.output_id = output_id; + res.connector_id = connector_id; return ioctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res); } @@ -574,13 +574,13 @@ void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) drmFree(ptr); } -int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, +int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, uint64_t value) { - struct drm_mode_output_set_property osp; + struct drm_mode_connector_set_property osp; int ret; - osp.output_id = output_id; + osp.connector_id = connector_id; osp.prop_id = property_id; osp.value = value; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 85e3d912..03268b10 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -60,8 +60,8 @@ typedef struct _drmModeRes { int count_crtcs; uint32_t *crtcs; - int count_outputs; - uint32_t *outputs; + int count_connectors; + uint32_t *connectors; int count_encoders; uint32_t *encoders; @@ -99,11 +99,11 @@ typedef struct _drmModeCrtc { int mode_valid; struct drm_mode_modeinfo mode; - int count_outputs; - uint32_t outputs; /**< Outputs that are connected */ + int count_connectors; + uint32_t connectors; /**< Connectors that are connected */ int count_possibles; - uint32_t possibles; /**< Outputs that can be connected */ + uint32_t possibles; /**< Connectors that can be connected */ int gamma_size; /**< Number of gamma stops */ @@ -131,12 +131,12 @@ typedef enum { DRM_MODE_SUBPIXEL_NONE = 6 } drmModeSubPixel; -typedef struct _drmModeOutput { - unsigned int output_id; +typedef struct _drmModeConnector { + unsigned int connector_id; unsigned int crtc; /**< Crtc currently connected to */ - unsigned int output_type; - unsigned int output_type_id; + unsigned int connector_type; + unsigned int connector_type_id; drmModeConnection connection; uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ drmModeSubPixel subpixel; @@ -156,7 +156,7 @@ typedef struct _drmModeOutput { int count_encoders; uint32_t *encoders; /**< List of encoder ids */ -} drmModeOutput, *drmModeOutputPtr; +} drmModeConnector, *drmModeConnectorPtr; @@ -164,7 +164,7 @@ extern void drmModeFreeModeInfo( struct drm_mode_modeinfo *ptr ); extern void drmModeFreeResources( drmModeResPtr ptr ); extern void drmModeFreeFB( drmModeFBPtr ptr ); extern void drmModeFreeCrtc( drmModeCrtcPtr ptr ); -extern void drmModeFreeOutput( drmModeOutputPtr ptr ); +extern void drmModeFreeConnector( drmModeConnectorPtr ptr ); extern void drmModeFreeEncoder( drmModeEncoderPtr ptr ); /** @@ -217,7 +217,7 @@ extern drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId); * Set the mode on a crtc crtcId with the given mode modeId. */ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, - uint32_t x, uint32_t y, uint32_t *outputs, int count, + uint32_t x, uint32_t y, uint32_t *connectors, int count, struct drm_mode_modeinfo *mode); /* @@ -240,31 +240,31 @@ int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y); drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id); /* - * Output manipulation + * Connector manipulation */ /** - * Retrive information about the output outputId. + * Retrive information about the connector connectorId. */ -extern drmModeOutputPtr drmModeGetOutput(int fd, - uint32_t outputId); +extern drmModeConnectorPtr drmModeGetConnector(int fd, + uint32_t connectorId); /** - * Attaches the given mode to an output. + * Attaches the given mode to an connector. */ -extern int drmModeAttachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo *mode_info); +extern int drmModeAttachMode(int fd, uint32_t connectorId, struct drm_mode_modeinfo *mode_info); /** - * Detaches a mode from the output + * Detaches a mode from the connector * must be unused, by the given mode. */ -extern int drmModeDetachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo *mode_info); +extern int drmModeDetachMode(int fd, uint32_t connectorId, struct drm_mode_modeinfo *mode_info); extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId); extern void drmModeFreeProperty(drmModePropertyPtr ptr); extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id); extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); -extern int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id, +extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, uint64_t value); extern int drmCheckModesettingSupported(const char *busid); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 60ae018e..7c7e201a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -743,7 +743,7 @@ struct drm_driver { struct drm_set_version *sv); /* FB routines, if present */ - int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); + int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); int (*fb_remove)(struct drm_device *dev, struct drm_framebuffer *fb); int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); @@ -1317,9 +1317,9 @@ extern void drm_sysfs_destroy(void); extern int drm_sysfs_device_add(struct drm_minor *minor); extern void drm_sysfs_hotplug_event(struct drm_device *dev); extern void drm_sysfs_device_remove(struct drm_minor *minor); -extern char *drm_get_output_status_name(enum drm_output_status status); -extern int drm_sysfs_output_add(struct drm_output *output); -extern void drm_sysfs_output_remove(struct drm_output *output); +extern char *drm_get_connector_status_name(enum drm_connector_status status); +extern int drm_sysfs_connector_add(struct drm_connector *connector); +extern void drm_sysfs_connector_remove(struct drm_connector *connector); /* * Basic memory manager support (drm_mm.c) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bb527413..c60476a4 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -60,43 +60,43 @@ char *drm_get_dpms_name(int val) return "unknown"; } -static struct drm_prop_enum_list drm_conn_enum_list[] = -{ { ConnectorUnknown, "Unknown" }, - { ConnectorVGA, "VGA" }, - { ConnectorDVII, "DVI-I" }, - { ConnectorDVID, "DVI-D" }, - { ConnectorDVIA, "DVI-A" }, - { ConnectorComposite, "Composite" }, - { ConnectorSVIDEO, "SVIDEO" }, - { ConnectorLVDS, "LVDS" }, - { ConnectorComponent, "Component" }, - { Connector9PinDIN, "9-pin DIN" }, - { ConnectorDisplayPort, "DisplayPort" }, - { ConnectorHDMIA, "HDMI Type A" }, - { ConnectorHDMIB, "HDMI Type B" }, +static struct drm_prop_enum_list drm_connector_enum_list[] = +{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "Composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "Component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, }; -static struct drm_prop_enum_list drm_output_enum_list[] = -{ { DRM_MODE_OUTPUT_NONE, "None" }, - { DRM_MODE_OUTPUT_VGA, "VGA" }, - { DRM_MODE_OUTPUT_TMDS, "TMDS" }, - { DRM_MODE_OUTPUT_LVDS, "LVDS" }, - { DRM_MODE_OUTPUT_TVDAC, "TV" }, +static struct drm_prop_enum_list drm_encoder_enum_list[] = +{ { DRM_MODE_ENCODER_NONE, "None" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TV" }, }; -char *drm_get_output_name(struct drm_output *output) +char *drm_get_connector_name(struct drm_connector *connector) { static char buf[32]; - snprintf(buf, 32, "%s-%d", drm_output_enum_list[output->output_type].name, - output->output_type_id); + snprintf(buf, 32, "%s-%d", drm_connector_enum_list[connector->connector_type].name, + connector->connector_type_id); return buf; } -char *drm_get_output_status_name(enum drm_output_status status) +char *drm_get_connector_status_name(enum drm_connector_status status) { - if (status == output_status_connected) + if (status == connector_status_connected) return "connected"; - else if (status == output_status_disconnected) + else if (status == connector_status_disconnected) return "disconnected"; else return "unknown"; @@ -111,7 +111,7 @@ char *drm_get_output_status_name(enum drm_output_status status) * Caller must hold DRM mode_config lock. * * Create a unique identifier based on @ptr in @dev's identifier space. Used - * for tracking modes, CRTCs and outputs. + * for tracking modes, CRTCs and connectors. * * RETURNS: * New unique (relative to other objects in @dev) integer identifier for the @@ -290,11 +290,11 @@ EXPORT_SYMBOL(drm_crtc_cleanup); */ bool drm_crtc_in_use(struct drm_crtc *crtc) { - struct drm_output *output; + struct drm_connector *connector; struct drm_device *dev = crtc->dev; /* FIXME: Locking around list access? */ - list_for_each_entry(output, &dev->mode_config.output_list, head) - if (output->crtc == crtc) + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + if (connector->crtc == crtc) return true; return false; } @@ -310,7 +310,7 @@ static struct drm_display_mode std_mode[] = { }; /** - * drm_crtc_probe_output_modes - get complete set of display modes + * drm_crtc_probe_connector_modes - get complete set of display modes * @dev: DRM device * @maxX: max width for modes * @maxY: max height for modes @@ -318,8 +318,8 @@ static struct drm_display_mode std_mode[] = { * LOCKING: * Caller must hold mode config lock. * - * Based on @dev's mode_config layout, scan all the outputs and try to detect - * modes on them. Modes will first be added to the output's probed_modes + * Based on @dev's mode_config layout, scan all the connectors and try to detect + * modes on them. Modes will first be added to the connector's probed_modes * list, then culled (based on validity and the @maxX, @maxY parameters) and * put into the normal modes list. * @@ -328,47 +328,47 @@ static struct drm_display_mode std_mode[] = { * * FIXME: take into account monitor limits */ -void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int maxY) +void drm_crtc_probe_single_connector_modes(struct drm_connector *connector, int maxX, int maxY) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_display_mode *mode, *t; int ret; //if (maxX == 0 || maxY == 0) // TODO /* set all modes to the unverified state */ - list_for_each_entry_safe(mode, t, &output->modes, head) + list_for_each_entry_safe(mode, t, &connector->modes, head) mode->status = MODE_UNVERIFIED; - output->status = (*output->funcs->detect)(output); + connector->status = (*connector->funcs->detect)(connector); - if (output->status == output_status_disconnected) { - DRM_DEBUG("%s is disconnected\n", drm_get_output_name(output)); + if (connector->status == connector_status_disconnected) { + DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(connector)); /* TODO set EDID to NULL */ return; } - ret = (*output->funcs->get_modes)(output); + ret = (*connector->funcs->get_modes)(connector); if (ret) { - drm_mode_output_list_update(output); + drm_mode_connector_list_update(connector); } if (maxX && maxY) - drm_mode_validate_size(dev, &output->modes, maxX, + drm_mode_validate_size(dev, &connector->modes, maxX, maxY, 0); - list_for_each_entry_safe(mode, t, &output->modes, head) { + list_for_each_entry_safe(mode, t, &connector->modes, head) { if (mode->status == MODE_OK) - mode->status = (*output->funcs->mode_valid)(output,mode); + mode->status = (*connector->funcs->mode_valid)(connector,mode); } - drm_mode_prune_invalid(dev, &output->modes, TRUE); + drm_mode_prune_invalid(dev, &connector->modes, TRUE); - if (list_empty(&output->modes)) { + if (list_empty(&connector->modes)) { struct drm_display_mode *stdmode; - DRM_DEBUG("No valid modes on %s\n", drm_get_output_name(output)); + DRM_DEBUG("No valid modes on %s\n", drm_get_connector_name(connector)); /* Should we do this here ??? * When no valid EDID modes are available we end up @@ -376,18 +376,18 @@ void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int * 640x480@60Hz mode and carry on. */ stdmode = drm_mode_duplicate(dev, &std_mode[0]); - drm_mode_probed_add(output, stdmode); - drm_mode_list_concat(&output->probed_modes, - &output->modes); + drm_mode_probed_add(connector, stdmode); + drm_mode_list_concat(&connector->probed_modes, + &connector->modes); DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", - drm_get_output_name(output)); + drm_get_connector_name(connector)); } - drm_mode_sort(&output->modes); + drm_mode_sort(&connector->modes); - DRM_DEBUG("Probed modes for %s\n", drm_get_output_name(output)); - list_for_each_entry_safe(mode, t, &output->modes, head) { + DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector)); + list_for_each_entry_safe(mode, t, &connector->modes, head) { mode->vrefresh = drm_mode_vrefresh(mode); drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); @@ -395,15 +395,15 @@ void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int } } -void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) +void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY) { - struct drm_output *output; + struct drm_connector *connector; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - drm_crtc_probe_single_output_modes(output, maxX, maxY); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_crtc_probe_single_connector_modes(connector, maxX, maxY); } } -EXPORT_SYMBOL(drm_crtc_probe_output_modes); +EXPORT_SYMBOL(drm_crtc_probe_connector_modes); /** @@ -413,17 +413,17 @@ EXPORT_SYMBOL(drm_crtc_probe_output_modes); * LOCKING: * Caller must hold mode config lock. * - * If an output or CRTC isn't part of @dev's mode_config, it can be disabled + * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled * by calling its dpms function, which should power it off. */ void drm_disable_unused_functions(struct drm_device *dev) { - struct drm_output *output; + struct drm_connector *connector; struct drm_crtc *crtc; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (!output->crtc) - (*output->funcs->dpms)(output, DPMSModeOff); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (!connector->crtc) + (*connector->funcs->dpms)(connector, DPMSModeOff); } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -434,33 +434,33 @@ void drm_disable_unused_functions(struct drm_device *dev) EXPORT_SYMBOL(drm_disable_unused_functions); /** - * drm_mode_probed_add - add a mode to the specified output's probed mode list - * @output: output the new mode + * drm_mode_probed_add - add a mode to the specified connector's probed mode list + * @connector: connector the new mode * @mode: mode data * * LOCKING: * Caller must hold mode config lock. * - * Add @mode to @output's mode list for later use. + * Add @mode to @connector's mode list for later use. */ -void drm_mode_probed_add(struct drm_output *output, +void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode) { - list_add(&mode->head, &output->probed_modes); + list_add(&mode->head, &connector->probed_modes); } EXPORT_SYMBOL(drm_mode_probed_add); /** * drm_mode_remove - remove and free a mode - * @output: output list to modify + * @connector: connector list to modify * @mode: mode to remove * * LOCKING: * Caller must hold mode config lock. * - * Remove @mode from @output's mode list, then free it. + * Remove @mode from @connector's mode list, then free it. */ -void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) +void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode) { list_del(&mode->head); kfree(mode); @@ -468,76 +468,76 @@ void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) EXPORT_SYMBOL(drm_mode_remove); /** - * drm_output_init - Init a preallocated output + * drm_connector_init - Init a preallocated connector * @dev: DRM device - * @output: the output to init - * @funcs: callbacks for this output - * @name: user visible name of the output + * @connector: the connector to init + * @funcs: callbacks for this connector + * @name: user visible name of the connector * * LOCKING: * Caller must hold @dev's mode_config lock. * - * Initialises a preallocated output. Outputs should be - * subclassed as part of driver output objects. + * Initialises a preallocated connector. Connectors should be + * subclassed as part of driver connector objects. */ -void drm_output_init(struct drm_device *dev, - struct drm_output *output, - const struct drm_output_funcs *funcs, - int output_type) +void drm_connector_init(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type) { - output->dev = dev; - output->funcs = funcs; - output->id = drm_idr_get(dev, output); - output->output_type = output_type; - output->output_type_id = 1; /* TODO */ - INIT_LIST_HEAD(&output->user_modes); - INIT_LIST_HEAD(&output->probed_modes); - INIT_LIST_HEAD(&output->modes); - /* randr_output? */ - /* output_set_monitor(output)? */ - /* check for output_ignored(output)? */ + connector->dev = dev; + connector->funcs = funcs; + connector->id = drm_idr_get(dev, connector); + connector->connector_type = connector_type; + connector->connector_type_id = 1; /* TODO */ + INIT_LIST_HEAD(&connector->user_modes); + INIT_LIST_HEAD(&connector->probed_modes); + INIT_LIST_HEAD(&connector->modes); + /* randr_connector? */ + /* connector_set_monitor(connector)? */ + /* check for connector_ignored(connector)? */ mutex_lock(&dev->mode_config.mutex); - list_add_tail(&output->head, &dev->mode_config.output_list); - dev->mode_config.num_output++; + list_add_tail(&connector->head, &dev->mode_config.connector_list); + dev->mode_config.num_connector++; - drm_output_attach_property(output, dev->mode_config.edid_property, 0); + drm_connector_attach_property(connector, dev->mode_config.edid_property, 0); - drm_output_attach_property(output, dev->mode_config.dpms_property, 0); + drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); mutex_unlock(&dev->mode_config.mutex); } -EXPORT_SYMBOL(drm_output_init); +EXPORT_SYMBOL(drm_connector_init); /** - * drm_output_cleanup - cleans up an initialised output - * @output: output to cleanup + * drm_connector_cleanup - cleans up an initialised connector + * @connector: connector to cleanup * * LOCKING: * Caller must hold @dev's mode_config lock. * - * Cleans up the output but doesn't free the object. + * Cleans up the connector but doesn't free the object. */ -void drm_output_cleanup(struct drm_output *output) +void drm_connector_cleanup(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_display_mode *mode, *t; - list_for_each_entry_safe(mode, t, &output->probed_modes, head) - drm_mode_remove(output, mode); + list_for_each_entry_safe(mode, t, &connector->probed_modes, head) + drm_mode_remove(connector, mode); - list_for_each_entry_safe(mode, t, &output->modes, head) - drm_mode_remove(output, mode); + list_for_each_entry_safe(mode, t, &connector->modes, head) + drm_mode_remove(connector, mode); - list_for_each_entry_safe(mode, t, &output->user_modes, head) - drm_mode_remove(output, mode); + list_for_each_entry_safe(mode, t, &connector->user_modes, head) + drm_mode_remove(connector, mode); mutex_lock(&dev->mode_config.mutex); - drm_idr_put(dev, output->id); - list_del(&output->head); + drm_idr_put(dev, connector->id); + list_del(&connector->head); mutex_unlock(&dev->mode_config.mutex); } -EXPORT_SYMBOL(drm_output_cleanup); +EXPORT_SYMBOL(drm_connector_cleanup); void drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, @@ -610,12 +610,12 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_destroy); -static int drm_mode_create_standard_output_properties(struct drm_device *dev) +static int drm_mode_create_standard_connector_properties(struct drm_device *dev) { int i; /* - * Standard properties (apply to all outputs) + * Standard properties (apply to all connectors) */ dev->mode_config.edid_property = drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, @@ -627,29 +627,17 @@ static int drm_mode_create_standard_output_properties(struct drm_device *dev) for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++) drm_property_add_enum(dev->mode_config.dpms_property, i, drm_dpms_enum_list[i].type, drm_dpms_enum_list[i].name); - dev->mode_config.connector_type_property = - drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, - "Connector Type", ARRAY_SIZE(drm_conn_enum_list)); - for (i = 0; i < ARRAY_SIZE(drm_conn_enum_list); i++) - drm_property_add_enum(dev->mode_config.connector_type_property, i, drm_conn_enum_list[i].type, drm_conn_enum_list[i].name); - - dev->mode_config.connector_num_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, - "Connector ID", 2); - dev->mode_config.connector_num_property->values[0] = 0; - dev->mode_config.connector_num_property->values[1] = 20; - return 0; } /** - * drm_create_tv_properties - create TV specific output properties + * drm_create_tv_properties - create TV specific connector properties * @dev: DRM device * @num_modes: number of different TV formats (modes) supported * @modes: array of pointers to strings containing name of each format * * Called by a driver's TV initialization routine, this function creates - * the TV specific output properties for a given device. Caller is + * the TV specific connector properties for a given device. Caller is * responsible for allocating a list of format names and passing them to * this routine. */ @@ -709,17 +697,17 @@ void drm_mode_config_init(struct drm_device *dev) mutex_init(&dev->mode_config.mutex); INIT_LIST_HEAD(&dev->mode_config.fb_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); - INIT_LIST_HEAD(&dev->mode_config.output_list); + INIT_LIST_HEAD(&dev->mode_config.connector_list); INIT_LIST_HEAD(&dev->mode_config.encoder_list); INIT_LIST_HEAD(&dev->mode_config.property_list); INIT_LIST_HEAD(&dev->mode_config.property_blob_list); idr_init(&dev->mode_config.crtc_idr); - drm_mode_create_standard_output_properties(dev); + drm_mode_create_standard_connector_properties(dev); /* Just to be sure */ dev->mode_config.num_fb = 0; - dev->mode_config.num_output = 0; + dev->mode_config.num_connector = 0; dev->mode_config.num_crtc = 0; dev->mode_config.num_encoder = 0; dev->mode_config.hotplug_counter = 0; @@ -780,14 +768,14 @@ out_err: * LOCKING: * Caller must hold mode config lock. * - * Free up all the outputs and CRTCs associated with this DRM device, then + * Free up all the connectors and CRTCs associated with this DRM device, then * free up the framebuffers and associated buffer objects. * * FIXME: cleanup any dangling user buffer objects too */ void drm_mode_config_cleanup(struct drm_device *dev) { - struct drm_output *output, *ot; + struct drm_connector *connector, *ot; struct drm_crtc *crtc, *ct; struct drm_encoder *encoder, *enct; struct drm_framebuffer *fb, *fbt; @@ -797,9 +785,9 @@ void drm_mode_config_cleanup(struct drm_device *dev) encoder->funcs->destroy(encoder); } - list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) { - drm_sysfs_output_remove(output); - output->funcs->destroy(output); + list_for_each_entry_safe(connector, ot, &dev->mode_config.connector_list, head) { + drm_sysfs_connector_remove(connector); + connector->funcs->destroy(connector); } list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, head) { @@ -906,7 +894,7 @@ void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modein * Takes mode config lock. * * Construct a set of configuration description structures and return - * them to the user, including CRTC, output and framebuffer configuration. + * them to the user, including CRTC, connector and framebuffer configuration. * * Called by the user via ioctl. * @@ -919,18 +907,18 @@ int drm_mode_getresources(struct drm_device *dev, struct drm_mode_card_res *card_res = data; struct list_head *lh; struct drm_framebuffer *fb; - struct drm_output *output; + struct drm_connector *connector; struct drm_crtc *crtc; struct drm_encoder *encoder; int ret = 0; - int output_count = 0; + int connector_count = 0; int crtc_count = 0; int fb_count = 0; int encoder_count = 0; int copied = 0; uint32_t __user *fb_id; uint32_t __user *crtc_id; - uint32_t __user *output_id; + uint32_t __user *connector_id; uint32_t __user *encoder_id; mutex_lock(&dev->mode_config.mutex); @@ -941,8 +929,8 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; - list_for_each(lh, &dev->mode_config.output_list) - output_count++; + list_for_each(lh, &dev->mode_config.connector_list) + connector_count++; list_for_each(lh, &dev->mode_config.encoder_list) encoder_count++; @@ -983,21 +971,21 @@ int drm_mode_getresources(struct drm_device *dev, card_res->count_crtcs = crtc_count; - /* Outputs */ - if (card_res->count_outputs >= output_count) { + /* Connectors */ + if (card_res->count_connectors >= connector_count) { copied = 0; - output_id = (uint32_t *)(unsigned long)card_res->output_id_ptr; - list_for_each_entry(output, &dev->mode_config.output_list, + connector_id = (uint32_t *)(unsigned long)card_res->connector_id_ptr; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - DRM_DEBUG("OUTPUT ID is %d\n", output->id); - if (put_user(output->id, output_id + copied)) { + DRM_DEBUG("CONNECTOR ID is %d\n", connector->id); + if (put_user(connector->id, connector_id + copied)) { ret = -EFAULT; goto out; } copied++; } } - card_res->count_outputs = output_count; + card_res->count_connectors = connector_count; /* Encoders */ if (card_res->count_encoders >= encoder_count) { @@ -1016,7 +1004,7 @@ int drm_mode_getresources(struct drm_device *dev, card_res->count_encoders = encoder_count; DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs, - card_res->count_outputs, card_res->count_encoders); + card_res->count_connectors, card_res->count_encoders); out: mutex_unlock(&dev->mode_config.mutex); @@ -1045,7 +1033,7 @@ int drm_mode_getcrtc(struct drm_device *dev, { struct drm_mode_crtc *crtc_resp = data; struct drm_crtc *crtc; - struct drm_output *output; + struct drm_connector *connector; int ocount; int ret = 0; @@ -1064,15 +1052,15 @@ int drm_mode_getcrtc(struct drm_device *dev, else crtc_resp->fb_id = 0; - crtc_resp->outputs = 0; + crtc_resp->connectors = 0; if (crtc->enabled) { drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); crtc_resp->mode_valid = 1; ocount = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == crtc) - crtc_resp->outputs |= 1 << (ocount++); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->crtc == crtc) + crtc_resp->connectors |= 1 << (ocount++); } } else { @@ -1085,7 +1073,7 @@ out: } /** - * drm_mode_getoutput - get output configuration + * drm_mode_getconnector - get connector configuration * @inode: inode from the ioctl * @filp: file * from the ioctl * @cmd: cmd from ioctl @@ -1094,18 +1082,18 @@ out: * LOCKING: * Caller? (FIXME) * - * Construct a output configuration structure to return to the user. + * Construct a connector configuration structure to return to the user. * * Called by the user via ioctl. * * RETURNS: * Zero on success, errno on failure. */ -int drm_mode_getoutput(struct drm_device *dev, +int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_get_output *out_resp = data; - struct drm_output *output; + struct drm_mode_get_connector *out_resp = data; + struct drm_connector *connector; struct drm_display_mode *mode; int mode_count = 0; int props_count = 0; @@ -1121,52 +1109,52 @@ int drm_mode_getoutput(struct drm_device *dev, memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); - DRM_DEBUG("output id %d:\n", out_resp->output); + DRM_DEBUG("connector id %d:\n", out_resp->connector); mutex_lock(&dev->mode_config.mutex); - output= idr_find(&dev->mode_config.crtc_idr, out_resp->output); - if (!output || (output->id != out_resp->output)) { + connector= idr_find(&dev->mode_config.crtc_idr, out_resp->connector); + if (!connector || (connector->id != out_resp->connector)) { ret = -EINVAL; goto out; } - list_for_each_entry(mode, &output->modes, head) + list_for_each_entry(mode, &connector->modes, head) mode_count++; - for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { - if (output->property_ids[i] != 0) { + for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { + if (connector->property_ids[i] != 0) { props_count++; } } - for (i = 0; i < DRM_OUTPUT_MAX_ENCODER; i++) { - if (output->encoder_ids[i] != 0) { + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] != 0) { encoders_count++; } } if (out_resp->count_modes == 0) { - drm_crtc_probe_single_output_modes(output, dev->mode_config.max_width, dev->mode_config.max_height); + drm_crtc_probe_single_connector_modes(connector, dev->mode_config.max_width, dev->mode_config.max_height); } - out_resp->output_type = output->output_type; - out_resp->output_type_id = output->output_type_id; - out_resp->mm_width = output->display_info.width_mm; - out_resp->mm_height = output->display_info.height_mm; - out_resp->subpixel = output->display_info.subpixel_order; - out_resp->connection = output->status; - if (output->crtc) - out_resp->crtc = output->crtc->id; + out_resp->connector_type = connector->connector_type; + out_resp->connector_type_id = connector->connector_type_id; + out_resp->mm_width = connector->display_info.width_mm; + out_resp->mm_height = connector->display_info.height_mm; + out_resp->subpixel = connector->display_info.subpixel_order; + out_resp->connection = connector->status; + if (connector->crtc) + out_resp->crtc = connector->crtc->id; else out_resp->crtc = 0; - out_resp->crtcs = output->possible_crtcs; - out_resp->clones = output->possible_clones; + out_resp->crtcs = connector->possible_crtcs; + out_resp->clones = connector->possible_clones; if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr; - list_for_each_entry(mode, &output->modes, head) { + list_for_each_entry(mode, &connector->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); if (copy_to_user(mode_ptr + copied, &u_mode, sizeof(u_mode))) { @@ -1183,14 +1171,14 @@ int drm_mode_getoutput(struct drm_device *dev, copied = 0; prop_ptr = (uint32_t *)(unsigned long)(out_resp->props_ptr); prop_values = (uint64_t *)(unsigned long)(out_resp->prop_values_ptr); - for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { - if (output->property_ids[i] != 0) { - if (put_user(output->property_ids[i], prop_ptr + copied)) { + for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { + if (connector->property_ids[i] != 0) { + if (put_user(connector->property_ids[i], prop_ptr + copied)) { ret = -EFAULT; goto out; } - if (put_user(output->property_values[i], prop_values + copied)) { + if (put_user(connector->property_values[i], prop_values + copied)) { ret = -EFAULT; goto out; } @@ -1203,9 +1191,9 @@ int drm_mode_getoutput(struct drm_device *dev, if ((out_resp->count_encoders >= encoders_count) && encoders_count) { copied = 0; encoder_ptr = (uint32_t *)(unsigned long)(out_resp->encoders_ptr); - for (i = 0; i < DRM_OUTPUT_MAX_ENCODER; i++) { - if (output->encoder_ids[i] != 0) { - if (put_user(output->encoder_ids[i], encoder_ptr + copied)) { + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] != 0) { + if (put_user(connector->encoder_ids[i], encoder_ptr + copied)) { ret = -EFAULT; goto out; } @@ -1267,11 +1255,11 @@ int drm_mode_setcrtc(struct drm_device *dev, { struct drm_mode_crtc *crtc_req = data; struct drm_crtc *crtc, *crtcfb; - struct drm_output **output_set = NULL, *output; + struct drm_connector **connector_set = NULL, *connector; struct drm_framebuffer *fb = NULL; struct drm_display_mode *mode = NULL; struct drm_mode_set set; - uint32_t __user *set_outputs_ptr; + uint32_t __user *set_connectors_ptr; int ret = 0; int i; @@ -1307,43 +1295,43 @@ int drm_mode_setcrtc(struct drm_device *dev, drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); } - if (crtc_req->count_outputs == 0 && mode) { - DRM_DEBUG("Count outputs is 0 but mode set\n"); + if (crtc_req->count_connectors == 0 && mode) { + DRM_DEBUG("Count connectors is 0 but mode set\n"); ret = -EINVAL; goto out; } - if (crtc_req->count_outputs > 0 && !mode && !fb) { - DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req->count_outputs); + if (crtc_req->count_connectors > 0 && !mode && !fb) { + DRM_DEBUG("Count connectors is %d but no mode or fb set\n", crtc_req->count_connectors); ret = -EINVAL; goto out; } - if (crtc_req->count_outputs > 0) { + if (crtc_req->count_connectors > 0) { u32 out_id; - /* Maybe we should check that count_outputs is a sensible value. */ - output_set = kmalloc(crtc_req->count_outputs * - sizeof(struct drm_output *), GFP_KERNEL); - if (!output_set) { + /* Maybe we should check that count_connectors is a sensible value. */ + connector_set = kmalloc(crtc_req->count_connectors * + sizeof(struct drm_connector *), GFP_KERNEL); + if (!connector_set) { ret = -ENOMEM; goto out; } - for (i = 0; i < crtc_req->count_outputs; i++) { - set_outputs_ptr = (uint32_t *)(unsigned long)crtc_req->set_outputs_ptr; - if (get_user(out_id, &set_outputs_ptr[i])) { + for (i = 0; i < crtc_req->count_connectors; i++) { + set_connectors_ptr = (uint32_t *)(unsigned long)crtc_req->set_connectors_ptr; + if (get_user(out_id, &set_connectors_ptr[i])) { ret = -EFAULT; goto out; } - output = idr_find(&dev->mode_config.crtc_idr, out_id); - if (!output || (out_id != output->id)) { - DRM_DEBUG("Output id %d unknown\n", out_id); + connector = idr_find(&dev->mode_config.crtc_idr, out_id); + if (!connector || (out_id != connector->id)) { + DRM_DEBUG("Connector id %d unknown\n", out_id); ret = -EINVAL; goto out; } - output_set[i] = output; + connector_set[i] = connector; } } @@ -1351,13 +1339,13 @@ int drm_mode_setcrtc(struct drm_device *dev, set.x = crtc_req->x; set.y = crtc_req->y; set.mode = mode; - set.outputs = output_set; - set.num_outputs = crtc_req->count_outputs; + set.connectors = connector_set; + set.num_connectors = crtc_req->count_connectors; set.fb =fb; ret = crtc->funcs->set_config(&set); out: - kfree(output_set); + kfree(connector_set); mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -1628,29 +1616,29 @@ void drm_fb_release(struct file *filp) */ static int drm_mode_attachmode(struct drm_device *dev, - struct drm_output *output, + struct drm_connector *connector, struct drm_display_mode *mode) { int ret = 0; - list_add_tail(&mode->head, &output->user_modes); + list_add_tail(&mode->head, &connector->user_modes); return ret; } int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, struct drm_display_mode *mode) { - struct drm_output *output; + struct drm_connector *connector; int ret = 0; struct drm_display_mode *dup_mode; int need_dup = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == crtc) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->crtc == crtc) { if (need_dup) dup_mode = drm_mode_duplicate(dev, mode); else dup_mode = mode; - ret = drm_mode_attachmode(dev, output, dup_mode); + ret = drm_mode_attachmode(dev, connector, dup_mode); if (ret) return ret; need_dup = 1; @@ -1661,14 +1649,14 @@ int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, EXPORT_SYMBOL(drm_mode_attachmode_crtc); static int drm_mode_detachmode(struct drm_device *dev, - struct drm_output *output, + struct drm_connector *connector, struct drm_display_mode *mode) { int found = 0; int ret = 0; struct drm_display_mode *match_mode, *t; - list_for_each_entry_safe(match_mode, t, &output->user_modes, head) { + list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) { if (drm_mode_equal(match_mode, mode)) { list_del(&match_mode->head); drm_mode_destroy(dev, match_mode); @@ -1685,23 +1673,23 @@ static int drm_mode_detachmode(struct drm_device *dev, int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) { - struct drm_output *output; + struct drm_connector *connector; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - drm_mode_detachmode(dev, output, mode); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_mode_detachmode(dev, connector, mode); } return 0; } EXPORT_SYMBOL(drm_mode_detachmode_crtc); /** - * drm_fb_attachmode - Attach a user mode to an output + * drm_fb_attachmode - Attach a user mode to an connector * @inode: inode from the ioctl * @filp: file * from the ioctl * @cmd: cmd from ioctl * @arg: arg from ioctl * - * This attaches a user specified mode to an output. + * This attaches a user specified mode to an connector. * Called by the user via ioctl. * * RETURNS: @@ -1711,15 +1699,15 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_mode_cmd *mode_cmd = data; - struct drm_output *output; + struct drm_connector *connector; struct drm_display_mode *mode; struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; mutex_lock(&dev->mode_config.mutex); - output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); - if (!output || (output->id != mode_cmd->output_id)) { + connector = idr_find(&dev->mode_config.crtc_idr, mode_cmd->connector_id); + if (!connector || (connector->id != mode_cmd->connector_id)) { ret = -EINVAL; goto out; } @@ -1732,7 +1720,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, drm_crtc_convert_umode(mode, umode); - ret = drm_mode_attachmode(dev, output, mode); + ret = drm_mode_attachmode(dev, connector, mode); out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1740,7 +1728,7 @@ out: /** - * drm_fb_detachmode - Detach a user specified mode from an output + * drm_fb_detachmode - Detach a user specified mode from an connector * @inode: inode from the ioctl * @filp: file * from the ioctl * @cmd: cmd from ioctl @@ -1755,21 +1743,21 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_mode_cmd *mode_cmd = data; - struct drm_output *output; + struct drm_connector *connector; struct drm_display_mode mode; struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; mutex_lock(&dev->mode_config.mutex); - output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id); - if (!output || (output->id != mode_cmd->output_id)) { + connector = idr_find(&dev->mode_config.crtc_idr, mode_cmd->connector_id); + if (!connector || (connector->id != mode_cmd->connector_id)) { ret = -EINVAL; goto out; } drm_crtc_convert_umode(&mode, umode); - ret = drm_mode_detachmode(dev, output, &mode); + ret = drm_mode_detachmode(dev, connector, &mode); out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1855,60 +1843,60 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) } EXPORT_SYMBOL(drm_property_destroy); -int drm_output_attach_property(struct drm_output *output, +int drm_connector_attach_property(struct drm_connector *connector, struct drm_property *property, uint64_t init_val) { int i; - for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { - if (output->property_ids[i] == 0) { - output->property_ids[i] = property->id; - output->property_values[i] = init_val; + for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { + if (connector->property_ids[i] == 0) { + connector->property_ids[i] = property->id; + connector->property_values[i] = init_val; break; } } - if (i == DRM_OUTPUT_MAX_PROPERTY) + if (i == DRM_CONNECTOR_MAX_PROPERTY) return -EINVAL; return 0; } -EXPORT_SYMBOL(drm_output_attach_property); +EXPORT_SYMBOL(drm_connector_attach_property); -int drm_output_property_set_value(struct drm_output *output, +int drm_connector_property_set_value(struct drm_connector *connector, struct drm_property *property, uint64_t value) { int i; - for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { - if (output->property_ids[i] == property->id) { - output->property_values[i] = value; + for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { + if (connector->property_ids[i] == property->id) { + connector->property_values[i] = value; break; } } - if (i == DRM_OUTPUT_MAX_PROPERTY) + if (i == DRM_CONNECTOR_MAX_PROPERTY) return -EINVAL; return 0; } -EXPORT_SYMBOL(drm_output_property_set_value); +EXPORT_SYMBOL(drm_connector_property_set_value); -int drm_output_property_get_value(struct drm_output *output, +int drm_connector_property_get_value(struct drm_connector *connector, struct drm_property *property, uint64_t *val) { int i; - for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { - if (output->property_ids[i] == property->id) { - *val = output->property_values[i]; + for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { + if (connector->property_ids[i] == property->id) { + *val = connector->property_values[i]; break; } } - if (i == DRM_OUTPUT_MAX_PROPERTY) + if (i == DRM_CONNECTOR_MAX_PROPERTY) return -EINVAL; return 0; } -EXPORT_SYMBOL(drm_output_property_get_value); +EXPORT_SYMBOL(drm_connector_property_get_value); int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -2070,41 +2058,41 @@ done: return ret; } -int drm_mode_output_update_edid_property(struct drm_output *output, struct edid *edid) +int drm_mode_connector_update_edid_property(struct drm_connector *connector, struct edid *edid) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; int ret = 0; - if (output->edid_blob_ptr) - drm_property_destroy_blob(dev, output->edid_blob_ptr); + if (connector->edid_blob_ptr) + drm_property_destroy_blob(dev, connector->edid_blob_ptr); - output->edid_blob_ptr = drm_property_create_blob(output->dev, 128, edid); + connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); - ret = drm_output_property_set_value(output, dev->mode_config.edid_property, output->edid_blob_ptr->id); + ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, connector->edid_blob_ptr->id); return ret; } -EXPORT_SYMBOL(drm_mode_output_update_edid_property); +EXPORT_SYMBOL(drm_mode_connector_update_edid_property); -int drm_mode_output_property_set_ioctl(struct drm_device *dev, +int drm_mode_connector_property_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_mode_output_set_property *out_resp = data; + struct drm_mode_connector_set_property *out_resp = data; struct drm_property *property; - struct drm_output *output; + struct drm_connector *connector; int ret = -EINVAL; int i; mutex_lock(&dev->mode_config.mutex); - output = idr_find(&dev->mode_config.crtc_idr, out_resp->output_id); - if (!output || (output->id != out_resp->output_id)) { + connector = idr_find(&dev->mode_config.crtc_idr, out_resp->connector_id); + if (!connector || (connector->id != out_resp->connector_id)) { goto out; } - for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) { - if (output->property_ids[i] == out_resp->prop_id) + for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { + if (connector->property_ids[i] == out_resp->prop_id) break; } - if (i == DRM_OUTPUT_MAX_PROPERTY) { + if (i == DRM_CONNECTOR_MAX_PROPERTY) { goto out; } @@ -2135,8 +2123,8 @@ int drm_mode_output_property_set_ioctl(struct drm_device *dev, } } - if (output->funcs->set_property) - ret = output->funcs->set_property(output, property, out_resp->value); + if (connector->funcs->set_property) + ret = connector->funcs->set_property(connector, property, out_resp->value); out: mutex_unlock(&dev->mode_config.mutex); @@ -2205,30 +2193,30 @@ out: } -int drm_mode_output_attach_encoder(struct drm_output *output, +int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder) { int i; - for (i = 0; i < DRM_OUTPUT_MAX_ENCODER; i++) { - if (output->encoder_ids[i] == 0) { - output->encoder_ids[i] = encoder->id; + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) { + connector->encoder_ids[i] = encoder->id; return 0; } } return -ENOMEM; } -EXPORT_SYMBOL(drm_mode_output_attach_encoder); +EXPORT_SYMBOL(drm_mode_connector_attach_encoder); -void drm_mode_output_detach_encoder(struct drm_output *output, +void drm_mode_connector_detach_encoder(struct drm_connector *connector, struct drm_encoder *encoder) { int i; - for (i = 0; i < DRM_OUTPUT_MAX_ENCODER; i++) { - if (output->encoder_ids[i] == encoder->id) { - output->encoder_ids[i] = 0; + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == encoder->id) { + connector->encoder_ids[i] = 0; break; } } } -EXPORT_SYMBOL(drm_mode_output_detach_encoder); +EXPORT_SYMBOL(drm_mode_connector_detach_encoder); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 03c336e2..568b6b31 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -17,10 +17,10 @@ struct drm_device; struct drm_mode_set; /* - * Note on terminology: here, for brevity and convenience, we refer to output - * control chips as 'CRTCs'. They can control any type of output, VGA, LVDS, + * Note on terminology: here, for brevity and convenience, we refer to connector + * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, * DVI, etc. And 'screen' refers to the whole of the visible display, which - * may span multiple monitors (and therefore multiple CRTC and output + * may span multiple monitors (and therefore multiple CRTC and connector * structures). */ @@ -80,7 +80,7 @@ struct drm_display_mode { struct list_head head; char name[DRM_DISPLAY_MODE_LEN]; int mode_id; - int output_count; + int connector_count; enum drm_mode_status status; int type; @@ -149,24 +149,24 @@ struct drm_display_mode { #define DPMSModeSuspend 2 #define DPMSModeOff 3 -#define ConnectorUnknown 0 -#define ConnectorVGA 1 -#define ConnectorDVII 2 -#define ConnectorDVID 3 -#define ConnectorDVIA 4 -#define ConnectorComposite 5 -#define ConnectorSVIDEO 6 -#define ConnectorLVDS 7 -#define ConnectorComponent 8 -#define Connector9PinDIN 9 -#define ConnectorDisplayPort 10 -#define ConnectorHDMIA 11 -#define ConnectorHDMIB 12 - -enum drm_output_status { - output_status_connected = 1, - output_status_disconnected = 2, - output_status_unknown = 3, +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 + +enum drm_connector_status { + connector_status_connected = 1, + connector_status_disconnected = 2, + connector_status_unknown = 3, }; enum subpixel_order { @@ -276,7 +276,7 @@ struct drm_property { }; struct drm_crtc; -struct drm_output; +struct drm_connector; struct drm_encoder; /** @@ -295,9 +295,9 @@ struct drm_encoder; * @destroy: deinit and free object. * * The drm_crtc_funcs structure is the central CRTC management structure - * in the DRM. Each CRTC controls one or more outputs (note that the name + * in the DRM. Each CRTC controls one or more connectors (note that the name * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc. - * outputs, not just CRTs). + * connectors, not just CRTs). * * Each driver is responsible for filling out this structure at startup time, * in addition to providing other modesetting features, like i2c and DDC @@ -339,7 +339,7 @@ struct drm_crtc_funcs { * @desired_y: desired y for desired_mode * @funcs: CRTC control functions * - * Each CRTC may have one or more outputs associated with it. This structure + * Each CRTC may have one or more connectors associated with it. This structure * allows the CRTC to be controlled. */ struct drm_crtc { @@ -348,7 +348,7 @@ struct drm_crtc { int id; /* idr assigned */ - /* framebuffer the output is currently bound to */ + /* framebuffer the connector is currently bound to */ struct drm_framebuffer *fb; bool enabled; @@ -365,32 +365,32 @@ struct drm_crtc { }; /** - * drm_output_funcs - control outputs on a given device + * drm_connector_funcs - control connectors on a given device * @dpms: set power state (see drm_crtc_funcs above) - * @save: save output state - * @restore: restore output state - * @mode_valid: is this mode valid on the given output? - * @mode_fixup: try to fixup proposed mode for this output + * @save: save connector state + * @restore: restore connector state + * @mode_valid: is this mode valid on the given connector? + * @mode_fixup: try to fixup proposed mode for this connector * @mode_set: set this mode - * @detect: is this output active? - * @get_modes: get mode list for this output - * @set_property: property for this output may need update + * @detect: is this connector active? + * @get_modes: get mode list for this connector + * @set_property: property for this connector may need update * @destroy: make object go away * - * Each CRTC may have one or more outputs attached to it. The functions - * below allow the core DRM code to control outputs, enumerate available modes, + * Each CRTC may have one or more connectors attached to it. The functions + * below allow the core DRM code to control connectors, enumerate available modes, * etc. */ -struct drm_output_funcs { - void (*dpms)(struct drm_output *output, int mode); - void (*save)(struct drm_output *output); - void (*restore)(struct drm_output *output); - enum drm_output_status (*detect)(struct drm_output *output); - int (*get_modes)(struct drm_output *output); - bool (*set_property)(struct drm_output *output, struct drm_property *property, +struct drm_connector_funcs { + void (*dpms)(struct drm_connector *connector, int mode); + void (*save)(struct drm_connector *connector); + void (*restore)(struct drm_connector *connector); + enum drm_connector_status (*detect)(struct drm_connector *connector); + int (*get_modes)(struct drm_connector *connector); + bool (*set_property)(struct drm_connector *connector, struct drm_property *property, uint64_t val); - void (*destroy)(struct drm_output *output); - int (*mode_valid)(struct drm_output *output, + void (*destroy)(struct drm_connector *connector); + int (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); }; @@ -399,10 +399,10 @@ struct drm_encoder_funcs { void (*destroy)(struct drm_encoder *encoder); }; -#define DRM_OUTPUT_MAX_UMODES 16 -#define DRM_OUTPUT_MAX_PROPERTY 16 -#define DRM_OUTPUT_LEN 32 -#define DRM_OUTPUT_MAX_ENCODER 2 +#define DRM_CONNECTOR_MAX_UMODES 16 +#define DRM_CONNECTOR_MAX_PROPERTY 16 +#define DRM_CONNECTOR_LEN 32 +#define DRM_CONNECTOR_MAX_ENCODER 2 /** * drm_encoder - central DRM encoder structure @@ -421,24 +421,24 @@ struct drm_encoder { }; /** - * drm_output - central DRM output control structure - * @crtc: CRTC this output is currently connected to, NULL if none - * @possible_crtcs: bitmap of CRTCS this output could be attached to - * @possible_clones: bitmap of possible outputs this output could clone - * @interlace_allowed: can this output handle interlaced modes? - * @doublescan_allowed: can this output handle doublescan? - * @available_modes: modes available on this output (from get_modes() + user) - * @initial_x: initial x position for this output - * @initial_y: initial y position for this output - * @status: output connected? - * @funcs: output control functions + * drm_connector - central DRM connector control structure + * @crtc: CRTC this connector is currently connected to, NULL if none + * @possible_crtcs: bitmap of CRTCS this connector could be attached to + * @possible_clones: bitmap of possible connectors this connector could clone + * @interlace_allowed: can this connector handle interlaced modes? + * @doublescan_allowed: can this connector handle doublescan? + * @available_modes: modes available on this connector (from get_modes() + user) + * @initial_x: initial x position for this connector + * @initial_y: initial y position for this connector + * @status: connector connected? + * @funcs: connector control functions * - * Each output may be connected to one or more CRTCs, or may be clonable by - * another output if they can share a CRTC. Each output also has a specific + * Each connector may be connected to one or more CRTCs, or may be clonable by + * another connector if they can share a CRTC. Each connector also has a specific * position in the broader display (referred to as a 'screen' though it could * span multiple monitors). */ -struct drm_output { +struct drm_connector { struct drm_device *dev; struct device kdev; struct device_attribute *attr; @@ -446,37 +446,37 @@ struct drm_output { struct drm_crtc *crtc; int id; /* idr assigned */ - int output_type; - int output_type_id; + int connector_type; + int connector_type_id; unsigned long possible_crtcs; unsigned long possible_clones; bool interlace_allowed; bool doublescan_allowed; - struct list_head modes; /* list of modes on this output */ + struct list_head modes; /* list of modes on this connector */ int initial_x, initial_y; - enum drm_output_status status; + enum drm_connector_status status; /* these are modes added by probing with DDC or the BIOS */ struct list_head probed_modes; struct drm_display_info display_info; - const struct drm_output_funcs *funcs; + const struct drm_connector_funcs *funcs; struct list_head user_modes; struct drm_property_blob *edid_blob_ptr; - u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; - uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; + u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY]; + uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY]; void *helper_private; - u32 encoder_ids[DRM_OUTPUT_MAX_ENCODER]; + u32 encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; }; /** * struct drm_mode_set * - * Represents a single crtc the outputs that it drives with what mode + * Represents a single crtc the connectors that it drives with what mode * and from which framebuffer it scans out from. * * This is used to set modes. @@ -490,8 +490,8 @@ struct drm_mode_set uint32_t x; uint32_t y; - struct drm_output **outputs; - size_t num_outputs; + struct drm_connector **connectors; + size_t num_connectors; }; /** @@ -501,7 +501,7 @@ struct drm_mode_set * Currently only a resize hook is available. DRM will call back into the * driver with a new screen width and height. If the driver can't support * the proposed size, it can return false. Otherwise it should adjust - * the CRTC<->output mappings as needed and update its view of the screen. + * the CRTC<->connector mappings as needed and update its view of the screen. */ struct drm_mode_config_funcs { bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); @@ -513,12 +513,12 @@ struct drm_mode_config_funcs { */ struct drm_mode_config { struct mutex mutex; /* protects configuration and IDR */ - struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output, modes - just makes life easier */ + struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ /* this is limited to one for now */ int num_fb; struct list_head fb_list; - int num_output; - struct list_head output_list; + int num_connector; + struct list_head connector_list; int num_encoder; struct list_head encoder_list; @@ -536,8 +536,6 @@ struct drm_mode_config { struct list_head property_blob_list; struct drm_property *edid_property; struct drm_property *dpms_property; - struct drm_property *connector_type_property; - struct drm_property *connector_num_property; /* TV properties */ struct drm_property *tv_mode_property; @@ -556,12 +554,12 @@ extern void drm_crtc_init(struct drm_device *dev, const struct drm_crtc_funcs *funcs); extern void drm_crtc_cleanup(struct drm_crtc *crtc); -extern void drm_output_init(struct drm_device *dev, - struct drm_output *output, - const struct drm_output_funcs *funcs, - int output_type); +extern void drm_connector_init(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type); -extern void drm_output_cleanup(struct drm_output *output); +extern void drm_connector_cleanup(struct drm_connector *connector); extern void drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, @@ -570,15 +568,15 @@ extern void drm_encoder_init(struct drm_device *dev, extern void drm_encoder_cleanup(struct drm_encoder *encoder); -extern char *drm_get_output_name(struct drm_output *output); +extern char *drm_get_connector_name(struct drm_connector *connector); extern char *drm_get_dpms_name(int val); extern void drm_fb_release(struct file *filp); -extern struct edid *drm_get_edid(struct drm_output *output, +extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); -extern int drm_add_edid_modes(struct drm_output *output, struct edid *edid); -extern void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode); -extern void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode); +extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); +extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); +extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode); @@ -607,13 +605,13 @@ extern void drm_mode_sort(struct list_head *mode_list); extern int drm_mode_vrefresh(struct drm_display_mode *mode); extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags); -extern void drm_mode_output_list_update(struct drm_output *output); -extern int drm_mode_output_update_edid_property(struct drm_output *output, +extern void drm_mode_connector_list_update(struct drm_connector *connector); +extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, struct edid *edid); -extern int drm_output_property_set_value(struct drm_output *output, +extern int drm_connector_property_set_value(struct drm_connector *connector, struct drm_property *property, uint64_t value); -extern int drm_output_property_get_value(struct drm_output *output, +extern int drm_connector_property_get_value(struct drm_connector *connector, struct drm_property *property, uint64_t *value); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); @@ -623,10 +621,10 @@ extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); -extern void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY); +extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); extern bool drm_crtc_in_use(struct drm_crtc *crtc); -extern int drm_output_attach_property(struct drm_output *output, +extern int drm_connector_attach_property(struct drm_connector *connector, struct drm_property *property, uint64_t init_val); extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values); @@ -636,9 +634,9 @@ extern int drm_property_add_enum(struct drm_property *property, int index, extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); -extern int drm_mode_output_attach_encoder(struct drm_output *output, +extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); -extern void drm_mode_output_detach_encoder(struct drm_output *output, +extern void drm_mode_connector_detach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); /* IOCTLs */ @@ -647,7 +645,7 @@ extern int drm_mode_getresources(struct drm_device *dev, extern int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mode_getoutput(struct drm_device *dev, +extern int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -672,7 +670,7 @@ extern int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mode_output_property_set_ioctl(struct drm_device *dev, +extern int drm_mode_connector_property_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_hotplug_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index f776dbed..98b112ed 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -36,7 +36,7 @@ /** - * drm_pick_crtcs - pick crtcs for output devices + * drm_pick_crtcs - pick crtcs for connector devices * @dev: DRM device * * LOCKING: @@ -45,36 +45,36 @@ static void drm_pick_crtcs (struct drm_device *dev) { int c, o, assigned; - struct drm_output *output, *output_equal; + struct drm_connector *connector, *connector_equal; struct drm_crtc *crtc; struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; int found; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - output->crtc = NULL; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + connector->crtc = NULL; - /* Don't hook up outputs that are disconnected ?? + /* Don't hook up connectors that are disconnected ?? * * This is debateable. Do we want fixed /dev/fbX or * dynamic on hotplug (need mode code for that though) ? * - * If we don't hook up outputs now, then we only create - * /dev/fbX for the output that's enabled, that's good as - * the users console will be on that output. + * If we don't hook up connectors now, then we only create + * /dev/fbX for the connector that's enabled, that's good as + * the users console will be on that connector. * - * If we do hook up outputs that are disconnected now, then + * If we do hook up connectors that are disconnected now, then * the user may end up having to muck about with the fbcon - * map flags to assign his console to the enabled output. Ugh. + * map flags to assign his console to the enabled connector. Ugh. */ - if (output->status != output_status_connected) + if (connector->status != connector_status_connected) continue; - if (list_empty(&output->modes)) + if (list_empty(&connector->modes)) continue; des_mode = NULL; found = 0; - list_for_each_entry(des_mode, &output->modes, head) { + list_for_each_entry(des_mode, &connector->modes, head) { if (des_mode->type & DRM_MODE_TYPE_PREFERRED) { found = 1; break; @@ -84,7 +84,7 @@ static void drm_pick_crtcs (struct drm_device *dev) /* No preferred mode, let's just select the first available */ if (!found) { des_mode = NULL; - list_for_each_entry(des_mode, &output->modes, head) { + list_for_each_entry(des_mode, &connector->modes, head) { break; } } @@ -94,15 +94,15 @@ static void drm_pick_crtcs (struct drm_device *dev) assigned = 0; c++; - if ((output->possible_crtcs & (1 << c)) == 0) + if ((connector->possible_crtcs & (1 << c)) == 0) continue; - list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { - if (output->id == output_equal->id) + list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { + if (connector->id == connector_equal->id) continue; /* Find out if crtc has been assigned before */ - if (output_equal->crtc == crtc) + if (connector_equal->crtc == crtc) assigned = 1; } @@ -112,16 +112,16 @@ static void drm_pick_crtcs (struct drm_device *dev) #endif o = -1; - list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { + list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { o++; - if (output->id == output_equal->id) + if (connector->id == connector_equal->id) continue; - list_for_each_entry(modes, &output->modes, head) { - list_for_each_entry(modes_equal, &output_equal->modes, head) { + list_for_each_entry(modes, &connector->modes, head) { + list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { - if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) { - printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones); + if ((connector->possible_clones & connector_equal->possible_clones) && (connector_equal->crtc == crtc)) { + printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),connector->possible_clones,drm_get_connector_name(connector_equal),connector_equal->possible_clones); des_mode = modes; assigned = 0; goto clone; @@ -137,10 +137,10 @@ clone: continue; /* Found a CRTC to attach to, do it ! */ - output->crtc = crtc; - output->crtc->desired_mode = des_mode; - output->initial_x = 0; - output->initial_y = 0; + connector->crtc = crtc; + connector->crtc->desired_mode = des_mode; + connector->initial_x = 0; + connector->initial_y = 0; DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); break; } @@ -158,7 +158,7 @@ EXPORT_SYMBOL(drm_pick_crtcs); * LOCKING: * Caller must hold mode config lock. * - * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance + * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance * to fixup or reject the mode prior to trying to set it. * * RETURNS: @@ -170,9 +170,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode, saved_mode; struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - struct drm_output_helper_funcs *output_funcs; + struct drm_connector_helper_funcs *connector_funcs; int saved_x, saved_y; - struct drm_output *output; + struct drm_connector *connector; bool ret = true; adjusted_mode = drm_mode_duplicate(dev, mode); @@ -200,16 +200,16 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo } } - /* Pass our mode to the outputs and the CRTC to give them a chance to - * adjust it according to limitations or output properties, and also + /* Pass our mode to the connectors and the CRTC to give them a chance to + * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; - output_funcs = output->helper_private; - if (!(ret = output_funcs->mode_fixup(output, mode, adjusted_mode))) { + connector_funcs = connector->helper_private; + if (!(ret = connector_funcs->mode_fixup(connector, mode, adjusted_mode))) { goto done; } } @@ -218,47 +218,47 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo goto done; } - /* Prepare the outputs and CRTCs before setting the mode. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { + /* Prepare the connectors and CRTCs before setting the mode. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; - output_funcs = output->helper_private; - /* Disable the output as the first thing we do. */ - output_funcs->prepare(output); + connector_funcs = connector->helper_private; + /* Disable the connector as the first thing we do. */ + connector_funcs->prepare(connector); } crtc_funcs->prepare(crtc); - /* Set up the DPLL and any output state that needs to adjust or depend + /* Set up the DPLL and any connector state that needs to adjust or depend * on the DPLL. */ crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y); - list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; - DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id); - output_funcs = output->helper_private; - output_funcs->mode_set(output, mode, adjusted_mode); + DRM_INFO("%s: set mode %s %x\n", drm_get_connector_name(connector), mode->name, mode->mode_id); + connector_funcs = connector->helper_private; + connector_funcs->mode_set(connector, mode, adjusted_mode); } - /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ + /* Now, enable the clocks, plane, pipe, and connectors that we set up. */ crtc_funcs->commit(crtc); - list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; - output_funcs = output->helper_private; - output_funcs->commit(output); + connector_funcs = connector->helper_private; + connector_funcs->commit(connector); #if 0 // TODO def RANDR_12_INTERFACE - if (output->randr_output) - RRPostPendingProperties (output->randr_output); + if (connector->randr_connector) + RRPostPendingProperties (connector->randr_connector); #endif } @@ -285,7 +285,7 @@ EXPORT_SYMBOL(drm_crtc_helper_set_mode); * @crtc: CRTC to setup * @crtc_info: user provided configuration * @new_mode: new mode to set - * @output_set: set of outputs for the new config + * @connector_set: set of connectors for the new config * @fb: new framebuffer * * LOCKING: @@ -304,7 +304,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) bool save_enabled; bool changed = false; bool flip_or_move = false; - struct drm_output *output; + struct drm_connector *connector; int count = 0, ro; struct drm_crtc_helper_funcs *crtc_funcs; @@ -321,14 +321,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; - DRM_DEBUG("crtc: %p fb: %p outputs: %p num_outputs: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->outputs, set->num_outputs, set->x, set->y); + DRM_DEBUG("crtc: %p fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->connectors, set->num_connectors, set->x, set->y); dev = set->crtc->dev; /* save previous config */ save_enabled = set->crtc->enabled; - /* this is meant to be num_output not num_crtc */ - save_crtcs = kzalloc(dev->mode_config.num_output * sizeof(struct drm_crtc *), GFP_KERNEL); + /* this is meant to be num_connector not num_crtc */ + save_crtcs = kzalloc(dev->mode_config.num_connector * sizeof(struct drm_crtc *), GFP_KERNEL); if (!save_crtcs) return -ENOMEM; @@ -347,21 +347,21 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) changed = true; } - list_for_each_entry(output, &dev->mode_config.output_list, head) { - save_crtcs[count++] = output->crtc; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + save_crtcs[count++] = connector->crtc; - if (output->crtc == set->crtc) + if (connector->crtc == set->crtc) new_crtc = NULL; else - new_crtc = output->crtc; + new_crtc = connector->crtc; - for (ro = 0; ro < set->num_outputs; ro++) { - if (set->outputs[ro] == output) + for (ro = 0; ro < set->num_connectors; ro++) { + if (set->connectors[ro] == connector) new_crtc = set->crtc; } - if (new_crtc != output->crtc) { + if (new_crtc != connector->crtc) { changed = true; - output->crtc = new_crtc; + connector->crtc = new_crtc; } } @@ -379,8 +379,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) set->y)) { set->crtc->enabled = save_enabled; count = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) - output->crtc = save_crtcs[count++]; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + connector->crtc = save_crtcs[count++]; kfree(save_crtcs); return -EINVAL; } @@ -402,14 +402,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) EXPORT_SYMBOL(drm_crtc_helper_set_config); /** - * drm_initial_config - setup a sane initial output configuration + * drm_initial_config - setup a sane initial connector configuration * @dev: DRM device * @can_grow: this configuration is growable * * LOCKING: * Called at init time, must take mode config lock. * - * Scan the CRTCs and outputs and try to put together an initial setup. + * Scan the CRTCs and connectors and try to put together an initial setup. * At the moment, this is a cloned configuration across all heads with * a new framebuffer object as the backing store. * @@ -418,32 +418,32 @@ EXPORT_SYMBOL(drm_crtc_helper_set_config); */ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) { - struct drm_output *output; + struct drm_connector *connector; int ret = false; mutex_lock(&dev->mode_config.mutex); - drm_crtc_probe_output_modes(dev, 2048, 2048); + drm_crtc_probe_connector_modes(dev, 2048, 2048); drm_pick_crtcs(dev); - /* This is a little screwy, as we've already walked the outputs + /* This is a little screwy, as we've already walked the connectors * above, but it's a little bit of magic too. There's the potential * for things not to get setup above if an existing device gets - * re-assigned thus confusing the hardware. By walking the outputs + * re-assigned thus confusing the hardware. By walking the connectors * this fixes up their crtc's. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - /* can't setup the output if there's no assigned mode */ - if (!output->crtc || !output->crtc->desired_mode) + /* can't setup the connector if there's no assigned mode */ + if (!connector->crtc || !connector->crtc->desired_mode) continue; - dev->driver->fb_probe(dev, output->crtc, output); + dev->driver->fb_probe(dev, connector->crtc, connector); /* and needs an attached fb */ - if (output->crtc->fb) - drm_crtc_helper_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); + if (connector->crtc->fb) + drm_crtc_helper_set_mode(connector->crtc, connector->crtc->desired_mode, 0, 0); } drm_disable_unused_functions(dev); @@ -456,7 +456,7 @@ EXPORT_SYMBOL(drm_helper_initial_config); /** * drm_hotplug_stage_two * @dev DRM device - * @output hotpluged output + * @connector hotpluged connector * * LOCKING. * Caller must hold mode config lock, function might grab struct lock. @@ -466,7 +466,7 @@ EXPORT_SYMBOL(drm_helper_initial_config); * RETURNS: * Zero on success, errno on failure. */ -int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, +int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, bool connected) { int has_config = 0; @@ -479,29 +479,29 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *outp return 0; } - if (output->crtc && output->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the output already has a config\n"); + if (connector->crtc && connector->crtc->desired_mode) { + DRM_DEBUG("drm thinks that the connector already has a config\n"); has_config = 1; } - drm_crtc_probe_output_modes(dev, 2048, 2048); + drm_crtc_probe_connector_modes(dev, 2048, 2048); if (!has_config) drm_pick_crtcs(dev); - if (!output->crtc || !output->crtc->desired_mode) { - DRM_DEBUG("could not find a desired mode or crtc for output\n"); + if (!connector->crtc || !connector->crtc->desired_mode) { + DRM_DEBUG("could not find a desired mode or crtc for connector\n"); return 1; } /* We should really check if there is a fb using this crtc */ if (!has_config) - dev->driver->fb_probe(dev, output->crtc, output); + dev->driver->fb_probe(dev, connector->crtc, connector); else { - dev->driver->fb_resize(dev, output->crtc); + dev->driver->fb_resize(dev, connector->crtc); #if 0 - if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) + if (!drm_crtc_set_mode(connector->crtc, connector->crtc->desired_mode, 0, 0)) DRM_ERROR("failed to set mode after hotplug\n"); #endif } diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 9e16861d..10420065 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -36,27 +36,27 @@ struct drm_crtc_helper_funcs { void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); }; -struct drm_output_helper_funcs { - bool (*mode_fixup)(struct drm_output *output, +struct drm_connector_helper_funcs { + bool (*mode_fixup)(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); - void (*prepare)(struct drm_output *output); - void (*commit)(struct drm_output *output); - void (*mode_set)(struct drm_output *output, + void (*prepare)(struct drm_connector *connector); + void (*commit)(struct drm_connector *connector); + void (*mode_set)(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); }; struct drm_encoder_helper_funcs { - void (*prepare)(struct drm_output *output); - void (*commit)(struct drm_output *output); - void (*mode_set)(struct drm_output *output, + void (*prepare)(struct drm_connector *connector); + void (*commit)(struct drm_connector *connector); + void (*mode_set)(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); }; -extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, +extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, bool connected); extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); extern int drm_crtc_helper_set_config(struct drm_mode_set *set); @@ -68,9 +68,9 @@ static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_c crtc->helper_private = (void *)funcs; } -static inline void drm_output_helper_add(struct drm_output *output, const struct drm_output_helper_funcs *funcs) +static inline void drm_connector_helper_add(struct drm_connector *connector, const struct drm_connector_helper_funcs *funcs) { - output->helper_private = (void *)funcs; + connector->helper_private = (void *)funcs; } diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 6111c850..5a16fe8d 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -126,14 +126,14 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_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_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index e033abdf..69906ed9 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -211,9 +211,9 @@ static struct drm_display_mode edid_est_modes[] = { * Each EDID block contains a bitmap of the supported "established modes" list * (defined above). Tease them out and add them to the global modes list. */ -static int add_established_modes(struct drm_output *output, struct edid *edid) +static int add_established_modes(struct drm_connector *connector, struct edid *edid) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; unsigned long est_bits = edid->established_timings.t1 | (edid->established_timings.t2 << 8) | ((edid->established_timings.mfg_rsvd & 0x80) << 9); @@ -224,7 +224,7 @@ static int add_established_modes(struct drm_output *output, struct edid *edid) struct drm_display_mode *newmode; newmode = drm_mode_duplicate(dev, &edid_est_modes[i]); if (newmode) { - drm_mode_probed_add(output, newmode); + drm_mode_probed_add(connector, newmode); modes++; } } @@ -239,9 +239,9 @@ static int add_established_modes(struct drm_output *output, struct edid *edid) * Standard modes can be calculated using the CVT standard. Grab them from * @edid, calculate them, and add them to the list. */ -static int add_standard_modes(struct drm_output *output, struct edid *edid) +static int add_standard_modes(struct drm_connector *connector, struct edid *edid) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; int i, modes = 0; for (i = 0; i < EDID_STD_TIMINGS; i++) { @@ -254,7 +254,7 @@ static int add_standard_modes(struct drm_output *output, struct edid *edid) newmode = drm_mode_std(dev, &edid->standard_timings[i]); if (newmode) { - drm_mode_probed_add(output, newmode); + drm_mode_probed_add(connector, newmode); modes++; } } @@ -269,9 +269,9 @@ static int add_standard_modes(struct drm_output *output, struct edid *edid) * Some of the detailed timing sections may contain mode information. Grab * it and add it to the list. */ -static int add_detailed_info(struct drm_output *output, struct edid *edid) +static int add_detailed_info(struct drm_connector *connector, struct edid *edid) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; int i, j, modes = 0; for (i = 0; i < EDID_DETAILED_TIMINGS; i++) { @@ -290,11 +290,11 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) if (newmode) { if (i == 0 && edid->preferred_timing) newmode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(output, newmode); + drm_mode_probed_add(connector, newmode); - /* Use first one for output's preferred mode */ - if (!output->display_info.preferred_mode) - output->display_info.preferred_mode = + /* Use first one for connector's preferred mode */ + if (!connector->display_info.preferred_mode) + connector->display_info.preferred_mode = newmode; modes++; } @@ -323,7 +323,7 @@ static int add_detailed_info(struct drm_output *output, struct edid *edid) std = &data->data.timings[j]; newmode = drm_mode_std(dev, std); if (newmode) { - drm_mode_probed_add(output, newmode); + drm_mode_probed_add(connector, newmode); modes++; } } @@ -440,32 +440,32 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) /** * drm_get_edid - get EDID data, if available - * @output: output we're probing + * @connector: connector we're probing * @adapter: i2c adapter to use for DDC * - * Poke the given output's i2c channel to grab EDID data if possible. + * Poke the given connector's i2c channel to grab EDID data if possible. * * Return edid data or NULL if we couldn't find any. */ -struct edid *drm_get_edid(struct drm_output *output, +struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { struct edid *edid; edid = (struct edid *)drm_ddc_read(adapter); if (!edid) { - dev_warn(&output->dev->pdev->dev, "%s: no EDID data\n", - drm_get_output_name(output)); + dev_warn(&connector->dev->pdev->dev, "%s: no EDID data\n", + drm_get_connector_name(connector)); return NULL; } if (!edid_valid(edid)) { - dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", - drm_get_output_name(output)); + dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", + drm_get_connector_name(connector)); kfree(edid); return NULL; } - output->display_info.raw_edid = (char *)edid; + connector->display_info.raw_edid = (char *)edid; return edid; } @@ -473,14 +473,14 @@ EXPORT_SYMBOL(drm_get_edid); /** * drm_add_edid_modes - add modes from EDID data, if available - * @output: output we're probing + * @connector: connector we're probing * @edid: edid data * - * Add the specified modes to the output's mode list. + * Add the specified modes to the connector's mode list. * * Return number of modes added or 0 if we couldn't find any. */ -int drm_add_edid_modes(struct drm_output *output, struct edid *edid) +int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) { int num_modes = 0; @@ -488,31 +488,31 @@ int drm_add_edid_modes(struct drm_output *output, struct edid *edid) return 0; } if (!edid_valid(edid)) { - dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n", - drm_get_output_name(output)); + dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", + drm_get_connector_name(connector)); return 0; } - num_modes += add_established_modes(output, edid); - num_modes += add_standard_modes(output, edid); - num_modes += add_detailed_info(output, edid); - - output->display_info.serration_vsync = edid->serration_vsync; - output->display_info.sync_on_green = edid->sync_on_green; - output->display_info.composite_sync = edid->composite_sync; - output->display_info.separate_syncs = edid->separate_syncs; - output->display_info.blank_to_black = edid->blank_to_black; - output->display_info.video_level = edid->video_level; - output->display_info.digital = edid->digital; - output->display_info.width_mm = edid->width_cm * 10; - output->display_info.height_mm = edid->height_cm * 10; - output->display_info.gamma = edid->gamma; - output->display_info.gtf_supported = edid->default_gtf; - output->display_info.standard_color = edid->standard_color; - output->display_info.display_type = edid->display_type; - output->display_info.active_off_supported = edid->pm_active_off; - output->display_info.suspend_supported = edid->pm_suspend; - output->display_info.standby_supported = edid->pm_standby; - output->display_info.gamma = edid->gamma; + num_modes += add_established_modes(connector, edid); + num_modes += add_standard_modes(connector, edid); + num_modes += add_detailed_info(connector, edid); + + connector->display_info.serration_vsync = edid->serration_vsync; + connector->display_info.sync_on_green = edid->sync_on_green; + connector->display_info.composite_sync = edid->composite_sync; + connector->display_info.separate_syncs = edid->separate_syncs; + connector->display_info.blank_to_black = edid->blank_to_black; + connector->display_info.video_level = edid->video_level; + connector->display_info.digital = edid->digital; + connector->display_info.width_mm = edid->width_cm * 10; + connector->display_info.height_mm = edid->height_cm * 10; + connector->display_info.gamma = edid->gamma; + connector->display_info.gtf_supported = edid->default_gtf; + connector->display_info.standard_color = edid->standard_color; + connector->display_info.display_type = edid->display_type; + connector->display_info.active_off_supported = edid->pm_active_off; + connector->display_info.suspend_supported = edid->pm_suspend; + connector->display_info.standby_supported = edid->pm_standby; + connector->display_info.gamma = edid->gamma; return num_modes; } diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 897777d0..26b96e73 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -521,27 +521,27 @@ void drm_mode_sort(struct list_head *mode_list) /** - * drm_mode_output_list_update - update the mode list for the output - * @output: the output to update + * drm_mode_connector_list_update - update the mode list for the connector + * @connector: the connector to update * * LOCKING: * Caller must hold a lock protecting @mode_list. * - * This moves the modes from the @output probed_modes list + * This moves the modes from the @connector probed_modes list * to the actual mode list. It compares the probed mode against the current * list and only adds different modes. All modes unverified after this point * will be removed by the prune invalid modes. */ -void drm_mode_output_list_update(struct drm_output *output) +void drm_mode_connector_list_update(struct drm_connector *connector) { struct drm_display_mode *mode; struct drm_display_mode *pmode, *pt; int found_it; - list_for_each_entry_safe(pmode, pt, &output->probed_modes, + list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) { found_it = 0; /* go through current modes checking for the new probed mode */ - list_for_each_entry(mode, &output->modes, head) { + list_for_each_entry(mode, &connector->modes, head) { if (drm_mode_equal(pmode, mode)) { found_it = 1; /* if equal delete the probed mode */ @@ -553,7 +553,7 @@ void drm_mode_output_list_update(struct drm_output *output) } if (!found_it) { - list_move_tail(&pmode->head, &output->modes); + list_move_tail(&pmode->head, &connector->modes); } } } diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 8691d156..01a3c047 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -147,27 +147,27 @@ static void drm_sysfs_device_release(struct device *dev) } /* - * Output properties + * Connector properties */ static ssize_t status_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_output *output = container_of(device, struct drm_output, kdev); + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); return snprintf(buf, PAGE_SIZE, "%s", - drm_get_output_status_name(output->funcs->detect(output))); + drm_get_connector_status_name(connector->funcs->detect(connector))); } static ssize_t dpms_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_output *output = container_of(device, struct drm_output, kdev); - struct drm_device *dev = output->dev; + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; uint64_t dpms_status; int ret; - ret = drm_output_property_get_value(output, + ret = drm_connector_property_get_value(connector, dev->mode_config.dpms_property, &dpms_status); if (ret) @@ -179,17 +179,17 @@ static ssize_t dpms_show(struct device *device, static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - struct device *output_dev = container_of(kobj, struct device, kobj); - struct drm_output *output = container_of(output_dev, struct drm_output, + struct device *connector_dev = container_of(kobj, struct device, kobj); + struct drm_connector *connector = container_of(connector_dev, struct drm_connector, kdev); unsigned char *edid; size_t size; - if (!output->edid_blob_ptr) + if (!connector->edid_blob_ptr) return 0; - edid = output->edid_blob_ptr->data; - size = output->edid_blob_ptr->length; + edid = connector->edid_blob_ptr->data; + size = connector->edid_blob_ptr->length; if (!edid) return 0; @@ -207,11 +207,11 @@ static ssize_t modes_show(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_output *output = container_of(device, struct drm_output, kdev); + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); struct drm_display_mode *mode; int written = 0; - list_for_each_entry(mode, &output->modes, head) { + list_for_each_entry(mode, &connector->modes, head) { written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", mode->name); } @@ -219,7 +219,7 @@ static ssize_t modes_show(struct device *device, return written; } -static struct device_attribute output_attrs[] = { +static struct device_attribute connector_attrs[] = { __ATTR_RO(status), __ATTR_RO(dpms), __ATTR_RO(modes), @@ -232,48 +232,48 @@ static struct bin_attribute edid_attr = { }; /** - * drm_sysfs_output_add - add an output to sysfs - * @output: output to add + * drm_sysfs_connector_add - add an connector to sysfs + * @connector: connector to add * - * Create an output device in sysfs, along with its associated output + * Create an connector device in sysfs, along with its associated connector * properties (so far, connection status, dpms, mode list & edid) and - * generate a hotplug event so userspace knows there's a new output + * generate a hotplug event so userspace knows there's a new connector * available. */ -int drm_sysfs_output_add(struct drm_output *output) +int drm_sysfs_connector_add(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; int ret = 0, i, j; - if (device_is_registered(&output->kdev)) + if (device_is_registered(&connector->kdev)) return 0; - output->kdev.parent = &dev->primary->kdev; - output->kdev.class = drm_class; - output->kdev.release = drm_sysfs_device_release; + connector->kdev.parent = &dev->primary->kdev; + connector->kdev.class = drm_class; + connector->kdev.release = drm_sysfs_device_release; - DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_output_name(output)); + DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_connector_name(connector)); - snprintf(output->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", - dev->primary->index, drm_get_output_name(output)); - ret = device_register(&output->kdev); + snprintf(connector->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", + dev->primary->index, drm_get_connector_name(connector)); + ret = device_register(&connector->kdev); if (ret) { - DRM_ERROR("failed to register output device: %d\n", ret); + DRM_ERROR("failed to register connector device: %d\n", ret); goto out; } - for (i = 0; i < ARRAY_SIZE(output_attrs); i++) { - ret = device_create_file(&output->kdev, &output_attrs[i]); + for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) { + ret = device_create_file(&connector->kdev, &connector_attrs[i]); if (ret) goto err_out_files; } - ret = sysfs_create_bin_file(&output->kdev.kobj, &edid_attr); + ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr); if (ret) goto err_out_files; - /* Let userspace know we have a new output */ + /* Let userspace know we have a new connector */ drm_sysfs_hotplug_event(dev); return 0; @@ -281,33 +281,33 @@ int drm_sysfs_output_add(struct drm_output *output) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&output->kdev, &output_attrs[i]); - device_unregister(&output->kdev); + device_remove_file(&connector->kdev, &connector_attrs[i]); + device_unregister(&connector->kdev); out: return ret; } -EXPORT_SYMBOL(drm_sysfs_output_add); +EXPORT_SYMBOL(drm_sysfs_connector_add); /** - * drm_sysfs_output_remove - remove an output device from sysfs - * @output: output to remove + * drm_sysfs_connector_remove - remove an connector device from sysfs + * @connector: connector to remove * - * Remove @output and its associated attributes from sysfs. Note that + * Remove @connector and its associated attributes from sysfs. Note that * the device model core will take care of sending the "remove" uevent * at this time, so we don't need to do it. */ -void drm_sysfs_output_remove(struct drm_output *output) +void drm_sysfs_connector_remove(struct drm_connector *connector) { int i; - DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_output_name(output)); - for (i = 0; i < ARRAY_SIZE(output_attrs); i++) - device_remove_file(&output->kdev, &output_attrs[i]); - sysfs_remove_bin_file(&output->kdev.kobj, &edid_attr); - device_unregister(&output->kdev); + DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_connector_name(connector)); + for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) + device_remove_file(&connector->kdev, &connector_attrs[i]); + sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr); + device_unregister(&connector->kdev); } -EXPORT_SYMBOL(drm_sysfs_output_remove); +EXPORT_SYMBOL(drm_sysfs_connector_remove); /** * drm_sysfs_hotplug_event - generate a DRM uevent diff --git a/linux-core/dvo.h b/linux-core/dvo.h index c6c1dbdb..b122ea1f 100644 --- a/linux-core/dvo.h +++ b/linux-core/dvo.h @@ -126,7 +126,7 @@ struct intel_dvo_dev_ops { /* * Probe for a connected output, and return detect_status. */ - enum drm_output_status (*detect)(struct intel_dvo_device *dvo); + enum drm_connector_status (*detect)(struct intel_dvo_device *dvo); /** * Query the device for the modes it provides. diff --git a/linux-core/dvo_ch7017.c b/linux-core/dvo_ch7017.c index 8349da1b..194a7af1 100644 --- a/linux-core/dvo_ch7017.c +++ b/linux-core/dvo_ch7017.c @@ -258,9 +258,9 @@ fail: return false; } -static enum drm_output_status ch7017_detect(struct intel_dvo_device *dvo) +static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) { - return output_status_unknown; + return connector_status_unknown; } static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, diff --git a/linux-core/dvo_ch7xxx.c b/linux-core/dvo_ch7xxx.c index 69827a7d..18922556 100644 --- a/linux-core/dvo_ch7xxx.c +++ b/linux-core/dvo_ch7xxx.c @@ -230,7 +230,7 @@ out: return false; } -static enum drm_output_status ch7xxx_detect(struct intel_dvo_device *dvo) +static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo) { uint8_t cdet, orig_pm, pm; @@ -247,8 +247,8 @@ static enum drm_output_status ch7xxx_detect(struct intel_dvo_device *dvo) ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm); if (cdet & CH7xxx_CDET_DVI) - return output_status_connected; - return output_status_disconnected; + return connector_status_connected; + return connector_status_disconnected; } static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo, diff --git a/linux-core/dvo_ivch.c b/linux-core/dvo_ivch.c index 5fce2462..80b85c89 100644 --- a/linux-core/dvo_ivch.c +++ b/linux-core/dvo_ivch.c @@ -293,9 +293,9 @@ out: return false; } -static enum drm_output_status ivch_detect(struct intel_dvo_device *dvo) +static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo) { - return output_status_connected; + return connector_status_connected; } static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, diff --git a/linux-core/dvo_sil164.c b/linux-core/dvo_sil164.c index 0cee59b1..d0fa4913 100644 --- a/linux-core/dvo_sil164.c +++ b/linux-core/dvo_sil164.c @@ -180,16 +180,16 @@ out: return false; } -static enum drm_output_status sil164_detect(struct intel_dvo_device *dvo) +static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo) { uint8_t reg9; sil164_readb(dvo, SIL164_REG9, ®9); if (reg9 & SIL164_9_HTPLG) - return output_status_connected; + return connector_status_connected; else - return output_status_disconnected; + return connector_status_disconnected; } static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo, diff --git a/linux-core/dvo_tfp410.c b/linux-core/dvo_tfp410.c index 64448509..c1d1aa96 100644 --- a/linux-core/dvo_tfp410.c +++ b/linux-core/dvo_tfp410.c @@ -207,16 +207,16 @@ out: return false; } -static enum drm_output_status tfp410_detect(struct intel_dvo_device *dvo) +static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo) { - enum drm_output_status ret = output_status_disconnected; + enum drm_connector_status ret = connector_status_disconnected; uint8_t ctl2; if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) { if (ctl2 & TFP410_CTL_2_HTPLG) - ret = output_status_connected; + ret = connector_status_connected; else - ret = output_status_disconnected; + ret = connector_status_disconnected; } return ret; diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 44035783..a98f7000 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -33,9 +33,9 @@ #include "i915_drm.h" #include "i915_drv.h" -static void intel_crt_dpms(struct drm_output *output, int mode) +static void intel_crt_dpms(struct drm_connector *connector, int mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 temp; @@ -61,17 +61,17 @@ static void intel_crt_dpms(struct drm_output *output, int mode) I915_WRITE(ADPA, temp); } -static void intel_crt_save(struct drm_output *output) +static void intel_crt_save(struct drm_connector *connector) { } -static void intel_crt_restore(struct drm_output *output) +static void intel_crt_restore(struct drm_connector *connector) { } -static int intel_crt_mode_valid(struct drm_output *output, +static int intel_crt_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { if (mode->flags & V_DBLSCAN) @@ -83,19 +83,19 @@ static int intel_crt_mode_valid(struct drm_output *output, return MODE_OK; } -static bool intel_crt_mode_fixup(struct drm_output *output, +static bool intel_crt_mode_fixup(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; } -static void intel_crt_mode_set(struct drm_output *output, +static void intel_crt_mode_set(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = output->dev; - struct drm_crtc *crtc = output->crtc; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc = connector->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_i915_private *dev_priv = dev->dev_private; int dpll_md_reg; @@ -138,9 +138,9 @@ static void intel_crt_mode_set(struct drm_output *output, * \return TRUE if CRT is connected. * \return FALSE if CRT is disconnected. */ -static bool intel_crt_detect_hotplug(struct drm_output *output) +static bool intel_crt_detect_hotplug(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 temp; @@ -164,57 +164,58 @@ static bool intel_crt_detect_hotplug(struct drm_output *output) return false; } -static bool intel_crt_detect_ddc(struct drm_output *output) +static bool intel_crt_detect_ddc(struct drm_connector *connector) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); /* CRT should always be at 0, but check anyway */ if (intel_output->type != INTEL_OUTPUT_ANALOG) return false; - return intel_ddc_probe(output); + return intel_ddc_probe(intel_output); } -static enum drm_output_status intel_crt_detect(struct drm_output *output) +static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - if (intel_crt_detect_hotplug(output)) - return output_status_connected; + if (intel_crt_detect_hotplug(connector)) + return connector_status_connected; else - return output_status_disconnected; + return connector_status_disconnected; } - if (intel_crt_detect_ddc(output)) - return output_status_connected; + if (intel_crt_detect_ddc(connector)) + return connector_status_connected; /* TODO use load detect */ - return output_status_unknown; + return connector_status_unknown; } -static void intel_crt_destroy(struct drm_output *output) +static void intel_crt_destroy(struct drm_connector *connector) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); intel_i2c_destroy(intel_output->ddc_bus); - drm_output_cleanup(output); - kfree(output); + drm_connector_cleanup(connector); + kfree(connector); } -static int intel_crt_get_modes(struct drm_output *output) +static int intel_crt_get_modes(struct drm_connector *connector) { - return intel_ddc_get_modes(output); + struct intel_output *intel_output = to_intel_output(connector); + return intel_ddc_get_modes(intel_output); } -static bool intel_crt_set_property(struct drm_output *output, +static bool intel_crt_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; if (property == dev->mode_config.dpms_property) - intel_crt_dpms(output, (uint32_t)(value & 0xf)); + intel_crt_dpms(connector, (uint32_t)(value & 0xf)); return true; } @@ -223,14 +224,14 @@ static bool intel_crt_set_property(struct drm_output *output, * Routines for controlling stuff on the analog port */ -static const struct drm_output_helper_funcs intel_crt_helper_funcs = { +static const struct drm_connector_helper_funcs intel_crt_helper_funcs = { .mode_fixup = intel_crt_mode_fixup, - .prepare = intel_output_prepare, - .commit = intel_output_commit, + .prepare = intel_connector_prepare, + .commit = intel_connector_commit, .mode_set = intel_crt_mode_set, }; -static const struct drm_output_funcs intel_crt_output_funcs = { +static const struct drm_connector_funcs intel_crt_connector_funcs = { .dpms = intel_crt_dpms, .save = intel_crt_save, .restore = intel_crt_restore, @@ -253,34 +254,36 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = { void intel_crt_init(struct drm_device *dev) { - struct drm_output *output; + struct drm_connector *connector; struct intel_output *intel_output; intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) return; - output = &intel_output->base; - drm_output_init(dev, &intel_output->base, &intel_crt_output_funcs, DRM_MODE_OUTPUT_VGA); + connector = &intel_output->base; + drm_connector_init(dev, &intel_output->base, &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); - drm_mode_output_attach_encoder(&intel_output->base, &intel_output->enc); + drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); /* Set up the DDC bus. */ intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); - intel_crt_destroy(output); + intel_crt_destroy(connector); return; } intel_output->type = INTEL_OUTPUT_ANALOG; - output->interlace_allowed = 0; - output->doublescan_allowed = 0; + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + drm_connector_helper_add(connector, &intel_crt_helper_funcs); + + drm_sysfs_connector_add(connector); - drm_output_helper_add(output, &intel_crt_helper_funcs); - drm_sysfs_output_add(output); } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index abcf5f5e..7fb1ea5f 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -225,9 +225,9 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type) { struct drm_device *dev = crtc->dev; struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_output *l_entry; + struct drm_connector *l_entry; - list_for_each_entry(l_entry, &mode_config->output_list, head) { + list_for_each_entry(l_entry, &mode_config->connector_list, head) { if (l_entry->crtc == crtc) { struct intel_output *intel_output = to_intel_output(l_entry); if (intel_output->type == type) @@ -240,7 +240,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type) #define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } /** * Returns whether the given set of divisors are valid for a given refclk with - * the given outputs. + * the given connectors. */ static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock) @@ -264,7 +264,7 @@ static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock) if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) INTELPllInvalid ("vco out of range\n"); /* XXX: We may need to be checking "Dot clock" depending on the multiplier, - * output, etc., rather than just a single range. + * connector, etc., rather than just a single range. */ if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) INTELPllInvalid ("dot out of range\n"); @@ -583,16 +583,16 @@ static void intel_crtc_commit (struct drm_crtc *crtc) crtc->funcs->dpms(crtc, DPMSModeOn); } -void intel_output_prepare (struct drm_output *output) +void intel_connector_prepare (struct drm_connector *connector) { /* lvds has its own version of prepare see intel_lvds_prepare */ - output->funcs->dpms(output, DPMSModeOff); + connector->funcs->dpms(connector, DPMSModeOff); } -void intel_output_commit (struct drm_output *output) +void intel_connector_commit (struct drm_connector *connector) { /* lvds has its own version of commit see intel_lvds_commit */ - output->funcs->dpms(output, DPMSModeOn); + connector->funcs->dpms(connector, DPMSModeOn); } static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, @@ -716,12 +716,12 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, bool ok, is_sdvo = false, is_dvo = false; bool is_crt = false, is_lvds = false, is_tv = false; struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_output *output; + struct drm_connector *connector; - list_for_each_entry(output, &mode_config->output_list, head) { - struct intel_output *intel_output = to_intel_output(output); + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_output *intel_output = to_intel_output(connector); - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; switch (intel_output->type) { @@ -1082,38 +1082,38 @@ static struct drm_display_mode load_detect_mode = { 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC), }; -struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, +struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_display_mode *mode, int *dpms_mode) { - struct drm_device *dev = output->dev; - struct intel_output *intel_output = to_intel_output(output); + struct drm_device *dev = connector->dev; + struct intel_output *intel_output = to_intel_output(connector); struct intel_crtc *intel_crtc; struct drm_crtc *possible_crtc; struct drm_crtc *supported_crtc =NULL; struct drm_crtc *crtc = NULL; - struct drm_output_helper_funcs *output_funcs; + struct drm_connector_helper_funcs *connector_funcs; int i = -1; /* * Algorithm gets a little messy: - * - if the output already has an assigned crtc, use it (but make + * - if the connector already has an assigned crtc, use it (but make * sure it's on first) - * - try to find the first unused crtc that can drive this output, + * - try to find the first unused crtc that can drive this connector, * and use that if we find one * - if there are no unused crtcs available, try to use the first - * one we found that supports the output + * one we found that supports the connector */ - /* See if we already have a CRTC for this output */ - if (output->crtc) { - crtc = output->crtc; - /* Make sure the crtc and output are running */ + /* See if we already have a CRTC for this connector */ + if (connector->crtc) { + crtc = connector->crtc; + /* Make sure the crtc and connector are running */ intel_crtc = to_intel_crtc(crtc); *dpms_mode = intel_crtc->dpms_mode; if (intel_crtc->dpms_mode != DPMSModeOn) { crtc->funcs->dpms(crtc, DPMSModeOn); - output->funcs->dpms(output, DPMSModeOn); + connector->funcs->dpms(connector, DPMSModeOn); } return crtc; } @@ -1121,7 +1121,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, /* Find an unused one (if possible) */ list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { i++; - if (!(output->possible_crtcs & (1 << i))) + if (!(connector->possible_crtcs & (1 << i))) continue; if (!possible_crtc->enabled) { crtc = possible_crtc; @@ -1133,7 +1133,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, /* * If we didn't find an unused CRTC, use the first available one - * that can drive this output. + * that can drive this connector. */ if (!crtc) { crtc = supported_crtc; @@ -1141,7 +1141,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, return NULL; } - output->crtc = crtc; + connector->crtc = crtc; intel_output->load_detect_temp = TRUE; intel_crtc = to_intel_crtc(crtc); @@ -1155,25 +1155,25 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, if (intel_crtc->dpms_mode != DPMSModeOn) crtc->funcs->dpms(crtc, DPMSModeOn); - output_funcs = output->helper_private; - /* Add this output to the crtc */ - output_funcs->mode_set(output, &crtc->mode, &crtc->mode); - output_funcs->commit(output); + connector_funcs = connector->helper_private; + /* Add this connector to the crtc */ + connector_funcs->mode_set(connector, &crtc->mode, &crtc->mode); + connector_funcs->commit(connector); } - /* let the output get through one full cycle before testing */ + /* let the connector get through one full cycle before testing */ intel_wait_for_vblank(dev); return crtc; } -void intel_release_load_detect_pipe(struct drm_output *output, int dpms_mode) +void intel_release_load_detect_pipe(struct drm_connector *connector, int dpms_mode) { - struct drm_device *dev = output->dev; - struct intel_output *intel_output = to_intel_output(output); - struct drm_crtc *crtc = output->crtc; + struct drm_device *dev = connector->dev; + struct intel_output *intel_output = to_intel_output(connector); + struct drm_crtc *crtc = connector->crtc; if (intel_output->load_detect_temp) { - output->crtc = NULL; + connector->crtc = NULL; intel_output->load_detect_temp = FALSE; crtc->enabled = drm_crtc_in_use(crtc); drm_disable_unused_functions(dev); @@ -1181,8 +1181,8 @@ void intel_release_load_detect_pipe(struct drm_output *output, int dpms_mode) /* Switch crtc and output back off if necessary */ if (crtc->enabled && dpms_mode != DPMSModeOn) { - if (output->crtc == crtc) - output->funcs->dpms(output, dpms_mode); + if (connector->crtc == crtc) + connector->funcs->dpms(connector, dpms_mode); crtc->funcs->dpms(crtc, dpms_mode); } } @@ -1257,7 +1257,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) } /* XXX: It would be nice to validate the clocks, but we can't reuse - * i830PllIsValid() because it relies on the xf86_config output + * i830PllIsValid() because it relies on the xf86_config connector * configuration being accurate, which it isn't necessarily. */ @@ -1358,14 +1358,14 @@ struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) return crtc; } -int intel_output_clones(struct drm_device *dev, int type_mask) +int intel_connector_clones(struct drm_device *dev, int type_mask) { int index_mask = 0; - struct drm_output *output; + struct drm_connector *connector; int entry = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - struct intel_output *intel_output = to_intel_output(output); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct intel_output *intel_output = to_intel_output(connector); if (type_mask & (1 << intel_output->type)) index_mask |= (1 << entry); entry++; @@ -1376,7 +1376,7 @@ int intel_output_clones(struct drm_device *dev, int type_mask) static void intel_setup_outputs(struct drm_device *dev) { - struct drm_output *output; + struct drm_connector *connector; intel_crt_init(dev); @@ -1393,8 +1393,8 @@ static void intel_setup_outputs(struct drm_device *dev) if (IS_I9XX(dev) && !IS_I915G(dev)) intel_tv_init(dev); - list_for_each_entry(output, &dev->mode_config.output_list, head) { - struct intel_output *intel_output = to_intel_output(output); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct intel_output *intel_output = to_intel_output(connector); int crtc_mask = 0, clone_mask = 0; /* valid crtcs */ @@ -1424,8 +1424,8 @@ static void intel_setup_outputs(struct drm_device *dev) clone_mask = (1 << INTEL_OUTPUT_TVOUT); break; } - output->possible_crtcs = crtc_mask; - output->possible_clones = intel_output_clones(dev, clone_mask); + connector->possible_crtcs = crtc_mask; + connector->possible_clones = intel_connector_clones(dev, clone_mask); } } diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 3f0c1664..44639525 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -47,7 +47,7 @@ struct intel_i2c_chan { }; struct intel_output { - struct drm_output base; + struct drm_connector base; struct drm_encoder enc; int type; @@ -72,8 +72,8 @@ struct intel_crtc { struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, const char *name); void intel_i2c_destroy(struct intel_i2c_chan *chan); -int intel_ddc_get_modes(struct drm_output *output); -extern bool intel_ddc_probe(struct drm_output *output); +int intel_ddc_get_modes(struct intel_output *intel_output); +extern bool intel_ddc_probe(struct intel_output *intel_output); extern void intel_crt_init(struct drm_device *dev); extern void intel_sdvo_init(struct drm_device *dev, int output_device); @@ -82,23 +82,23 @@ extern void intel_tv_init(struct drm_device *dev); extern void intel_lvds_init(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); -extern void intel_output_prepare (struct drm_output *output); -extern void intel_output_commit (struct drm_output *output); +extern void intel_connector_prepare (struct drm_connector *connector); +extern void intel_connector_commit (struct drm_connector *connector); extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_wait_for_vblank(struct drm_device *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); -extern struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, +extern struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_display_mode *mode, int *dpms_mode); -extern void intel_release_load_detect_pipe(struct drm_output *output, +extern void intel_release_load_detect_pipe(struct drm_connector *connector, int dpms_mode); -extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB); -extern int intel_sdvo_supports_hotplug(struct drm_output *output); -extern void intel_sdvo_set_hotplug(struct drm_output *output, int enable); +extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); +extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); +extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); -extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output); +extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index d9f39af6..7fc5ccea 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -85,10 +85,10 @@ struct intel_dvo_device intel_dvo_devices[] = { } }; -static void intel_dvo_dpms(struct drm_output *output, int mode) +static void intel_dvo_dpms(struct drm_connector *connector, int mode) { - struct drm_i915_private *dev_priv = output->dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; u32 dvo_reg = dvo->dvo_reg; u32 temp = I915_READ(dvo_reg); @@ -104,10 +104,10 @@ static void intel_dvo_dpms(struct drm_output *output, int mode) } } -static void intel_dvo_save(struct drm_output *output) +static void intel_dvo_save(struct drm_connector *connector) { - struct drm_i915_private *dev_priv = output->dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; /* Each output should probably just save the registers it touches, @@ -120,10 +120,10 @@ static void intel_dvo_save(struct drm_output *output) dvo->dev_ops->save(dvo); } -static void intel_dvo_restore(struct drm_output *output) +static void intel_dvo_restore(struct drm_connector *connector) { - struct drm_i915_private *dev_priv = output->dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; dvo->dev_ops->restore(dvo); @@ -133,10 +133,10 @@ static void intel_dvo_restore(struct drm_output *output) I915_WRITE(DVOC, dev_priv->saveDVOC); } -static int intel_dvo_mode_valid(struct drm_output *output, +static int intel_dvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; if (mode->flags & V_DBLSCAN) @@ -154,11 +154,11 @@ static int intel_dvo_mode_valid(struct drm_output *output, return dvo->dev_ops->mode_valid(dvo, mode); } -static bool intel_dvo_mode_fixup(struct drm_output *output, +static bool intel_dvo_mode_fixup(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; /* If we have timings from the BIOS for the panel, put them in @@ -187,14 +187,14 @@ static bool intel_dvo_mode_fixup(struct drm_output *output, return true; } -static void intel_dvo_mode_set(struct drm_output *output, +static void intel_dvo_mode_set(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(output->crtc); - struct intel_output *intel_output = to_intel_output(output); + struct intel_crtc *intel_crtc = to_intel_crtc(connector->crtc); + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; int pipe = intel_crtc->pipe; u32 dvo_val; @@ -247,17 +247,17 @@ static void intel_dvo_mode_set(struct drm_output *output, * * Unimplemented. */ -static enum drm_output_status intel_dvo_detect(struct drm_output *output) +static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; return dvo->dev_ops->detect(dvo); } -static int intel_dvo_get_modes(struct drm_output *output) +static int intel_dvo_get_modes(struct drm_connector *connector) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; /* We should probably have an i2c driver get_modes function for those @@ -265,8 +265,8 @@ static int intel_dvo_get_modes(struct drm_output *output) * (TV-out, for example), but for now with just TMDS and LVDS, * that's not the case. */ - intel_ddc_get_modes(output); - if (!list_empty(&output->probed_modes)) + intel_ddc_get_modes(intel_output); + if (!list_empty(&connector->probed_modes)) return 1; #if 0 @@ -280,18 +280,18 @@ static int intel_dvo_get_modes(struct drm_output *output) if (dvo->panel_fixed_mode != NULL) { struct drm_display_mode *mode; - mode = drm_mode_duplicate(output->dev, dvo->panel_fixed_mode); + mode = drm_mode_duplicate(connector->dev, dvo->panel_fixed_mode); if (mode) { - drm_mode_probed_add(output, mode); + drm_mode_probed_add(connector, mode); return 1; } } return 0; } -static void intel_dvo_destroy (struct drm_output *output) +static void intel_dvo_destroy (struct drm_connector *connector) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; if (dvo) { @@ -306,16 +306,16 @@ static void intel_dvo_destroy (struct drm_output *output) intel_i2c_destroy(intel_output->i2c_bus); if (intel_output->ddc_bus) intel_i2c_destroy(intel_output->ddc_bus); - drm_output_cleanup(output); - kfree(output); + drm_connector_cleanup(connector); + kfree(intel_output); } #ifdef RANDR_GET_CRTC_INTERFACE -static struct drm_crtc *intel_dvo_get_crtc(struct drm_output *output) +static struct drm_crtc *intel_dvo_get_crtc(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT); @@ -323,14 +323,14 @@ static struct drm_crtc *intel_dvo_get_crtc(struct drm_output *output) } #endif -static const struct drm_output_helper_funcs intel_dvo_helper_funcs = { +static const struct drm_connector_helper_funcs intel_dvo_helper_funcs = { .mode_fixup = intel_dvo_mode_fixup, - .prepare = intel_output_prepare, + .prepare = intel_connector_prepare, .mode_set = intel_dvo_mode_set, - .commit = intel_output_commit, + .commit = intel_connector_commit, }; -static const struct drm_output_funcs intel_dvo_output_funcs = { +static const struct drm_connector_funcs intel_dvo_connector_funcs = { .dpms = intel_dvo_dpms, .save = intel_dvo_save, .restore = intel_dvo_restore, @@ -340,6 +340,16 @@ static const struct drm_output_funcs intel_dvo_output_funcs = { .mode_valid = intel_dvo_mode_valid, }; +void intel_dvo_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs intel_dvo_enc_funcs = { + .destroy = intel_dvo_enc_destroy, +}; + + /** * Attempts to get a fixed panel timing for LVDS (currently only the i830). * @@ -347,11 +357,11 @@ static const struct drm_output_funcs intel_dvo_output_funcs = { * chip being on DVOB/C and having multiple pipes. */ static struct drm_display_mode * -intel_dvo_get_current_mode (struct drm_output *output) +intel_dvo_get_current_mode (struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; uint32_t dvo_reg = dvo->dvo_reg; uint32_t dvo_val = I915_READ(dvo_reg); @@ -388,8 +398,7 @@ void intel_dvo_init(struct drm_device *dev) int ret = 0; int i; int gpio_inited = 0; - int connector = ConnectorUnknown; - + int encoder_type = DRM_MODE_ENCODER_NONE; intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) return; @@ -401,7 +410,7 @@ void intel_dvo_init(struct drm_device *dev) /* Now, try to find a controller */ for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { - struct drm_output *output = &intel_output->base; + struct drm_connector *connector = &intel_output->base; int gpio; dvo = &intel_dvo_devices[i]; @@ -442,25 +451,28 @@ void intel_dvo_init(struct drm_device *dev) intel_output->type = INTEL_OUTPUT_DVO; switch (dvo->type) { case INTEL_DVO_CHIP_TMDS: - connector = ConnectorDVID; - drm_output_init(dev, output, &intel_dvo_output_funcs, - DRM_MODE_OUTPUT_TMDS); + // connector = DRM_MODE_CONNECTOR_DVID; + drm_connector_init(dev, connector, &intel_dvo_connector_funcs, + DRM_MODE_CONNECTOR_DVII); + encoder_type = DRM_MODE_ENCODER_TMDS; break; case INTEL_DVO_CHIP_LVDS: - connector = ConnectorLVDS; - drm_output_init(dev, output, &intel_dvo_output_funcs, - DRM_MODE_OUTPUT_LVDS); + // connector = DRM_MODE_CONNECTOR_LVDS; + drm_connector_init(dev, connector, &intel_dvo_connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + encoder_type = DRM_MODE_ENCODER_LVDS; break; } - drm_output_helper_add(output, &intel_dvo_helper_funcs); - output->display_info.subpixel_order = SubPixelHorizontalRGB; - output->interlace_allowed = false; - output->doublescan_allowed = false; + drm_connector_helper_add(connector, &intel_dvo_helper_funcs); + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; intel_output->dev_priv = dvo; intel_output->i2c_bus = i2cbus; + drm_encoder_init(dev, &intel_output->enc, &intel_dvo_enc_funcs, encoder_type); if (dvo->type == INTEL_DVO_CHIP_LVDS) { /* For our LVDS chipsets, we should hopefully be able * to dig the fixed panel mode out of the BIOS data. @@ -469,14 +481,11 @@ void intel_dvo_init(struct drm_device *dev) * headers, likely), so for now, just get the current * mode being output through DVO. */ - dvo->panel_fixed_mode = intel_dvo_get_current_mode(output); + dvo->panel_fixed_mode = intel_dvo_get_current_mode(connector); dvo->panel_wants_dither = true; } - drm_sysfs_output_add(output); - drm_output_attach_property(output, - dev->mode_config.connector_type_property, - connector); + drm_sysfs_connector_add(connector); return; } diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 05fc3b29..394d2344 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -53,7 +53,7 @@ struct intelfb_par { */ struct drm_display_mode *our_mode; struct drm_mode_set set; - struct drm_output *hack; + struct drm_connector *hack; }; /* static int @@ -114,7 +114,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; /*struct drm_device *dev = par->dev;*/ struct drm_framebuffer *fb = par->set.fb; - /*struct drm_output *output;*/ + /*struct drm_connector *connector;*/ int depth/*, found = 0*/; if (!var->pixclock) @@ -195,17 +195,17 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, } #if 0 - /* Here we walk the output mode list and look for modes. If we haven't + /* Here we walk the connector mode list and look for modes. If we haven't * got it, then bail. Not very nice, so this is disabled. * In the set_par code, we create our mode based on the incoming * parameters. Nicer, but may not be desired by some. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->crtc) + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->crtc == par->crtc) break; } - list_for_each_entry(drm_mode, &output->modes, head) { + list_for_each_entry(drm_mode, &connector->modes, head) { if (drm_mode->hdisplay == var->xres && drm_mode->vdisplay == var->yres && (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && @@ -230,7 +230,7 @@ static int intelfb_set_par(struct fb_info *info) struct drm_framebuffer *fb = par->set.fb; struct drm_device *dev = par->dev; struct drm_display_mode *drm_mode, *search_mode; - struct drm_output *output = NULL; + struct drm_connector *connector = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; @@ -276,20 +276,20 @@ static int intelfb_set_par(struct fb_info *info) drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); found = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) { - if (output->crtc == par->set.crtc){ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->crtc == par->set.crtc){ found = 1; break; } } - /* no output bound, bail */ + /* no connector bound, bail */ if (!found) return -EINVAL; found = 0; drm_mode_debug_printmodeline(drm_mode); - list_for_each_entry(search_mode, &output->modes, head) { + list_for_each_entry(search_mode, &connector->modes, head) { drm_mode_debug_printmodeline(search_mode); if (drm_mode_equal(drm_mode, search_mode)) { drm_mode_destroy(dev, drm_mode); @@ -299,7 +299,7 @@ static int intelfb_set_par(struct fb_info *info) } } - /* If we didn't find a matching mode that exists on our output, + /* If we didn't find a matching mode that exists on our connector, * create a new attachment for the incoming user specified mode */ if (!found) { @@ -566,7 +566,7 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_output *output) +int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector) { struct fb_info *info; struct intelfb_par *par; @@ -581,7 +581,7 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_outp return -EINVAL; } - if (!output) + if (!connector) return -EINVAL; fb = drm_framebuffer_create(dev); @@ -627,9 +627,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_outp par->dev = dev; par->set.crtc = crtc; par->set.fb = fb; - par->hack = output; - par->set.outputs = &par->hack; - par->set.num_outputs = 1; + par->hack = connector; + par->set.connectors = &par->hack; + par->set.num_connectors = 1; info->fbops = &intelfb_ops; diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 6781a47c..019c45fe 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -89,9 +89,9 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) } } -static void intel_lvds_dpms(struct drm_output *output, int mode) +static void intel_lvds_dpms(struct drm_connector *connector, int mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; if (mode == DPMSModeOn) intel_lvds_set_power(dev, true); @@ -101,9 +101,9 @@ static void intel_lvds_dpms(struct drm_output *output, int mode) /* XXX: We never power down the LVDS pairs. */ } -static void intel_lvds_save(struct drm_output *output) +static void intel_lvds_save(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS); @@ -122,9 +122,9 @@ static void intel_lvds_save(struct drm_output *output) intel_lvds_get_max_backlight(dev); } -static void intel_lvds_restore(struct drm_output *output) +static void intel_lvds_restore(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); @@ -138,10 +138,10 @@ static void intel_lvds_restore(struct drm_output *output) intel_lvds_set_power(dev, false); } -static int intel_lvds_mode_valid(struct drm_output *output, +static int intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; @@ -155,14 +155,14 @@ static int intel_lvds_mode_valid(struct drm_output *output, return MODE_OK; } -static bool intel_lvds_mode_fixup(struct drm_output *output, +static bool intel_lvds_mode_fixup(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(output->crtc); - struct drm_output *tmp_output; + struct intel_crtc *intel_crtc = to_intel_crtc(connector->crtc); + struct drm_connector *tmp_connector; /* Should never happen!! */ if (!IS_I965G(dev) && intel_crtc->pipe == 0) { @@ -171,10 +171,10 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, } /* Should never happen!! */ - list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) { - if (tmp_output != output && tmp_output->crtc == output->crtc) { + list_for_each_entry(tmp_connector, &dev->mode_config.connector_list, head) { + if (tmp_connector != connector && tmp_connector->crtc == connector->crtc) { printk(KERN_ERR "Can't enable LVDS and another " - "output on the same pipe\n"); + "connector on the same pipe\n"); return false; } } @@ -211,9 +211,9 @@ static bool intel_lvds_mode_fixup(struct drm_output *output, return true; } -static void intel_lvds_prepare(struct drm_output *output) +static void intel_lvds_prepare(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); @@ -223,9 +223,9 @@ static void intel_lvds_prepare(struct drm_output *output) intel_lvds_set_power(dev, false); } -static void intel_lvds_commit( struct drm_output *output) +static void intel_lvds_commit( struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->backlight_duty_cycle == 0) @@ -235,13 +235,13 @@ static void intel_lvds_commit( struct drm_output *output) intel_lvds_set_power(dev, true); } -static void intel_lvds_mode_set(struct drm_output *output, +static void intel_lvds_mode_set(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(output->crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(connector->crtc); u32 pfit_control; /* @@ -276,24 +276,25 @@ static void intel_lvds_mode_set(struct drm_output *output, /** * Detect the LVDS connection. * - * This always returns OUTPUT_STATUS_CONNECTED. This output should only have + * This always returns CONNECTOR_STATUS_CONNECTED. This connector should only have * been set up if the LVDS was actually connected anyway. */ -static enum drm_output_status intel_lvds_detect(struct drm_output *output) +static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector) { - return output_status_connected; + return connector_status_connected; } /** * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. */ -static int intel_lvds_get_modes(struct drm_output *output) +static int intel_lvds_get_modes(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; + struct intel_output *intel_output = to_intel_output(connector); struct drm_i915_private *dev_priv = dev->dev_private; int ret = 0; - ret = intel_ddc_get_modes(output); + ret = intel_ddc_get_modes(intel_output); if (ret) return ret; @@ -302,15 +303,15 @@ static int intel_lvds_get_modes(struct drm_output *output) * Set wide sync ranges so we get all modes * handed to valid_mode for checking */ - output->display_info.min_vfreq = 0; - output->display_info.max_vfreq = 200; - output->display_info.min_hfreq = 0; - output->display_info.max_hfreq = 200; + connector->display_info.min_vfreq = 0; + connector->display_info.max_vfreq = 200; + connector->display_info.min_hfreq = 0; + connector->display_info.max_hfreq = 200; if (dev_priv->panel_fixed_mode != NULL) { struct drm_display_mode *mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); - drm_mode_probed_add(output, mode); + drm_mode_probed_add(connector, mode); return 1; } @@ -319,28 +320,28 @@ static int intel_lvds_get_modes(struct drm_output *output) /** * intel_lvds_destroy - unregister and free LVDS structures - * @output: output to free + * @connector: connector to free * - * Unregister the DDC bus for this output then free the driver private + * Unregister the DDC bus for this connector then free the driver private * structure. */ -static void intel_lvds_destroy(struct drm_output *output) +static void intel_lvds_destroy(struct drm_connector *connector) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); intel_i2c_destroy(intel_output->ddc_bus); - drm_output_cleanup(output); - kfree(output); + drm_connector_cleanup(connector); + kfree(connector); } -static const struct drm_output_helper_funcs intel_lvds_helper_funcs = { +static const struct drm_connector_helper_funcs intel_lvds_helper_funcs = { .mode_fixup = intel_lvds_mode_fixup, .prepare = intel_lvds_prepare, .mode_set = intel_lvds_mode_set, .commit = intel_lvds_commit, }; -static const struct drm_output_funcs intel_lvds_output_funcs = { +static const struct drm_connector_funcs intel_lvds_connector_funcs = { .dpms = intel_lvds_dpms, .save = intel_lvds_save, .restore = intel_lvds_restore, @@ -350,18 +351,28 @@ static const struct drm_output_funcs intel_lvds_output_funcs = { .mode_valid = intel_lvds_mode_valid, }; + +static void intel_lvds_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs intel_lvds_enc_funcs = { + .destroy = intel_lvds_enc_destroy, +}; + /** - * intel_lvds_init - setup LVDS outputs on this device + * intel_lvds_init - setup LVDS connectors on this device * @dev: drm device * - * Create the output, register the LVDS DDC bus, and try to figure out what + * Create the connector, register the LVDS DDC bus, and try to figure out what * modes we can display on the LVDS panel (if present). */ void intel_lvds_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_output *intel_output; - struct drm_output *output; + struct drm_connector *connector; struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; u32 lvds; @@ -372,16 +383,19 @@ void intel_lvds_init(struct drm_device *dev) return; } - output = &intel_output->base; - drm_output_init(dev, &intel_output->base, &intel_lvds_output_funcs, - DRM_MODE_OUTPUT_LVDS); + connector = &intel_output->base; + drm_connector_init(dev, &intel_output->base, &intel_lvds_connector_funcs, + DRM_MODE_CONNECTOR_LVDS); + + drm_encoder_init(dev, &intel_output->enc, &intel_lvds_enc_funcs, + DRM_MODE_ENCODER_LVDS); intel_output->type = INTEL_OUTPUT_LVDS; - drm_output_helper_add(output, &intel_lvds_helper_funcs); - output->display_info.subpixel_order = SubPixelHorizontalRGB; - output->interlace_allowed = FALSE; - output->doublescan_allowed = FALSE; + drm_connector_helper_add(connector, &intel_lvds_helper_funcs); + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + connector->interlace_allowed = FALSE; + connector->doublescan_allowed = FALSE; /* @@ -399,7 +413,7 @@ void intel_lvds_init(struct drm_device *dev) if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); - intel_lvds_destroy(output); + intel_lvds_destroy(connector); return; } @@ -407,9 +421,9 @@ void intel_lvds_init(struct drm_device *dev) * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ - intel_ddc_get_modes(output); + intel_ddc_get_modes(intel_output); - list_for_each_entry(scan, &output->probed_modes, head) { + list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { dev_priv->panel_fixed_mode = drm_mode_duplicate(dev, scan); @@ -481,11 +495,10 @@ void intel_lvds_init(struct drm_device *dev) #endif out: - drm_sysfs_output_add(output); - drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorLVDS); + drm_sysfs_connector_add(connector); return; failed: DRM_DEBUG("No LVDS modes found, disabling.\n"); - intel_lvds_destroy(output); + intel_lvds_destroy(connector); } diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c index 8e9a506a..79be3575 100644 --- a/linux-core/intel_modes.c +++ b/linux-core/intel_modes.c @@ -13,9 +13,8 @@ * intel_ddc_probe * */ -bool intel_ddc_probe(struct drm_output *output) +bool intel_ddc_probe(struct intel_output *intel_output) { - struct intel_output *intel_output = to_intel_output(output); u8 out_buf[] = { 0x0, 0x0}; u8 buf[2]; int ret; @@ -43,20 +42,19 @@ bool intel_ddc_probe(struct drm_output *output) /** * intel_ddc_get_modes - get modelist from monitor - * @output: DRM output device to use + * @connector: DRM connector device to use * - * Fetch the EDID information from @output using the DDC bus. + * Fetch the EDID information from @connector using the DDC bus. */ -int intel_ddc_get_modes(struct drm_output *output) +int intel_ddc_get_modes(struct intel_output *intel_output) { - struct intel_output *intel_output = to_intel_output(output); struct edid *edid; int ret = 0; - edid = drm_get_edid(output, &intel_output->ddc_bus->adapter); + edid = drm_get_edid(&intel_output->base, &intel_output->ddc_bus->adapter); if (edid) { - drm_mode_output_update_edid_property(output, edid); - ret = drm_add_edid_modes(output, edid); + drm_mode_connector_update_edid_property(&intel_output->base, edid); + ret = drm_add_edid_modes(&intel_output->base, edid); kfree(edid); } return ret; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 2b232e9a..85bee96b 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -60,11 +60,10 @@ struct intel_sdvo_priv { * SDVOB and SDVOC to work around apparent hardware issues (according to * comments in the BIOS). */ -void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) +void intel_sdvo_write_sdvox(struct intel_output *intel_output, u32 val) { - struct drm_device *dev = output->dev; + struct drm_device *dev = intel_output->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u32 bval = val, cval = val; int i; @@ -88,10 +87,9 @@ void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) } } -static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr, +static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr, u8 *ch) { - struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u8 out_buf[2]; u8 buf[2]; @@ -126,10 +124,9 @@ static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr, return false; } -static bool intel_sdvo_write_byte(struct drm_output *output, int addr, +static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr, u8 ch) { - struct intel_output *intel_output = to_intel_output(output); u8 out_buf[2]; struct i2c_msg msgs[] = { { @@ -198,10 +195,9 @@ const static struct _sdvo_cmd_name { #define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC") #define SDVO_PRIV(output) ((struct intel_sdvo_priv *) (output)->dev_priv) -static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd, +static void intel_sdvo_write_cmd(struct intel_output *intel_output, u8 cmd, void *args, int args_len) { - struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; @@ -223,10 +219,10 @@ static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd, } for (i = 0; i < args_len; i++) { - intel_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]); + intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]); } - intel_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd); + intel_sdvo_write_byte(intel_output, SDVO_I2C_OPCODE, cmd); } static const char *cmd_status_names[] = { @@ -239,10 +235,9 @@ static const char *cmd_status_names[] = { "Scaling not supported" }; -static u8 intel_sdvo_read_response(struct drm_output *output, void *response, +static u8 intel_sdvo_read_response(struct intel_output *intel_output, void *response, int response_len) { - struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; u8 status; @@ -251,12 +246,12 @@ static u8 intel_sdvo_read_response(struct drm_output *output, void *response, while (retry--) { /* Read the command response */ for (i = 0; i < response_len; i++) { - intel_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i, + intel_sdvo_read_byte(intel_output, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i]); } /* read the return status */ - intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status); + intel_sdvo_read_byte(intel_output, SDVO_I2C_CMD_STATUS, &status); if (1) { DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv)); @@ -295,12 +290,12 @@ int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) * SDVO chips which defeats the purpose of doing a bus switch in the first * place. */ -void intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target) +void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output, u8 target) { - intel_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); } -static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0, bool target_1) +static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1) { struct intel_sdvo_set_target_input_args targets = {0}; u8 status; @@ -311,10 +306,10 @@ static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0 if (target_1) targets.target_1 = 1; - intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets, + intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_INPUT, &targets, sizeof(targets)); - status = intel_sdvo_read_response(output, NULL, 0); + status = intel_sdvo_read_response(intel_output, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } @@ -325,13 +320,13 @@ static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0 * This function is making an assumption about the layout of the response, * which should be checked against the docs. */ -static bool intel_sdvo_get_trained_inputs(struct drm_output *output, bool *input_1, bool *input_2) +static bool intel_sdvo_get_trained_inputs(struct intel_output *intel_output, bool *input_1, bool *input_2) { struct intel_sdvo_get_trained_inputs_response response; u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); - status = intel_sdvo_read_response(output, &response, sizeof(response)); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); + status = intel_sdvo_read_response(intel_output, &response, sizeof(response)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -340,29 +335,29 @@ static bool intel_sdvo_get_trained_inputs(struct drm_output *output, bool *input return true; } -static bool intel_sdvo_get_active_outputs(struct drm_output *output, +static bool intel_sdvo_get_active_outputs(struct intel_output *intel_output, u16 *outputs) { u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); - status = intel_sdvo_read_response(output, outputs, sizeof(*outputs)); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); + status = intel_sdvo_read_response(intel_output, outputs, sizeof(*outputs)); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_set_active_outputs(struct drm_output *output, +static bool intel_sdvo_set_active_outputs(struct intel_output *intel_output, u16 outputs) { u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, + intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, sizeof(outputs)); - status = intel_sdvo_read_response(output, NULL, 0); + status = intel_sdvo_read_response(intel_output, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_set_encoder_power_state(struct drm_output *output, +static bool intel_sdvo_set_encoder_power_state(struct intel_output *intel_output, int mode) { u8 status, state = SDVO_ENCODER_STATE_ON; @@ -382,24 +377,24 @@ static bool intel_sdvo_set_encoder_power_state(struct drm_output *output, break; } - intel_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, + intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state)); - status = intel_sdvo_read_response(output, NULL, 0); + status = intel_sdvo_read_response(intel_output, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_get_input_pixel_clock_range(struct drm_output *output, +static bool intel_sdvo_get_input_pixel_clock_range(struct intel_output *intel_output, int *clock_min, int *clock_max) { struct intel_sdvo_pixel_clock_range clocks; u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, NULL, 0); - status = intel_sdvo_read_response(output, &clocks, sizeof(clocks)); + status = intel_sdvo_read_response(intel_output, &clocks, sizeof(clocks)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -411,31 +406,31 @@ static bool intel_sdvo_get_input_pixel_clock_range(struct drm_output *output, return true; } -static bool intel_sdvo_set_target_output(struct drm_output *output, +static bool intel_sdvo_set_target_output(struct intel_output *intel_output, u16 outputs) { u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, + intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, sizeof(outputs)); - status = intel_sdvo_read_response(output, NULL, 0); + status = intel_sdvo_read_response(intel_output, NULL, 0); return (status == SDVO_CMD_STATUS_SUCCESS); } -static bool intel_sdvo_get_timing(struct drm_output *output, u8 cmd, +static bool intel_sdvo_get_timing(struct intel_output *intel_output, u8 cmd, struct intel_sdvo_dtd *dtd) { u8 status; - intel_sdvo_write_cmd(output, cmd, NULL, 0); - status = intel_sdvo_read_response(output, &dtd->part1, + intel_sdvo_write_cmd(intel_output, cmd, NULL, 0); + status = intel_sdvo_read_response(intel_output, &dtd->part1, sizeof(dtd->part1)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; - intel_sdvo_write_cmd(output, cmd + 1, NULL, 0); - status = intel_sdvo_read_response(output, &dtd->part2, + intel_sdvo_write_cmd(intel_output, cmd + 1, NULL, 0); + status = intel_sdvo_read_response(intel_output, &dtd->part2, sizeof(dtd->part2)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -443,71 +438,70 @@ static bool intel_sdvo_get_timing(struct drm_output *output, u8 cmd, return true; } -static bool intel_sdvo_get_input_timing(struct drm_output *output, +static bool intel_sdvo_get_input_timing(struct intel_output *intel_output, struct intel_sdvo_dtd *dtd) { - return intel_sdvo_get_timing(output, + return intel_sdvo_get_timing(intel_output, SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); } -static bool intel_sdvo_get_output_timing(struct drm_output *output, +static bool intel_sdvo_get_output_timing(struct intel_output *intel_output, struct intel_sdvo_dtd *dtd) { - return intel_sdvo_get_timing(output, + return intel_sdvo_get_timing(intel_output, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); } -static bool intel_sdvo_set_timing(struct drm_output *output, u8 cmd, +static bool intel_sdvo_set_timing(struct intel_output *intel_output, u8 cmd, struct intel_sdvo_dtd *dtd) { u8 status; - intel_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1)); - status = intel_sdvo_read_response(output, NULL, 0); + intel_sdvo_write_cmd(intel_output, cmd, &dtd->part1, sizeof(dtd->part1)); + status = intel_sdvo_read_response(intel_output, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; - intel_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); - status = intel_sdvo_read_response(output, NULL, 0); + intel_sdvo_write_cmd(intel_output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); + status = intel_sdvo_read_response(intel_output, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -static bool intel_sdvo_set_input_timing(struct drm_output *output, +static bool intel_sdvo_set_input_timing(struct intel_output *intel_output, struct intel_sdvo_dtd *dtd) { - return intel_sdvo_set_timing(output, + return intel_sdvo_set_timing(intel_output, SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); } -static bool intel_sdvo_set_output_timing(struct drm_output *output, +static bool intel_sdvo_set_output_timing(struct intel_output *intel_output, struct intel_sdvo_dtd *dtd) { - return intel_sdvo_set_timing(output, + return intel_sdvo_set_timing(intel_output, SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); } #if 0 -static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output, +static bool intel_sdvo_get_preferred_input_timing(struct intel_output *intel_output, struct intel_sdvo_dtd *dtd) { - struct intel_output *intel_output = to_intel_output(output); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, NULL, 0); - status = intel_sdvo_read_response(output, &dtd->part1, + status = intel_sdvo_read_response(intel_output, &dtd->part1, sizeof(dtd->part1)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, NULL, 0); - status = intel_sdvo_read_response(output, &dtd->part2, + status = intel_sdvo_read_response(intel_output, &dtd->part2, sizeof(dtd->part2)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; @@ -516,12 +510,12 @@ static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output, } #endif -static int intel_sdvo_get_clock_rate_mult(struct drm_output *output) +static int intel_sdvo_get_clock_rate_mult(struct intel_output *intel_output) { u8 response, status; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); - status = intel_sdvo_read_response(output, &response, 1); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); + status = intel_sdvo_read_response(intel_output, &response, 1); if (status != SDVO_CMD_STATUS_SUCCESS) { DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n"); @@ -533,19 +527,19 @@ static int intel_sdvo_get_clock_rate_mult(struct drm_output *output) return response; } -static bool intel_sdvo_set_clock_rate_mult(struct drm_output *output, u8 val) +static bool intel_sdvo_set_clock_rate_mult(struct intel_output *intel_output, u8 val) { u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); - status = intel_sdvo_read_response(output, NULL, 0); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); + status = intel_sdvo_read_response(intel_output, NULL, 0); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -static bool intel_sdvo_mode_fixup(struct drm_output *output, +static bool intel_sdvo_mode_fixup(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { @@ -556,15 +550,15 @@ static bool intel_sdvo_mode_fixup(struct drm_output *output, return true; } -static void intel_sdvo_mode_set(struct drm_output *output, +static void intel_sdvo_mode_set(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = output->crtc; + struct drm_crtc *crtc = connector->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u16 width, height; u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; @@ -618,11 +612,11 @@ static void intel_sdvo_mode_set(struct drm_output *output, output_dtd.part2.reserved = 0; /* Set the output timing to the screen */ - intel_sdvo_set_target_output(output, sdvo_priv->active_outputs); - intel_sdvo_set_output_timing(output, &output_dtd); + intel_sdvo_set_target_output(intel_output, sdvo_priv->active_outputs); + intel_sdvo_set_output_timing(intel_output, &output_dtd); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(output, true, false); + intel_sdvo_set_target_input(intel_output, true, false); /* We would like to use i830_sdvo_create_preferred_input_timing() to * provide the device with a timing it can support, if it supports that @@ -630,29 +624,29 @@ static void intel_sdvo_mode_set(struct drm_output *output, * output the preferred timing, and we don't support that currently. */ #if 0 - success = intel_sdvo_create_preferred_input_timing(output, clock, + success = intel_sdvo_create_preferred_input_timing(connector, clock, width, height); if (success) { struct intel_sdvo_dtd *input_dtd; - intel_sdvo_get_preferred_input_timing(output, &input_dtd); - intel_sdvo_set_input_timing(output, &input_dtd); + intel_sdvo_get_preferred_input_timing(connector, &input_dtd); + intel_sdvo_set_input_timing(connector, &input_dtd); } #else - intel_sdvo_set_input_timing(output, &output_dtd); + intel_sdvo_set_input_timing(intel_output, &output_dtd); #endif switch (intel_sdvo_get_pixel_multiplier(mode)) { case 1: - intel_sdvo_set_clock_rate_mult(output, + intel_sdvo_set_clock_rate_mult(intel_output, SDVO_CLOCK_RATE_MULT_1X); break; case 2: - intel_sdvo_set_clock_rate_mult(output, + intel_sdvo_set_clock_rate_mult(intel_output, SDVO_CLOCK_RATE_MULT_2X); break; case 4: - intel_sdvo_set_clock_rate_mult(output, + intel_sdvo_set_clock_rate_mult(intel_output, SDVO_CLOCK_RATE_MULT_4X); break; } @@ -686,26 +680,26 @@ static void intel_sdvo_mode_set(struct drm_output *output, sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; } - intel_sdvo_write_sdvox(output, sdvox); + intel_sdvo_write_sdvox(intel_output, sdvox); } -static void intel_sdvo_dpms(struct drm_output *output, int mode) +static void intel_sdvo_dpms(struct drm_connector *connector, int mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u32 temp; if (mode != DPMSModeOn) { - intel_sdvo_set_active_outputs(output, 0); + intel_sdvo_set_active_outputs(intel_output, 0); if (0) - intel_sdvo_set_encoder_power_state(output, mode); + intel_sdvo_set_encoder_power_state(intel_output, mode); if (mode == DPMSModeOff) { temp = I915_READ(sdvo_priv->output_device); if ((temp & SDVO_ENABLE) != 0) { - intel_sdvo_write_sdvox(output, temp & ~SDVO_ENABLE); + intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE); } } } else { @@ -715,11 +709,11 @@ static void intel_sdvo_dpms(struct drm_output *output, int mode) temp = I915_READ(sdvo_priv->output_device); if ((temp & SDVO_ENABLE) == 0) - intel_sdvo_write_sdvox(output, temp | SDVO_ENABLE); + intel_sdvo_write_sdvox(intel_output, temp | SDVO_ENABLE); for (i = 0; i < 2; i++) intel_wait_for_vblank(dev); - status = intel_sdvo_get_trained_inputs(output, &input1, + status = intel_sdvo_get_trained_inputs(intel_output, &input1, &input2); @@ -733,32 +727,32 @@ static void intel_sdvo_dpms(struct drm_output *output, int mode) } if (0) - intel_sdvo_set_encoder_power_state(output, mode); - intel_sdvo_set_active_outputs(output, sdvo_priv->active_outputs); + intel_sdvo_set_encoder_power_state(intel_output, mode); + intel_sdvo_set_active_outputs(intel_output, sdvo_priv->active_outputs); } return; } -static void intel_sdvo_save(struct drm_output *output) +static void intel_sdvo_save(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int o; - sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(output); - intel_sdvo_get_active_outputs(output, &sdvo_priv->save_active_outputs); + sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_output); + intel_sdvo_get_active_outputs(intel_output, &sdvo_priv->save_active_outputs); if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { - intel_sdvo_set_target_input(output, true, false); - intel_sdvo_get_input_timing(output, + intel_sdvo_set_target_input(intel_output, true, false); + intel_sdvo_get_input_timing(intel_output, &sdvo_priv->save_input_dtd_1); } if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { - intel_sdvo_set_target_input(output, false, true); - intel_sdvo_get_input_timing(output, + intel_sdvo_set_target_input(intel_output, false, true); + intel_sdvo_get_input_timing(intel_output, &sdvo_priv->save_input_dtd_2); } @@ -767,8 +761,8 @@ static void intel_sdvo_save(struct drm_output *output) u16 this_output = (1 << o); if (sdvo_priv->caps.output_flags & this_output) { - intel_sdvo_set_target_output(output, this_output); - intel_sdvo_get_output_timing(output, + intel_sdvo_set_target_output(intel_output, this_output); + intel_sdvo_get_output_timing(intel_output, &sdvo_priv->save_output_dtd[o]); } } @@ -776,39 +770,39 @@ static void intel_sdvo_save(struct drm_output *output) sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device); } -static void intel_sdvo_restore(struct drm_output *output) +static void intel_sdvo_restore(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int o; int i; bool input1, input2; u8 status; - intel_sdvo_set_active_outputs(output, 0); + intel_sdvo_set_active_outputs(intel_output, 0); for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) { u16 this_output = (1 << o); if (sdvo_priv->caps.output_flags & this_output) { - intel_sdvo_set_target_output(output, this_output); - intel_sdvo_set_output_timing(output, &sdvo_priv->save_output_dtd[o]); + intel_sdvo_set_target_output(intel_output, this_output); + intel_sdvo_set_output_timing(intel_output, &sdvo_priv->save_output_dtd[o]); } } if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { - intel_sdvo_set_target_input(output, true, false); - intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_1); + intel_sdvo_set_target_input(intel_output, true, false); + intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_1); } if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { - intel_sdvo_set_target_input(output, false, true); - intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_2); + intel_sdvo_set_target_input(intel_output, false, true); + intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_2); } - intel_sdvo_set_clock_rate_mult(output, sdvo_priv->save_sdvo_mult); + intel_sdvo_set_clock_rate_mult(intel_output, sdvo_priv->save_sdvo_mult); I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX); @@ -816,19 +810,19 @@ static void intel_sdvo_restore(struct drm_output *output) { for (i = 0; i < 2; i++) intel_wait_for_vblank(dev); - status = intel_sdvo_get_trained_inputs(output, &input1, &input2); + status = intel_sdvo_get_trained_inputs(intel_output, &input1, &input2); if (status == SDVO_CMD_STATUS_SUCCESS && !input1) DRM_DEBUG("First %s output reported failure to sync\n", SDVO_NAME(sdvo_priv)); } - intel_sdvo_set_active_outputs(output, sdvo_priv->save_active_outputs); + intel_sdvo_set_active_outputs(intel_output, sdvo_priv->save_active_outputs); } -static int intel_sdvo_mode_valid(struct drm_output *output, +static int intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; if (mode->flags & V_DBLSCAN) @@ -843,27 +837,27 @@ static int intel_sdvo_mode_valid(struct drm_output *output, return MODE_OK; } -static bool intel_sdvo_get_capabilities(struct drm_output *output, struct intel_sdvo_caps *caps) +static bool intel_sdvo_get_capabilities(struct intel_output *intel_output, struct intel_sdvo_caps *caps) { u8 status; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); - status = intel_sdvo_read_response(output, caps, sizeof(*caps)); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); + status = intel_sdvo_read_response(intel_output, caps, sizeof(*caps)); if (status != SDVO_CMD_STATUS_SUCCESS) return false; return true; } -struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB) +struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB) { - struct drm_output *output = 0; - struct intel_output *iout = 0; + struct drm_connector *connector = NULL; + struct intel_output *iout = NULL; struct intel_sdvo_priv *sdvo; - /* find the sdvo output */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - iout = to_intel_output(output); + /* find the sdvo connector */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + iout = to_intel_output(connector); if (iout->type != INTEL_OUTPUT_SDVO) continue; @@ -871,27 +865,30 @@ struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB) sdvo = iout->dev_priv; if (sdvo->output_device == SDVOB && sdvoB) - return output; + return connector; if (sdvo->output_device == SDVOC && !sdvoB) - return output; + return connector; - } - - return 0; + } + + return NULL; } -int intel_sdvo_supports_hotplug(struct drm_output *output) +int intel_sdvo_supports_hotplug(struct drm_connector *connector) { u8 response[2]; u8 status; + struct intel_output *intel_output; DRM_DEBUG("\n"); - if (!output) + if (!connector) return 0; - intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(output, &response, 2); + intel_output = to_intel_output(connector); + + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); + status = intel_sdvo_read_response(intel_output, &response, 2); if (response[0] !=0) return 1; @@ -899,51 +896,55 @@ int intel_sdvo_supports_hotplug(struct drm_output *output) return 0; } -void intel_sdvo_set_hotplug(struct drm_output *output, int on) +void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) { u8 response[2]; u8 status; + struct intel_output *intel_output = to_intel_output(connector); - intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - intel_sdvo_read_response(output, &response, 2); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); + intel_sdvo_read_response(intel_output, &response, 2); if (on) { - intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(output, &response, 2); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); + status = intel_sdvo_read_response(intel_output, &response, 2); - intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); } else { response[0] = 0; response[1] = 0; - intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); } - intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - intel_sdvo_read_response(output, &response, 2); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); + intel_sdvo_read_response(intel_output, &response, 2); } -static enum drm_output_status intel_sdvo_detect(struct drm_output *output) +static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) { u8 response[2]; u8 status; + struct intel_output *intel_output = to_intel_output(connector); - intel_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); - status = intel_sdvo_read_response(output, &response, 2); + intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); + status = intel_sdvo_read_response(intel_output, &response, 2); DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); if ((response[0] != 0) || (response[1] != 0)) - return output_status_connected; + return connector_status_connected; else - return output_status_disconnected; + return connector_status_disconnected; } -static int intel_sdvo_get_modes(struct drm_output *output) +static int intel_sdvo_get_modes(struct drm_connector *connector) { + struct intel_output *intel_output = to_intel_output(connector); + /* set the bus switch and get the modes */ - intel_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2); - intel_ddc_get_modes(output); + intel_sdvo_set_control_bus_switch(intel_output, SDVO_CONTROL_BUS_DDC2); + intel_ddc_get_modes(intel_output); - if (list_empty(&output->probed_modes)) + if (list_empty(&connector->probed_modes)) return 0; return 1; #if 0 @@ -959,25 +960,25 @@ static int intel_sdvo_get_modes(struct drm_output *output) #endif } -static void intel_sdvo_destroy(struct drm_output *output) +static void intel_sdvo_destroy(struct drm_connector *connector) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); if (intel_output->i2c_bus) intel_i2c_destroy(intel_output->i2c_bus); - drm_output_cleanup(output); + drm_connector_cleanup(connector); kfree(intel_output); } -static const struct drm_output_helper_funcs intel_sdvo_helper_funcs = { +static const struct drm_connector_helper_funcs intel_sdvo_helper_funcs = { .mode_fixup = intel_sdvo_mode_fixup, - .prepare = intel_output_prepare, + .prepare = intel_connector_prepare, .mode_set = intel_sdvo_mode_set, - .commit = intel_output_commit, + .commit = intel_connector_commit, }; -static const struct drm_output_funcs intel_sdvo_output_funcs = { +static const struct drm_connector_funcs intel_sdvo_connector_funcs = { .dpms = intel_sdvo_dpms, .save = intel_sdvo_save, .restore = intel_sdvo_restore, @@ -987,32 +988,43 @@ static const struct drm_output_funcs intel_sdvo_output_funcs = { .mode_valid = intel_sdvo_mode_valid, }; + +void intel_sdvo_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { + .destroy = intel_sdvo_enc_destroy, +}; + + void intel_sdvo_init(struct drm_device *dev, int output_device) { - struct drm_output *output; + struct drm_connector *connector; struct intel_output *intel_output; struct intel_sdvo_priv *sdvo_priv; struct intel_i2c_chan *i2cbus = NULL; int connector_type; u8 ch[0x40]; int i; - int output_type, output_id; + int encoder_type, output_id; intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); if (!intel_output) { return; } - output = &intel_output->base; + connector = &intel_output->base; - drm_output_init(dev, output, &intel_sdvo_output_funcs, - DRM_MODE_OUTPUT_NONE); + drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, + DRM_MODE_CONNECTOR_Unknown); sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_SDVO; - drm_output_helper_add(output, &intel_sdvo_helper_funcs); - output->interlace_allowed = 0; - output->doublescan_allowed = 0; + drm_connector_helper_add(connector, &intel_sdvo_helper_funcs); + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; /* setup the DDC bus. */ if (output_device == SDVOB) @@ -1021,7 +1033,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); if (i2cbus == NULL) { - intel_sdvo_destroy(output); + intel_sdvo_destroy(connector); return; } @@ -1042,15 +1054,15 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { - if (!intel_sdvo_read_byte(output, i, &ch[i])) { + if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { DRM_DEBUG("No SDVO device found on SDVO%c\n", output_device == SDVOB ? 'B' : 'C'); - intel_sdvo_destroy(output); + intel_sdvo_destroy(connector); return; } } - intel_sdvo_get_capabilities(output, &sdvo_priv->caps); + intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); @@ -1058,30 +1070,30 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; - output->display_info.subpixel_order = SubPixelHorizontalRGB; - output_type = DRM_MODE_OUTPUT_VGA; - connector_type = ConnectorVGA; + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + encoder_type = DRM_MODE_ENCODER_DAC; + connector_type = DRM_MODE_CONNECTOR_VGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) { sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; - output->display_info.subpixel_order = SubPixelHorizontalRGB; - output_type = DRM_MODE_OUTPUT_VGA; - connector_type = ConnectorVGA; + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + encoder_type = DRM_MODE_ENCODER_DAC; + connector_type = DRM_MODE_CONNECTOR_VGA; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; - output->display_info.subpixel_order = SubPixelHorizontalRGB; - output_type = DRM_MODE_OUTPUT_TMDS; - connector_type = ConnectorDVID; + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + encoder_type = DRM_MODE_ENCODER_TMDS; + connector_type = DRM_MODE_CONNECTOR_DVID; } else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) { sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; - output->display_info.subpixel_order = SubPixelHorizontalRGB; - output_type = DRM_MODE_OUTPUT_TMDS; - connector_type = ConnectorDVID; + connector->display_info.subpixel_order = SubPixelHorizontalRGB; + encoder_type = DRM_MODE_ENCODER_TMDS; + connector_type = DRM_MODE_CONNECTOR_DVID; } else { @@ -1091,19 +1103,19 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", SDVO_NAME(sdvo_priv), bytes[0], bytes[1]); - intel_sdvo_destroy(output); + intel_sdvo_destroy(connector); return; } - output->output_type = output_type; - output->output_type_id = output_id; + drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); + connector->connector_type = connector_type; - drm_sysfs_output_add(output); + drm_sysfs_connector_add(connector); /* Set the input timing to the screen. Assume always input 0. */ - intel_sdvo_set_target_input(output, true, false); + intel_sdvo_set_target_input(intel_output, true, false); - intel_sdvo_get_input_pixel_clock_range(output, + intel_sdvo_get_input_pixel_clock_range(intel_output, &sdvo_priv->pixel_clock_min, &sdvo_priv->pixel_clock_max); @@ -1127,5 +1139,4 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) intel_output->ddc_bus = i2cbus; - drm_output_attach_property(output, dev->mode_config.connector_type_property, connector_type); } diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index e3e78a9f..330c204a 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -898,9 +898,9 @@ const static struct tv_mode tv_modes[] = { #define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0]) static void -intel_tv_dpms(struct drm_output *output, int mode) +intel_tv_dpms(struct drm_connector *connector, int mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; switch(mode) { @@ -916,11 +916,11 @@ intel_tv_dpms(struct drm_output *output, int mode) } static void -intel_tv_save(struct drm_output *output) +intel_tv_save(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_tv_priv *tv_priv = intel_output->dev_priv; int i; @@ -966,13 +966,13 @@ intel_tv_save(struct drm_output *output) } static void -intel_tv_restore(struct drm_output *output) +intel_tv_restore(struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_tv_priv *tv_priv = intel_output->dev_priv; - struct drm_crtc *crtc = output->crtc; + struct drm_crtc *crtc = connector->crtc; struct intel_crtc *intel_crtc; int i; @@ -1067,18 +1067,18 @@ intel_tv_mode_lookup (char *tv_format) } static const struct tv_mode * -intel_tv_mode_find (struct drm_output *output) +intel_tv_mode_find (struct intel_output *intel_output) { - struct intel_output *intel_output = to_intel_output(output); struct intel_tv_priv *tv_priv = intel_output->dev_priv; return intel_tv_mode_lookup(tv_priv->tv_format); } static enum drm_mode_status -intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode) +intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - const struct tv_mode *tv_mode = intel_tv_mode_find(output); + struct intel_output *intel_output = to_intel_output(connector); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); /* Ensure TV refresh is close to desired refresh */ if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1) @@ -1088,21 +1088,22 @@ intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode) static bool -intel_tv_mode_fixup(struct drm_output *output, struct drm_display_mode *mode, +intel_tv_mode_fixup(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_mode_config *drm_config = &dev->mode_config; - const struct tv_mode *tv_mode = intel_tv_mode_find (output); - struct drm_output *other_output; + struct intel_output *intel_output = to_intel_output(connector); + const struct tv_mode *tv_mode = intel_tv_mode_find (intel_output); + struct drm_connector *other_connector; if (!tv_mode) return FALSE; - /* FIXME: lock output list */ - list_for_each_entry(other_output, &drm_config->output_list, head) { - if (other_output != output && - other_output->crtc == output->crtc) + /* FIXME: lock connector list */ + list_for_each_entry(other_connector, &drm_config->connector_list, head) { + if (other_connector != connector && + other_connector->crtc == connector->crtc) return FALSE; } @@ -1111,16 +1112,16 @@ intel_tv_mode_fixup(struct drm_output *output, struct drm_display_mode *mode, } static void -intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, +intel_tv_mode_set(struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = output->crtc; + struct drm_crtc *crtc = connector->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_tv_priv *tv_priv = intel_output->dev_priv; - const struct tv_mode *tv_mode = intel_tv_mode_find(output); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); u32 tv_ctl; u32 hctl1, hctl2, hctl3; u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; @@ -1137,14 +1138,14 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, switch (tv_priv->type) { default: - case ConnectorUnknown: - case ConnectorComposite: + case DRM_MODE_CONNECTOR_Unknown: + case DRM_MODE_CONNECTOR_Composite: tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; video_levels = tv_mode->composite_levels; color_conversion = tv_mode->composite_color; burst_ena = tv_mode->burst_ena; break; - case ConnectorComponent: + case DRM_MODE_CONNECTOR_Component: tv_ctl |= TV_ENC_OUTPUT_COMPONENT; video_levels = &component_levels; if (tv_mode->burst_ena) @@ -1153,7 +1154,7 @@ intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode, color_conversion = &hdtv_csc_yprpb; burst_ena = FALSE; break; - case ConnectorSVIDEO: + case DRM_MODE_CONNECTOR_SVIDEO: tv_ctl |= TV_ENC_OUTPUT_SVIDEO; video_levels = tv_mode->svideo_levels; color_conversion = tv_mode->svideo_color; @@ -1355,15 +1356,15 @@ static const struct drm_display_mode reported_modes[] = { * \return FALSE if TV is disconnected. */ static int -intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) +intel_tv_detect_type (struct drm_crtc *crtc, struct drm_connector *connector) { - struct drm_device *dev = output->dev; + struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); u32 pipeastat, pipeastat_save; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; - int type = ConnectorUnknown; + int type = DRM_MODE_CONNECTOR_Unknown; tv_dac = I915_READ(TV_DAC); @@ -1410,13 +1411,13 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) */ if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { DRM_DEBUG("Detected Composite TV connection\n"); - type = ConnectorComposite; + type = DRM_MODE_CONNECTOR_Composite; } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { DRM_DEBUG("Detected S-Video TV connection\n"); - type = ConnectorSVIDEO; + type = DRM_MODE_CONNECTOR_SVIDEO; } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { DRM_DEBUG("Detected Component TV connection\n"); - type = ConnectorComponent; + type = DRM_MODE_CONNECTOR_Component; } else { DRM_DEBUG("No TV connection detected\n"); type = -1; @@ -1432,15 +1433,15 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output) /** * Detect the TV connection. * - * Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure + * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure * we have a pipe programmed in order to probe the TV. */ -static enum drm_output_status -intel_tv_detect(struct drm_output *output) +static enum drm_connector_status +intel_tv_detect(struct drm_connector *connector) { struct drm_crtc *crtc; struct drm_display_mode mode; - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); struct intel_tv_priv *tv_priv = intel_output->dev_priv; int dpms_mode; int type = tv_priv->type; @@ -1448,30 +1449,31 @@ intel_tv_detect(struct drm_output *output) mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); - if (output->crtc) { - type = intel_tv_detect_type(output->crtc, output); + if (connector->crtc) { + type = intel_tv_detect_type(connector->crtc, connector); } else { - crtc = intel_get_load_detect_pipe(output, &mode, &dpms_mode); + crtc = intel_get_load_detect_pipe(connector, &mode, &dpms_mode); if (crtc) { - type = intel_tv_detect_type(crtc, output); - intel_release_load_detect_pipe(output, dpms_mode); + type = intel_tv_detect_type(crtc, connector); + intel_release_load_detect_pipe(connector, dpms_mode); } else type = -1; } +#if 0 if (type != tv_priv->type) { struct drm_property *connector_property = - output->dev->mode_config.connector_type_property; + connector->dev->mode_config.connector_type_property; tv_priv->type = type; - drm_output_property_set_value(output, connector_property, + drm_connector_property_set_value(connector, connector_property, type); } - +#endif if (type < 0) - return output_status_disconnected; + return connector_status_disconnected; - return output_status_connected; + return connector_status_connected; } static struct input_res { @@ -1496,10 +1498,11 @@ static struct input_res { */ static int -intel_tv_get_modes(struct drm_output *output) +intel_tv_get_modes(struct drm_connector *connector) { struct drm_display_mode *mode_ptr; - const struct tv_mode *tv_mode = intel_tv_mode_find(output); + struct intel_output *intel_output = to_intel_output(connector); + const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); int j; for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]); @@ -1538,33 +1541,33 @@ intel_tv_get_modes(struct drm_output *output) mode_ptr->htotal / 1000) / 1000; mode_ptr->type = DRM_MODE_TYPE_DRIVER; - drm_mode_probed_add(output, mode_ptr); + drm_mode_probed_add(connector, mode_ptr); } return 0; } static void -intel_tv_destroy (struct drm_output *output) +intel_tv_destroy (struct drm_connector *connector) { - struct intel_output *intel_output = to_intel_output(output); + struct intel_output *intel_output = to_intel_output(connector); - drm_output_cleanup(output); + drm_connector_cleanup(connector); drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); } static bool -intel_tv_set_property(struct drm_output *output, struct drm_property *property, +intel_tv_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { - struct drm_device *dev = output->dev; - struct intel_output *intel_output = to_intel_output(output); + struct drm_device *dev = connector->dev; + struct intel_output *intel_output = to_intel_output(connector); struct intel_tv_priv *tv_priv = intel_output->dev_priv; int ret = 0; - ret = drm_output_property_set_value(output, property, val); + ret = drm_connector_property_set_value(connector, property, val); if (ret < 0) goto out; @@ -1582,25 +1585,25 @@ intel_tv_set_property(struct drm_output *output, struct drm_property *property, goto out; } tv_priv->tv_format = tv_modes[val].name; - intel_tv_mode_set(output, NULL, NULL); + intel_tv_mode_set(connector, NULL, NULL); } else { ret = -EINVAL; goto out; } - intel_tv_mode_set(output, NULL, NULL); + intel_tv_mode_set(connector, NULL, NULL); out: return ret; } -static const struct drm_output_helper_funcs intel_tv_helper_funcs = { +static const struct drm_connector_helper_funcs intel_tv_helper_funcs = { .mode_fixup = intel_tv_mode_fixup, - .prepare = intel_output_prepare, + .prepare = intel_connector_prepare, .mode_set = intel_tv_mode_set, - .commit = intel_output_commit, + .commit = intel_connector_commit, }; -static const struct drm_output_funcs intel_tv_output_funcs = { +static const struct drm_connector_funcs intel_tv_connector_funcs = { .dpms = intel_tv_dpms, .save = intel_tv_save, .restore = intel_tv_restore, @@ -1615,7 +1618,7 @@ void intel_tv_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_output *output; + struct drm_connector *connector; struct intel_output *intel_output; struct intel_tv_priv *tv_priv; u32 tv_dac_on, tv_dac_off, save_tv_dac; @@ -1657,17 +1660,17 @@ intel_tv_init(struct drm_device *dev) if (!intel_output) { return; } - output = &intel_output->base; + connector = &intel_output->base; - drm_output_init(dev, output, &intel_tv_output_funcs, - DRM_MODE_OUTPUT_TVDAC); + drm_connector_init(dev, connector, &intel_tv_connector_funcs, + DRM_MODE_CONNECTOR_Unknown); tv_priv = (struct intel_tv_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_TVOUT; - output->possible_crtcs = ((1 << 0) | (1 << 1)); - output->possible_clones = (1 << INTEL_OUTPUT_TVOUT); + connector->possible_crtcs = ((1 << 0) | (1 << 1)); + connector->possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_output->dev_priv = tv_priv; - tv_priv->type = ConnectorUnknown; + tv_priv->type = DRM_MODE_CONNECTOR_Unknown; /* BIOS margin values */ tv_priv->margin[TV_MARGIN_LEFT] = 54; @@ -1677,13 +1680,9 @@ intel_tv_init(struct drm_device *dev) tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); - drm_output_helper_add(output, &intel_tv_helper_funcs); - output->interlace_allowed = FALSE; - output->doublescan_allowed = FALSE; - - drm_output_attach_property(output, - dev->mode_config.connector_type_property, - ConnectorUnknown); + drm_connector_helper_add(connector, &intel_tv_helper_funcs); + connector->interlace_allowed = FALSE; + connector->doublescan_allowed = FALSE; /* Create TV properties then attach current values */ tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, @@ -1694,20 +1693,20 @@ intel_tv_init(struct drm_device *dev) tv_format_names[i] = tv_modes[i].name; drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); - drm_output_attach_property(output, dev->mode_config.tv_mode_property, + drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); - drm_output_attach_property(output, + drm_connector_attach_property(connector, dev->mode_config.tv_left_margin_property, tv_priv->margin[TV_MARGIN_LEFT]); - drm_output_attach_property(output, + drm_connector_attach_property(connector, dev->mode_config.tv_top_margin_property, tv_priv->margin[TV_MARGIN_TOP]); - drm_output_attach_property(output, + drm_connector_attach_property(connector, dev->mode_config.tv_right_margin_property, tv_priv->margin[TV_MARGIN_RIGHT]); - drm_output_attach_property(output, + drm_connector_attach_property(connector, dev->mode_config.tv_bottom_margin_property, tv_priv->margin[TV_MARGIN_BOTTOM]); out: - drm_sysfs_output_add(output); + drm_sysfs_connector_add(connector); } diff --git a/shared-core/drm.h b/shared-core/drm.h index 0005bb0b..a7f590dc 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -558,7 +558,7 @@ union drm_wait_vblank { /* Handle monitor hotplug. * * May want to extend this later to pass reply information which - * details the outputs which generated the hotplug event. + * details the connectors which generated the hotplug event. * Some chipsets can't determine that though, and we'd need to leave * it to the higher levels to determine exactly what changed. */ @@ -998,7 +998,7 @@ struct drm_mm_info_arg { * Drm mode setting */ #define DRM_DISPLAY_INFO_LEN 32 -#define DRM_OUTPUT_NAME_LEN 32 +#define DRM_CONNECTOR_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 #define DRM_PROP_NAME_LEN 32 @@ -1025,29 +1025,29 @@ struct drm_mode_modeinfo { struct drm_mode_card_res { uint64_t fb_id_ptr; uint64_t crtc_id_ptr; - uint64_t output_id_ptr; + uint64_t connector_id_ptr; uint64_t encoder_id_ptr; int count_fbs; int count_crtcs; - int count_outputs; + int count_connectors; int count_encoders; int min_width, max_width; int min_height, max_height; }; struct drm_mode_crtc { - uint64_t set_outputs_ptr; + uint64_t set_connectors_ptr; unsigned int crtc_id; /**< Id */ unsigned int fb_id; /**< Id of framebuffer */ int x, y; /**< Position on the frameuffer */ - int count_outputs; - unsigned int outputs; /**< Outputs that are connected */ + int count_connectors; + unsigned int connectors; /**< Connectors that are connected */ int count_possibles; - unsigned int possibles; /**< Outputs that can be connected */ + unsigned int possibles; /**< Connectors that can be connected */ int gamma_size; int mode_valid; struct drm_mode_modeinfo mode; @@ -1068,13 +1068,7 @@ struct drm_mode_get_encoder { #define DRM_MODE_ENCODER_LVDS 3 #define DRM_MODE_ENCODER_TVDAC 4 -#define DRM_MODE_OUTPUT_NONE 0 -#define DRM_MODE_OUTPUT_VGA 1 -#define DRM_MODE_OUTPUT_TMDS 2 -#define DRM_MODE_OUTPUT_LVDS 3 -#define DRM_MODE_OUTPUT_TVDAC 4 - -struct drm_mode_get_output { +struct drm_mode_get_connector { uint64_t encoders_ptr; uint64_t modes_ptr; @@ -1085,10 +1079,10 @@ struct drm_mode_get_output { int count_props; int count_encoders; - unsigned int output; /**< Id */ + unsigned int connector; /**< Id */ unsigned int crtc; /**< Id of crtc */ - unsigned int output_type; - unsigned int output_type_id; + unsigned int connector_type; + unsigned int connector_type_id; unsigned int connection; unsigned int mm_width, mm_height; /**< HxW in millimeters */ @@ -1122,10 +1116,10 @@ struct drm_mode_get_property { int count_enum_blobs; }; -struct drm_mode_output_set_property { +struct drm_mode_connector_set_property { uint64_t value; unsigned int prop_id; - unsigned int output_id; + unsigned int connector_id; }; struct drm_mode_get_blob { @@ -1144,7 +1138,7 @@ struct drm_mode_fb_cmd { }; struct drm_mode_mode_cmd { - unsigned int output_id; + unsigned int connector_id; struct drm_mode_modeinfo mode; }; @@ -1280,13 +1274,13 @@ struct drm_mode_hotplug { #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) -#define DRM_IOCTL_MODE_GETOUTPUT DRM_IOWR(0xA2, struct drm_mode_get_output) +#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA2, struct drm_mode_get_connector) #define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc) #define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xA4, struct drm_mode_fb_cmd) #define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) #define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) -#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xA7, struct drm_mode_output_set_property) +#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xA7, struct drm_mode_connector_set_property) #define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_blob) #define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) #define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index abf916ed..4c147a08 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -453,15 +453,15 @@ static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; static void i915_hotplug_tv(struct drm_device *dev) { - struct drm_output *output; + struct drm_connector *connector; struct intel_output *iout; - enum drm_output_status status; + enum drm_connector_status status; mutex_lock(&dev->mode_config.mutex); /* find the crt output */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - iout = to_intel_output(output); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + iout = to_intel_output(connector); if (iout->type == INTEL_OUTPUT_TVOUT) break; else @@ -471,9 +471,9 @@ static void i915_hotplug_tv(struct drm_device *dev) if (iout == 0) goto unlock; - status = output->funcs->detect(output); - drm_helper_hotplug_stage_two(dev, output, - status == output_status_connected ? 1 : 0); + status = connector->funcs->detect(connector); + drm_helper_hotplug_stage_two(dev, connector, + status == connector_status_connected ? 1 : 0); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -481,14 +481,14 @@ unlock: static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) { - struct drm_output *output; + struct drm_connector *connector; struct intel_output *iout; mutex_lock(&dev->mode_config.mutex); /* find the crt output */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - iout = to_intel_output(output); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + iout = to_intel_output(connector); if (iout->type == INTEL_OUTPUT_ANALOG) break; else @@ -498,7 +498,7 @@ static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) if (iout == 0) goto unlock; - drm_helper_hotplug_stage_two(dev, output, isconnected); + drm_helper_hotplug_stage_two(dev, connector, isconnected); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -506,24 +506,24 @@ unlock: static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) { - struct drm_output *output = 0; - enum drm_output_status status; + struct drm_connector *connector = 0; + enum drm_connector_status status; mutex_lock(&dev->mode_config.mutex); - output = intel_sdvo_find(dev, sdvoB); + connector = intel_sdvo_find(dev, sdvoB); - if (!output) + if (!connector) goto unlock; - status = output->funcs->detect(output); + status = connector->funcs->detect(connector); - if (status != output_status_connected) - drm_helper_hotplug_stage_two(dev, output, false); + if (status != connector_status_connected) + drm_helper_hotplug_stage_two(dev, connector, false); else - drm_helper_hotplug_stage_two(dev, output, true); + drm_helper_hotplug_stage_two(dev, connector, true); - intel_sdvo_set_hotplug(output, 1); + intel_sdvo_set_hotplug(connector, 1); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -961,15 +961,15 @@ void i915_disable_vblank(struct drm_device *dev, int plane) void i915_enable_interrupt (struct drm_device *dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - struct drm_output *o; + struct drm_connector *o; dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { - if (dev->mode_config.num_output) + if (dev->mode_config.num_connector) dev_priv->irq_enable_reg |= I915_DISPLAY_PORT_INTERRUPT; } else { - if (dev->mode_config.num_output) + if (dev->mode_config.num_connector) dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; /* Enable global interrupts for hotplug - not a pipeA event */ diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index eba072ee..3ff78f96 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -47,7 +47,7 @@ int printMode(struct drm_mode_modeinfo *mode) return 0; } -int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) +int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id) { int i = 0, j; struct drm_mode_modeinfo *mode = NULL; @@ -55,28 +55,28 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) drmModeEncoderPtr enc; unsigned char *name = NULL; - printf("Output: %d-%d\n", output->output_type, output->output_type_id); + printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); printf("\tid : %i\n", id); - printf("\tcrtc id : %i\n", output->crtc); - printf("\tconn : %s\n", getConnectionText(output->connection)); - printf("\tsize : %ix%i (mm)\n", output->mmWidth, output->mmHeight); - printf("\tcount_crtcs : %i\n", output->count_crtcs); - printf("\tcrtcs : %i\n", output->crtcs); - printf("\tcount_clones : %i\n", output->count_clones); - printf("\tclones : %i\n", output->clones); - printf("\tcount_modes : %i\n", output->count_modes); - printf("\tcount_props : %i\n", output->count_props); - printf("\tcount_encs : %i\n", output->count_encoders); - - for (i = 0; i < output->count_encoders; i++) { - enc = drmModeGetEncoder(fd, output->encoders[i]); + printf("\tcrtc id : %i\n", connector->crtc); + printf("\tconn : %s\n", getConnectionText(connector->connection)); + printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); + printf("\tcount_crtcs : %i\n", connector->count_crtcs); + printf("\tcrtcs : %i\n", connector->crtcs); + printf("\tcount_clones : %i\n", connector->count_clones); + printf("\tclones : %i\n", connector->clones); + printf("\tcount_modes : %i\n", connector->count_modes); + printf("\tcount_props : %i\n", connector->count_props); + printf("\tcount_encs : %i\n", connector->count_encoders); + + for (i = 0; i < connector->count_encoders; i++) { + enc = drmModeGetEncoder(fd, connector->encoders[i]); if (enc) { printf("Encoder: %d %d %d %d\n", enc->encoder_id, enc->encoder_type, enc->crtcs, enc->clones); } } - for (i = 0; i < output->count_props; i++) { - props = drmModeGetProperty(fd, output->props[i]); + for (i = 0; i < connector->count_props; i++) { + props = drmModeGetProperty(fd, connector->props[i]); name = NULL; if (props) { printf("Property: %s\n", props->name); @@ -91,7 +91,7 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) if (props->flags & DRM_MODE_PROP_BLOB) { drmModePropertyBlobPtr blob; - blob = drmModeGetPropertyBlob(fd, output->prop_values[i]); + blob = drmModeGetPropertyBlob(fd, connector->prop_values[i]); if (blob) { printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); drmModeFreePropertyBlob(blob); @@ -103,15 +103,15 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) for (j = 0; j < props->count_enums; j++) { printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); - if (output->prop_values[i] == props->enums[j].value) + if (connector->prop_values[i] == props->enums[j].value) name = props->enums[j].name; } if (props->count_enums && name) { - printf("\toutput property name %s %s\n", props->name, name); + printf("\tconnector property name %s %s\n", props->name, name); } else { - printf("\toutput property id %s %lli\n", props->name, output->prop_values[i]); + printf("\tconnector property id %s %lli\n", props->name, connector->prop_values[i]); } } @@ -119,12 +119,12 @@ int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id) } } - for (i = 0; i < output->count_modes; i++) { - mode = &output->modes[i]; + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; if (mode) printMode(mode); else - printf("\t\tmode: Invalid mode %p\n", &output->modes[i]); + printf("\t\tmode: Invalid mode %p\n", &connector->modes[i]); } return 0; @@ -149,8 +149,8 @@ int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) printf("\twidth : %i\n", crtc->width); printf("\theight : %i\n", crtc->height); printf("\tmode : %p\n", &crtc->mode); - printf("\tnum outputs : %i\n", crtc->count_outputs); - printf("\toutputs : %i\n", crtc->outputs); + printf("\tnum connectors : %i\n", crtc->count_connectors); + printf("\tconnectors : %i\n", crtc->connectors); printf("\tnum possible : %i\n", crtc->count_possibles); printf("\tpossibles : %i\n", crtc->possibles); @@ -174,19 +174,19 @@ int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb) int printRes(int fd, drmModeResPtr res) { int i; - drmModeOutputPtr output; + drmModeConnectorPtr connector; drmModeCrtcPtr crtc; drmModeFBPtr fb; drmModeEncoderPtr encoder; - for (i = 0; i < res->count_outputs; i++) { - output = drmModeGetOutput(fd, res->outputs[i]); + for (i = 0; i < res->count_connectors; i++) { + connector = drmModeGetConnector(fd, res->connectors[i]); - if (!output) - printf("Could not get output %i\n", i); + if (!connector) + printf("Could not get connector %i\n", i); else { - printOutput(fd, res, output, res->outputs[i]); - drmModeFreeOutput(output); + printConnector(fd, res, connector, res->connectors[i]); + drmModeFreeConnector(connector); } } @@ -246,24 +246,24 @@ static struct drm_mode_modeinfo mode = { int testMode(int fd, drmModeResPtr res) { - uint32_t output = res->outputs[0]; + uint32_t connector = res->connectors[0]; uint32_t newMode = 0; int ret = 0; int error = 0; - printf("Test: adding mode to output %i\n", output); + printf("Test: adding mode to connector %i\n", connector); /* printMode(&mode); */ - printf("\tAttaching mode %i to output %i\n", newMode, output); + printf("\tAttaching mode %i to connector %i\n", newMode, connector); - ret = drmModeAttachMode(fd, output, &mode); + ret = drmModeAttachMode(fd, connector, &mode); if (ret) goto err_mode; - printf("\tDetaching mode %i from output %i\n", newMode, output); - ret = drmModeDetachMode(fd, output, &mode); + printf("\tDetaching mode %i from connector %i\n", newMode, connector); + ret = drmModeDetachMode(fd, connector, &mode); if (ret) goto err_mode; @@ -362,15 +362,15 @@ err: int testDPMS(int fd, drmModeResPtr res) { - int output_id; + int connector_id; int i; - for (i = 0; i < res->count_outputs; i++) { - output_id = res->outputs[i]; - /* turn output off */ - drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 3); + for (i = 0; i < res->count_connectors; i++) { + connector_id = res->connectors[i]; + /* turn connector off */ + drmModeConnectorSetProperty(fd, connector_id, dpms_prop_id, 3); sleep(2); - drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 0); + drmModeConnectorSetProperty(fd, connector_id, dpms_prop_id, 0); } return 1; -- cgit v1.2.3 From 30fc88fdf9084ffcb9e76acbdee95d9691ac4ba4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 15:18:07 +1000 Subject: modesetting: drop crtcs/clones from the connectors --- tests/mode/modetest.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 3ff78f96..382cba65 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -60,10 +60,6 @@ int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uin printf("\tcrtc id : %i\n", connector->crtc); printf("\tconn : %s\n", getConnectionText(connector->connection)); printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); - printf("\tcount_crtcs : %i\n", connector->count_crtcs); - printf("\tcrtcs : %i\n", connector->crtcs); - printf("\tcount_clones : %i\n", connector->count_clones); - printf("\tclones : %i\n", connector->clones); printf("\tcount_modes : %i\n", connector->count_modes); printf("\tcount_props : %i\n", connector->count_props); printf("\tcount_encs : %i\n", connector->count_encoders); -- cgit v1.2.3 From 5d47185eb69d73dd7e6ee3ddde4d0c7642c2d5b7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 15:32:58 +1000 Subject: drm: switch possible crtc/clones over to encoders --- libdrm/xf86drmMode.c | 8 -------- libdrm/xf86drmMode.h | 6 ------ linux-core/drm_crtc.c | 6 +++--- linux-core/drm_crtc.h | 8 +++----- linux-core/drm_crtc_helper.c | 15 ++++++++++++--- linux-core/intel_display.c | 12 +++++++++--- linux-core/intel_tv.c | 17 +++++++++++++++-- shared-core/drm.h | 4 ---- 8 files changed, 42 insertions(+), 34 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index a18c4290..8b7f2bcf 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -381,10 +381,6 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) conn.connector = connector_id; conn.connector_type_id = 0; conn.connector_type = 0; - conn.count_crtcs = 0; - conn.crtcs = 0; - conn.count_clones = 0; - conn.clones = 0; conn.count_modes = 0; conn.modes_ptr = 0; conn.count_props = 0; @@ -420,12 +416,8 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) r->mmWidth = conn.mm_width; r->mmHeight = conn.mm_height; r->subpixel = conn.subpixel; - r->count_crtcs = conn.count_crtcs; - r->count_clones = conn.count_clones; r->count_modes = conn.count_modes; /* TODO we should test if these alloc & cpy fails. */ - r->crtcs = conn.crtcs; - r->clones = conn.clones; r->count_props = conn.count_props; r->props = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t)); r->prop_values = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t)); diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 03268b10..ceaa9abc 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -141,12 +141,6 @@ typedef struct _drmModeConnector { uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ drmModeSubPixel subpixel; - int count_crtcs; - uint32_t crtcs; /**< Possible crtc to connect to */ - - int count_clones; - uint32_t clones; /**< Mask of clones */ - int count_modes; struct drm_mode_modeinfo *modes; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c60476a4..bf6afd6a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1148,9 +1148,6 @@ int drm_mode_getconnector(struct drm_device *dev, else out_resp->crtc = 0; - out_resp->crtcs = connector->possible_crtcs; - out_resp->clones = connector->possible_clones; - if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr; @@ -2201,6 +2198,9 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] == 0) { connector->encoder_ids[i] = encoder->id; + /* pick the first added encoder as the current */ + if (i == 0) + connector->current_encoder_id = encoder->id; return 0; } } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 568b6b31..09886c15 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -423,8 +423,6 @@ struct drm_encoder { /** * drm_connector - central DRM connector control structure * @crtc: CRTC this connector is currently connected to, NULL if none - * @possible_crtcs: bitmap of CRTCS this connector could be attached to - * @possible_clones: bitmap of possible connectors this connector could clone * @interlace_allowed: can this connector handle interlaced modes? * @doublescan_allowed: can this connector handle doublescan? * @available_modes: modes available on this connector (from get_modes() + user) @@ -448,8 +446,6 @@ struct drm_connector { int connector_type; int connector_type_id; - unsigned long possible_crtcs; - unsigned long possible_clones; bool interlace_allowed; bool doublescan_allowed; struct list_head modes; /* list of modes on this connector */ @@ -470,7 +466,9 @@ struct drm_connector { void *helper_private; - u32 encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; + uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; + uint32_t force_encoder_id; + uint32_t current_encoder_id; }; /** diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 98b112ed..e5774ccc 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -46,6 +46,7 @@ static void drm_pick_crtcs (struct drm_device *dev) { int c, o, assigned; struct drm_connector *connector, *connector_equal; + struct drm_encoder *encoder, *encoder_equal; struct drm_crtc *crtc; struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; int found; @@ -89,12 +90,16 @@ static void drm_pick_crtcs (struct drm_device *dev) } } + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->id == connector->current_encoder_id) + break; + c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { assigned = 0; c++; - if ((connector->possible_crtcs & (1 << c)) == 0) + if ((encoder->possible_crtcs & (1 << c)) == 0) continue; list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { @@ -117,11 +122,15 @@ static void drm_pick_crtcs (struct drm_device *dev) if (connector->id == connector_equal->id) continue; + list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) + if (encoder_equal->id == connector_equal->current_encoder_id) + break; + list_for_each_entry(modes, &connector->modes, head) { list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { - if ((connector->possible_clones & connector_equal->possible_clones) && (connector_equal->crtc == crtc)) { - printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),connector->possible_clones,drm_get_connector_name(connector_equal),connector_equal->possible_clones); + if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->crtc == crtc)) { + printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); des_mode = modes; assigned = 0; goto clone; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 7fb1ea5f..f0cbc385 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1091,6 +1091,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, struct intel_crtc *intel_crtc; struct drm_crtc *possible_crtc; struct drm_crtc *supported_crtc =NULL; + struct drm_encoder *encoder = NULL; struct drm_crtc *crtc = NULL; struct drm_connector_helper_funcs *connector_funcs; int i = -1; @@ -1118,10 +1119,14 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, return crtc; } + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->id == connector->current_encoder_id) + break; + /* Find an unused one (if possible) */ list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { i++; - if (!(connector->possible_crtcs & (1 << i))) + if (!(encoder->possible_crtcs & (1 << i))) continue; if (!possible_crtc->enabled) { crtc = possible_crtc; @@ -1395,6 +1400,7 @@ static void intel_setup_outputs(struct drm_device *dev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct intel_output *intel_output = to_intel_output(connector); + struct drm_encoder *encoder = &intel_output->enc; int crtc_mask = 0, clone_mask = 0; /* valid crtcs */ @@ -1424,8 +1430,8 @@ static void intel_setup_outputs(struct drm_device *dev) clone_mask = (1 << INTEL_OUTPUT_TVOUT); break; } - connector->possible_crtcs = crtc_mask; - connector->possible_clones = intel_connector_clones(dev, clone_mask); + encoder->possible_crtcs = crtc_mask; + encoder->possible_clones = intel_connector_clones(dev, clone_mask); } } diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 330c204a..c2658f13 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1614,6 +1614,16 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = { .set_property = intel_tv_set_property, }; +void intel_tv_enc_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs intel_tv_enc_funcs = { + .destroy = intel_tv_enc_destroy, +}; + + void intel_tv_init(struct drm_device *dev) { @@ -1665,10 +1675,13 @@ intel_tv_init(struct drm_device *dev) drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_Unknown); + drm_encoder_init(dev, &intel_output->enc, &intel_tv_enc_funcs, + DRM_MODE_ENCODER_TVDAC); + tv_priv = (struct intel_tv_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_TVOUT; - connector->possible_crtcs = ((1 << 0) | (1 << 1)); - connector->possible_clones = (1 << INTEL_OUTPUT_TVOUT); + intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1)); + intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_output->dev_priv = tv_priv; tv_priv->type = DRM_MODE_CONNECTOR_Unknown; diff --git a/shared-core/drm.h b/shared-core/drm.h index a7f590dc..1fcbf144 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1087,10 +1087,6 @@ struct drm_mode_get_connector { unsigned int connection; unsigned int mm_width, mm_height; /**< HxW in millimeters */ unsigned int subpixel; - int count_crtcs; - int count_clones; - unsigned int crtcs; /**< possible crtc to connect to */ - unsigned int clones; /**< list of clones */ }; #define DRM_MODE_PROP_PENDING (1<<0) -- cgit v1.2.3 From efb48c6cf7bbb57e7b2ea6ce7671905e84384963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Fri, 30 May 2008 14:23:04 -0400 Subject: Fix ivch i2c read function to use the "special" i2c format. --- linux-core/dvo_ivch.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/linux-core/dvo_ivch.c b/linux-core/dvo_ivch.c index 5fce2462..9209dd02 100644 --- a/linux-core/dvo_ivch.c +++ b/linux-core/dvo_ivch.c @@ -186,28 +186,32 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) { struct ivch_priv *priv = dvo->dev_priv; struct intel_i2c_chan *i2cbus = dvo->i2c_bus; - u8 out_buf[2]; + u8 out_buf[1]; u8 in_buf[2]; struct i2c_msg msgs[] = { { .addr = i2cbus->slave_addr, - .flags = 0, + .flags = I2C_M_RD, + .len = 0, + }, + { + .addr = 0, + .flags = I2C_M_NOSTART, .len = 1, .buf = out_buf, }, { .addr = i2cbus->slave_addr, - .flags = I2C_M_RD, + .flags = I2C_M_RD | I2C_M_NOSTART, .len = 2, .buf = in_buf, } }; out_buf[0] = addr; - out_buf[1] = 0; - if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { + if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) { *data = (in_buf[1] << 8) | in_buf[0]; return true; }; -- cgit v1.2.3 From e439e74776b215d70d8e34e8aa9cea22179dcbc6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 10:05:54 +1000 Subject: drm/modesetting: another re-org of some internals. Move dpms into the helper functions. Move crtc into the encoder. Move disable unused functions into the helper. --- linux-core/drm_crtc.c | 62 +++++++++----------- linux-core/drm_crtc.h | 12 +--- linux-core/drm_crtc_helper.c | 136 ++++++++++++++++++++++++++----------------- linux-core/drm_crtc_helper.h | 32 +++++----- linux-core/intel_crt.c | 27 ++++----- linux-core/intel_display.c | 78 +++++++++++++------------ linux-core/intel_drv.h | 9 +-- linux-core/intel_dvo.c | 29 ++++----- linux-core/intel_fb.c | 2 +- linux-core/intel_lvds.c | 40 +++++++------ linux-core/intel_sdvo.c | 33 ++++++----- linux-core/intel_tv.c | 61 +++++++++---------- shared-core/drm.h | 3 +- 13 files changed, 274 insertions(+), 250 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bf6afd6a..27bf7c27 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -83,6 +83,15 @@ static struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_TVDAC, "TV" }, }; +char *drm_get_encoder_name(struct drm_encoder *encoder) +{ + static char buf[32]; + + snprintf(buf, 32, "%s-%d", drm_encoder_enum_list[encoder->encoder_type].name, + encoder->id); + return buf; +} + char *drm_get_connector_name(struct drm_connector *connector) { static char buf[32]; @@ -290,11 +299,11 @@ EXPORT_SYMBOL(drm_crtc_cleanup); */ bool drm_crtc_in_use(struct drm_crtc *crtc) { - struct drm_connector *connector; + struct drm_encoder *encoder; struct drm_device *dev = crtc->dev; /* FIXME: Locking around list access? */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - if (connector->crtc == crtc) + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->crtc == crtc) return true; return false; } @@ -406,33 +415,6 @@ void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY) EXPORT_SYMBOL(drm_crtc_probe_connector_modes); -/** - * drm_disable_unused_functions - disable unused objects - * @dev: DRM device - * - * LOCKING: - * Caller must hold mode config lock. - * - * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled - * by calling its dpms function, which should power it off. - */ -void drm_disable_unused_functions(struct drm_device *dev) -{ - struct drm_connector *connector; - struct drm_crtc *crtc; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (!connector->crtc) - (*connector->funcs->dpms)(connector, DPMSModeOff); - } - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (!crtc->enabled) - crtc->funcs->dpms(crtc, DPMSModeOff); - } -} -EXPORT_SYMBOL(drm_disable_unused_functions); - /** * drm_mode_probed_add - add a mode to the specified connector's probed mode list * @connector: connector the new mode @@ -1059,7 +1041,7 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->mode_valid = 1; ocount = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->crtc == crtc) + if (connector->encoder->crtc == crtc) crtc_resp->connectors |= 1 << (ocount++); } @@ -1143,10 +1125,10 @@ int drm_mode_getconnector(struct drm_device *dev, out_resp->mm_height = connector->display_info.height_mm; out_resp->subpixel = connector->display_info.subpixel_order; out_resp->connection = connector->status; - if (connector->crtc) - out_resp->crtc = connector->crtc->id; + if (connector->encoder) + out_resp->encoder = connector->encoder->id; else - out_resp->crtc = 0; + out_resp->encoder = 0; if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; @@ -1220,6 +1202,10 @@ int drm_mode_getencoder(struct drm_device *dev, goto out; } + if (encoder->crtc) + enc_resp->crtc = encoder->crtc->id; + else + enc_resp->crtc = 0; enc_resp->encoder_type = encoder->encoder_type; enc_resp->encoder_id = encoder->id; enc_resp->crtcs = encoder->possible_crtcs; @@ -1630,7 +1616,9 @@ int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, struct drm_display_mode *dup_mode; int need_dup = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->crtc == crtc) { + if (!connector->encoder) + break; + if (connector->encoder->crtc == crtc) { if (need_dup) dup_mode = drm_mode_duplicate(dev, mode); else @@ -2200,7 +2188,7 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, connector->encoder_ids[i] = encoder->id; /* pick the first added encoder as the current */ if (i == 0) - connector->current_encoder_id = encoder->id; + connector->encoder = encoder; return 0; } } @@ -2215,6 +2203,8 @@ void drm_mode_connector_detach_encoder(struct drm_connector *connector, for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] == encoder->id) { connector->encoder_ids[i] = 0; + if (connector->encoder == encoder) + connector->encoder = NULL; break; } } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 09886c15..14aa5038 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -304,12 +304,6 @@ struct drm_encoder; * bus accessors. */ struct drm_crtc_funcs { - /* - * Control power levels on the CRTC. If the mode passed in is - * unsupported, the provider must use the next lowest power level. - */ - void (*dpms)(struct drm_crtc *crtc, int mode); - /* Save CRTC state */ void (*save)(struct drm_crtc *crtc); /* suspend? */ /* Restore CRTC state */ @@ -416,6 +410,7 @@ struct drm_encoder { uint32_t possible_crtcs; uint32_t possible_clones; + struct drm_crtc *crtc; const struct drm_encoder_funcs *funcs; void *helper_private; }; @@ -441,7 +436,6 @@ struct drm_connector { struct device kdev; struct device_attribute *attr; struct list_head head; - struct drm_crtc *crtc; int id; /* idr assigned */ int connector_type; @@ -468,7 +462,7 @@ struct drm_connector { uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; uint32_t force_encoder_id; - uint32_t current_encoder_id; + struct drm_encoder *encoder; /* currently active encoder */ }; /** @@ -582,7 +576,6 @@ extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_set_name(struct drm_display_mode *mode); extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); -extern void drm_disable_unused_functions(struct drm_device *dev); /* for us by fb module */ extern int drm_mode_attachmode_crtc(struct drm_device *dev, @@ -631,6 +624,7 @@ extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); +extern char *drm_get_encoder_name(struct drm_encoder *encoder); extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index e5774ccc..82862b55 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -34,6 +34,35 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" +/** + * drm_disable_unused_functions - disable unused objects + * @dev: DRM device + * + * LOCKING: + * Caller must hold mode config lock. + * + * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled + * by calling its dpms function, which should power it off. + */ +void drm_helper_disable_unused_functions(struct drm_device *dev) +{ + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_crtc *crtc; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder_funcs = encoder->helper_private; + if (!encoder->crtc) + (*encoder_funcs->dpms)(encoder, DPMSModeOff); + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + if (!crtc->enabled) + crtc_funcs->dpms(crtc, DPMSModeOff); + } +} +EXPORT_SYMBOL(drm_helper_disable_unused_functions); /** * drm_pick_crtcs - pick crtcs for connector devices @@ -52,7 +81,7 @@ static void drm_pick_crtcs (struct drm_device *dev) int found; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector->crtc = NULL; + connector->encoder->crtc = NULL; /* Don't hook up connectors that are disconnected ?? * @@ -90,9 +119,7 @@ static void drm_pick_crtcs (struct drm_device *dev) } } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) - if (encoder->id == connector->current_encoder_id) - break; + encoder = connector->encoder; c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -107,7 +134,7 @@ static void drm_pick_crtcs (struct drm_device *dev) continue; /* Find out if crtc has been assigned before */ - if (connector_equal->crtc == crtc) + if (connector_equal->encoder->crtc == crtc) assigned = 1; } @@ -122,14 +149,12 @@ static void drm_pick_crtcs (struct drm_device *dev) if (connector->id == connector_equal->id) continue; - list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) - if (encoder_equal->id == connector_equal->current_encoder_id) - break; + encoder_equal = connector_equal->encoder; list_for_each_entry(modes, &connector->modes, head) { list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { - if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->crtc == crtc)) { + if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->encoder->crtc == crtc)) { printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); des_mode = modes; assigned = 0; @@ -146,8 +171,8 @@ clone: continue; /* Found a CRTC to attach to, do it ! */ - connector->crtc = crtc; - connector->crtc->desired_mode = des_mode; + connector->encoder->crtc = crtc; + connector->encoder->crtc->desired_mode = des_mode; connector->initial_x = 0; connector->initial_y = 0; DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); @@ -179,9 +204,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode, saved_mode; struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - struct drm_connector_helper_funcs *connector_funcs; + struct drm_encoder_helper_funcs *encoder_funcs; int saved_x, saved_y; - struct drm_connector *connector; + struct drm_encoder *encoder; bool ret = true; adjusted_mode = drm_mode_duplicate(dev, mode); @@ -213,12 +238,12 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (connector->crtc != crtc) + if (encoder->crtc != crtc) continue; - connector_funcs = connector->helper_private; - if (!(ret = connector_funcs->mode_fixup(connector, mode, adjusted_mode))) { + encoder_funcs = encoder->helper_private; + if (!(ret = encoder_funcs->mode_fixup(encoder, mode, adjusted_mode))) { goto done; } } @@ -227,48 +252,44 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo goto done; } - /* Prepare the connectors and CRTCs before setting the mode. */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + /* Prepare the encoders and CRTCs before setting the mode. */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (connector->crtc != crtc) + if (encoder->crtc != crtc) continue; - connector_funcs = connector->helper_private; - /* Disable the connector as the first thing we do. */ - connector_funcs->prepare(connector); + encoder_funcs = encoder->helper_private; + /* Disable the encoders as the first thing we do. */ + encoder_funcs->prepare(encoder); } crtc_funcs->prepare(crtc); - /* Set up the DPLL and any connector state that needs to adjust or depend + /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. */ crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (connector->crtc != crtc) + if (encoder->crtc != crtc) continue; - DRM_INFO("%s: set mode %s %x\n", drm_get_connector_name(connector), mode->name, mode->mode_id); - connector_funcs = connector->helper_private; - connector_funcs->mode_set(connector, mode, adjusted_mode); + DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder), mode->name, mode->mode_id); + encoder_funcs = encoder->helper_private; + encoder_funcs->mode_set(encoder, mode, adjusted_mode); } /* Now, enable the clocks, plane, pipe, and connectors that we set up. */ crtc_funcs->commit(crtc); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (connector->crtc != crtc) + if (encoder->crtc != crtc) continue; - connector_funcs = connector->helper_private; - connector_funcs->commit(connector); + encoder_funcs = encoder->helper_private; + encoder_funcs->commit(encoder); -#if 0 // TODO def RANDR_12_INTERFACE - if (connector->randr_connector) - RRPostPendingProperties (connector->randr_connector); -#endif } /* XXX free adjustedmode */ @@ -357,20 +378,23 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - save_crtcs[count++] = connector->crtc; + if (!connector->encoder) + continue; - if (connector->crtc == set->crtc) + save_crtcs[count++] = connector->encoder->crtc; + + if (connector->encoder->crtc == set->crtc) new_crtc = NULL; else - new_crtc = connector->crtc; + new_crtc = connector->encoder->crtc; for (ro = 0; ro < set->num_connectors; ro++) { if (set->connectors[ro] == connector) new_crtc = set->crtc; } - if (new_crtc != connector->crtc) { + if (new_crtc != connector->encoder->crtc) { changed = true; - connector->crtc = new_crtc; + connector->encoder->crtc = new_crtc; } } @@ -389,7 +413,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) set->crtc->enabled = save_enabled; count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) - connector->crtc = save_crtcs[count++]; + connector->encoder->crtc = save_crtcs[count++]; kfree(save_crtcs); return -EINVAL; } @@ -398,7 +422,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) set->crtc->desired_y = set->y; set->crtc->desired_mode = set->mode; } - drm_disable_unused_functions(dev); + drm_helper_disable_unused_functions(dev); } else if (flip_or_move) { if (set->crtc->fb != set->fb) set->crtc->fb = set->fb; @@ -444,18 +468,19 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_crtc *crtc = connector->encoder->crtc; /* can't setup the connector if there's no assigned mode */ - if (!connector->crtc || !connector->crtc->desired_mode) + if (!crtc || !crtc->desired_mode) continue; - dev->driver->fb_probe(dev, connector->crtc, connector); + dev->driver->fb_probe(dev, crtc, connector); /* and needs an attached fb */ - if (connector->crtc->fb) - drm_crtc_helper_set_mode(connector->crtc, connector->crtc->desired_mode, 0, 0); + if (crtc->fb) + drm_crtc_helper_set_mode(crtc, crtc->desired_mode, 0, 0); } - drm_disable_unused_functions(dev); + drm_helper_disable_unused_functions(dev); mutex_unlock(&dev->mode_config.mutex); return ret; @@ -488,7 +513,7 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c return 0; } - if (connector->crtc && connector->crtc->desired_mode) { + if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { DRM_DEBUG("drm thinks that the connector already has a config\n"); has_config = 1; } @@ -498,27 +523,28 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c if (!has_config) drm_pick_crtcs(dev); - if (!connector->crtc || !connector->crtc->desired_mode) { + if (!connector->encoder->crtc || !connector->encoder->crtc->desired_mode) { DRM_DEBUG("could not find a desired mode or crtc for connector\n"); return 1; } /* We should really check if there is a fb using this crtc */ if (!has_config) - dev->driver->fb_probe(dev, connector->crtc, connector); + dev->driver->fb_probe(dev, connector->encoder->crtc, connector); else { - dev->driver->fb_resize(dev, connector->crtc); + dev->driver->fb_resize(dev, connector->encoder->crtc); #if 0 - if (!drm_crtc_set_mode(connector->crtc, connector->crtc->desired_mode, 0, 0)) + if (!drm_crtc_set_mode(connector->encoder->crtc, connector->encoder->crtc->desired_mode, 0, 0)) DRM_ERROR("failed to set mode after hotplug\n"); #endif } drm_sysfs_hotplug_event(dev); - drm_disable_unused_functions(dev); + drm_helper_disable_unused_functions(dev); return 0; } EXPORT_SYMBOL(drm_helper_hotplug_stage_two); + diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 10420065..063d1f7a 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -21,6 +21,11 @@ #include struct drm_crtc_helper_funcs { + /* + * Control power levels on the CRTC. If the mode passed in is + * unsupported, the provider must use the next lowest power level. + */ + void (*dpms)(struct drm_crtc *crtc, int mode); void (*prepare)(struct drm_crtc *crtc); void (*commit)(struct drm_crtc *crtc); @@ -36,26 +41,23 @@ struct drm_crtc_helper_funcs { void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); }; -struct drm_connector_helper_funcs { - bool (*mode_fixup)(struct drm_connector *connector, +struct drm_encoder_helper_funcs { + void (*dpms)(struct drm_encoder *encoder, int mode); + void (*save)(struct drm_encoder *encoder); + void (*restore)(struct drm_encoder *encoder); + + bool (*mode_fixup)(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); - void (*prepare)(struct drm_connector *connector); - void (*commit)(struct drm_connector *connector); - void (*mode_set)(struct drm_connector *connector, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); -}; - -struct drm_encoder_helper_funcs { - void (*prepare)(struct drm_connector *connector); - void (*commit)(struct drm_connector *connector); - void (*mode_set)(struct drm_connector *connector, + void (*prepare)(struct drm_encoder *encoder); + void (*commit)(struct drm_encoder *encoder); + void (*mode_set)(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); }; +extern void drm_helper_disable_unused_functions(struct drm_device *dev); extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, bool connected); extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); @@ -68,9 +70,9 @@ static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_c crtc->helper_private = (void *)funcs; } -static inline void drm_connector_helper_add(struct drm_connector *connector, const struct drm_connector_helper_funcs *funcs) +static inline void drm_encoder_helper_add(struct drm_encoder *encoder, const struct drm_encoder_helper_funcs *funcs) { - connector->helper_private = (void *)funcs; + encoder->helper_private = (void *)funcs; } diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index a98f7000..ec4c2bf9 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -33,9 +33,9 @@ #include "i915_drm.h" #include "i915_drv.h" -static void intel_crt_dpms(struct drm_connector *connector, int mode) +static void intel_crt_dpms(struct drm_encoder *encoder, int mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 temp; @@ -83,19 +83,20 @@ static int intel_crt_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_crt_mode_fixup(struct drm_connector *connector, +static bool intel_crt_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; } -static void intel_crt_mode_set(struct drm_connector *connector, +static void intel_crt_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = connector->dev; - struct drm_crtc *crtc = connector->crtc; + + struct drm_device *dev = encoder->dev; + struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_i915_private *dev_priv = dev->dev_private; int dpll_md_reg; @@ -214,8 +215,8 @@ static bool intel_crt_set_property(struct drm_connector *connector, { struct drm_device *dev = connector->dev; - if (property == dev->mode_config.dpms_property) - intel_crt_dpms(connector, (uint32_t)(value & 0xf)); + if (property == dev->mode_config.dpms_property && connector->encoder) + intel_crt_dpms(connector->encoder, (uint32_t)(value & 0xf)); return true; } @@ -224,15 +225,15 @@ static bool intel_crt_set_property(struct drm_connector *connector, * Routines for controlling stuff on the analog port */ -static const struct drm_connector_helper_funcs intel_crt_helper_funcs = { +static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { + .dpms = intel_crt_dpms, .mode_fixup = intel_crt_mode_fixup, - .prepare = intel_connector_prepare, - .commit = intel_connector_commit, + .prepare = intel_encoder_prepare, + .commit = intel_encoder_commit, .mode_set = intel_crt_mode_set, }; static const struct drm_connector_funcs intel_crt_connector_funcs = { - .dpms = intel_crt_dpms, .save = intel_crt_save, .restore = intel_crt_restore, .detect = intel_crt_detect, @@ -281,7 +282,7 @@ void intel_crt_init(struct drm_device *dev) connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - drm_connector_helper_add(connector, &intel_crt_helper_funcs); + drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs); drm_sysfs_connector_add(connector); diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index f0cbc385..c1cb2bff 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -228,7 +228,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type) struct drm_connector *l_entry; list_for_each_entry(l_entry, &mode_config->connector_list, head) { - if (l_entry->crtc == crtc) { + if (l_entry->encoder->crtc == crtc) { struct intel_output *intel_output = to_intel_output(l_entry); if (intel_output->type == type) return true; @@ -575,24 +575,28 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) static void intel_crtc_prepare (struct drm_crtc *crtc) { - crtc->funcs->dpms(crtc, DPMSModeOff); + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DPMSModeOff); } static void intel_crtc_commit (struct drm_crtc *crtc) { - crtc->funcs->dpms(crtc, DPMSModeOn); + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DPMSModeOn); } -void intel_connector_prepare (struct drm_connector *connector) +void intel_encoder_prepare (struct drm_encoder *encoder) { + struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; /* lvds has its own version of prepare see intel_lvds_prepare */ - connector->funcs->dpms(connector, DPMSModeOff); + encoder_funcs->dpms(encoder, DPMSModeOff); } -void intel_connector_commit (struct drm_connector *connector) +void intel_encoder_commit (struct drm_encoder *encoder) { + struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; /* lvds has its own version of commit see intel_lvds_commit */ - connector->funcs->dpms(connector, DPMSModeOn); + encoder_funcs->dpms(encoder, DPMSModeOn); } static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, @@ -721,7 +725,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, list_for_each_entry(connector, &mode_config->connector_list, head) { struct intel_output *intel_output = to_intel_output(connector); - if (connector->crtc != crtc) + if (!connector->encoder || connector->encoder->crtc != crtc) continue; switch (intel_output->type) { @@ -1082,18 +1086,18 @@ static struct drm_display_mode load_detect_mode = { 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC), }; -struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, +struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, struct drm_display_mode *mode, int *dpms_mode) { - struct drm_device *dev = connector->dev; - struct intel_output *intel_output = to_intel_output(connector); struct intel_crtc *intel_crtc; struct drm_crtc *possible_crtc; struct drm_crtc *supported_crtc =NULL; - struct drm_encoder *encoder = NULL; + struct drm_encoder *encoder = &intel_output->enc; struct drm_crtc *crtc = NULL; - struct drm_connector_helper_funcs *connector_funcs; + struct drm_device *dev = encoder->dev; + struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; + struct drm_crtc_helper_funcs *crtc_funcs; int i = -1; /* @@ -1107,22 +1111,19 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, */ /* See if we already have a CRTC for this connector */ - if (connector->crtc) { - crtc = connector->crtc; + if (encoder->crtc) { + crtc = encoder->crtc; /* Make sure the crtc and connector are running */ intel_crtc = to_intel_crtc(crtc); *dpms_mode = intel_crtc->dpms_mode; if (intel_crtc->dpms_mode != DPMSModeOn) { - crtc->funcs->dpms(crtc, DPMSModeOn); - connector->funcs->dpms(connector, DPMSModeOn); + crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DPMSModeOn); + encoder_funcs->dpms(encoder, DPMSModeOn); } return crtc; } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) - if (encoder->id == connector->current_encoder_id) - break; - /* Find an unused one (if possible) */ list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { i++; @@ -1146,7 +1147,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, return NULL; } - connector->crtc = crtc; + encoder->crtc = crtc; intel_output->load_detect_temp = TRUE; intel_crtc = to_intel_crtc(crtc); @@ -1157,13 +1158,14 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, mode = &load_detect_mode; drm_crtc_helper_set_mode(crtc, mode, 0, 0); } else { - if (intel_crtc->dpms_mode != DPMSModeOn) - crtc->funcs->dpms(crtc, DPMSModeOn); + if (intel_crtc->dpms_mode != DPMSModeOn) { + crtc_funcs = crtc->helper_private; + crtc_funcs->dpms(crtc, DPMSModeOn); + } - connector_funcs = connector->helper_private; /* Add this connector to the crtc */ - connector_funcs->mode_set(connector, &crtc->mode, &crtc->mode); - connector_funcs->commit(connector); + encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode); + encoder_funcs->commit(encoder); } /* let the connector get through one full cycle before testing */ intel_wait_for_vblank(dev); @@ -1171,24 +1173,26 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, return crtc; } -void intel_release_load_detect_pipe(struct drm_connector *connector, int dpms_mode) +void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_mode) { - struct drm_device *dev = connector->dev; - struct intel_output *intel_output = to_intel_output(connector); - struct drm_crtc *crtc = connector->crtc; + struct drm_encoder *encoder = &intel_output->enc; + struct drm_device *dev = encoder->dev; + struct drm_crtc *crtc = encoder->crtc; + struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; if (intel_output->load_detect_temp) { - connector->crtc = NULL; + encoder->crtc = NULL; intel_output->load_detect_temp = FALSE; crtc->enabled = drm_crtc_in_use(crtc); - drm_disable_unused_functions(dev); + drm_helper_disable_unused_functions(dev); } /* Switch crtc and output back off if necessary */ if (crtc->enabled && dpms_mode != DPMSModeOn) { - if (connector->crtc == crtc) - connector->funcs->dpms(connector, dpms_mode); - crtc->funcs->dpms(crtc, dpms_mode); + if (encoder->crtc == crtc) + encoder_funcs->dpms(encoder, dpms_mode); + crtc_funcs->dpms(crtc, dpms_mode); } } @@ -1311,6 +1315,7 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) } static const struct drm_crtc_helper_funcs intel_helper_funcs = { + .dpms = intel_crtc_dpms, .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, @@ -1319,7 +1324,6 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { }; static const struct drm_crtc_funcs intel_crtc_funcs = { - .dpms = intel_crtc_dpms, .cursor_set = intel_crtc_cursor_set, .cursor_move = intel_crtc_cursor_move, .gamma_set = intel_crtc_gamma_set, diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 44639525..0a5e350e 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -68,6 +68,7 @@ struct intel_crtc { #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_output(x) container_of(x, struct intel_output, base) +#define enc_to_intel_output(x) container_of(x, struct intel_output, enc) struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, const char *name); @@ -82,16 +83,16 @@ extern void intel_tv_init(struct drm_device *dev); extern void intel_lvds_init(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); -extern void intel_connector_prepare (struct drm_connector *connector); -extern void intel_connector_commit (struct drm_connector *connector); +extern void intel_encoder_prepare (struct drm_encoder *encoder); +extern void intel_encoder_commit (struct drm_encoder *encoder); extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_wait_for_vblank(struct drm_device *dev); extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); -extern struct drm_crtc *intel_get_load_detect_pipe(struct drm_connector *connector, +extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, struct drm_display_mode *mode, int *dpms_mode); -extern void intel_release_load_detect_pipe(struct drm_connector *connector, +extern void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_mode); extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index 7fc5ccea..364cd659 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -85,10 +85,10 @@ struct intel_dvo_device intel_dvo_devices[] = { } }; -static void intel_dvo_dpms(struct drm_connector *connector, int mode) +static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) { - struct drm_i915_private *dev_priv = connector->dev->dev_private; - struct intel_output *intel_output = to_intel_output(connector); + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct intel_output *intel_output = enc_to_intel_output(encoder); struct intel_dvo_device *dvo = intel_output->dev_priv; u32 dvo_reg = dvo->dvo_reg; u32 temp = I915_READ(dvo_reg); @@ -154,11 +154,11 @@ static int intel_dvo_mode_valid(struct drm_connector *connector, return dvo->dev_ops->mode_valid(dvo, mode); } -static bool intel_dvo_mode_fixup(struct drm_connector *connector, +static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct intel_output *intel_output = to_intel_output(connector); + struct intel_output *intel_output = enc_to_intel_output(encoder); struct intel_dvo_device *dvo = intel_output->dev_priv; /* If we have timings from the BIOS for the panel, put them in @@ -187,14 +187,14 @@ static bool intel_dvo_mode_fixup(struct drm_connector *connector, return true; } -static void intel_dvo_mode_set(struct drm_connector *connector, +static void intel_dvo_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(connector->crtc); - struct intel_output *intel_output = to_intel_output(connector); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); + struct intel_output *intel_output = enc_to_intel_output(encoder); struct intel_dvo_device *dvo = intel_output->dev_priv; int pipe = intel_crtc->pipe; u32 dvo_val; @@ -323,15 +323,15 @@ static struct drm_crtc *intel_dvo_get_crtc(struct drm_connector *connector) } #endif -static const struct drm_connector_helper_funcs intel_dvo_helper_funcs = { +static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { + .dpms = intel_dvo_dpms, .mode_fixup = intel_dvo_mode_fixup, - .prepare = intel_connector_prepare, + .prepare = intel_encoder_prepare, .mode_set = intel_dvo_mode_set, - .commit = intel_connector_commit, + .commit = intel_encoder_commit, }; static const struct drm_connector_funcs intel_dvo_connector_funcs = { - .dpms = intel_dvo_dpms, .save = intel_dvo_save, .restore = intel_dvo_restore, .detect = intel_dvo_detect, @@ -464,7 +464,6 @@ void intel_dvo_init(struct drm_device *dev) break; } - drm_connector_helper_add(connector, &intel_dvo_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = false; connector->doublescan_allowed = false; @@ -473,6 +472,8 @@ void intel_dvo_init(struct drm_device *dev) intel_output->i2c_bus = i2cbus; drm_encoder_init(dev, &intel_output->enc, &intel_dvo_enc_funcs, encoder_type); + drm_encoder_helper_add(&intel_output->enc, &intel_dvo_helper_funcs); + if (dvo->type == INTEL_DVO_CHIP_LVDS) { /* For our LVDS chipsets, we should hopefully be able * to dig the fixed panel mode out of the BIOS data. diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 394d2344..138d189e 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -277,7 +277,7 @@ static int intelfb_set_par(struct fb_info *info) found = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->crtc == par->set.crtc){ + if (connector->encoder->crtc == par->set.crtc){ found = 1; break; } diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 019c45fe..b83f3923 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -89,9 +89,9 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on) } } -static void intel_lvds_dpms(struct drm_connector *connector, int mode) +static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; if (mode == DPMSModeOn) intel_lvds_set_power(dev, true); @@ -155,14 +155,14 @@ static int intel_lvds_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_lvds_mode_fixup(struct drm_connector *connector, +static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(connector->crtc); - struct drm_connector *tmp_connector; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); + struct drm_encoder *tmp_encoder; /* Should never happen!! */ if (!IS_I965G(dev) && intel_crtc->pipe == 0) { @@ -171,10 +171,10 @@ static bool intel_lvds_mode_fixup(struct drm_connector *connector, } /* Should never happen!! */ - list_for_each_entry(tmp_connector, &dev->mode_config.connector_list, head) { - if (tmp_connector != connector && tmp_connector->crtc == connector->crtc) { + list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) { + if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) { printk(KERN_ERR "Can't enable LVDS and another " - "connector on the same pipe\n"); + "encoder on the same pipe\n"); return false; } } @@ -211,9 +211,9 @@ static bool intel_lvds_mode_fixup(struct drm_connector *connector, return true; } -static void intel_lvds_prepare(struct drm_connector *connector) +static void intel_lvds_prepare(struct drm_encoder *encoder) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); @@ -223,9 +223,9 @@ static void intel_lvds_prepare(struct drm_connector *connector) intel_lvds_set_power(dev, false); } -static void intel_lvds_commit( struct drm_connector *connector) +static void intel_lvds_commit( struct drm_encoder *encoder) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->backlight_duty_cycle == 0) @@ -235,13 +235,13 @@ static void intel_lvds_commit( struct drm_connector *connector) intel_lvds_set_power(dev, true); } -static void intel_lvds_mode_set(struct drm_connector *connector, +static void intel_lvds_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(connector->crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); u32 pfit_control; /* @@ -334,7 +334,8 @@ static void intel_lvds_destroy(struct drm_connector *connector) kfree(connector); } -static const struct drm_connector_helper_funcs intel_lvds_helper_funcs = { +static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { + .dpms = intel_lvds_dpms, .mode_fixup = intel_lvds_mode_fixup, .prepare = intel_lvds_prepare, .mode_set = intel_lvds_mode_set, @@ -342,7 +343,6 @@ static const struct drm_connector_helper_funcs intel_lvds_helper_funcs = { }; static const struct drm_connector_funcs intel_lvds_connector_funcs = { - .dpms = intel_lvds_dpms, .save = intel_lvds_save, .restore = intel_lvds_restore, .detect = intel_lvds_detect, @@ -373,6 +373,7 @@ void intel_lvds_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_output *intel_output; struct drm_connector *connector; + struct drm_encoder *encoder; struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; u32 lvds; @@ -384,6 +385,7 @@ void intel_lvds_init(struct drm_device *dev) } connector = &intel_output->base; + encoder = &intel_output->enc; drm_connector_init(dev, &intel_output->base, &intel_lvds_connector_funcs, DRM_MODE_CONNECTOR_LVDS); @@ -392,7 +394,7 @@ void intel_lvds_init(struct drm_device *dev) intel_output->type = INTEL_OUTPUT_LVDS; - drm_connector_helper_add(connector, &intel_lvds_helper_funcs); + drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = FALSE; connector->doublescan_allowed = FALSE; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 85bee96b..498ad989 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -539,7 +539,7 @@ static bool intel_sdvo_set_clock_rate_mult(struct intel_output *intel_output, u8 return true; } -static bool intel_sdvo_mode_fixup(struct drm_connector *connector, +static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { @@ -550,15 +550,15 @@ static bool intel_sdvo_mode_fixup(struct drm_connector *connector, return true; } -static void intel_sdvo_mode_set(struct drm_connector *connector, +static void intel_sdvo_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = connector->crtc; + struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_output *intel_output = to_intel_output(connector); + struct intel_output *intel_output = enc_to_intel_output(encoder); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u16 width, height; u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; @@ -624,13 +624,13 @@ static void intel_sdvo_mode_set(struct drm_connector *connector, * output the preferred timing, and we don't support that currently. */ #if 0 - success = intel_sdvo_create_preferred_input_timing(connector, clock, + success = intel_sdvo_create_preferred_input_timing(intel_output, clock, width, height); if (success) { struct intel_sdvo_dtd *input_dtd; - intel_sdvo_get_preferred_input_timing(connector, &input_dtd); - intel_sdvo_set_input_timing(connector, &input_dtd); + intel_sdvo_get_preferred_input_timing(intel_output, &input_dtd); + intel_sdvo_set_input_timing(intel_output, &input_dtd); } #else intel_sdvo_set_input_timing(intel_output, &output_dtd); @@ -683,11 +683,11 @@ static void intel_sdvo_mode_set(struct drm_connector *connector, intel_sdvo_write_sdvox(intel_output, sdvox); } -static void intel_sdvo_dpms(struct drm_connector *connector, int mode) +static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(connector); + struct intel_output *intel_output = enc_to_intel_output(encoder); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u32 temp; @@ -971,15 +971,15 @@ static void intel_sdvo_destroy(struct drm_connector *connector) kfree(intel_output); } -static const struct drm_connector_helper_funcs intel_sdvo_helper_funcs = { +static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { + .dpms = intel_sdvo_dpms, .mode_fixup = intel_sdvo_mode_fixup, - .prepare = intel_connector_prepare, + .prepare = intel_encoder_prepare, .mode_set = intel_sdvo_mode_set, - .commit = intel_connector_commit, + .commit = intel_encoder_commit, }; static const struct drm_connector_funcs intel_sdvo_connector_funcs = { - .dpms = intel_sdvo_dpms, .save = intel_sdvo_save, .restore = intel_sdvo_restore, .detect = intel_sdvo_detect, @@ -1022,7 +1022,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_SDVO; - drm_connector_helper_add(connector, &intel_sdvo_helper_funcs); + connector->interlace_allowed = 0; connector->doublescan_allowed = 0; @@ -1108,6 +1108,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) } drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); + drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); connector->connector_type = connector_type; drm_sysfs_connector_add(connector); diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index c2658f13..b13b035f 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -898,9 +898,9 @@ const static struct tv_mode tv_modes[] = { #define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0]) static void -intel_tv_dpms(struct drm_connector *connector, int mode) +intel_tv_dpms(struct drm_encoder *encoder, int mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; switch(mode) { @@ -972,7 +972,7 @@ intel_tv_restore(struct drm_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_output *intel_output = to_intel_output(connector); struct intel_tv_priv *tv_priv = intel_output->dev_priv; - struct drm_crtc *crtc = connector->crtc; + struct drm_crtc *crtc = connector->encoder->crtc; struct intel_crtc *intel_crtc; int i; @@ -1088,22 +1088,22 @@ intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mo static bool -intel_tv_mode_fixup(struct drm_connector *connector, struct drm_display_mode *mode, +intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_mode_config *drm_config = &dev->mode_config; - struct intel_output *intel_output = to_intel_output(connector); + struct intel_output *intel_output = enc_to_intel_output(encoder); const struct tv_mode *tv_mode = intel_tv_mode_find (intel_output); - struct drm_connector *other_connector; + struct drm_encoder *other_encoder; if (!tv_mode) return FALSE; - /* FIXME: lock connector list */ - list_for_each_entry(other_connector, &drm_config->connector_list, head) { - if (other_connector != connector && - other_connector->crtc == connector->crtc) + /* FIXME: lock encoder list */ + list_for_each_entry(other_encoder, &drm_config->encoder_list, head) { + if (other_encoder != encoder && + other_encoder->crtc == encoder->crtc) return FALSE; } @@ -1112,14 +1112,14 @@ intel_tv_mode_fixup(struct drm_connector *connector, struct drm_display_mode *mo } static void -intel_tv_mode_set(struct drm_connector *connector, struct drm_display_mode *mode, +intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = connector->crtc; + struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_output *intel_output = to_intel_output(connector); + struct intel_output *intel_output = enc_to_intel_output(encoder); struct intel_tv_priv *tv_priv = intel_output->dev_priv; const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); u32 tv_ctl; @@ -1356,11 +1356,11 @@ static const struct drm_display_mode reported_modes[] = { * \return FALSE if TV is disconnected. */ static int -intel_tv_detect_type (struct drm_crtc *crtc, struct drm_connector *connector) +intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output) { - struct drm_device *dev = connector->dev; + struct drm_encoder *encoder = &intel_output->enc; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_output *intel_output = to_intel_output(connector); u32 pipeastat, pipeastat_save; u32 tv_ctl, save_tv_ctl; u32 tv_dac, save_tv_dac; @@ -1443,19 +1443,20 @@ intel_tv_detect(struct drm_connector *connector) struct drm_display_mode mode; struct intel_output *intel_output = to_intel_output(connector); struct intel_tv_priv *tv_priv = intel_output->dev_priv; + struct drm_encoder *encoder = &intel_output->enc; int dpms_mode; int type = tv_priv->type; mode = reported_modes[0]; drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); - if (connector->crtc) { - type = intel_tv_detect_type(connector->crtc, connector); + if (encoder->crtc) { + type = intel_tv_detect_type(encoder->crtc, intel_output); } else { - crtc = intel_get_load_detect_pipe(connector, &mode, &dpms_mode); + crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode); if (crtc) { - type = intel_tv_detect_type(crtc, connector); - intel_release_load_detect_pipe(connector, dpms_mode); + type = intel_tv_detect_type(crtc, intel_output); + intel_release_load_detect_pipe(intel_output, dpms_mode); } else type = -1; } @@ -1585,26 +1586,26 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop goto out; } tv_priv->tv_format = tv_modes[val].name; - intel_tv_mode_set(connector, NULL, NULL); + intel_tv_mode_set(&intel_output->enc, NULL, NULL); } else { ret = -EINVAL; goto out; } - intel_tv_mode_set(connector, NULL, NULL); + intel_tv_mode_set(&intel_output->enc, NULL, NULL); out: return ret; } -static const struct drm_connector_helper_funcs intel_tv_helper_funcs = { +static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { + .dpms = intel_tv_dpms, .mode_fixup = intel_tv_mode_fixup, - .prepare = intel_connector_prepare, + .prepare = intel_encoder_prepare, .mode_set = intel_tv_mode_set, - .commit = intel_connector_commit, + .commit = intel_encoder_commit, }; static const struct drm_connector_funcs intel_tv_connector_funcs = { - .dpms = intel_tv_dpms, .save = intel_tv_save, .restore = intel_tv_restore, .mode_valid = intel_tv_mode_valid, @@ -1693,7 +1694,7 @@ intel_tv_init(struct drm_device *dev) tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); - drm_connector_helper_add(connector, &intel_tv_helper_funcs); + drm_encoder_helper_add(&intel_output->enc, &intel_tv_helper_funcs); connector->interlace_allowed = FALSE; connector->doublescan_allowed = FALSE; diff --git a/shared-core/drm.h b/shared-core/drm.h index 1fcbf144..7e94fb82 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1058,6 +1058,7 @@ struct drm_mode_get_encoder { uint32_t encoder_type; uint32_t encoder_id; + unsigned int crtc; /**< Id of crtc */ uint32_t crtcs; uint32_t clones; }; @@ -1079,8 +1080,8 @@ struct drm_mode_get_connector { int count_props; int count_encoders; + unsigned int encoder; /**< Current Encoder */ unsigned int connector; /**< Id */ - unsigned int crtc; /**< Id of crtc */ unsigned int connector_type; unsigned int connector_type_id; -- cgit v1.2.3 From dba95ec34315d62934ff0e493e085aa6a03cde7c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 10:41:12 +1000 Subject: drm: fixup some interfaces so test code works again --- libdrm/xf86drmMode.c | 14 +++----------- libdrm/xf86drmMode.h | 3 ++- linux-core/drm_crtc.c | 7 ------- tests/mode/modetest.c | 4 ++-- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 8b7f2bcf..d11fc12e 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -254,10 +254,6 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) struct drm_mode_crtc crtc; drmModeCrtcPtr r; - crtc.count_connectors = 0; - crtc.connectors = 0; - crtc.count_possibles = 0; - crtc.possibles = 0; crtc.crtc_id = crtcId; if (ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc)) @@ -278,12 +274,6 @@ drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo)); r->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; - r->count_connectors = crtc.count_connectors; - r->count_possibles = crtc.count_possibles; - /* TODO we realy should test if these alloc & cpy fails. */ - r->connectors = crtc.connectors; - r->possibles = crtc.possibles; - return r; } @@ -362,6 +352,8 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) if (!(r = drmMalloc(sizeof(*r)))) return 0; + r->encoder_id = enc.encoder_id; + r->crtc = enc.crtc; r->encoder_type = enc.encoder_type; r->crtcs = enc.crtcs; r->clones = enc.clones; @@ -411,7 +403,7 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) } r->connector_id = conn.connector; - r->crtc = conn.crtc; + r->encoder = conn.encoder; r->connection = conn.connection; r->mmWidth = conn.mm_width; r->mmHeight = conn.mm_height; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index ceaa9abc..2f3a8f74 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -112,6 +112,7 @@ typedef struct _drmModeCrtc { typedef struct _drmModeEncoder { unsigned int encoder_id; unsigned int encoder_type; + uint32_t crtc; uint32_t crtcs; uint32_t clones; } drmModeEncoder, *drmModeEncoderPtr; @@ -134,7 +135,7 @@ typedef enum { typedef struct _drmModeConnector { unsigned int connector_id; - unsigned int crtc; /**< Crtc currently connected to */ + unsigned int encoder; /**< Crtc currently connected to */ unsigned int connector_type; unsigned int connector_type_id; drmModeConnection connection; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 27bf7c27..c4210fd4 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1015,8 +1015,6 @@ int drm_mode_getcrtc(struct drm_device *dev, { struct drm_mode_crtc *crtc_resp = data; struct drm_crtc *crtc; - struct drm_connector *connector; - int ocount; int ret = 0; mutex_lock(&dev->mode_config.mutex); @@ -1039,11 +1037,6 @@ int drm_mode_getcrtc(struct drm_device *dev, drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); crtc_resp->mode_valid = 1; - ocount = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder->crtc == crtc) - crtc_resp->connectors |= 1 << (ocount++); - } } else { crtc_resp->mode_valid = 0; diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index 382cba65..bd1e8000 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -57,7 +57,7 @@ int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uin printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); printf("\tid : %i\n", id); - printf("\tcrtc id : %i\n", connector->crtc); + printf("\tencoder id : %i\n", connector->encoder); printf("\tconn : %s\n", getConnectionText(connector->connection)); printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); printf("\tcount_modes : %i\n", connector->count_modes); @@ -67,7 +67,7 @@ int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uin for (i = 0; i < connector->count_encoders; i++) { enc = drmModeGetEncoder(fd, connector->encoders[i]); if (enc) { - printf("Encoder: %d %d %d %d\n", enc->encoder_id, enc->encoder_type, enc->crtcs, enc->clones); + printf("Encoder: %d %d %d %d %d\n", enc->crtc, enc->encoder_id, enc->encoder_type, enc->crtcs, enc->clones); } } -- cgit v1.2.3 From 0dd000b578adec6ff101c957bce7dc9a32b76713 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 11:12:28 +1000 Subject: drm/modesetting: move some connector functions to helper. Migrated the output mode collection into the helper. --- linux-core/drm_crtc.c | 132 +--------------------------------------- linux-core/drm_crtc.h | 5 +- linux-core/drm_crtc_helper.c | 140 +++++++++++++++++++++++++++++++++++++++++-- linux-core/drm_crtc_helper.h | 15 ++++- linux-core/intel_crt.c | 10 +++- linux-core/intel_display.c | 2 +- linux-core/intel_dvo.c | 7 ++- linux-core/intel_lvds.c | 11 +++- linux-core/intel_sdvo.c | 9 ++- linux-core/intel_tv.c | 9 ++- 10 files changed, 186 insertions(+), 154 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c4210fd4..74e526bd 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -285,136 +285,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_cleanup); -/** - * drm_crtc_in_use - check if a given CRTC is in a mode_config - * @crtc: CRTC to check - * - * LOCKING: - * Caller must hold mode config lock. - * - * Walk @crtc's DRM device's mode_config and see if it's in use. - * - * RETURNS: - * True if @crtc is part of the mode_config, false otherwise. - */ -bool drm_crtc_in_use(struct drm_crtc *crtc) -{ - struct drm_encoder *encoder; - struct drm_device *dev = crtc->dev; - /* FIXME: Locking around list access? */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) - if (encoder->crtc == crtc) - return true; - return false; -} -EXPORT_SYMBOL(drm_crtc_in_use); - -/* - * Detailed mode info for a standard 640x480@60Hz monitor - */ -static struct drm_display_mode std_mode[] = { - { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, - 752, 800, 0, 480, 490, 492, 525, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ -}; - -/** - * drm_crtc_probe_connector_modes - get complete set of display modes - * @dev: DRM device - * @maxX: max width for modes - * @maxY: max height for modes - * - * LOCKING: - * Caller must hold mode config lock. - * - * Based on @dev's mode_config layout, scan all the connectors and try to detect - * modes on them. Modes will first be added to the connector's probed_modes - * list, then culled (based on validity and the @maxX, @maxY parameters) and - * put into the normal modes list. - * - * Intended to be used either at bootup time or when major configuration - * changes have occurred. - * - * FIXME: take into account monitor limits - */ -void drm_crtc_probe_single_connector_modes(struct drm_connector *connector, int maxX, int maxY) -{ - struct drm_device *dev = connector->dev; - struct drm_display_mode *mode, *t; - int ret; - //if (maxX == 0 || maxY == 0) - // TODO - - /* set all modes to the unverified state */ - list_for_each_entry_safe(mode, t, &connector->modes, head) - mode->status = MODE_UNVERIFIED; - - connector->status = (*connector->funcs->detect)(connector); - - if (connector->status == connector_status_disconnected) { - DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(connector)); - /* TODO set EDID to NULL */ - return; - } - - ret = (*connector->funcs->get_modes)(connector); - - if (ret) { - drm_mode_connector_list_update(connector); - } - - if (maxX && maxY) - drm_mode_validate_size(dev, &connector->modes, maxX, - maxY, 0); - list_for_each_entry_safe(mode, t, &connector->modes, head) { - if (mode->status == MODE_OK) - mode->status = (*connector->funcs->mode_valid)(connector,mode); - } - - - drm_mode_prune_invalid(dev, &connector->modes, TRUE); - - if (list_empty(&connector->modes)) { - struct drm_display_mode *stdmode; - - DRM_DEBUG("No valid modes on %s\n", drm_get_connector_name(connector)); - - /* Should we do this here ??? - * When no valid EDID modes are available we end up - * here and bailed in the past, now we add a standard - * 640x480@60Hz mode and carry on. - */ - stdmode = drm_mode_duplicate(dev, &std_mode[0]); - drm_mode_probed_add(connector, stdmode); - drm_mode_list_concat(&connector->probed_modes, - &connector->modes); - - DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", - drm_get_connector_name(connector)); - } - - drm_mode_sort(&connector->modes); - - DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector)); - list_for_each_entry_safe(mode, t, &connector->modes, head) { - mode->vrefresh = drm_mode_vrefresh(mode); - - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - drm_mode_debug_printmodeline(mode); - } -} - -void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY) -{ - struct drm_connector *connector; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - drm_crtc_probe_single_connector_modes(connector, maxX, maxY); - } -} -EXPORT_SYMBOL(drm_crtc_probe_connector_modes); - - /** * drm_mode_probed_add - add a mode to the specified connector's probed mode list * @connector: connector the new mode @@ -1109,7 +979,7 @@ int drm_mode_getconnector(struct drm_device *dev, } if (out_resp->count_modes == 0) { - drm_crtc_probe_single_connector_modes(connector, dev->mode_config.max_width, dev->mode_config.max_height); + connector->funcs->fill_modes(connector, dev->mode_config.max_width, dev->mode_config.max_height); } out_resp->connector_type = connector->connector_type; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 14aa5038..6dbc88a4 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -380,13 +380,10 @@ struct drm_connector_funcs { void (*save)(struct drm_connector *connector); void (*restore)(struct drm_connector *connector); enum drm_connector_status (*detect)(struct drm_connector *connector); - int (*get_modes)(struct drm_connector *connector); + void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); bool (*set_property)(struct drm_connector *connector, struct drm_property *property, uint64_t val); void (*destroy)(struct drm_connector *connector); - int (*mode_valid)(struct drm_connector *connector, - struct drm_display_mode *mode); - }; struct drm_encoder_funcs { diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 82862b55..f1a72707 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -34,6 +34,136 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" +/* + * Detailed mode info for a standard 640x480@60Hz monitor + */ +static struct drm_display_mode std_mode[] = { + { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ +}; + +/** + * drm_helper_probe_connector_modes - get complete set of display modes + * @dev: DRM device + * @maxX: max width for modes + * @maxY: max height for modes + * + * LOCKING: + * Caller must hold mode config lock. + * + * Based on @dev's mode_config layout, scan all the connectors and try to detect + * modes on them. Modes will first be added to the connector's probed_modes + * list, then culled (based on validity and the @maxX, @maxY parameters) and + * put into the normal modes list. + * + * Intended to be used either at bootup time or when major configuration + * changes have occurred. + * + * FIXME: take into account monitor limits + */ +void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *mode, *t; + struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + int ret; + + /* set all modes to the unverified state */ + list_for_each_entry_safe(mode, t, &connector->modes, head) + mode->status = MODE_UNVERIFIED; + + connector->status = (*connector->funcs->detect)(connector); + + if (connector->status == connector_status_disconnected) { + DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(connector)); + /* TODO set EDID to NULL */ + return; + } + + ret = (*connector_funcs->get_modes)(connector); + + if (ret) { + drm_mode_connector_list_update(connector); + } + + if (maxX && maxY) + drm_mode_validate_size(dev, &connector->modes, maxX, + maxY, 0); + list_for_each_entry_safe(mode, t, &connector->modes, head) { + if (mode->status == MODE_OK) + mode->status = (*connector_funcs->mode_valid)(connector,mode); + } + + + drm_mode_prune_invalid(dev, &connector->modes, TRUE); + + if (list_empty(&connector->modes)) { + struct drm_display_mode *stdmode; + + DRM_DEBUG("No valid modes on %s\n", drm_get_connector_name(connector)); + + /* Should we do this here ??? + * When no valid EDID modes are available we end up + * here and bailed in the past, now we add a standard + * 640x480@60Hz mode and carry on. + */ + stdmode = drm_mode_duplicate(dev, &std_mode[0]); + drm_mode_probed_add(connector, stdmode); + drm_mode_list_concat(&connector->probed_modes, + &connector->modes); + + DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", + drm_get_connector_name(connector)); + } + + drm_mode_sort(&connector->modes); + + DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector)); + list_for_each_entry_safe(mode, t, &connector->modes, head) { + mode->vrefresh = drm_mode_vrefresh(mode); + + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + drm_mode_debug_printmodeline(mode); + } +} +EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); + +void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, uint32_t maxY) +{ + struct drm_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_helper_probe_single_connector_modes(connector, maxX, maxY); + } +} +EXPORT_SYMBOL(drm_helper_probe_connector_modes); + + +/** + * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config + * @crtc: CRTC to check + * + * LOCKING: + * Caller must hold mode config lock. + * + * Walk @crtc's DRM device's mode_config and see if it's in use. + * + * RETURNS: + * True if @crtc is part of the mode_config, false otherwise. + */ +bool drm_helper_crtc_in_use(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + struct drm_device *dev = crtc->dev; + /* FIXME: Locking around list access? */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->crtc == crtc) + return true; + return false; +} +EXPORT_SYMBOL(drm_helper_crtc_in_use); + /** * drm_disable_unused_functions - disable unused objects * @dev: DRM device @@ -81,8 +211,8 @@ static void drm_pick_crtcs (struct drm_device *dev) int found; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector->encoder->crtc = NULL; - + connector->encoder->crtc = NULL; + /* Don't hook up connectors that are disconnected ?? * * This is debateable. Do we want fixed /dev/fbX or @@ -211,7 +341,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo adjusted_mode = drm_mode_duplicate(dev, mode); - crtc->enabled = drm_crtc_in_use(crtc); + crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) return true; @@ -456,7 +586,7 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) mutex_lock(&dev->mode_config.mutex); - drm_crtc_probe_connector_modes(dev, 2048, 2048); + drm_helper_probe_connector_modes(dev, 2048, 2048); drm_pick_crtcs(dev); @@ -518,7 +648,7 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c has_config = 1; } - drm_crtc_probe_connector_modes(dev, 2048, 2048); + drm_helper_probe_connector_modes(dev, 2048, 2048); if (!has_config) drm_pick_crtcs(dev); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 063d1f7a..80cb4b49 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -55,8 +55,14 @@ struct drm_encoder_helper_funcs { struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); }; - +struct drm_connector_helper_funcs { + int (*get_modes)(struct drm_connector *connector); + int (*mode_valid)(struct drm_connector *connector, + struct drm_display_mode *mode); +}; + +extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); extern void drm_helper_disable_unused_functions(struct drm_device *dev); extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, bool connected); @@ -64,7 +70,7 @@ extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); - +extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) { crtc->helper_private = (void *)funcs; @@ -75,6 +81,11 @@ static inline void drm_encoder_helper_add(struct drm_encoder *encoder, const str encoder->helper_private = (void *)funcs; } +static inline void drm_connector_helper_add(struct drm_connector *connector, const struct drm_connector_helper_funcs *funcs) +{ + connector->helper_private = (void *)funcs; +} + #endif diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index ec4c2bf9..21a1e7d7 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -237,13 +237,16 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { .save = intel_crt_save, .restore = intel_crt_restore, .detect = intel_crt_detect, - .get_modes = intel_crt_get_modes, + .fill_modes = drm_helper_probe_single_connector_modes, .destroy = intel_crt_destroy, .set_property = intel_crt_set_property, - .mode_valid = intel_crt_mode_valid, - }; +static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { + .mode_valid = intel_crt_mode_valid, + .get_modes = intel_crt_get_modes, +}; + void intel_crt_enc_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); @@ -283,6 +286,7 @@ void intel_crt_init(struct drm_device *dev) connector->doublescan_allowed = 0; drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs); + drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index c1cb2bff..bbaa19d1 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1184,7 +1184,7 @@ void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_ if (intel_output->load_detect_temp) { encoder->crtc = NULL; intel_output->load_detect_temp = FALSE; - crtc->enabled = drm_crtc_in_use(crtc); + crtc->enabled = drm_helper_crtc_in_use(crtc); drm_helper_disable_unused_functions(dev); } diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index 364cd659..e895d5b6 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -335,9 +335,13 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = { .save = intel_dvo_save, .restore = intel_dvo_restore, .detect = intel_dvo_detect, - .get_modes = intel_dvo_get_modes, .destroy = intel_dvo_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, +}; + +static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = { .mode_valid = intel_dvo_mode_valid, + .get_modes = intel_dvo_get_modes, }; void intel_dvo_enc_destroy(struct drm_encoder *encoder) @@ -464,6 +468,7 @@ void intel_dvo_init(struct drm_device *dev) break; } + drm_connector_helper_add(connector, &intel_dvo_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = false; connector->doublescan_allowed = false; diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index b83f3923..cbe8b53d 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -342,13 +342,17 @@ static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { .commit = intel_lvds_commit, }; +static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { + .get_modes = intel_lvds_get_modes, + .mode_valid = intel_lvds_mode_valid, +}; + static const struct drm_connector_funcs intel_lvds_connector_funcs = { .save = intel_lvds_save, .restore = intel_lvds_restore, .detect = intel_lvds_detect, - .get_modes = intel_lvds_get_modes, + .fill_modes = drm_helper_probe_single_connector_modes, .destroy = intel_lvds_destroy, - .mode_valid = intel_lvds_mode_valid, }; @@ -361,6 +365,8 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = { .destroy = intel_lvds_enc_destroy, }; + + /** * intel_lvds_init - setup LVDS connectors on this device * @dev: drm device @@ -395,6 +401,7 @@ void intel_lvds_init(struct drm_device *dev) intel_output->type = INTEL_OUTPUT_LVDS; drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs); + drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; connector->interlace_allowed = FALSE; connector->doublescan_allowed = FALSE; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 498ad989..d3ca2a20 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -983,11 +983,14 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = { .save = intel_sdvo_save, .restore = intel_sdvo_restore, .detect = intel_sdvo_detect, - .get_modes = intel_sdvo_get_modes, + .fill_modes = drm_helper_probe_single_connector_modes, .destroy = intel_sdvo_destroy, - .mode_valid = intel_sdvo_mode_valid, }; +static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { + .get_modes = intel_sdvo_get_modes, + .mode_valid = intel_sdvo_mode_valid, +}; void intel_sdvo_enc_destroy(struct drm_encoder *encoder) { @@ -1019,7 +1022,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, DRM_MODE_CONNECTOR_Unknown); - + drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_SDVO; diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index b13b035f..c3b5c093 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1608,11 +1608,15 @@ static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { static const struct drm_connector_funcs intel_tv_connector_funcs = { .save = intel_tv_save, .restore = intel_tv_restore, - .mode_valid = intel_tv_mode_valid, .detect = intel_tv_detect, - .get_modes = intel_tv_get_modes, .destroy = intel_tv_destroy, .set_property = intel_tv_set_property, + .fill_modes = drm_helper_probe_single_connector_modes, +}; + +static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { + .mode_valid = intel_tv_mode_valid, + .get_modes = intel_tv_get_modes, }; void intel_tv_enc_destroy(struct drm_encoder *encoder) @@ -1695,6 +1699,7 @@ intel_tv_init(struct drm_device *dev) tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); drm_encoder_helper_add(&intel_output->enc, &intel_tv_helper_funcs); + drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); connector->interlace_allowed = FALSE; connector->doublescan_allowed = FALSE; -- cgit v1.2.3 From 46c78a2223802b9105a87b7125fd4872ab69c4ca Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 11:44:35 +1000 Subject: drm/modesetting: add best encoder finding for modesetting This asks the driver to suggest the best encoder for the connector during the pick crtcs stage. Need to also do this during mode setting stages --- linux-core/drm_crtc.c | 5 +---- linux-core/drm_crtc.h | 2 +- linux-core/drm_crtc_helper.c | 28 +++++++++++++++++++++------- linux-core/drm_crtc_helper.h | 1 + linux-core/intel_crt.c | 1 + linux-core/intel_display.c | 11 +++++++++++ linux-core/intel_drv.h | 4 +++- linux-core/intel_dvo.c | 2 ++ linux-core/intel_lvds.c | 2 ++ linux-core/intel_sdvo.c | 2 ++ linux-core/intel_tv.c | 2 ++ 11 files changed, 47 insertions(+), 13 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 74e526bd..73c7f2a3 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2042,16 +2042,13 @@ out: } int drm_mode_connector_attach_encoder(struct drm_connector *connector, - struct drm_encoder *encoder) + struct drm_encoder *encoder) { int i; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] == 0) { connector->encoder_ids[i] = encoder->id; - /* pick the first added encoder as the current */ - if (i == 0) - connector->encoder = encoder; return 0; } } diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 6dbc88a4..390ab2d3 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -624,7 +624,7 @@ extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, extern char *drm_get_encoder_name(struct drm_encoder *encoder); extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, - struct drm_encoder *encoder); + struct drm_encoder *encoder); extern void drm_mode_connector_detach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index f1a72707..a4168f68 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -208,10 +208,17 @@ static void drm_pick_crtcs (struct drm_device *dev) struct drm_encoder *encoder, *encoder_equal; struct drm_crtc *crtc; struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; + struct drm_connector_helper_funcs *connector_funcs; int found; + /* clean out all the encoder/crtc combos */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder->crtc = NULL; + } + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector->encoder->crtc = NULL; + connector_funcs = connector->helper_private; + connector->encoder = NULL; /* Don't hook up connectors that are disconnected ?? * @@ -249,7 +256,11 @@ static void drm_pick_crtcs (struct drm_device *dev) } } - encoder = connector->encoder; + encoder = connector_funcs->best_encoder(connector); + if (!encoder) + continue; + + connector->encoder = encoder; c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -259,12 +270,12 @@ static void drm_pick_crtcs (struct drm_device *dev) if ((encoder->possible_crtcs & (1 << c)) == 0) continue; - list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { - if (connector->id == connector_equal->id) + list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) { + if (encoder->id == encoder_equal->id) continue; /* Find out if crtc has been assigned before */ - if (connector_equal->encoder->crtc == crtc) + if (encoder_equal->crtc == crtc) assigned = 1; } @@ -281,6 +292,9 @@ static void drm_pick_crtcs (struct drm_device *dev) encoder_equal = connector_equal->encoder; + if (!encoder_equal) + continue; + list_for_each_entry(modes, &connector->modes, head) { list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { @@ -301,8 +315,8 @@ clone: continue; /* Found a CRTC to attach to, do it ! */ - connector->encoder->crtc = crtc; - connector->encoder->crtc->desired_mode = des_mode; + encoder->crtc = crtc; + encoder->crtc->desired_mode = des_mode; connector->initial_x = 0; connector->initial_y = 0; DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 80cb4b49..3a3a4d4f 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -60,6 +60,7 @@ struct drm_connector_helper_funcs { int (*get_modes)(struct drm_connector *connector); int (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode); + struct drm_encoder *(*best_encoder)(struct drm_connector *connector); }; extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 21a1e7d7..bf7c449e 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -245,6 +245,7 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = { static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { .mode_valid = intel_crt_mode_valid, .get_modes = intel_crt_get_modes, + .best_encoder = intel_best_encoder, }; void intel_crt_enc_destroy(struct drm_encoder *encoder) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index bbaa19d1..e23b3973 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1489,3 +1489,14 @@ void intel_modeset_cleanup(struct drm_device *dev) { drm_mode_config_cleanup(dev); } + + +/* current intel driver doesn't take advantage of encoders + always give back the encoder for the connector +*/ +struct drm_encoder *intel_best_encoder(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + + return &intel_output->enc; +} diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 0a5e350e..24287e37 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -85,6 +85,9 @@ extern void intel_lvds_init(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); extern void intel_encoder_commit (struct drm_encoder *encoder); + +extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector); + extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_wait_for_vblank(struct drm_device *dev); @@ -98,7 +101,6 @@ extern void intel_release_load_detect_pipe(struct intel_output *intel_output, extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); - extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index e895d5b6..b061b1c5 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -342,6 +342,7 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = { static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = { .mode_valid = intel_dvo_mode_valid, .get_modes = intel_dvo_get_modes, + .best_encoder = intel_best_encoder, }; void intel_dvo_enc_destroy(struct drm_encoder *encoder) @@ -479,6 +480,7 @@ void intel_dvo_init(struct drm_device *dev) drm_encoder_init(dev, &intel_output->enc, &intel_dvo_enc_funcs, encoder_type); drm_encoder_helper_add(&intel_output->enc, &intel_dvo_helper_funcs); + drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); if (dvo->type == INTEL_DVO_CHIP_LVDS) { /* For our LVDS chipsets, we should hopefully be able * to dig the fixed panel mode out of the BIOS data. diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index cbe8b53d..f2fe4612 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -345,6 +345,7 @@ static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { .get_modes = intel_lvds_get_modes, .mode_valid = intel_lvds_mode_valid, + .best_encoder = intel_best_encoder, }; static const struct drm_connector_funcs intel_lvds_connector_funcs = { @@ -398,6 +399,7 @@ void intel_lvds_init(struct drm_device *dev) drm_encoder_init(dev, &intel_output->enc, &intel_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); + drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); intel_output->type = INTEL_OUTPUT_LVDS; drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs); diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index d3ca2a20..9ae0d567 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -990,6 +990,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = { static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { .get_modes = intel_sdvo_get_modes, .mode_valid = intel_sdvo_mode_valid, + .best_encoder = intel_best_encoder, }; void intel_sdvo_enc_destroy(struct drm_encoder *encoder) @@ -1114,6 +1115,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); connector->connector_type = connector_type; + drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); drm_sysfs_connector_add(connector); /* Set the input timing to the screen. Assume always input 0. */ diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index c3b5c093..e45cfa3b 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1617,6 +1617,7 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = { static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { .mode_valid = intel_tv_mode_valid, .get_modes = intel_tv_get_modes, + .best_encoder = intel_best_encoder, }; void intel_tv_enc_destroy(struct drm_encoder *encoder) @@ -1683,6 +1684,7 @@ intel_tv_init(struct drm_device *dev) drm_encoder_init(dev, &intel_output->enc, &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC); + drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); tv_priv = (struct intel_tv_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_TVOUT; intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1)); -- cgit v1.2.3 From 7fec6c0e2a2457925b88ed3bd70d9defde77b81b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 12:57:09 +1000 Subject: drm: fixup encoder picking in set_config stage --- linux-core/drm_crtc_helper.c | 68 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index a4168f68..2ceaa860 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -386,7 +386,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo if (encoder->crtc != crtc) continue; - encoder_funcs = encoder->helper_private; + encoder_funcs = encoder->helper_private; if (!(ret = encoder_funcs->mode_fixup(encoder, mode, adjusted_mode))) { goto done; } @@ -475,12 +475,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_crtc **save_crtcs, *new_crtc; + struct drm_encoder **save_encoders, *new_encoder; bool save_enabled; bool changed = false; bool flip_or_move = false; struct drm_connector *connector; - int count = 0, ro; + int count = 0, ro, fail = 0; struct drm_crtc_helper_funcs *crtc_funcs; + int ret = 0; DRM_DEBUG("\n"); @@ -506,6 +508,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) if (!save_crtcs) return -ENOMEM; + save_encoders = kzalloc(dev->mode_config.num_connector * sizeof(struct drm_encoders *), GFP_KERNEL); + if (!save_encoders) { + kfree(save_crtcs); + return -ENOMEM; + } + /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ if (set->crtc->fb != set->fb) @@ -521,6 +529,35 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) changed = true; } + /* a) traverse passed in connector list and get encoders for them */ + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + save_encoders[count++] = connector->encoder; + new_encoder = NULL; + for (ro = 0; ro < set->num_connectors; ro++) { + if (set->connectors[ro] == connector) { + new_encoder = connector_funcs->best_encoder(connector); + /* if we can't get an encoder for a connector + we are setting now - then fail */ + if (new_encoder == NULL) + /* don't break so fail path works correct */ + fail = 1; + break; + } + } + + if (new_encoder != connector->encoder) { + changed = true; + connector->encoder = new_encoder; + } + } + + if (fail) { + ret = -EINVAL; + goto fail_no_encoder; + } + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) continue; @@ -553,13 +590,9 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) DRM_DEBUG("attempting to set mode from userspace\n"); drm_mode_debug_printmodeline(set->mode); if (!drm_crtc_helper_set_mode(set->crtc, set->mode, set->x, - set->y)) { - set->crtc->enabled = save_enabled; - count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - connector->encoder->crtc = save_crtcs[count++]; - kfree(save_crtcs); - return -EINVAL; + set->y)) { + ret = -EINVAL; + goto fail_set_mode; } /* TODO are these needed? */ set->crtc->desired_x = set->x; @@ -573,8 +606,25 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs->mode_set_base(set->crtc, set->x, set->y); } + kfree(save_encoders); kfree(save_crtcs); return 0; + +fail_set_mode: + set->crtc->enabled = save_enabled; + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + connector->encoder->crtc = save_crtcs[count++]; +fail_no_encoder: + kfree(save_crtcs); + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + connector->encoder = save_encoders[count++]; + } + kfree(save_encoders); + return ret; + + } EXPORT_SYMBOL(drm_crtc_helper_set_config); -- cgit v1.2.3 From 4e7b24639808e5e1e2c05143028db1a3bc2812e9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 14:04:41 +1000 Subject: drm: add functions to get/set gamma ramps --- libdrm/xf86drmMode.c | 36 ++++++++++++++ libdrm/xf86drmMode.h | 5 ++ linux-core/drm_crtc.c | 115 +++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_crtc.h | 19 ++++++-- linux-core/drm_drv.c | 2 + linux-core/drm_fb.c | 3 -- linux-core/intel_display.c | 21 ++++++++- linux-core/intel_drv.h | 3 +- linux-core/intel_fb.c | 4 +- linux-core/radeon_ms_fb.c | 6 +-- shared-core/drm.h | 15 +++++- tests/mode/modetest.c | 1 + 12 files changed, 214 insertions(+), 16 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index d11fc12e..a393f965 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -657,3 +657,39 @@ int drmModeReplaceFB(int fd, uint32_t buffer_id, return 0; } + +int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, uint16_t *blue) +{ + int ret; + struct drm_mode_crtc_lut l; + + l.crtc_id = crtc_id; + l.gamma_size = size; + l.red = VOID2U64(red); + l.green = VOID2U64(green); + l.blue = VOID2U64(blue); + + if ((ret = ioctl(fd, DRM_IOCTL_MODE_GETGAMMA, &l))) + return ret; + + return 0; +} + +int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, uint16_t *blue) +{ + int ret; + struct drm_mode_crtc_lut l; + + l.crtc_id = crtc_id; + l.gamma_size = size; + l.red = VOID2U64(red); + l.green = VOID2U64(green); + l.blue = VOID2U64(blue); + + if ((ret = ioctl(fd, DRM_IOCTL_MODE_SETGAMMA, &l))) + return ret; + + return 0; +} diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 2f3a8f74..56908d8f 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -263,3 +263,8 @@ extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, uint64_t value); extern int drmCheckModesettingSupported(const char *busid); + +extern int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, uint16_t *blue); +extern int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, uint16_t *blue); diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 73c7f2a3..7746fd50 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -279,6 +279,11 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; + if (crtc->gamma_store) { + kfree(crtc->gamma_store); + crtc->gamma_store = NULL; + } + drm_idr_put(dev, crtc->id); list_del(&crtc->head); dev->mode_config.num_crtc--; @@ -896,6 +901,7 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->x = crtc->x; crtc_resp->y = crtc->y; + crtc_resp->gamma_size = crtc->gamma_size; if (crtc->fb) crtc_resp->fb_id = crtc->fb->id; @@ -2070,3 +2076,112 @@ void drm_mode_connector_detach_encoder(struct drm_connector *connector, } } EXPORT_SYMBOL(drm_mode_connector_detach_encoder); + +bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, + int gamma_size) +{ + crtc->gamma_size = gamma_size; + + crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL); + if (!crtc->gamma_store) { + crtc->gamma_size = 0; + return false; + } + + return true; +} +EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); + +int drm_mode_gamma_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_lut *crtc_lut = data; + struct drm_crtc *crtc; + void *r_base, *g_base, *b_base; + int size; + int ret = 0; + + mutex_lock(&dev->mode_config.mutex); + crtc = idr_find(&dev->mode_config.crtc_idr, crtc_lut->crtc_id); + if (!crtc || (crtc->id != crtc_lut->crtc_id)) { + ret = -EINVAL; + goto out; + } + + /* memcpy into gamma store */ + if (crtc_lut->gamma_size != crtc->gamma_size) { + ret = -EINVAL; + goto out; + } + + size = crtc_lut->gamma_size * (sizeof(uint16_t)); + r_base = crtc->gamma_store; + if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { + ret = -EFAULT; + goto out; + } + + g_base = r_base + size; + if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { + ret = -EFAULT; + goto out; + } + + b_base = g_base + size; + if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { + ret = -EFAULT; + goto out; + } + + crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size); + +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; + +} + +int drm_mode_gamma_get_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_crtc_lut *crtc_lut = data; + struct drm_crtc *crtc; + void *r_base, *g_base, *b_base; + int size; + int ret = 0; + + mutex_lock(&dev->mode_config.mutex); + crtc = idr_find(&dev->mode_config.crtc_idr, crtc_lut->crtc_id); + if (!crtc || (crtc->id != crtc_lut->crtc_id)) { + ret = -EINVAL; + goto out; + } + + /* memcpy into gamma store */ + if (crtc_lut->gamma_size != crtc->gamma_size) { + ret = -EINVAL; + goto out; + } + + size = crtc_lut->gamma_size * (sizeof(uint16_t)); + r_base = crtc->gamma_store; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { + ret = -EFAULT; + goto out; + } + + g_base = r_base + size; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { + ret = -EFAULT; + goto out; + } + + b_base = g_base + size; + if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { + ret = -EFAULT; + goto out; + } +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 390ab2d3..151d1732 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -315,8 +315,8 @@ struct drm_crtc_funcs { int (*cursor_move)(struct drm_crtc *crtc, int x, int y); /* Set gamma on the CRTC */ - void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b, - int regno); + void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, + uint32_t size); /* Object destroy routine */ void (*destroy)(struct drm_crtc *crtc); @@ -354,6 +354,10 @@ struct drm_crtc { int desired_x, desired_y; const struct drm_crtc_funcs *funcs; + /* CRTC gamma size for reporting to userspace */ + uint32_t gamma_size; + uint16_t *gamma_store; + /* if you are using the helper */ void *helper_private; }; @@ -627,7 +631,8 @@ extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); extern void drm_mode_connector_detach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); - +extern bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, + int gamma_size); /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -665,7 +670,11 @@ extern int drm_mode_hotplug_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_replacefb(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_mode_getencoder(struct drm_device *dev, - void *data, struct drm_file *file_priv); +extern int drm_mode_getencoder(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); #endif /* __DRM_CRTC_H__ */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 5a16fe8d..82e5af57 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -143,6 +143,8 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_REPLACEFB, drm_mode_replacefb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 775fd180..74a4394a 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -58,9 +58,6 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 1; if (fb->depth == 8) { - if (crtc->funcs->gamma_set) { - crtc->funcs->gamma_set(crtc, red, green, blue, regno); - } return 0; } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index e23b3973..ba9441d6 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1056,7 +1056,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) } /** Sets the color ramps on behalf of RandR */ -static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, +void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -1066,6 +1066,24 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, intel_crtc->lut_b[regno] = blue >> 8; } +static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, uint32_t size) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int i; + + if (size != 256) + return; + + for (i = 0; i < 256; i++) { + intel_crtc->lut_r[i] = red[i] >> 8; + intel_crtc->lut_g[i] = green[i] >> 8; + intel_crtc->lut_b[i] = blue[i] >> 8; + } + + intel_crtc_load_lut(crtc); +} + /** * Get a pipe with a simple mode set on it for doing load-based monitor * detection. @@ -1343,6 +1361,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); + drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); intel_crtc->pipe = pipe; for (i = 0; i < 256; i++) { intel_crtc->lut_r[i] = i; diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 24287e37..210ed990 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -104,5 +104,6 @@ extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); - +extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno); #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 138d189e..268e95c5 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -41,6 +41,7 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" +#include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -79,8 +80,7 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, return 1; if (fb->depth == 8) { - if (crtc->funcs->gamma_set) - crtc->funcs->gamma_set(crtc, red, green, blue, regno); + intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); return 0; } diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c index e320144e..0ac9207c 100644 --- a/linux-core/radeon_ms_fb.c +++ b/linux-core/radeon_ms_fb.c @@ -54,9 +54,9 @@ static int radeonfb_setcolreg(unsigned regno, unsigned red, if (regno > 255) { return 1; } - if (crtc->funcs->gamma_set) { - crtc->funcs->gamma_set(crtc, red, green, blue, regno); - } + // if (crtc->funcs->gamma_set) { + // crtc->funcs->gamma_set(crtc, red, green, blue, regno); + // } if (regno < 16) { switch (fb->depth) { case 15: diff --git a/shared-core/drm.h b/shared-core/drm.h index 7e94fb82..132c7746 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1048,7 +1048,7 @@ struct drm_mode_crtc { int count_possibles; unsigned int possibles; /**< Connectors that can be connected */ - int gamma_size; + uint32_t gamma_size; int mode_valid; struct drm_mode_modeinfo mode; }; @@ -1173,6 +1173,16 @@ struct drm_mode_hotplug { uint32_t counter; }; +struct drm_mode_crtc_lut { + + uint32_t crtc_id; + uint32_t gamma_size; + + uint64_t red; + uint64_t green; + uint64_t blue; +}; + /** * \name Ioctls Definitions */ @@ -1289,6 +1299,9 @@ struct drm_mode_hotplug { #define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xAF, struct drm_mode_fb_cmd) #define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xB0, struct drm_mode_get_encoder) +#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xB1, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xB2, struct drm_mode_crtc_lut) + /*@}*/ /** diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c index bd1e8000..bb91e832 100644 --- a/tests/mode/modetest.c +++ b/tests/mode/modetest.c @@ -145,6 +145,7 @@ int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) printf("\twidth : %i\n", crtc->width); printf("\theight : %i\n", crtc->height); printf("\tmode : %p\n", &crtc->mode); + printf("\tgamma size : %d\n", crtc->gamma_size); printf("\tnum connectors : %i\n", crtc->count_connectors); printf("\tconnectors : %i\n", crtc->connectors); printf("\tnum possible : %i\n", crtc->count_possibles); -- cgit v1.2.3 From c321bc4f9280fe93e2df2b1c47e13cba7499e486 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 14:33:42 +1000 Subject: drm: only report framebuffers available on this fd. Not 100% sure this is a good idea, but I think I'd rather things communicate with bo handles not fb ids. --- linux-core/drm_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 7746fd50..d82d8390 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -780,7 +780,7 @@ int drm_mode_getresources(struct drm_device *dev, mutex_lock(&dev->mode_config.mutex); - list_for_each(lh, &dev->mode_config.fb_list) + list_for_each(lh, &file_priv->fbs) fb_count++; list_for_each(lh, &dev->mode_config.crtc_list) @@ -802,7 +802,7 @@ int drm_mode_getresources(struct drm_device *dev, if (card_res->count_fbs >= fb_count) { copied = 0; fb_id = (uint32_t *)(unsigned long)card_res->fb_id_ptr; - list_for_each_entry(fb, &dev->mode_config.fb_list, head) { + list_for_each_entry(fb, &file_priv->fbs, head) { if (put_user(fb->id, fb_id + copied)) { ret = -EFAULT; goto out; -- cgit v1.2.3 From 50d3e5bd020d0b6877a5fef441408f16e31121cd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 16:19:21 +1000 Subject: drm/modesetting: redo object handles around a core object. handle crtc/encoders/connectors/fb/mode/property/blob using this system. --- linux-core/drm_crtc.c | 211 ++++++++++++++++++++++++++----------------- linux-core/drm_crtc.h | 41 +++++++-- linux-core/drm_crtc_helper.c | 8 +- linux-core/drm_modes.c | 6 +- 4 files changed, 170 insertions(+), 96 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index d82d8390..79dc137e 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -88,7 +88,7 @@ char *drm_get_encoder_name(struct drm_encoder *encoder) static char buf[32]; snprintf(buf, 32, "%s-%d", drm_encoder_enum_list[encoder->encoder_type].name, - encoder->id); + encoder->base.id); return buf; } @@ -126,25 +126,27 @@ char *drm_get_connector_status_name(enum drm_connector_status status) * New unique (relative to other objects in @dev) integer identifier for the * object. */ -int drm_idr_get(struct drm_device *dev, void *ptr) +static int drm_mode_object_get(struct drm_device *dev, struct drm_mode_object *obj, uint32_t obj_type) { int new_id = 0; int ret; again: if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) { DRM_ERROR("Ran out memory getting a mode number\n"); - return 0; + return -EINVAL; } - ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id); + ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); if (ret == -EAGAIN) goto again; - return new_id; + obj->id = new_id; + obj->type = obj_type; + return 0; } /** - * drm_idr_put - free an identifer + * drm_mode_object_put - free an identifer * @dev: DRM device * @id: ID to free * @@ -153,9 +155,20 @@ again: * * Free @id from @dev's unique identifier pool. */ -void drm_idr_put(struct drm_device *dev, int id) +static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object *object) +{ + idr_remove(&dev->mode_config.crtc_idr, object->id); +} + +static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { - idr_remove(&dev->mode_config.crtc_idr, id); + struct drm_mode_object *obj; + + obj = idr_find(&dev->mode_config.crtc_idr, id); + if (!obj || (obj->type != type) || (obj->id != id)) + return NULL; + + return obj; } /** @@ -203,7 +216,7 @@ struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev) if (!fb) return NULL; - fb->id = drm_idr_get(dev, fb); + drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); fb->dev = dev; dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); @@ -233,7 +246,7 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) crtc->fb = NULL; } - drm_idr_put(dev, fb->id); + drm_mode_object_put(dev, &fb->base); list_del(&fb->head); dev->mode_config.num_fb--; @@ -258,7 +271,7 @@ void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, crtc->dev = dev; crtc->funcs = funcs; - crtc->id = drm_idr_get(dev, crtc); + drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); list_add_tail(&crtc->head, &dev->mode_config.crtc_list); dev->mode_config.num_crtc++; @@ -284,7 +297,7 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) crtc->gamma_store = NULL; } - drm_idr_put(dev, crtc->id); + drm_mode_object_put(dev, &crtc->base); list_del(&crtc->head); dev->mode_config.num_crtc--; } @@ -344,7 +357,7 @@ void drm_connector_init(struct drm_device *dev, { connector->dev = dev; connector->funcs = funcs; - connector->id = drm_idr_get(dev, connector); + drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); connector->connector_type = connector_type; connector->connector_type_id = 1; /* TODO */ INIT_LIST_HEAD(&connector->user_modes); @@ -390,7 +403,7 @@ void drm_connector_cleanup(struct drm_connector *connector) drm_mode_remove(connector, mode); mutex_lock(&dev->mode_config.mutex); - drm_idr_put(dev, connector->id); + drm_mode_object_put(dev, &connector->base); list_del(&connector->head); mutex_unlock(&dev->mode_config.mutex); } @@ -402,7 +415,8 @@ void drm_encoder_init(struct drm_device *dev, int encoder_type) { encoder->dev = dev; - encoder->id = drm_idr_get(dev, encoder); + + drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); encoder->encoder_type = encoder_type; encoder->funcs = funcs; @@ -418,7 +432,7 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; mutex_lock(&dev->mode_config.mutex); - drm_idr_put(dev, encoder->id); + drm_mode_object_put(dev, &encoder->base); list_del(&encoder->head); mutex_unlock(&dev->mode_config.mutex); } @@ -444,7 +458,7 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev) if (!nmode) return NULL; - nmode->mode_id = drm_idr_get(dev, nmode); + drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE); return nmode; } EXPORT_SYMBOL(drm_mode_create); @@ -461,7 +475,7 @@ EXPORT_SYMBOL(drm_mode_create); */ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) { - drm_idr_put(dev, mode->mode_id); + drm_mode_object_put(dev, &mode->base); kfree(mode); } @@ -803,7 +817,7 @@ int drm_mode_getresources(struct drm_device *dev, copied = 0; fb_id = (uint32_t *)(unsigned long)card_res->fb_id_ptr; list_for_each_entry(fb, &file_priv->fbs, head) { - if (put_user(fb->id, fb_id + copied)) { + if (put_user(fb->base.id, fb_id + copied)) { ret = -EFAULT; goto out; } @@ -817,8 +831,8 @@ int drm_mode_getresources(struct drm_device *dev, copied = 0; crtc_id = (uint32_t *)(unsigned long)card_res->crtc_id_ptr; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ - DRM_DEBUG("CRTC ID is %d\n", crtc->id); - if (put_user(crtc->id, crtc_id + copied)) { + DRM_DEBUG("CRTC ID is %d\n", crtc->base.id); + if (put_user(crtc->base.id, crtc_id + copied)) { ret = -EFAULT; goto out; } @@ -834,8 +848,8 @@ int drm_mode_getresources(struct drm_device *dev, connector_id = (uint32_t *)(unsigned long)card_res->connector_id_ptr; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - DRM_DEBUG("CONNECTOR ID is %d\n", connector->id); - if (put_user(connector->id, connector_id + copied)) { + DRM_DEBUG("CONNECTOR ID is %d\n", connector->base.id); + if (put_user(connector->base.id, connector_id + copied)) { ret = -EFAULT; goto out; } @@ -850,8 +864,8 @@ int drm_mode_getresources(struct drm_device *dev, encoder_id = (uint32_t *)(unsigned long)card_res->encoder_id_ptr; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - DRM_DEBUG("ENCODER ID is %d\n", encoder->id); - if (put_user(encoder->id, encoder_id + copied)) { + DRM_DEBUG("ENCODER ID is %d\n", encoder->base.id); + if (put_user(encoder->base.id, encoder_id + copied)) { ret = -EFAULT; goto out; } @@ -890,21 +904,24 @@ int drm_mode_getcrtc(struct drm_device *dev, { struct drm_mode_crtc *crtc_resp = data; struct drm_crtc *crtc; + struct drm_mode_object *obj; int ret = 0; mutex_lock(&dev->mode_config.mutex); - crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp->crtc_id); - if (!crtc || (crtc->id != crtc_resp->crtc_id)) { + + obj = drm_mode_object_find(dev, crtc_resp->crtc_id, DRM_MODE_OBJECT_CRTC); + if (!obj) { ret = -EINVAL; goto out; } + crtc = obj_to_crtc(obj); crtc_resp->x = crtc->x; crtc_resp->y = crtc->y; crtc_resp->gamma_size = crtc->gamma_size; if (crtc->fb) - crtc_resp->fb_id = crtc->fb->id; + crtc_resp->fb_id = crtc->fb->base.id; else crtc_resp->fb_id = 0; @@ -944,6 +961,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_get_connector *out_resp = data; + struct drm_mode_object *obj; struct drm_connector *connector; struct drm_display_mode *mode; int mode_count = 0; @@ -963,11 +981,13 @@ int drm_mode_getconnector(struct drm_device *dev, DRM_DEBUG("connector id %d:\n", out_resp->connector); mutex_lock(&dev->mode_config.mutex); - connector= idr_find(&dev->mode_config.crtc_idr, out_resp->connector); - if (!connector || (connector->id != out_resp->connector)) { + + obj = drm_mode_object_find(dev, out_resp->connector, DRM_MODE_OBJECT_CONNECTOR); + if (!obj) { ret = -EINVAL; goto out; } + connector = obj_to_connector(obj); list_for_each_entry(mode, &connector->modes, head) mode_count++; @@ -995,7 +1015,7 @@ int drm_mode_getconnector(struct drm_device *dev, out_resp->subpixel = connector->display_info.subpixel_order; out_resp->connection = connector->status; if (connector->encoder) - out_resp->encoder = connector->encoder->id; + out_resp->encoder = connector->encoder->base.id; else out_resp->encoder = 0; @@ -1060,23 +1080,24 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_get_encoder *enc_resp = data; + struct drm_mode_object *obj; struct drm_encoder *encoder; int ret = 0; mutex_lock(&dev->mode_config.mutex); - encoder = idr_find(&dev->mode_config.crtc_idr, enc_resp->encoder_id); - if (!encoder || (encoder->id != enc_resp->encoder_id)) { - DRM_DEBUG("Unknown encoder ID %d\n", enc_resp->encoder_id); + obj = drm_mode_object_find(dev, enc_resp->encoder_id, DRM_MODE_OBJECT_ENCODER); + if (!obj) { ret = -EINVAL; goto out; } + encoder = obj_to_encoder(obj); if (encoder->crtc) - enc_resp->crtc = encoder->crtc->id; + enc_resp->crtc = encoder->crtc->base.id; else enc_resp->crtc = 0; enc_resp->encoder_type = encoder->encoder_type; - enc_resp->encoder_id = encoder->id; + enc_resp->encoder_id = encoder->base.id; enc_resp->crtcs = encoder->possible_crtcs; enc_resp->clones = encoder->possible_clones; @@ -1106,6 +1127,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_crtc *crtc_req = data; + struct drm_mode_object *obj; struct drm_crtc *crtc, *crtcfb; struct drm_connector **connector_set = NULL, *connector; struct drm_framebuffer *fb = NULL; @@ -1116,13 +1138,14 @@ int drm_mode_setcrtc(struct drm_device *dev, int i; mutex_lock(&dev->mode_config.mutex); - crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req->crtc_id); - if (!crtc || (crtc->id != crtc_req->crtc_id)) { + obj = drm_mode_object_find(dev, crtc_req->crtc_id, DRM_MODE_OBJECT_CRTC); + if (!obj) { DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req->crtc_id); ret = -EINVAL; goto out; } - + crtc = obj_to_crtc(obj); + if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ @@ -1134,12 +1157,13 @@ int drm_mode_setcrtc(struct drm_device *dev, } } } else { - fb = idr_find(&dev->mode_config.crtc_idr, crtc_req->fb_id); - if (!fb || (fb->id != crtc_req->fb_id)) { + obj = drm_mode_object_find(dev, crtc_req->fb_id, DRM_MODE_OBJECT_FB); + if (!obj) { DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id); ret = -EINVAL; goto out; } + fb = obj_to_fb(obj); } mode = drm_mode_create(dev); @@ -1176,12 +1200,13 @@ int drm_mode_setcrtc(struct drm_device *dev, goto out; } - connector = idr_find(&dev->mode_config.crtc_idr, out_id); - if (!connector || (out_id != connector->id)) { + obj = drm_mode_object_find(dev, out_id, DRM_MODE_OBJECT_CONNECTOR); + if (!obj) { DRM_DEBUG("Connector id %d unknown\n", out_id); ret = -EINVAL; goto out; } + connector = obj_to_connector(obj); connector_set[i] = connector; } @@ -1206,6 +1231,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_cursor *req = data; + struct drm_mode_object *obj; struct drm_crtc *crtc; struct drm_buffer_object *bo = NULL; /* must be set */ int ret = 0; @@ -1218,12 +1244,13 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, } mutex_lock(&dev->mode_config.mutex); - crtc = idr_find(&dev->mode_config.crtc_idr, req->crtc); - if (!crtc || (crtc->id != req->crtc)) { + obj = drm_mode_object_find(dev, req->crtc, DRM_MODE_OBJECT_CRTC); + if (!obj) { DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc); ret = -EINVAL; goto out; } + crtc = obj_to_crtc(obj); if (req->flags & DRM_MODE_CURSOR_BO) { /* Turn of the cursor if handle is 0 */ @@ -1320,7 +1347,7 @@ int drm_mode_addfb(struct drm_device *dev, fb->depth = r->depth; fb->bo = bo; - r->buffer_id = fb->id; + r->buffer_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); @@ -1349,6 +1376,7 @@ out: int drm_mode_rmfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_mode_object *obj; struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fbl = NULL; uint32_t *id = data; @@ -1356,13 +1384,14 @@ int drm_mode_rmfb(struct drm_device *dev, int found = 0; mutex_lock(&dev->mode_config.mutex); - fb = idr_find(&dev->mode_config.crtc_idr, *id); + obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); /* TODO check that we realy get a framebuffer back. */ - if (!fb || (*id != fb->id)) { + if (!obj) { DRM_ERROR("mode invalid framebuffer id\n"); ret = -EINVAL; goto out; } + fb = obj_to_fb(obj); list_for_each_entry(fbl, &file_priv->fbs, filp_head) if (fb == fbl) @@ -1409,16 +1438,18 @@ int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_fb_cmd *r = data; + struct drm_mode_object *obj; struct drm_framebuffer *fb; int ret = 0; mutex_lock(&dev->mode_config.mutex); - fb = idr_find(&dev->mode_config.crtc_idr, r->buffer_id); - if (!fb || (r->buffer_id != fb->id)) { + obj = drm_mode_object_find(dev, r->buffer_id, DRM_MODE_OBJECT_FB); + if (!obj) { DRM_ERROR("invalid framebuffer id\n"); ret = -EINVAL; goto out; } + fb = obj_to_fb(obj); r->height = fb->height; r->width = fb->width; @@ -1555,16 +1586,18 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, struct drm_mode_mode_cmd *mode_cmd = data; struct drm_connector *connector; struct drm_display_mode *mode; + struct drm_mode_object *obj; struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; mutex_lock(&dev->mode_config.mutex); - connector = idr_find(&dev->mode_config.crtc_idr, mode_cmd->connector_id); - if (!connector || (connector->id != mode_cmd->connector_id)) { + obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); + if (!obj) { ret = -EINVAL; goto out; } + connector = obj_to_connector(obj); mode = drm_mode_create(dev); if (!mode) { @@ -1596,6 +1629,7 @@ out: int drm_mode_detachmode_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_mode_object *obj; struct drm_mode_mode_cmd *mode_cmd = data; struct drm_connector *connector; struct drm_display_mode mode; @@ -1604,11 +1638,12 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, mutex_lock(&dev->mode_config.mutex); - connector = idr_find(&dev->mode_config.crtc_idr, mode_cmd->connector_id); - if (!connector || (connector->id != mode_cmd->connector_id)) { + obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); + if (!obj) { ret = -EINVAL; goto out; } + connector = obj_to_connector(obj); drm_crtc_convert_umode(&mode, umode); ret = drm_mode_detachmode(dev, connector, &mode); @@ -1632,7 +1667,7 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, goto fail; } - property->id = drm_idr_get(dev, property); + drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); property->flags = flags; property->num_values = num_values; INIT_LIST_HEAD(&property->enum_blob_list); @@ -1691,7 +1726,7 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) if (property->num_values) kfree(property->values); - drm_idr_put(dev, property->id); + drm_mode_object_put(dev, &property->base); list_del(&property->head); kfree(property); } @@ -1704,7 +1739,7 @@ int drm_connector_attach_property(struct drm_connector *connector, for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { if (connector->property_ids[i] == 0) { - connector->property_ids[i] = property->id; + connector->property_ids[i] = property->base.id; connector->property_values[i] = init_val; break; } @@ -1722,7 +1757,7 @@ int drm_connector_property_set_value(struct drm_connector *connector, int i; for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { - if (connector->property_ids[i] == property->id) { + if (connector->property_ids[i] == property->base.id) { connector->property_values[i] = value; break; } @@ -1740,7 +1775,7 @@ int drm_connector_property_get_value(struct drm_connector *connector, int i; for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { - if (connector->property_ids[i] == property->id) { + if (connector->property_ids[i] == property->base.id) { *val = connector->property_values[i]; break; } @@ -1755,6 +1790,7 @@ EXPORT_SYMBOL(drm_connector_property_get_value); int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_mode_object *obj; struct drm_mode_get_property *out_resp = data; struct drm_property *property; int enum_count = 0; @@ -1770,11 +1806,12 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, uint32_t __user *blob_length_ptr; mutex_lock(&dev->mode_config.mutex); - property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); - if (!property || (property->id != out_resp->prop_id)) { + obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); + if (!obj) { ret = -EINVAL; goto done; } + property = obj_to_property(obj); if (property->flags & DRM_MODE_PROP_ENUM) { list_for_each_entry(prop_enum, &property->enum_blob_list, head) @@ -1831,7 +1868,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr; list_for_each_entry(prop_blob, &property->enum_blob_list, head) { - if (put_user(prop_blob->id, blob_id_ptr + copied)) { + if (put_user(prop_blob->base.id, blob_id_ptr + copied)) { ret = -EFAULT; goto done; } @@ -1868,7 +1905,7 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev memcpy(blob->data, data, length); - blob->id = drm_idr_get(dev, blob); + drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); list_add_tail(&blob->head, &dev->mode_config.property_blob_list); return blob; @@ -1877,7 +1914,7 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev static void drm_property_destroy_blob(struct drm_device *dev, struct drm_property_blob *blob) { - drm_idr_put(dev, blob->id); + drm_mode_object_put(dev, &blob->base); list_del(&blob->head); kfree(blob); } @@ -1885,18 +1922,19 @@ static void drm_property_destroy_blob(struct drm_device *dev, int drm_mode_getblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_mode_object *obj; struct drm_mode_get_blob *out_resp = data; struct drm_property_blob *blob; int ret = 0; void *blob_ptr; mutex_lock(&dev->mode_config.mutex); - - blob = idr_find(&dev->mode_config.crtc_idr, out_resp->blob_id); - if (!blob || (blob->id != out_resp->blob_id)) { + obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_CONNECTOR); + if (!obj) { ret = -EINVAL; goto done; } + blob = obj_to_blob(obj); if (out_resp->length == blob->length) { blob_ptr = (void *)(unsigned long)out_resp->data; @@ -1921,7 +1959,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, str connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); - ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, connector->edid_blob_ptr->id); + ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, connector->edid_blob_ptr->base.id); return ret; } EXPORT_SYMBOL(drm_mode_connector_update_edid_property); @@ -1930,16 +1968,19 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_connector_set_property *out_resp = data; + struct drm_mode_object *obj; struct drm_property *property; struct drm_connector *connector; int ret = -EINVAL; int i; mutex_lock(&dev->mode_config.mutex); - connector = idr_find(&dev->mode_config.crtc_idr, out_resp->connector_id); - if (!connector || (connector->id != out_resp->connector_id)) { + + obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); + if (!obj) { goto out; } + connector = obj_to_connector(obj); for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { if (connector->property_ids[i] == out_resp->prop_id) @@ -1950,10 +1991,11 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, goto out; } - property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id); - if (!property || (property->id != out_resp->prop_id)) { + obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); + if (!obj) { goto out; } + property = obj_to_property(obj); if (property->flags & DRM_MODE_PROP_IMMUTABLE) goto out; @@ -1990,6 +2032,7 @@ int drm_mode_replacefb(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_fb_cmd *r = data; + struct drm_mode_object *obj; struct drm_framebuffer *fb; struct drm_buffer_object *bo; int found = 0; @@ -2002,12 +2045,12 @@ int drm_mode_replacefb(struct drm_device *dev, ret = -EINVAL; goto out; } - - fb = idr_find(&dev->mode_config.crtc_idr, r->buffer_id); - if (!fb || (r->buffer_id != fb->id)) { + obj = drm_mode_object_find(dev, r->buffer_id, DRM_MODE_OBJECT_FB); + if (!obj) { ret = -EINVAL; goto out; } + fb = obj_to_fb(obj); list_for_each_entry(fbl, &file_priv->fbs, filp_head) if (fb == fbl) @@ -2036,7 +2079,7 @@ int drm_mode_replacefb(struct drm_device *dev, #if 0 /* find all crtcs connected to this fb */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb->id == r->buffer_id) { + if (crtc->fb->base.id == r->buffer_id) { crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); } } @@ -2054,7 +2097,7 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] == 0) { - connector->encoder_ids[i] = encoder->id; + connector->encoder_ids[i] = encoder->base.id; return 0; } } @@ -2067,7 +2110,7 @@ void drm_mode_connector_detach_encoder(struct drm_connector *connector, { int i; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - if (connector->encoder_ids[i] == encoder->id) { + if (connector->encoder_ids[i] == encoder->base.id) { connector->encoder_ids[i] = 0; if (connector->encoder == encoder) connector->encoder = NULL; @@ -2096,17 +2139,19 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_crtc_lut *crtc_lut = data; + struct drm_mode_object *obj; struct drm_crtc *crtc; void *r_base, *g_base, *b_base; int size; int ret = 0; mutex_lock(&dev->mode_config.mutex); - crtc = idr_find(&dev->mode_config.crtc_idr, crtc_lut->crtc_id); - if (!crtc || (crtc->id != crtc_lut->crtc_id)) { + obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); + if (!obj) { ret = -EINVAL; goto out; } + crtc = obj_to_crtc(obj); /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { @@ -2145,17 +2190,19 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_mode_crtc_lut *crtc_lut = data; + struct drm_mode_object *obj; struct drm_crtc *crtc; void *r_base, *g_base, *b_base; int size; int ret = 0; mutex_lock(&dev->mode_config.mutex); - crtc = idr_find(&dev->mode_config.crtc_idr, crtc_lut->crtc_id); - if (!crtc || (crtc->id != crtc_lut->crtc_id)) { + obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); + if (!obj) { ret = -EINVAL; goto out; } + crtc = obj_to_crtc(obj); /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 151d1732..3c11dfc6 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -16,6 +16,20 @@ struct drm_device; struct drm_mode_set; + +#define DRM_MODE_OBJECT_CRTC 0xcccccccc +#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 +#define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0 +#define DRM_MODE_OBJECT_MODE 0xdededede +#define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0 +#define DRM_MODE_OBJECT_FB 0xfbfbfbfb +#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb + +struct drm_mode_object { + uint32_t id; + uint32_t type; +}; + /* * Note on terminology: here, for brevity and convenience, we refer to connector * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, @@ -78,8 +92,10 @@ enum drm_mode_status { struct drm_display_mode { /* Header */ struct list_head head; + struct drm_mode_object base; + char name[DRM_DISPLAY_MODE_LEN]; - int mode_id; + int connector_count; enum drm_mode_status status; int type; @@ -178,6 +194,7 @@ enum subpixel_order { SubPixelNone, }; + /* * Describes a given display (e.g. CRT or flat panel) and its limitations. */ @@ -236,7 +253,7 @@ struct drm_display_info { struct drm_framebuffer { struct drm_device *dev; struct list_head head; - int id; /* idr assigned */ + struct drm_mode_object base; unsigned int pitch; unsigned int width; unsigned int height; @@ -252,9 +269,9 @@ struct drm_framebuffer { }; struct drm_property_blob { + struct drm_mode_object base; struct list_head head; unsigned int length; - unsigned int id; void *data; }; @@ -266,7 +283,7 @@ struct drm_property_enum { struct drm_property { struct list_head head; - int id; /* idr assigned */ + struct drm_mode_object base; uint32_t flags; char name[DRM_PROP_NAME_LEN]; uint32_t num_values; @@ -340,7 +357,7 @@ struct drm_crtc { struct drm_device *dev; struct list_head head; - int id; /* idr assigned */ + struct drm_mode_object base; /* framebuffer the connector is currently bound to */ struct drm_framebuffer *fb; @@ -362,6 +379,7 @@ struct drm_crtc { void *helper_private; }; + /** * drm_connector_funcs - control connectors on a given device * @dpms: set power state (see drm_crtc_funcs above) @@ -406,7 +424,7 @@ struct drm_encoder { struct drm_device *dev; struct list_head head; - int id; + struct drm_mode_object base; int encoder_type; uint32_t possible_crtcs; uint32_t possible_clones; @@ -437,7 +455,8 @@ struct drm_connector { struct device kdev; struct device_attribute *attr; struct list_head head; - int id; /* idr assigned */ + + struct drm_mode_object base; int connector_type; int connector_type_id; @@ -541,6 +560,14 @@ struct drm_mode_config { uint32_t hotplug_counter; }; +#define obj_to_crtc(x) container_of(x, struct drm_crtc, base) +#define obj_to_connector(x) container_of(x, struct drm_connector, base) +#define obj_to_encoder(x) container_of(x, struct drm_encoder, base) +#define obj_to_mode(x) container_of(x, struct drm_display_mode, base) +#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) +#define obj_to_property(x) container_of(x, struct drm_property, base) +#define obj_to_blob(x) container_of(x, struct drm_property_blob, base) + extern void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 2ceaa860..52a87da7 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -271,7 +271,7 @@ static void drm_pick_crtcs (struct drm_device *dev) continue; list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) { - if (encoder->id == encoder_equal->id) + if (encoder->base.id == encoder_equal->base.id) continue; /* Find out if crtc has been assigned before */ @@ -287,7 +287,7 @@ static void drm_pick_crtcs (struct drm_device *dev) o = -1; list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { o++; - if (connector->id == connector_equal->id) + if (connector->base.id == connector_equal->base.id) continue; encoder_equal = connector_equal->encoder; @@ -319,7 +319,7 @@ clone: encoder->crtc->desired_mode = des_mode; connector->initial_x = 0; connector->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); + DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->base.id, des_mode->name); break; } } @@ -418,7 +418,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo if (encoder->crtc != crtc) continue; - DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder), mode->name, mode->mode_id); + DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder), mode->name, mode->base.id); encoder_funcs = encoder->helper_private; encoder_funcs->mode_set(encoder, mode, adjusted_mode); } diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 26b96e73..bf0d85ee 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -46,7 +46,7 @@ void drm_mode_debug_printmodeline(struct drm_display_mode *mode) { DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", - mode->mode_id, mode->name, mode->vrefresh, mode->clock, + mode->base.id, mode->name, mode->vrefresh, mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->vdisplay, mode->vsync_start, @@ -253,9 +253,9 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, if (!nmode) return NULL; - new_id = nmode->mode_id; + new_id = nmode->base.id; *nmode = *mode; - nmode->mode_id = new_id; + nmode->base.id = new_id; INIT_LIST_HEAD(&nmode->head); return nmode; } -- cgit v1.2.3 From 149b17311ad5f117e8f53a7a8cc032e369b95ed2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 16:45:44 +1000 Subject: drm: initial mode object groups. This creates a default group attached to the legacy drm minor nodes. It covers all the objects in the set. make set resources only return objects for this set. Need to fix up other functions to only work on objects in their allowed set. --- linux-core/drmP.h | 2 +- linux-core/drm_crtc.c | 154 ++++++++++++++++++++++++++++++++++++++------------ linux-core/drm_crtc.h | 11 +++- linux-core/drm_stub.c | 5 ++ 4 files changed, 135 insertions(+), 37 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 7c7e201a..11c01386 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -792,7 +792,7 @@ struct drm_minor { struct drm_master *master; /* currently active master for this node */ struct list_head master_list; - /* possibly needs a list of configured modesetting pieces */ + struct drm_mode_group mode_group; }; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 79dc137e..784c2f74 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -585,6 +585,45 @@ void drm_mode_config_init(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_init); +int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) +{ + uint32_t total_objects = 0; + + total_objects += dev->mode_config.num_crtc; + total_objects += dev->mode_config.num_connector; + total_objects += dev->mode_config.num_encoder; + + group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); + if (!group->id_list) + return -ENOMEM; + + group->num_crtcs = 0; + group->num_connectors = 0; + group->num_encoders = 0; + return 0; +} + +int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group) +{ + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + + if (drm_mode_group_init(dev, group)) + return -ENOMEM; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + group->id_list[group->num_crtcs++] = crtc->base.id; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + group->id_list[group->num_crtcs + group->num_encoders++] = encoder->base.id; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + group->id_list[group->num_crtcs + group->num_encoders + group->num_connectors++] = connector->base.id; + + return 0; +} + /** * drm_get_buffer_object - find the buffer object for a given handle * @dev: DRM device @@ -786,25 +825,37 @@ int drm_mode_getresources(struct drm_device *dev, int crtc_count = 0; int fb_count = 0; int encoder_count = 0; - int copied = 0; + int copied = 0, i; uint32_t __user *fb_id; uint32_t __user *crtc_id; uint32_t __user *connector_id; uint32_t __user *encoder_id; + struct drm_mode_group *mode_group; mutex_lock(&dev->mode_config.mutex); + /* for the non-control nodes we need to limit the list of resources by IDs in the + group list for this node */ list_for_each(lh, &file_priv->fbs) fb_count++; - list_for_each(lh, &dev->mode_config.crtc_list) - crtc_count++; + mode_group = &file_priv->master->minor->mode_group; + if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { + + list_for_each(lh, &dev->mode_config.crtc_list) + crtc_count++; - list_for_each(lh, &dev->mode_config.connector_list) - connector_count++; + list_for_each(lh, &dev->mode_config.connector_list) + connector_count++; - list_for_each(lh, &dev->mode_config.encoder_list) - encoder_count++; + list_for_each(lh, &dev->mode_config.encoder_list) + encoder_count++; + } else { + + crtc_count = mode_group->num_crtcs; + connector_count = mode_group->num_connectors; + encoder_count = mode_group->num_encoders; + } card_res->max_height = dev->mode_config.max_height; card_res->min_height = dev->mode_config.min_height; @@ -830,49 +881,82 @@ int drm_mode_getresources(struct drm_device *dev, if (card_res->count_crtcs >= crtc_count) { copied = 0; crtc_id = (uint32_t *)(unsigned long)card_res->crtc_id_ptr; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ - DRM_DEBUG("CRTC ID is %d\n", crtc->base.id); - if (put_user(crtc->base.id, crtc_id + copied)) { - ret = -EFAULT; - goto out; + if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + DRM_DEBUG("CRTC ID is %d\n", crtc->base.id); + if (put_user(crtc->base.id, crtc_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } else { + for (i = 0; i < mode_group->num_crtcs; i++) { + if (put_user(mode_group->id_list[i], crtc_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; } - copied++; } } card_res->count_crtcs = crtc_count; + /* Encoders */ + if (card_res->count_encoders >= encoder_count) { + copied = 0; + encoder_id = (uint32_t *)(unsigned long)card_res->encoder_id_ptr; + if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + head) { + DRM_DEBUG("ENCODER ID is %d\n", encoder->base.id); + if (put_user(encoder->base.id, encoder_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } else { + for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { + if (put_user(mode_group->id_list[i], encoder_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + + } + } + card_res->count_encoders = encoder_count; /* Connectors */ if (card_res->count_connectors >= connector_count) { copied = 0; connector_id = (uint32_t *)(unsigned long)card_res->connector_id_ptr; - list_for_each_entry(connector, &dev->mode_config.connector_list, - head) { - DRM_DEBUG("CONNECTOR ID is %d\n", connector->base.id); - if (put_user(connector->base.id, connector_id + copied)) { - ret = -EFAULT; - goto out; + if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { + list_for_each_entry(connector, &dev->mode_config.connector_list, + head) { + DRM_DEBUG("CONNECTOR ID is %d\n", connector->base.id); + if (put_user(connector->base.id, connector_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } else { + int start = mode_group->num_crtcs + mode_group->num_encoders; + for (i = start; i < start + mode_group->num_connectors; i++) { + if (put_user(mode_group->id_list[i], connector_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; } - copied++; } } card_res->count_connectors = connector_count; + - /* Encoders */ - if (card_res->count_encoders >= encoder_count) { - copied = 0; - encoder_id = (uint32_t *)(unsigned long)card_res->encoder_id_ptr; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, - head) { - DRM_DEBUG("ENCODER ID is %d\n", encoder->base.id); - if (put_user(encoder->base.id, encoder_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - card_res->count_encoders = encoder_count; DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs, card_res->count_connectors, card_res->count_encoders); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 3c11dfc6..01cf9af7 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -519,6 +519,15 @@ struct drm_mode_config_funcs { bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); }; +struct drm_mode_group { + uint32_t num_crtcs; + uint32_t num_encoders; + uint32_t num_connectors; + + /* list of object IDs for this group */ + uint32_t *id_list; +}; + /** * drm_mode_config - Mode configuration control structure * @@ -591,7 +600,7 @@ extern void drm_encoder_cleanup(struct drm_encoder *encoder); extern char *drm_get_connector_name(struct drm_connector *connector); extern char *drm_get_dpms_name(int val); extern void drm_fb_release(struct file *filp); - +extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index f66dec07..45b8f386 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -378,6 +378,11 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, if ((ret = dev->driver->load(dev, ent->driver_data))) goto err_g5; + /* setup the grouping for the legacy output */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + if (drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group)) + goto err_g5; + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, dev->primary->index); -- cgit v1.2.3 From dc022084cda0a5558f033c3caa657d5af84ef544 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 2 Jun 2008 10:03:28 +0100 Subject: Fix warnings --- linux-core/drm_crtc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 52a87da7..a8c44b76 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -299,7 +299,7 @@ static void drm_pick_crtcs (struct drm_device *dev) list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->encoder->crtc == crtc)) { - printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); + printk("Cloning %s (0x%x) to %s (0x%x)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); des_mode = modes; assigned = 0; goto clone; -- cgit v1.2.3 From 3ed17803d826b10f8f94d09acf12877e9738823c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 2 Jun 2008 10:44:29 +0100 Subject: more checks for NULL encoder so we don't segfault. --- linux-core/drm_crtc_helper.c | 9 ++++++++- linux-core/intel_display.c | 3 ++- linux-core/intel_fb.c | 3 ++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index a8c44b76..fcb1243c 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -662,7 +662,14 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct drm_crtc *crtc = connector->encoder->crtc; + struct drm_encoder *encoder = connector->encoder; + struct drm_crtc *crtc; + + if (!encoder) + continue; + + crtc = connector->encoder->crtc; + /* can't setup the connector if there's no assigned mode */ if (!crtc || !crtc->desired_mode) continue; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index ba9441d6..8a8f4edb 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -228,7 +228,8 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type) struct drm_connector *l_entry; list_for_each_entry(l_entry, &mode_config->connector_list, head) { - if (l_entry->encoder->crtc == crtc) { + if (l_entry->encoder && + l_entry->encoder->crtc == crtc) { struct intel_output *intel_output = to_intel_output(l_entry); if (intel_output->type == type) return true; diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 268e95c5..d490880a 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -277,7 +277,8 @@ static int intelfb_set_par(struct fb_info *info) found = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder->crtc == par->set.crtc){ + if (connector->encoder && + connector->encoder->crtc == par->set.crtc){ found = 1; break; } -- cgit v1.2.3 From 40229b6ad539cebad5ebe8ca373796ca2422efdb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 10:34:34 +1000 Subject: drm: make mode comparison more betterer. This compares the clocks after converting to fb pico timings so we get the same answer if the X and fb modes are the same. --- linux-core/drm_modes.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index bf0d85ee..3ed427fb 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -276,8 +276,15 @@ EXPORT_SYMBOL(drm_mode_duplicate); */ bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2) { - if (mode1->clock == mode2->clock && - mode1->hdisplay == mode2->hdisplay && + /* do clock check convert to PICOS so fb modes get matched + * the same */ + if (mode1->clock && mode2->clock) { + if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock)) + return false; + } else if (mode1->clock != mode2->clock) + return false; + + if (mode1->hdisplay == mode2->hdisplay && mode1->hsync_start == mode2->hsync_start && mode1->hsync_end == mode2->hsync_end && mode1->htotal == mode2->htotal && -- cgit v1.2.3 From 76a44f14d6339e5bc0c936ef4a360f6c152511bd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 11:59:28 +1000 Subject: drm/modesetting: overhaul the fb create/delete. Move TTM code into the driver --- linux-core/drmP.h | 1 - linux-core/drm_crtc.c | 68 +++++++++----------------------------------- linux-core/drm_crtc.h | 15 +++++++--- linux-core/drm_crtc_helper.c | 14 +++++++++ linux-core/drm_crtc_helper.h | 4 +++ linux-core/i915_drv.c | 1 - linux-core/intel_display.c | 47 +++++++++++++++++++++++++++++- linux-core/intel_drv.h | 11 +++++++ linux-core/intel_fb.c | 58 +++++++++++++++++++++---------------- 9 files changed, 133 insertions(+), 86 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 11c01386..6e627cd9 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -744,7 +744,6 @@ struct drm_driver { /* FB routines, if present */ int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); - int (*fb_remove)(struct drm_device *dev, struct drm_framebuffer *fb); int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); /* Master routines */ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 784c2f74..7f843925 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -208,25 +208,21 @@ struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, * RETURNS: * Pointer to new framebuffer or NULL on error. */ -struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev) +struct drm_framebuffer *drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + const struct drm_framebuffer_funcs *funcs) { - struct drm_framebuffer *fb; - - fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); - if (!fb) - return NULL; - drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); fb->dev = dev; + fb->funcs = funcs; dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); return fb; } -EXPORT_SYMBOL(drm_framebuffer_create); +EXPORT_SYMBOL(drm_framebuffer_init); /** - * drm_framebuffer_destroy - remove a framebuffer object + * drm_framebuffer_cleanup - remove a framebuffer object * @fb: framebuffer to remove * * LOCKING: @@ -235,7 +231,7 @@ EXPORT_SYMBOL(drm_framebuffer_create); * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes * it, setting it to NULL. */ -void drm_framebuffer_destroy(struct drm_framebuffer *fb) +void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; struct drm_crtc *crtc; @@ -249,10 +245,8 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) drm_mode_object_put(dev, &fb->base); list_del(&fb->head); dev->mode_config.num_fb--; - - kfree(fb); } -EXPORT_SYMBOL(drm_framebuffer_destroy); +EXPORT_SYMBOL(drm_framebuffer_cleanup); /** * drm_crtc_init - Initialise a new CRTC object @@ -705,11 +699,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) } list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { - /* there should only be bo of kernel type left */ - if (fb->bo->type != drm_bo_type_kernel) - drm_framebuffer_destroy(fb); - else - dev->driver->fb_remove(dev, fb); + fb->funcs->destroy(fb); } list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { @@ -1393,7 +1383,6 @@ int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *r = data; struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; - struct drm_buffer_object *bo; int ret = 0; if ((config->min_width > r->width) || (r->width > config->max_width)) { @@ -1406,33 +1395,18 @@ int drm_mode_addfb(struct drm_device *dev, } mutex_lock(&dev->mode_config.mutex); - /* TODO check limits are okay */ - ret = drm_get_buffer_object(dev, &bo, r->handle); - if (ret || !bo) { - DRM_ERROR("BO handle not valid\n"); - ret = -EINVAL; - goto out; - } /* TODO check buffer is sufficently large */ /* TODO setup destructor callback */ - fb = drm_framebuffer_create(dev); + fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); if (!fb) { DRM_ERROR("could not create framebuffer\n"); ret = -EINVAL; goto out; } - fb->width = r->width; - fb->height = r->height; - fb->pitch = r->pitch; - fb->bits_per_pixel = r->bpp; - fb->depth = r->depth; - fb->bo = bo; - r->buffer_id = fb->base.id; - list_add(&fb->filp_head, &file_priv->fbs); out: @@ -1490,11 +1464,8 @@ int drm_mode_rmfb(struct drm_device *dev, /* TODO release all crtc connected to the framebuffer */ /* TODO unhock the destructor from the buffer object */ - if (fb->bo->type == drm_bo_type_kernel) - DRM_ERROR("the bo type should not be of kernel type\n"); - list_del(&fb->filp_head); - drm_framebuffer_destroy(fb); + fb->funcs->destroy(fb); out: mutex_unlock(&dev->mode_config.mutex); @@ -1539,7 +1510,7 @@ int drm_mode_getfb(struct drm_device *dev, r->width = fb->width; r->depth = fb->depth; r->bpp = fb->bits_per_pixel; - r->handle = fb->bo->base.hash.key; + r->handle = fb->mm_handle; r->pitch = fb->pitch; out: @@ -1570,10 +1541,7 @@ void drm_fb_release(struct file *filp) mutex_lock(&dev->mode_config.mutex); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { list_del(&fb->filp_head); - if (fb->bo->type == drm_bo_type_kernel) - DRM_ERROR("the bo type should not be of kernel_type, the kernel will probably explode, why Dave\n"); - - drm_framebuffer_destroy(fb); + fb->funcs->destroy(fb); } mutex_unlock(&dev->mode_config.mutex); } @@ -2118,17 +2086,12 @@ int drm_mode_replacefb(struct drm_device *dev, struct drm_mode_fb_cmd *r = data; struct drm_mode_object *obj; struct drm_framebuffer *fb; - struct drm_buffer_object *bo; int found = 0; struct drm_framebuffer *fbl = NULL; int ret = 0; + /* right replace the current bo attached to this fb with a new bo */ mutex_lock(&dev->mode_config.mutex); - ret = drm_get_buffer_object(dev, &bo, r->handle); - if (ret || !bo) { - ret = -EINVAL; - goto out; - } obj = drm_mode_object_find(dev, r->buffer_id, DRM_MODE_OBJECT_FB); if (!obj) { ret = -EINVAL; @@ -2146,15 +2109,12 @@ int drm_mode_replacefb(struct drm_device *dev, goto out; } - if (fb->bo->type == drm_bo_type_kernel) - DRM_ERROR("the bo should not be a kernel bo\n"); - fb->width = r->width; fb->height = r->height; fb->pitch = r->pitch; fb->bits_per_pixel = r->bpp; fb->depth = r->depth; - fb->bo = bo; + fb->mm_handle = r->handle; if (dev->mode_config.funcs->resize_fb) dev->mode_config.funcs->resize_fb(dev, fb); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 01cf9af7..5c2d0b3c 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -15,6 +15,7 @@ struct drm_device; struct drm_mode_set; +struct drm_framebuffer; #define DRM_MODE_OBJECT_CRTC 0xcccccccc @@ -250,10 +251,15 @@ struct drm_display_info { char *raw_edid; /* if any */ }; +struct drm_framebuffer_funcs { + void (*destroy)(struct drm_framebuffer *framebuffer); +}; + struct drm_framebuffer { struct drm_device *dev; struct list_head head; struct drm_mode_object base; + const struct drm_framebuffer_funcs *funcs; unsigned int pitch; unsigned int width; unsigned int height; @@ -261,11 +267,10 @@ struct drm_framebuffer { unsigned int depth; int bits_per_pixel; int flags; - struct drm_buffer_object *bo; void *fbdev; u32 pseudo_palette[17]; - struct drm_bo_kmap_obj kmap; struct list_head filp_head; + uint32_t mm_handle; }; struct drm_property_blob { @@ -517,6 +522,7 @@ struct drm_mode_set */ struct drm_mode_config_funcs { bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); + struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); }; struct drm_mode_group { @@ -645,8 +651,9 @@ extern int drm_connector_property_get_value(struct drm_connector *connector, extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); -extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); -extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); +extern struct drm_framebuffer *drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, + const struct drm_framebuffer_funcs *funcs); +extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index fcb1243c..f35c0a49 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -749,3 +749,17 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c } EXPORT_SYMBOL(drm_helper_hotplug_stage_two); + +int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + struct drm_mode_fb_cmd *mode_cmd) +{ + fb->width = mode_cmd->width; + fb->height = mode_cmd->height; + fb->pitch = mode_cmd->pitch; + fb->bits_per_pixel = mode_cmd->bpp; + fb->depth = mode_cmd->depth; + fb->mm_handle = mode_cmd->handle; + + return 0; +} +EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 3a3a4d4f..460fd0d0 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -72,6 +72,10 @@ extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y); extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); + +extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + struct drm_mode_fb_cmd *mode_cmd); + static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) { crtc->helper_private = (void *)funcs; diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 51262d79..2aac4926 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -589,7 +589,6 @@ static struct drm_driver driver = { .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, .fb_probe = intelfb_probe, - .fb_remove = intelfb_remove, .fb_resize = intelfb_resize, .master_create = i915_master_create, .master_destroy = i915_master_destroy, diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 8a8f4edb..529cae14 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -368,6 +368,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; int pipe = intel_crtc->pipe; unsigned long Start, Offset; int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); @@ -382,7 +383,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) return; } - Start = crtc->fb->bo->offset; + intel_fb = to_intel_framebuffer(crtc->fb); + + Start = intel_fb->bo->offset; Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); I915_WRITE(dspstride, crtc->fb->pitch); @@ -1459,8 +1462,50 @@ static void intel_setup_outputs(struct drm_device *dev) } } +static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_device *dev = fb->dev; + if (fb->fbdev) + intelfb_remove(dev, fb); + + drm_framebuffer_cleanup(fb); + + kfree(intel_fb); +} + +static const struct drm_framebuffer_funcs intel_fb_funcs = { + .destroy = intel_user_framebuffer_destroy, +}; + +struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_mode_fb_cmd *mode_cmd) +{ + struct intel_framebuffer *intel_fb; + + intel_fb = kmalloc(sizeof(*intel_fb), GFP_KERNEL); + if (!intel_fb) + return NULL; + + drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); + drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); + + if (file_priv) { + mutex_lock(&dev->struct_mutex); + intel_fb->bo = drm_lookup_buffer_object(file_priv, intel_fb->base.mm_handle, 0); + mutex_unlock(&dev->struct_mutex); + if (!intel_fb->bo) { + kfree(intel_fb); + return NULL; + } + } + return &intel_fb->base; +} + static const struct drm_mode_config_funcs intel_mode_funcs = { .resize_fb = NULL, + .fb_create = intel_user_framebuffer_create, }; void intel_modeset_init(struct drm_device *dev) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 210ed990..46f0fbec 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -46,6 +46,12 @@ struct intel_i2c_chan { u8 slave_addr; }; +struct intel_framebuffer { + struct drm_framebuffer base; + struct drm_buffer_object *bo; + struct drm_bo_kmap_obj kmap; +}; + struct intel_output { struct drm_connector base; @@ -69,6 +75,7 @@ struct intel_crtc { #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_output(x) container_of(x, struct intel_output, base) #define enc_to_intel_output(x) container_of(x, struct intel_output, enc) +#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, const char *name); @@ -106,4 +113,8 @@ extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); + +extern struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_mode_fb_cmd *mode_cmd); #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index d490880a..1107cbfb 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -573,7 +573,10 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn struct intelfb_par *par; struct device *device = &dev->pdev->dev; struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; struct drm_display_mode *mode = crtc->desired_mode; + struct drm_mode_fb_cmd mode_cmd; + struct drm_buffer_object *fbo = NULL; int ret; @@ -585,22 +588,14 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn if (!connector) return -EINVAL; - fb = drm_framebuffer_create(dev); - if (!fb) { - framebuffer_release(info); - DRM_ERROR("failed to allocate fb.\n"); - return -EINVAL; - } - crtc->fb = fb; - - /* To allow resizeing without swapping buffers */ - fb->width = 2048;/* crtc->desired_mode->hdisplay; */ - fb->height = 2048;/* crtc->desired_mode->vdisplay; */ + mode_cmd.width = 2048;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = 2048;/* crtc->desired_mode->vdisplay; */ + + mode_cmd.bpp = 32; + mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); + mode_cmd.depth = 24; - fb->bits_per_pixel = 32; - fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); - fb->depth = 24; - ret = drm_buffer_object_create(dev, fb->pitch * fb->height, + ret = drm_buffer_object_create(dev, mode_cmd.pitch * mode_cmd.height, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | @@ -611,14 +606,27 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn &fbo); if (ret || !fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); - drm_framebuffer_destroy(fb); framebuffer_release(info); return -EINVAL; } + - fb->bo = fbo; - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width, - fb->height, fbo->offset, fbo); + fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); + if (!fb) { + framebuffer_release(info); + drm_bo_usage_deref_unlocked(&fbo); + DRM_ERROR("failed to allocate fb.\n"); + return -EINVAL; + } + + intel_fb = to_intel_framebuffer(fb); + + intel_fb->bo = fbo; + crtc->fb = fb; + + /* To allow resizeing without swapping buffers */ + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, + intel_fb->base.height, intel_fb->bo->offset, fbo); fb->fbdev = info; @@ -653,16 +661,16 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn } info->fix.line_length = fb->pitch; - info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base; + info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base; info->fix.smem_len = info->fix.line_length * fb->height; info->flags = FBINFO_DEFAULT; - ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap); + ret = drm_bo_kmap(intel_fb->bo, 0, intel_fb->bo->num_pages, &intel_fb->kmap); if (ret) DRM_ERROR("error mapping fb: %d\n", ret); - info->screen_base = fb->kmap.virtual; + info->screen_base = intel_fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; @@ -771,6 +779,7 @@ EXPORT_SYMBOL(intelfb_probe); int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) { struct fb_info *info; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); if (!fb) return -EINVAL; @@ -779,9 +788,8 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) if (info) { unregister_framebuffer(info); - drm_bo_kunmap(&fb->kmap); - drm_bo_usage_deref_unlocked(&fb->bo); - drm_framebuffer_destroy(fb); + drm_bo_kunmap(&intel_fb->kmap); + drm_bo_usage_deref_unlocked(&intel_fb->bo); framebuffer_release(info); } return 0; -- cgit v1.2.3 From fd27591c6cadd2a868f4110b8993a86c37837d3e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:00:31 +1000 Subject: drm/modesetting: pass object handle to driver !bo --- linux-core/drm_crtc.c | 58 +------------------------------------------- linux-core/drm_crtc.h | 2 +- linux-core/drm_crtc_helper.c | 49 ++++++++++++++++++++++++++++++++++--- linux-core/drm_crtc_helper.h | 2 +- linux-core/intel_display.c | 11 +++++++-- 5 files changed, 58 insertions(+), 64 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 7f843925..4f2297a2 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -618,53 +618,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_gro return 0; } -/** - * drm_get_buffer_object - find the buffer object for a given handle - * @dev: DRM device - * @bo: pointer to caller's buffer_object pointer - * @handle: handle to lookup - * - * LOCKING: - * Must take @dev's struct_mutex to protect buffer object lookup. - * - * Given @handle, lookup the buffer object in @dev and put it in the caller's - * @bo pointer. - * - * RETURNS: - * Zero on success, -EINVAL if the handle couldn't be found. - */ -static int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle) -{ - struct drm_user_object *uo; - struct drm_hash_item *hash; - int ret; - - *bo = NULL; - - mutex_lock(&dev->struct_mutex); - ret = drm_ht_find_item(&dev->object_hash, handle, &hash); - if (ret) { - DRM_ERROR("Couldn't find handle.\n"); - ret = -EINVAL; - goto out_err; - } - - uo = drm_hash_entry(hash, struct drm_user_object, hash); - if (uo->type != drm_buffer_type) { - ret = -EINVAL; - goto out_err; - } - - *bo = drm_user_object_entry(uo, struct drm_buffer_object, base); - ret = 0; -out_err: - mutex_unlock(&dev->struct_mutex); - return ret; -} - - - - /** * drm_mode_config_cleanup - free up DRM mode_config info * @dev: DRM device @@ -1328,17 +1281,8 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (req->flags & DRM_MODE_CURSOR_BO) { /* Turn of the cursor if handle is 0 */ - if (req->handle) - ret = drm_get_buffer_object(dev, &bo, req->handle); - - if (ret) { - DRM_ERROR("invalid buffer id\n"); - ret = -EINVAL; - goto out; - } - if (crtc->funcs->cursor_set) { - ret = crtc->funcs->cursor_set(crtc, bo, req->width, req->height); + ret = crtc->funcs->cursor_set(crtc, req->handle, req->width, req->height); } else { DRM_ERROR("crtc does not support cursor\n"); ret = -EFAULT; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 5c2d0b3c..c92c59bf 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -332,7 +332,7 @@ struct drm_crtc_funcs { void (*restore)(struct drm_crtc *crtc); /* resume? */ /* cursor controls */ - int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo, + int (*cursor_set)(struct drm_crtc *crtc, uint32_t buffer_handle, uint32_t width, uint32_t height); int (*cursor_move)(struct drm_crtc *crtc, int x, int y); diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index f35c0a49..58d21b99 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -1,6 +1,4 @@ - -/* - * Copyright (c) 2006-2007 Intel Corporation +/* (c) 2006-2007 Intel Corporation * Copyright (c) 2007 Dave Airlie * * DRM core CRTC related functions @@ -763,3 +761,48 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, return 0; } EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); + +/** + * drm_get_buffer_object - find the buffer object for a given handle + * @dev: DRM device + * @bo: pointer to caller's buffer_object pointer + * @handle: handle to lookup + * + * LOCKING: + * Must take @dev's struct_mutex to protect buffer object lookup. + * + * Given @handle, lookup the buffer object in @dev and put it in the caller's + * @bo pointer. + * + * RETURNS: + * Zero on success, -EINVAL if the handle couldn't be found. + */ +int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle) +{ + struct drm_user_object *uo; + struct drm_hash_item *hash; + int ret; + + *bo = NULL; + + mutex_lock(&dev->struct_mutex); + ret = drm_ht_find_item(&dev->object_hash, handle, &hash); + if (ret) { + DRM_ERROR("Couldn't find handle.\n"); + ret = -EINVAL; + goto out_err; + } + + uo = drm_hash_entry(hash, struct drm_user_object, hash); + if (uo->type != drm_buffer_type) { + ret = -EINVAL; + goto out_err; + } + + *bo = drm_user_object_entry(uo, struct drm_buffer_object, base); + ret = 0; +out_err: + mutex_unlock(&dev->struct_mutex); + return ret; +} +EXPORT_SYMBOL(drm_get_buffer_object); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 460fd0d0..7b7f23dc 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -91,6 +91,6 @@ static inline void drm_connector_helper_add(struct drm_connector *connector, con connector->helper_private = (void *)funcs; } - +extern int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle); #endif diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 529cae14..3f5afac0 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -972,22 +972,24 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } static int intel_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_buffer_object *bo, + uint32_t handle, uint32_t width, uint32_t height) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_buffer_object *bo; int pipe = intel_crtc->pipe; uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; uint32_t temp; + int ret; size_t addr; DRM_DEBUG("\n"); /* if we want to turn of the cursor ignore width and height */ - if (!bo) { + if (!handle) { DRM_DEBUG("cursor off\n"); /* turn of the cursor */ temp = 0; @@ -1004,6 +1006,11 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, return -EINVAL; } + ret = drm_get_buffer_object(dev, &bo, handle); + if (ret) { + return -EINVAL; + } + if ((bo->mem.flags & DRM_BO_MASK_MEM) != DRM_BO_FLAG_MEM_VRAM) { DRM_ERROR("buffer needs to be in VRAM\n"); return -ENOMEM; -- cgit v1.2.3 From 58aca7485a4cd9fcccc6e4044325048abcc2f9c7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:03:23 +1000 Subject: drm: remove sysfs in driver for now.. should probably be in helper --- linux-core/drm_crtc.c | 3 --- linux-core/intel_crt.c | 1 + linux-core/intel_dvo.c | 1 + linux-core/intel_lvds.c | 1 + linux-core/intel_sdvo.c | 2 +- linux-core/intel_tv.c | 1 + 6 files changed, 5 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 4f2297a2..73ad317a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -643,7 +643,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) } list_for_each_entry_safe(connector, ot, &dev->mode_config.connector_list, head) { - drm_sysfs_connector_remove(connector); connector->funcs->destroy(connector); } @@ -662,8 +661,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_cleanup); - - int drm_mode_hotplug_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index bf7c449e..e32a9551 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -199,6 +199,7 @@ static void intel_crt_destroy(struct drm_connector *connector) struct intel_output *intel_output = to_intel_output(connector); intel_i2c_destroy(intel_output->ddc_bus); + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(connector); } diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index b061b1c5..e6df8fdd 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -306,6 +306,7 @@ static void intel_dvo_destroy (struct drm_connector *connector) intel_i2c_destroy(intel_output->i2c_bus); if (intel_output->ddc_bus) intel_i2c_destroy(intel_output->ddc_bus); + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(intel_output); } diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index f2fe4612..cf9294ee 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -330,6 +330,7 @@ static void intel_lvds_destroy(struct drm_connector *connector) struct intel_output *intel_output = to_intel_output(connector); intel_i2c_destroy(intel_output->ddc_bus); + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(connector); } diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 9ae0d567..ef67ef9b 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -966,7 +966,7 @@ static void intel_sdvo_destroy(struct drm_connector *connector) if (intel_output->i2c_bus) intel_i2c_destroy(intel_output->i2c_bus); - + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(intel_output); } diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index e45cfa3b..25fb2e6b 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1553,6 +1553,7 @@ intel_tv_destroy (struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); + drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); -- cgit v1.2.3 From 8690ad8ae0778f2ccd8b428e1c6a8614ebc51707 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:09:05 +1000 Subject: drm/modesetting: bo not used anymore --- linux-core/drm_crtc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 73ad317a..d2060fd1 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1257,7 +1257,6 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, struct drm_mode_cursor *req = data; struct drm_mode_object *obj; struct drm_crtc *crtc; - struct drm_buffer_object *bo = NULL; /* must be set */ int ret = 0; DRM_DEBUG("\n"); -- cgit v1.2.3 From 8e4c61e52651c47f3d9fbbe5e80455baff0de2bb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:09:20 +1000 Subject: intel: use kzalloc --- linux-core/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 3f5afac0..6493af16 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1491,7 +1491,7 @@ struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, { struct intel_framebuffer *intel_fb; - intel_fb = kmalloc(sizeof(*intel_fb), GFP_KERNEL); + intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); if (!intel_fb) return NULL; -- cgit v1.2.3 From 9f31bd09c1e748f72a30f6a0861cd72d93258992 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:16:49 +1000 Subject: drm/sysfs: don't try an unregister if not registered --- linux-core/drm_sysfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 01a3c047..c148256a 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -301,6 +301,9 @@ void drm_sysfs_connector_remove(struct drm_connector *connector) { int i; + if (!device_is_registered(&connector->kdev)) + return; + DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_connector_name(connector)); for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) device_remove_file(&connector->kdev, &connector_attrs[i]); -- cgit v1.2.3 From 382aa3ceeb79165a9bdddc8f944de131c8cbf2dd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:49:43 +1000 Subject: drm: introduce generation counter to interface. Idea being if you want to add new crtc/output/encoder dynamically later, you just increase the generation counter and userspace should re-read all the resources --- libdrm/xf86drmMode.h | 11 ++++++++++- linux-core/drm_crtc.c | 6 +++++- linux-core/drm_crtc.h | 3 +++ shared-core/drm.h | 7 +++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 56908d8f..3bd30a92 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -51,9 +51,16 @@ * buffer object interface. This object needs to be pinned. */ +/* + * generation - these are to be read by userspace, and if it notices + * while calling a get output or get crtc that the generation has changed + * it should re-call the mode resource functions resync its view of the + * outputs with current view. + */ typedef struct _drmModeRes { + uint32_t generation; int count_fbs; uint32_t *fbs; @@ -93,6 +100,7 @@ typedef struct _drmModeProperty { typedef struct _drmModeCrtc { unsigned int crtc_id; unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/ + uint32_t generation; uint32_t x, y; /**< Position on the frameuffer */ uint32_t width, height; @@ -110,6 +118,7 @@ typedef struct _drmModeCrtc { } drmModeCrtc, *drmModeCrtcPtr; typedef struct _drmModeEncoder { + uint32_t generation; unsigned int encoder_id; unsigned int encoder_type; uint32_t crtc; @@ -133,8 +142,8 @@ typedef enum { } drmModeSubPixel; typedef struct _drmModeConnector { + uint32_t generation; unsigned int connector_id; - unsigned int encoder; /**< Crtc currently connected to */ unsigned int connector_type; unsigned int connector_type_id; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index d2060fd1..4c6afd16 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -571,6 +571,7 @@ void drm_mode_config_init(struct drm_device *dev) drm_mode_create_standard_connector_properties(dev); /* Just to be sure */ + dev->mode_config.current_generation = 0; dev->mode_config.num_fb = 0; dev->mode_config.num_connector = 0; dev->mode_config.num_crtc = 0; @@ -801,6 +802,7 @@ int drm_mode_getresources(struct drm_device *dev, card_res->min_height = dev->mode_config.min_height; card_res->max_width = dev->mode_config.max_width; card_res->min_width = dev->mode_config.min_width; + card_res->generation = dev->mode_config.current_generation; /* handle this in 4 parts */ /* FBs */ @@ -943,7 +945,7 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->x = crtc->x; crtc_resp->y = crtc->y; crtc_resp->gamma_size = crtc->gamma_size; - + crtc_resp->generation = dev->mode_config.current_generation; if (crtc->fb) crtc_resp->fb_id = crtc->fb->base.id; else @@ -1032,6 +1034,7 @@ int drm_mode_getconnector(struct drm_device *dev, connector->funcs->fill_modes(connector, dev->mode_config.max_width, dev->mode_config.max_height); } + out_resp->generation = dev->mode_config.current_generation; out_resp->connector_type = connector->connector_type; out_resp->connector_type_id = connector->connector_type_id; out_resp->mm_width = connector->display_info.width_mm; @@ -1120,6 +1123,7 @@ int drm_mode_getencoder(struct drm_device *dev, enc_resp->crtc = encoder->crtc->base.id; else enc_resp->crtc = 0; + enc_resp->generation = dev->mode_config.current_generation; enc_resp->encoder_type = encoder->encoder_type; enc_resp->encoder_id = encoder->base.id; enc_resp->crtcs = encoder->possible_crtcs; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index c92c59bf..f3953692 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -554,6 +554,9 @@ struct drm_mode_config { struct list_head property_list; + /* currently in use generation id */ + int current_generation; + int min_width, min_height; int max_width, max_height; struct drm_mode_config_funcs *funcs; diff --git a/shared-core/drm.h b/shared-core/drm.h index 132c7746..40653b4b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1033,6 +1033,7 @@ struct drm_mode_card_res { int count_encoders; int min_width, max_width; int min_height, max_height; + uint32_t generation; }; struct drm_mode_crtc { @@ -1043,6 +1044,8 @@ struct drm_mode_crtc { int x, y; /**< Position on the frameuffer */ + uint32_t generation; + int count_connectors; unsigned int connectors; /**< Connectors that are connected */ @@ -1055,6 +1058,8 @@ struct drm_mode_crtc { struct drm_mode_get_encoder { + uint32_t generation; + uint32_t encoder_type; uint32_t encoder_id; @@ -1085,6 +1090,8 @@ struct drm_mode_get_connector { unsigned int connector_type; unsigned int connector_type_id; + uint32_t generation; + unsigned int connection; unsigned int mm_width, mm_height; /**< HxW in millimeters */ unsigned int subpixel; -- cgit v1.2.3 From 9390bdab7cce67ad0eb8103da8782aec7bfad017 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:53:33 +1000 Subject: libdrm: shouldn't rely on this --- libdrm/xf86drmMode.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 3bd30a92..f1b7c86e 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -32,7 +32,6 @@ */ #include -#include "xf86mm.h" /* * This is the interface for modesetting for drm. -- cgit v1.2.3 From a8725d95bc2b51500ff56c4e6365408d15f3bc6e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 15:17:00 +1000 Subject: intel: report a known connector --- linux-core/intel_tv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 25fb2e6b..39f33d6c 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1680,7 +1680,7 @@ intel_tv_init(struct drm_device *dev) connector = &intel_output->base; drm_connector_init(dev, connector, &intel_tv_connector_funcs, - DRM_MODE_CONNECTOR_Unknown); + DRM_MODE_CONNECTOR_SVIDEO); drm_encoder_init(dev, &intel_output->enc, &intel_tv_enc_funcs, DRM_MODE_ENCODER_TVDAC); -- cgit v1.2.3 From cf1964f971cc298ece91064953f7d00ed13e541d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 15:17:13 +1000 Subject: drm: fix hotplug oops --- linux-core/drm_crtc_helper.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 58d21b99..4083d6b7 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -712,9 +712,11 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c return 0; } - if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the connector already has a config\n"); - has_config = 1; + if (connector->encoder) { + if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { + DRM_DEBUG("drm thinks that the connector already has a config\n"); + has_config = 1; + } } drm_helper_probe_connector_modes(dev, 2048, 2048); @@ -722,6 +724,11 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c if (!has_config) drm_pick_crtcs(dev); + if (!connector->encoder) { + DRM_DEBUG("could not find a desired mode or crtc for connector\n"); + return 1; + } + if (!connector->encoder->crtc || !connector->encoder->crtc->desired_mode) { DRM_DEBUG("could not find a desired mode or crtc for connector\n"); return 1; -- cgit v1.2.3 From 52183fb05b8f8db0705e230fc0b8a436512759a1 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 4 Jun 2008 09:38:44 -0700 Subject: Fix crash in drm_mode_connector_update_edid_property We need to initialize the edid_blob_ptr to NULL when we init a connector, otherwise drm_mode_connector_update_edid_property may think there's a valid EDID lying around and try to destroy it, causing a crash. --- linux-core/drm_crtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 4c6afd16..7a049da8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -357,6 +357,7 @@ void drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->user_modes); INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); + connector->edid_blob_ptr = NULL; /* randr_connector? */ /* connector_set_monitor(connector)? */ /* check for connector_ignored(connector)? */ -- cgit v1.2.3 From e90716671d7a5dabf13c22a339f750dba77f438a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 4 Jun 2008 12:50:03 -0700 Subject: i915: use kzalloc to allocate intel_output for lvds Better to initialize all the struct fields to 0. Also more consistent with other output init routines. --- linux-core/intel_lvds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index cf9294ee..8d65c161 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -387,7 +387,7 @@ void intel_lvds_init(struct drm_device *dev) u32 lvds; int pipe; - intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL); + intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) { return; } -- cgit v1.2.3 From 967bd219116a4f20aec828b890a225d2f92afd0b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:11:22 +1000 Subject: modesetting: initial attempt at debonging fb --- linux-core/drmP.h | 2 +- linux-core/drm_crtc.h | 2 + linux-core/drm_crtc_helper.c | 13 +- linux-core/i915_drv.c | 6 + linux-core/intel_display.c | 7 + linux-core/intel_drv.h | 4 +- linux-core/intel_fb.c | 537 ++++++++++++++++++++++++------------------- shared-core/i915_drv.h | 2 + 8 files changed, 330 insertions(+), 243 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6e627cd9..9845b5c8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -743,7 +743,7 @@ struct drm_driver { struct drm_set_version *sv); /* FB routines, if present */ - int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); + int (*fb_probe)(struct drm_device *dev); int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); /* Master routines */ diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index f3953692..da05ff27 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -500,6 +500,8 @@ struct drm_connector { */ struct drm_mode_set { + struct list_head head; + struct drm_framebuffer *fb; struct drm_crtc *crtc; struct drm_display_mode *mode; diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 4083d6b7..3ff7e07e 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -643,15 +643,20 @@ EXPORT_SYMBOL(drm_crtc_helper_set_config); */ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) { - struct drm_connector *connector; int ret = false; mutex_lock(&dev->mode_config.mutex); - drm_helper_probe_connector_modes(dev, 2048, 2048); + drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); drm_pick_crtcs(dev); + /* use all the info we have to setup the fb */ + dev->driver->fb_probe(dev); +#if 0 + /* have to do a driver pick here */ + /* get the lowest common denom of width height that will fit nicely - size the fb to this + size, however may need a wider stride for crtc alignment */ /* This is a little screwy, as we've already walked the connectors * above, but it's a little bit of magic too. There's the potential * for things not to get setup above if an existing device gets @@ -680,7 +685,7 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) } drm_helper_disable_unused_functions(dev); - +#endif mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -736,7 +741,7 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c /* We should really check if there is a fb using this crtc */ if (!has_config) - dev->driver->fb_probe(dev, connector->encoder->crtc, connector); + dev->driver->fb_probe(dev); else { dev->driver->fb_resize(dev, connector->encoder->crtc); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 2aac4926..b81db3a6 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -42,6 +42,12 @@ static struct pci_device_id pciidlist[] = { unsigned int i915_modeset = 0; module_param_named(modeset, i915_modeset, int, 0400); +unsigned int i915_fbpercrtc = 1; +module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); + +unsigned int i915_rightof = 1; +module_param_named(i915_rightof, i915_rightof, int, 0400); + #ifdef I915_HAVE_FENCE extern struct drm_fence_driver i915_fence_driver; #endif diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 6493af16..8baae1b3 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1383,6 +1383,12 @@ void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_addr = 0; intel_crtc->dpms_mode = DPMSModeOff; drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); + + if (i915_fbpercrtc) { + + + + } } struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) @@ -1554,6 +1560,7 @@ void intel_modeset_init(struct drm_device *dev) intel_setup_outputs(dev); + /* setup fbs */ //drm_initial_config(dev, false); } diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 46f0fbec..25e2a652 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -52,6 +52,7 @@ struct intel_framebuffer { struct drm_bo_kmap_obj kmap; }; + struct intel_output { struct drm_connector base; @@ -70,6 +71,7 @@ struct intel_crtc { uint32_t cursor_addr; u8 lut_r[256], lut_g[256], lut_b[256]; int dpms_mode; + struct intel_framebuffer *fbdev_fb; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) @@ -108,7 +110,7 @@ extern void intel_release_load_detect_pipe(struct intel_output *intel_output, extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); -extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector); +extern int intelfb_probe(struct drm_device *dev); extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 1107cbfb..2f28ca1b 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -47,14 +47,10 @@ struct intelfb_par { struct drm_device *dev; -/* - struct drm_crtc *crtc; - struct drm_display_mode *fb_mode; - struct drm_framebuffer *fb; -*/ struct drm_display_mode *our_mode; - struct drm_mode_set set; - struct drm_connector *hack; + struct intel_framebuffer *intel_fb; + int crtc_count; + struct list_head mode_set_list; }; /* static int @@ -73,38 +69,41 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->set.fb; - struct drm_crtc *crtc = par->set.crtc; + struct drm_mode_set *modeset; - if (regno > 255) - return 1; + list_for_each_entry(modeset, &par->mode_set_list, head) { + struct drm_crtc *crtc = modeset->crtc; + struct drm_framebuffer *fb = modeset->fb; - if (fb->depth == 8) { - intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); - return 0; - } + if (regno > 255) + return 1; - if (regno < 16) { - switch (fb->depth) { - case 15: - fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11); - break; - case 16: - fb->pseudo_palette[regno] = (red & 0xf800) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - case 24: - case 32: - fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | - (green & 0xff00) | - ((blue & 0xff00) >> 8); - break; + if (fb->depth == 8) { + intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); + return 0; } - } + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + } return 0; } @@ -112,12 +111,11 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - /*struct drm_device *dev = par->dev;*/ - struct drm_framebuffer *fb = par->set.fb; - /*struct drm_connector *connector;*/ - int depth/*, found = 0*/; + struct intel_framebuffer *intel_fb = par->intel_fb; + struct drm_framebuffer *fb = &intel_fb->base; + int depth; - if (!var->pixclock) + if (var->pixclock == -1 || !var->pixclock) return -EINVAL; /* Need to resize the fb object !!! */ @@ -194,31 +192,6 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, return -EINVAL; } -#if 0 - /* Here we walk the connector mode list and look for modes. If we haven't - * got it, then bail. Not very nice, so this is disabled. - * In the set_par code, we create our mode based on the incoming - * parameters. Nicer, but may not be desired by some. - */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->crtc == par->crtc) - break; - } - - list_for_each_entry(drm_mode, &connector->modes, head) { - if (drm_mode->hdisplay == var->xres && - drm_mode->vdisplay == var->yres && - (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) && - (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) { - found = 1; - break; - } - } - - if (!found) - return -EINVAL; -#endif - return 0; } @@ -227,123 +200,122 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_framebuffer *fb = par->set.fb; struct drm_device *dev = par->dev; - struct drm_display_mode *drm_mode, *search_mode; - struct drm_connector *connector = NULL; struct fb_var_screeninfo *var = &info->var; int found = 0; - DRM_DEBUG("\n"); + DRM_DEBUG("%d %d\n", var->xres, var->pixclock); - switch (var->bits_per_pixel) { - case 16: - fb->depth = (var->green.length == 6) ? 16 : 15; - break; - case 32: - fb->depth = (var->transp.length > 0) ? 32 : 24; - break; - default: - fb->depth = var->bits_per_pixel; - break; - } - - fb->bits_per_pixel = var->bits_per_pixel; - info->fix.line_length = fb->pitch; - info->fix.smem_len = info->fix.line_length * fb->height; - info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - - info->screen_size = info->fix.smem_len; /* ??? */ - - /* create a drm mode */ - drm_mode = drm_mode_create(dev); - drm_mode->hdisplay = var->xres; - drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; - drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; - drm_mode->htotal = drm_mode->hsync_end + var->left_margin; - drm_mode->vdisplay = var->yres; - drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; - drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; - drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; - drm_mode->clock = PICOS2KHZ(var->pixclock); - drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); - drm_mode->flags = 0; - drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; - drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; - - drm_mode_set_name(drm_mode); - drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); - - found = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder && - connector->encoder->crtc == par->set.crtc){ - found = 1; - break; - } - } + if (var->pixclock != -1) { - /* no connector bound, bail */ - if (!found) - return -EINVAL; + DRM_ERROR("PIXEL CLCOK SET\n"); +#if 0 + struct intel_framebuffer *intel_fb = par->intel_fb; + struct drm_framebuffer *fb = &intel_fb->base; + struct drm_display_mode *drm_mode, *search_mode; + struct drm_connector *connector = NULL; - found = 0; - drm_mode_debug_printmodeline(drm_mode); - list_for_each_entry(search_mode, &connector->modes, head) { - drm_mode_debug_printmodeline(search_mode); - if (drm_mode_equal(drm_mode, search_mode)) { - drm_mode_destroy(dev, drm_mode); - drm_mode = search_mode; - found = 1; + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + fb->depth = var->bits_per_pixel; break; } - } - - /* If we didn't find a matching mode that exists on our connector, - * create a new attachment for the incoming user specified mode - */ - if (!found) { - if (par->our_mode) { - /* this also destroys the mode */ - drm_mode_detachmode_crtc(dev, par->our_mode); + + fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = fb->pitch; + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + info->screen_size = info->fix.smem_len; /* ??? */ + /* reuse desired mode if possible */ + /* create a drm mode */ + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode->flags = 0; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + + drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + + found = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder && + connector->encoder->crtc == par->set.crtc){ + found = 1; + break; + } } - - par->set.mode = drm_mode; - par->our_mode = drm_mode; + + /* no connector bound, bail */ + if (!found) + return -EINVAL; + + found = 0; drm_mode_debug_printmodeline(drm_mode); - /* attach mode */ - drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + list_for_each_entry(search_mode, &connector->modes, head) { + drm_mode_debug_printmodeline(search_mode); + if (drm_mode_equal(drm_mode, search_mode)) { + drm_mode_destroy(dev, drm_mode); + drm_mode = search_mode; + found = 1; + break; + } + } + + /* If we didn't find a matching mode that exists on our connector, + * create a new attachment for the incoming user specified mode + */ + if (!found) { + if (par->our_mode) { + /* this also destroys the mode */ + drm_mode_detachmode_crtc(dev, par->our_mode); + } + + par->set.mode = drm_mode; + par->our_mode = drm_mode; + drm_mode_debug_printmodeline(drm_mode); + /* attach mode */ + drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + } else { + par->set.mode = drm_mode; + if (par->our_mode) + drm_mode_detachmode_crtc(dev, par->our_mode); + par->our_mode = NULL; + } + return par->set.crtc->funcs->set_config(&par->set); +#endif + return -EINVAL; } else { - par->set.mode = drm_mode; - if (par->our_mode) - drm_mode_detachmode_crtc(dev, par->our_mode); - par->our_mode = NULL; - } - -#if 0 - /* re-attach fb */ - if (!par->crtc->fb) { - par->crtc->fb = par->fb; - changed = 1; + struct drm_mode_set *modeset; + int ret; + + list_for_each_entry(modeset, &par->mode_set_list, head) { + if (modeset->num_connectors) { + ret = modeset->crtc->funcs->set_config(modeset); + if (ret) + return ret; + } + } + return 0; } - - if (par->crtc->x != var->xoffset || par->crtc->y != var->yoffset) - changed = 1; - - drm_mode_debug_printmodeline(drm_mode); - drm_mode_debug_printmodeline(&par->crtc->mode); - if (!drm_mode_equal(drm_mode, &par->crtc->mode)) - changed = 1; - - if (changed) - if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset)) - return -EINVAL; - - return 0; -#else - return par->set.crtc->funcs->set_config(&par->set); -#endif } #if 0 @@ -495,17 +467,22 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; - int ret; + struct drm_mode_set *modeset; + int ret = 0; DRM_DEBUG("\n"); - - par->set.x = var->xoffset; - par->set.y = var->yoffset; - ret = par->set.crtc->funcs->set_config(&par->set); + list_for_each_entry(modeset, &par->mode_set_list, head) { + modeset->x = var->xoffset; + modeset->y = var->yoffset; - if (!ret) { - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; + if (modeset->num_connectors) { + ret = modeset->crtc->funcs->set_config(modeset); + + if (!ret) { + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + } + } } return ret; @@ -567,29 +544,19 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_connector *connector) +int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, struct intel_framebuffer **intel_fb_p) { struct fb_info *info; struct intelfb_par *par; - struct device *device = &dev->pdev->dev; struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; - struct drm_display_mode *mode = crtc->desired_mode; struct drm_mode_fb_cmd mode_cmd; - struct drm_buffer_object *fbo = NULL; + struct device *device = &dev->pdev->dev; int ret; - info = framebuffer_alloc(sizeof(struct intelfb_par), device); - if (!info){ - return -EINVAL; - } - - if (!connector) - return -EINVAL; - - mode_cmd.width = 2048;/* crtc->desired_mode->hdisplay; */ - mode_cmd.height = 2048;/* crtc->desired_mode->vdisplay; */ + mode_cmd.width = fb_width;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = fb_height;/* crtc->desired_mode->vdisplay; */ mode_cmd.bpp = 32; mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); @@ -606,43 +573,29 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn &fbo); if (ret || !fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); - framebuffer_release(info); return -EINVAL; } fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); if (!fb) { - framebuffer_release(info); drm_bo_usage_deref_unlocked(&fbo); DRM_ERROR("failed to allocate fb.\n"); return -EINVAL; } intel_fb = to_intel_framebuffer(fb); + *intel_fb_p = intel_fb; intel_fb->bo = fbo; - crtc->fb = fb; - - /* To allow resizeing without swapping buffers */ - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, - intel_fb->base.height, intel_fb->bo->offset, fbo); + info = framebuffer_alloc(sizeof(struct intelfb_par), device); + if (!info) + return -EINVAL; - fb->fbdev = info; - par = info->par; - par->dev = dev; - par->set.crtc = crtc; - par->set.fb = fb; - par->hack = connector; - par->set.connectors = &par->hack; - par->set.num_connectors = 1; - - info->fbops = &intelfb_ops; - - strcpy(info->fix.id, "intelfb"); + strcpy(info->fix.id, "inteldrmfb"); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_TRUECOLOR; info->fix.type_aux = 0; @@ -651,14 +604,10 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn info->fix.ywrapstep = 0; info->fix.accel = FB_ACCEL_I830; info->fix.type_aux = 0; - - if (IS_I9XX(dev)) { - info->fix.mmio_start = pci_resource_start(dev->pdev, 0); - info->fix.mmio_len = pci_resource_len(dev->pdev, 0); - } else { - info->fix.mmio_start = pci_resource_start(dev->pdev, 1); - info->fix.mmio_len = pci_resource_len(dev->pdev, 1); - } + + info->flags = FBINFO_DEFAULT; + + info->fbops = &intelfb_ops; info->fix.line_length = fb->pitch; info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base; @@ -682,28 +631,16 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn info->var.height = -1; info->var.width = -1; - info->var.xres = mode->hdisplay; - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.yres = mode->vdisplay; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; - info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = KHZ2PICOS(mode->clock); - - if (mode->flags & V_PHSYNC) - info->var.sync |= FB_SYNC_HOR_HIGH_ACT; - - if (mode->flags & V_PVSYNC) - info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + info->var.xres = fb_width; + info->var.yres = fb_height; - if (mode->flags & V_INTERLACE) - info->var.vmode = FB_VMODE_INTERLACED; - else if (mode->flags & V_DBLSCAN) - info->var.vmode = FB_VMODE_DOUBLE; - else - info->var.vmode = FB_VMODE_NONINTERLACED; + if (IS_I9XX(dev)) { + info->fix.mmio_start = pci_resource_start(dev->pdev, 0); + info->fix.mmio_len = pci_resource_len(dev->pdev, 0); + } else { + info->fix.mmio_start = pci_resource_start(dev->pdev, 1); + info->fix.mmio_len = pci_resource_len(dev->pdev, 1); + } info->pixmap.size = 64*1024; info->pixmap.buf_align = 8; @@ -767,12 +704,138 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc, struct drm_conn break; } + fb->fbdev = info; + + INIT_LIST_HEAD(&par->mode_set_list); + + par->intel_fb = intel_fb; + + /* To allow resizeing without swapping buffers */ + printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, + intel_fb->base.height, intel_fb->bo->offset, fbo); + + return 0; +} + +int intelfb_probe(struct drm_device *dev) +{ + struct fb_info *info; + struct intelfb_par *par; + struct device *device = &dev->pdev->dev; + struct intel_framebuffer *intel_fb; + struct drm_mode_set *modeset; + struct drm_crtc *crtc; + struct drm_connector *connector; + int ret; + int crtc_count = 0, i; + unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + + DRM_DEBUG("\n"); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->desired_mode) { + if (crtc->desired_mode->hdisplay < fb_width) + fb_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay < fb_height) + fb_height = crtc->desired_mode->vdisplay; + } + crtc_count++; + } + + if (fb_width == -1 || fb_height == -1) { + return -EINVAL; + } + + DRM_DEBUG("here %d %d\n", fb_width, fb_height); + ret = intelfb_create(dev, fb_width, fb_height, &intel_fb); + if (ret) + return -EINVAL; + + DRM_DEBUG("here %p\n", intel_fb); + info = intel_fb->base.fbdev; + par = info->par; + + DRM_DEBUG("crtc count is %d\n", crtc_count); + /* make up a couple of config sets */ + for (i = 0; i < crtc_count; i++) { + int conn_count = 0; + + modeset = kzalloc(sizeof(struct drm_mode_set), GFP_KERNEL); + modeset->fb = &intel_fb->base; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->pipe == i) + modeset->crtc = crtc; + } + + + DRM_DEBUG("1\n"); + /* find out how many connectors are on this */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) + conn_count++; + } + + list_add_tail(&modeset->head, &par->mode_set_list); + + if (!conn_count) + continue; + + DRM_DEBUG("cc %d\n", conn_count); + modeset->connectors = kcalloc(conn_count, sizeof(struct drm_connector *), GFP_KERNEL); + if (!modeset->connectors) { + ret = -ENOMEM; + goto fail; + } + + modeset->num_connectors = conn_count; + + conn_count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) + modeset->connectors[conn_count++] = connector; + } + modeset->mode = modeset->crtc->desired_mode; + } + + info->var.pixclock = -1; +#if 0 + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = KHZ2PICOS(mode->clock); + + if (mode->flags & V_PHSYNC) + info->var.sync |= FB_SYNC_HOR_HIGH_ACT; + + if (mode->flags & V_PVSYNC) + info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + + if (mode->flags & V_INTERLACE) + info->var.vmode = FB_VMODE_INTERLACED; + else if (mode->flags & V_DBLSCAN) + info->var.vmode = FB_VMODE_DOUBLE; + else + info->var.vmode = FB_VMODE_NONINTERLACED; + +#endif + if (register_framebuffer(info) < 0) return -EINVAL; printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); return 0; +fail: + /* TODO */ + return ret; } EXPORT_SYMBOL(intelfb_probe); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a54f5af9..34e81ad5 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -372,6 +372,8 @@ int i915_execbuffer(struct drm_device *dev, void *data, #endif +extern unsigned int i915_fbpercrtc; + #ifdef __linux__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) extern void intel_init_chipset_flush_compat(struct drm_device *dev); -- cgit v1.2.3 From 1d980669e6d448e15c61507d81552c532b93bcd8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:20:52 +1000 Subject: modesetting: add surface width/heights --- linux-core/intel_fb.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 2f28ca1b..a87672d8 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -544,7 +544,9 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); -int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, struct intel_framebuffer **intel_fb_p) +int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, + uint32_t surface_width, uint32_t surface_height, + struct intel_framebuffer **intel_fb_p) { struct fb_info *info; struct intelfb_par *par; @@ -622,8 +624,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height info->screen_base = intel_fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ info->pseudo_palette = fb->pseudo_palette; - info->var.xres_virtual = fb->width; - info->var.yres_virtual = fb->height; + info->var.xres_virtual = surface_width; + info->var.yres_virtual = surface_height; info->var.bits_per_pixel = fb->bits_per_pixel; info->var.xoffset = 0; info->var.yoffset = 0; @@ -729,6 +731,7 @@ int intelfb_probe(struct drm_device *dev) int ret; int crtc_count = 0, i; unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + unsigned int surface_width = 0, surface_height = 0; DRM_DEBUG("\n"); @@ -739,6 +742,12 @@ int intelfb_probe(struct drm_device *dev) if (crtc->desired_mode->vdisplay < fb_height) fb_height = crtc->desired_mode->vdisplay; + + if (crtc->desired_mode->hdisplay > surface_width) + surface_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay > surface_height) + surface_height = crtc->desired_mode->vdisplay; } crtc_count++; } @@ -747,8 +756,8 @@ int intelfb_probe(struct drm_device *dev) return -EINVAL; } - DRM_DEBUG("here %d %d\n", fb_width, fb_height); - ret = intelfb_create(dev, fb_width, fb_height, &intel_fb); + DRM_DEBUG("here %d %d %d %d\n", fb_width, fb_height, surface_width, surface_height); + ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); if (ret) return -EINVAL; -- cgit v1.2.3 From 1495dd31d60e588743f20a9e470c8b0045313e7c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:24:57 +1000 Subject: modesetting: use surface width height for buffer allocs --- linux-core/intel_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index a87672d8..ae290f3c 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -557,8 +557,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height struct device *device = &dev->pdev->dev; int ret; - mode_cmd.width = fb_width;/* crtc->desired_mode->hdisplay; */ - mode_cmd.height = fb_height;/* crtc->desired_mode->vdisplay; */ + mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */ mode_cmd.bpp = 32; mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); -- cgit v1.2.3 From 56a1293184e4f628498c88e38e1601349b05ad93 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:43:48 +1000 Subject: modesetting: fix fb clearing up --- linux-core/intel_fb.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index ae290f3c..0355e784 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -623,9 +623,12 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height info->screen_base = intel_fb->kmap.virtual; info->screen_size = info->fix.smem_len; /* FIXME */ + + memset(intel_fb->kmap.virtual, 0, info->screen_size); + info->pseudo_palette = fb->pseudo_palette; - info->var.xres_virtual = surface_width; - info->var.yres_virtual = surface_height; + info->var.xres_virtual = fb->width; + info->var.yres_virtual = fb->height; info->var.bits_per_pixel = fb->bits_per_pixel; info->var.xoffset = 0; info->var.yoffset = 0; -- cgit v1.2.3 From f73e54bbf0b97a8f5184ede64d4f263020d623ee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 13:40:08 +1000 Subject: drm: modesetting unify the hotplug init paths a lot. remove fb callbacks, just probe into the driver to sort it out --- linux-core/drmP.h | 4 -- linux-core/drm_crtc.h | 1 + linux-core/drm_crtc_helper.c | 107 ++++++++----------------------------------- linux-core/i915_drv.c | 2 - linux-core/intel_fb.c | 1 - 5 files changed, 19 insertions(+), 96 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 9845b5c8..5b2d7829 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -742,10 +742,6 @@ struct drm_driver { void (*set_version) (struct drm_device *dev, struct drm_set_version *sv); - /* FB routines, if present */ - int (*fb_probe)(struct drm_device *dev); - int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc); - /* Master routines */ int (*master_create)(struct drm_device *dev, struct drm_master *master); void (*master_destroy)(struct drm_device *dev, struct drm_master *master); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index da05ff27..c1d89ee8 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -525,6 +525,7 @@ struct drm_mode_set struct drm_mode_config_funcs { bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); + void (*fb_changed)(struct drm_device *dev); }; struct drm_mode_group { diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 3ff7e07e..1b6118de 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -496,6 +496,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; DRM_DEBUG("crtc: %p fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->connectors, set->num_connectors, set->x, set->y); + dev = set->crtc->dev; /* save previous config */ @@ -532,7 +533,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; save_encoders[count++] = connector->encoder; - new_encoder = NULL; + new_encoder = connector->encoder; for (ro = 0; ro < set->num_connectors; ro++) { if (set->connectors[ro] == connector) { new_encoder = connector_funcs->best_encoder(connector); @@ -626,6 +627,20 @@ fail_no_encoder: } EXPORT_SYMBOL(drm_crtc_helper_set_config); +bool drm_helper_plugged_event(struct drm_device *dev) +{ + drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); + + drm_pick_crtcs(dev); + + /* alert the driver fb layer */ + dev->mode_config.funcs->fb_changed(dev); + + drm_helper_disable_unused_functions(dev); + + drm_sysfs_hotplug_event(dev); + return true; +} /** * drm_initial_config - setup a sane initial connector configuration * @dev: DRM device @@ -645,48 +660,7 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) { int ret = false; - mutex_lock(&dev->mode_config.mutex); - - drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); - - drm_pick_crtcs(dev); - - /* use all the info we have to setup the fb */ - dev->driver->fb_probe(dev); -#if 0 - /* have to do a driver pick here */ - /* get the lowest common denom of width height that will fit nicely - size the fb to this - size, however may need a wider stride for crtc alignment */ - /* This is a little screwy, as we've already walked the connectors - * above, but it's a little bit of magic too. There's the potential - * for things not to get setup above if an existing device gets - * re-assigned thus confusing the hardware. By walking the connectors - * this fixes up their crtc's. - */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - - struct drm_encoder *encoder = connector->encoder; - struct drm_crtc *crtc; - - if (!encoder) - continue; - - crtc = connector->encoder->crtc; - - /* can't setup the connector if there's no assigned mode */ - if (!crtc || !crtc->desired_mode) - continue; - - dev->driver->fb_probe(dev, crtc, connector); - - /* and needs an attached fb */ - if (crtc->fb) - drm_crtc_helper_set_mode(crtc, crtc->desired_mode, 0, 0); - } - - drm_helper_disable_unused_functions(dev); -#endif - mutex_unlock(&dev->mode_config.mutex); + drm_helper_plugged_event(dev); return ret; } EXPORT_SYMBOL(drm_helper_initial_config); @@ -707,59 +681,14 @@ EXPORT_SYMBOL(drm_helper_initial_config); int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, bool connected) { - int has_config = 0; - dev->mode_config.hotplug_counter++; - /* We might want to do something more here */ - if (!connected) { - DRM_DEBUG("not connected\n"); - return 0; - } - - if (connector->encoder) { - if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the connector already has a config\n"); - has_config = 1; - } - } - - drm_helper_probe_connector_modes(dev, 2048, 2048); - - if (!has_config) - drm_pick_crtcs(dev); - - if (!connector->encoder) { - DRM_DEBUG("could not find a desired mode or crtc for connector\n"); - return 1; - } - - if (!connector->encoder->crtc || !connector->encoder->crtc->desired_mode) { - DRM_DEBUG("could not find a desired mode or crtc for connector\n"); - return 1; - } - - /* We should really check if there is a fb using this crtc */ - if (!has_config) - dev->driver->fb_probe(dev); - else { - dev->driver->fb_resize(dev, connector->encoder->crtc); - -#if 0 - if (!drm_crtc_set_mode(connector->encoder->crtc, connector->encoder->crtc->desired_mode, 0, 0)) - DRM_ERROR("failed to set mode after hotplug\n"); -#endif - } - - drm_sysfs_hotplug_event(dev); - - drm_helper_disable_unused_functions(dev); + drm_helper_plugged_event(dev); return 0; } EXPORT_SYMBOL(drm_helper_hotplug_stage_two); - int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, struct drm_mode_fb_cmd *mode_cmd) { diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index b81db3a6..f4c50752 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -594,8 +594,6 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, - .fb_probe = intelfb_probe, - .fb_resize = intelfb_resize, .master_create = i915_master_create, .master_destroy = i915_master_destroy, .ioctls = i915_ioctls, diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 0355e784..9b2e9314 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -469,7 +469,6 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; struct drm_mode_set *modeset; int ret = 0; - DRM_DEBUG("\n"); list_for_each_entry(modeset, &par->mode_set_list, head) { modeset->x = var->xoffset; -- cgit v1.2.3 From efcf066eff690887ace33c0f1192168a31115805 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 15:21:07 +1000 Subject: drm/modesetting: attempt to make fb code more sane --- linux-core/drm_crtc.c | 1 + linux-core/drm_crtc.h | 6 +- linux-core/intel_fb.c | 234 +++++++++++++++++++++++++++++++------------------- 3 files changed, 149 insertions(+), 92 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 4c6afd16..92a7d513 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -561,6 +561,7 @@ void drm_mode_config_init(struct drm_device *dev) { mutex_init(&dev->mode_config.mutex); INIT_LIST_HEAD(&dev->mode_config.fb_list); + INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list); INIT_LIST_HEAD(&dev->mode_config.crtc_list); INIT_LIST_HEAD(&dev->mode_config.connector_list); INIT_LIST_HEAD(&dev->mode_config.encoder_list); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index c1d89ee8..043b4a57 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -498,8 +498,7 @@ struct drm_connector { * * This is used to set modes. */ -struct drm_mode_set -{ +struct drm_mode_set { struct list_head head; struct drm_framebuffer *fb; @@ -557,6 +556,9 @@ struct drm_mode_config { struct list_head property_list; + /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */ + struct list_head fb_kernel_list; + /* currently in use generation id */ int current_generation; diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 9b2e9314..2355bf3d 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -585,6 +585,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height return -EINVAL; } + list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); + intel_fb = to_intel_framebuffer(fb); *intel_fb_p = intel_fb; @@ -721,129 +723,181 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height return 0; } -int intelfb_probe(struct drm_device *dev) +#define INTELFB_CONN_LIMIT 4 + +static int intelfb_create_crtcmodesets(struct intel_framebuffer *intel_fb, int num_sets, int crtc_base) { - struct fb_info *info; + int i,j; + struct drm_device *dev = intel_fb->base.dev; struct intelfb_par *par; - struct device *device = &dev->pdev->dev; - struct intel_framebuffer *intel_fb; struct drm_mode_set *modeset; struct drm_crtc *crtc; - struct drm_connector *connector; - int ret; - int crtc_count = 0, i; - unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; - unsigned int surface_width = 0, surface_height = 0; - - DRM_DEBUG("\n"); - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->desired_mode) { - if (crtc->desired_mode->hdisplay < fb_width) - fb_width = crtc->desired_mode->hdisplay; + struct fb_info *info; - if (crtc->desired_mode->vdisplay < fb_height) - fb_height = crtc->desired_mode->vdisplay; + info = intel_fb->base.fbdev; + par = info->par; - if (crtc->desired_mode->hdisplay > surface_width) - surface_width = crtc->desired_mode->hdisplay; + for (i = 0; i < num_sets; i++) { + modeset = kzalloc(sizeof(struct drm_mode_set) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); + if (!modeset) + goto fail; - if (crtc->desired_mode->vdisplay > surface_height) - surface_height = crtc->desired_mode->vdisplay; + /* attach a CRTC to the modeset */ + j = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (j == i + crtc_base) { + modeset->crtc = crtc; + break; + } + j++; } - crtc_count++; + modeset->fb = &intel_fb->base; + + modeset->connectors = (struct drm_connector **)(modeset + 1); + list_add_tail(&modeset->head, &par->mode_set_list); } - if (fb_width == -1 || fb_height == -1) { - return -EINVAL; +fail: + list_for_each_entry(modeset, &par->mode_set_list, head) { + list_del(&modeset->head); + kfree(modeset); } - DRM_DEBUG("here %d %d %d %d\n", fb_width, fb_height, surface_width, surface_height); - ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); - if (ret) - return -EINVAL; + return -ENOMEM; +} - DRM_DEBUG("here %p\n", intel_fb); - info = intel_fb->base.fbdev; - par = info->par; +static int intelfb_single_fb_probe(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_connector *connector; + unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + unsigned int surface_width = 0, surface_height = 0; + int new_fb = 0; + int crtc_count = 0; + int ret, i, conn_count = 0; + struct intel_framebuffer *intel_fb; + struct fb_info *info; + struct intelfb_par *par; + struct drm_mode_set *modeset; - DRM_DEBUG("crtc count is %d\n", crtc_count); - /* make up a couple of config sets */ - for (i = 0; i < crtc_count; i++) { - int conn_count = 0; + /* first up get a count of crtcs now in use and new min/maxes width/heights */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (drm_helper_crtc_in_use(crtc)) { + if (crtc->desired_mode) { + if (crtc->desired_mode->hdisplay < fb_width) + fb_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay < fb_height) + fb_height = crtc->desired_mode->vdisplay; + + if (crtc->desired_mode->hdisplay > surface_width) + surface_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay > surface_height) + surface_height = crtc->desired_mode->vdisplay; + } + crtc_count++; + } + } - modeset = kzalloc(sizeof(struct drm_mode_set), GFP_KERNEL); - modeset->fb = &intel_fb->base; + if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { + /* hmm everyone went away - assume VGA cable just fell out + and will come back later. */ + return 0; + } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->pipe == i) - modeset->crtc = crtc; + /* do we have an fb already? */ + if (list_empty(&dev->mode_config.fb_kernel_list)) { + /* create an fb if we don't have one */ + ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); + if (ret) + return -EINVAL; + + /* create a set per crtc connected to this fb */ + ret = intelfb_create_crtcmodesets(intel_fb, dev->mode_config.num_crtc, 0); + if (ret) + return ret; + new_fb = 1; + } else { + struct drm_framebuffer *fb; + fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); + intel_fb = to_intel_framebuffer(fb); + + /* check if we are going to have a size issue */ + /* do a surface compare */ + if ((fb->width < surface_width) || (fb->height < surface_height)) { + DRM_ERROR("NEED BIGGER SURFACE DUDE\n"); + return -EINVAL; } + } + info = intel_fb->base.fbdev; + par = info->par; - DRM_DEBUG("1\n"); - /* find out how many connectors are on this */ + /* okay we need to setup new connector sets in the crtcs */ + list_for_each_entry(modeset, &par->mode_set_list, head) { + + conn_count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder) - if (connector->encoder->crtc == modeset->crtc) + if(connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; conn_count++; + if (conn_count > INTELFB_CONN_LIMIT) + BUG(); + } } - list_add_tail(&modeset->head, &par->mode_set_list); - - if (!conn_count) - continue; - - DRM_DEBUG("cc %d\n", conn_count); - modeset->connectors = kcalloc(conn_count, sizeof(struct drm_connector *), GFP_KERNEL); - if (!modeset->connectors) { - ret = -ENOMEM; - goto fail; - } + for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; modeset->num_connectors = conn_count; - - conn_count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder) - if (connector->encoder->crtc == modeset->crtc) - modeset->connectors[conn_count++] = connector; - } - modeset->mode = modeset->crtc->desired_mode; + if (modeset->mode != modeset->crtc->desired_mode) + modeset->mode = modeset->crtc->desired_mode; } - - info->var.pixclock = -1; -#if 0 - info->var.right_margin = mode->hsync_start - mode->hdisplay; - info->var.hsync_len = mode->hsync_end - mode->hsync_start; - info->var.left_margin = mode->htotal - mode->hsync_end; - info->var.lower_margin = mode->vsync_start - mode->vdisplay; - info->var.vsync_len = mode->vsync_end - mode->vsync_start; - info->var.upper_margin = mode->vtotal - mode->vsync_end; - info->var.pixclock = KHZ2PICOS(mode->clock); - if (mode->flags & V_PHSYNC) - info->var.sync |= FB_SYNC_HOR_HIGH_ACT; + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} + +int intelfb_probe(struct drm_device *dev) +{ + int ret; - if (mode->flags & V_PVSYNC) - info->var.sync |= FB_SYNC_VERT_HIGH_ACT; + DRM_DEBUG("\n"); - if (mode->flags & V_INTERLACE) - info->var.vmode = FB_VMODE_INTERLACED; - else if (mode->flags & V_DBLSCAN) - info->var.vmode = FB_VMODE_DOUBLE; - else - info->var.vmode = FB_VMODE_NONINTERLACED; + /* something has changed in the lower levels of hell - deal with it + here */ + + /* two modes : a) 1 fb to rule all crtcs. + b) one fb per crtc. + two actions 1) new connected device + 2) device removed. + case a/1 : if the fb surface isn't big enough - resize the surface fb. + if the fb size isn't big enough - resize fb into surface. + if everything big enough configure the new crtc/etc. + case a/2 : undo the configuration + possibly resize down the fb to fit the new configuration. + case b/1 : see if it is on a new crtc - setup a new fb and add it. + case b/2 : teardown the new fb. + */ -#endif + /* mode a first */ + /* search for an fb */ + if (i915_fbpercrtc == 1) { + ret = -EINVAL; + goto fail; + } - if (register_framebuffer(info) < 0) - return -EINVAL; + ret = intelfb_single_fb_probe(dev); - printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, - info->fix.id); - return 0; fail: /* TODO */ return ret; -- cgit v1.2.3 From b31adb005afc5553fb30aa2c1710faee299bc730 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 15:55:03 +1000 Subject: drm/modesetting: more fb interface cleanups --- linux-core/i915_drv.c | 2 +- linux-core/intel_display.c | 1 + linux-core/intel_fb.c | 9 ++++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index f4c50752..f755dcd4 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -42,7 +42,7 @@ static struct pci_device_id pciidlist[] = { unsigned int i915_modeset = 0; module_param_named(modeset, i915_modeset, int, 0400); -unsigned int i915_fbpercrtc = 1; +unsigned int i915_fbpercrtc = 0; module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); unsigned int i915_rightof = 1; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 8baae1b3..e1d9d4d0 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1519,6 +1519,7 @@ struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, static const struct drm_mode_config_funcs intel_mode_funcs = { .resize_fb = NULL, .fb_create = intel_user_framebuffer_create, + .fb_changed = intelfb_probe, }; void intel_modeset_init(struct drm_device *dev) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 2355bf3d..b4afb155 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -200,9 +200,7 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_device *dev = par->dev; struct fb_var_screeninfo *var = &info->var; - int found = 0; DRM_DEBUG("%d %d\n", var->xres, var->pixclock); @@ -215,6 +213,9 @@ static int intelfb_set_par(struct fb_info *info) struct drm_framebuffer *fb = &intel_fb->base; struct drm_display_mode *drm_mode, *search_mode; struct drm_connector *connector = NULL; + struct drm_device *dev = par->dev; + + int found = 0; switch (var->bits_per_pixel) { case 16: @@ -756,6 +757,7 @@ static int intelfb_create_crtcmodesets(struct intel_framebuffer *intel_fb, int n modeset->connectors = (struct drm_connector **)(modeset + 1); list_add_tail(&modeset->head, &par->mode_set_list); } + return 0; fail: list_for_each_entry(modeset, &par->mode_set_list, head) { @@ -860,7 +862,8 @@ static int intelfb_single_fb_probe(struct drm_device *dev) info->var.pixclock = -1; if (register_framebuffer(info) < 0) return -EINVAL; - } + } else + intelfb_set_par(info); printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); -- cgit v1.2.3 From d9ead89c79732124f54b4a9dfe698bc7aad7faee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 16:32:41 +1000 Subject: drm/modeset: add more debugging and fixup some fb enable/disabe bits --- linux-core/drm_crtc_helper.c | 18 +++++++++++++++--- linux-core/intel_fb.c | 9 ++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 1b6118de..edb739f5 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -67,6 +67,7 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ui struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; int ret; + DRM_DEBUG("%s\n", drm_get_connector_name(connector)); /* set all modes to the unverified state */ list_for_each_entry_safe(mode, t, &connector->modes, head) mode->status = MODE_UNVERIFIED; @@ -186,8 +187,11 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - if (!crtc->enabled) + crtc->enabled = drm_helper_crtc_in_use(crtc); + if (!crtc->enabled) { crtc_funcs->dpms(crtc, DPMSModeOff); + crtc->fb = NULL; + } } } EXPORT_SYMBOL(drm_helper_disable_unused_functions); @@ -209,6 +213,7 @@ static void drm_pick_crtcs (struct drm_device *dev) struct drm_connector_helper_funcs *connector_funcs; int found; + DRM_DEBUG("\n"); /* clean out all the encoder/crtc combos */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { encoder->crtc = NULL; @@ -515,8 +520,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) - flip_or_move = true; + if (set->crtc->fb != set->fb) { + /* if we have no fb then its a change not a flip */ + if (set->crtc->fb == NULL) + changed = true; + else + flip_or_move = true; + } if (set->x != set->crtc->x || set->y != set->crtc->y) flip_or_move = true; @@ -629,6 +639,8 @@ EXPORT_SYMBOL(drm_crtc_helper_set_config); bool drm_helper_plugged_event(struct drm_device *dev) { + DRM_DEBUG("\n"); + drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); drm_pick_crtcs(dev); diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index b4afb155..5ec5bb8f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -309,11 +309,9 @@ static int intelfb_set_par(struct fb_info *info) int ret; list_for_each_entry(modeset, &par->mode_set_list, head) { - if (modeset->num_connectors) { - ret = modeset->crtc->funcs->set_config(modeset); - if (ret) - return ret; - } + ret = modeset->crtc->funcs->set_config(modeset); + if (ret) + return ret; } return 0; } @@ -782,6 +780,7 @@ static int intelfb_single_fb_probe(struct drm_device *dev) struct intelfb_par *par; struct drm_mode_set *modeset; + DRM_DEBUG("\n"); /* first up get a count of crtcs now in use and new min/maxes width/heights */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (drm_helper_crtc_in_use(crtc)) { -- cgit v1.2.3 From 03bf1fba67413f381d2a548fe08bd634a48fcc48 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 5 Jun 2008 15:58:43 -0700 Subject: sysfs registration/teardown fixups A check in drm_sysfs_connector_remove was supposed to allow it to be called even with unregistered objects, to make cleanup paths a little simpler. However, device_is_regsitered didn't always seem to return what we thought it would, so we'd sometimes end up leaving objects lying around rather than unregistering them. Fix this situation up by requiring devices to be registered before being removed. Any problems resulting from this change should be easier to track down than the alternative (which is leaving kobjects registered after unload). --- linux-core/drm_sysfs.c | 32 ++++++++++++++++++++++++++------ linux-core/intel_crt.c | 12 ++++++------ linux-core/intel_lvds.c | 35 +++++++++++++++++------------------ linux-core/intel_sdvo.c | 23 ++++++++++++++--------- 4 files changed, 63 insertions(+), 39 deletions(-) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index c148256a..92371c22 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -239,20 +239,26 @@ static struct bin_attribute edid_attr = { * properties (so far, connection status, dpms, mode list & edid) and * generate a hotplug event so userspace knows there's a new connector * available. + * + * Note: + * This routine should only be called *once* for each DRM minor registered. + * A second call for an already registered device will trigger the BUG_ON + * below. */ int drm_sysfs_connector_add(struct drm_connector *connector) { struct drm_device *dev = connector->dev; int ret = 0, i, j; - if (device_is_registered(&connector->kdev)) - return 0; + /* We shouldn't get called more than once for the same connector */ + BUG_ON(device_is_registered(&connector->kdev)); connector->kdev.parent = &dev->primary->kdev; connector->kdev.class = drm_class; connector->kdev.release = drm_sysfs_device_release; - DRM_DEBUG("adding \"%s\" to sysfs\n", drm_get_connector_name(connector)); + DRM_DEBUG("adding \"%s\" to sysfs\n", + drm_get_connector_name(connector)); snprintf(connector->kdev.bus_id, BUS_ID_SIZE, "card%d-%s", dev->primary->index, drm_get_connector_name(connector)); @@ -296,15 +302,19 @@ EXPORT_SYMBOL(drm_sysfs_connector_add); * Remove @connector and its associated attributes from sysfs. Note that * the device model core will take care of sending the "remove" uevent * at this time, so we don't need to do it. + * + * Note: + * This routine should only be called if the connector was previously + * successfully registered. If @connector hasn't been registered yet, + * you'll likely see a panic somewhere deep in sysfs code when called. */ void drm_sysfs_connector_remove(struct drm_connector *connector) { int i; - if (!device_is_registered(&connector->kdev)) - return; + DRM_DEBUG("removing \"%s\" from sysfs\n", + drm_get_connector_name(connector)); - DRM_DEBUG("removing \"%s\" from sysfs\n", drm_get_connector_name(connector)); for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) device_remove_file(&connector->kdev, &connector_attrs[i]); sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr); @@ -342,6 +352,11 @@ static struct device_attribute dri_attrs[] = { * Add a DRM device to the DRM's device model class. We use @dev's PCI device * as the parent for the Linux device, and make sure it has a file containing * the driver we're using (for userspace compatibility). + * + * Note: + * This routine should only be called *once* for each DRM minor registered. + * A second call for an already registered device will trigger the BUG_ON + * below. */ int drm_sysfs_device_add(struct drm_minor *minor) { @@ -362,6 +377,11 @@ int drm_sysfs_device_add(struct drm_minor *minor) snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); + /* Shouldn't register more than once */ + BUG_ON(device_is_registered(&minor->kdev)); + + DRM_DEBUG("registering DRM device \"%s\"\n", minor->kdev.bus_id); + err = device_register(&minor->kdev); if (err) { DRM_ERROR("device add failed: %d\n", err); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index e32a9551..b9e8ee63 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -268,18 +268,20 @@ void intel_crt_init(struct drm_device *dev) return; connector = &intel_output->base; - drm_connector_init(dev, &intel_output->base, &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); + drm_connector_init(dev, &intel_output->base, + &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); - drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs, DRM_MODE_ENCODER_DAC); + drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs, + DRM_MODE_ENCODER_DAC); - drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); + drm_mode_connector_attach_encoder(&intel_output->base, + &intel_output->enc); /* Set up the DDC bus. */ intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); - intel_crt_destroy(connector); return; } @@ -291,6 +293,4 @@ void intel_crt_init(struct drm_device *dev) drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); - - } diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 8d65c161..04e110e4 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -329,7 +329,8 @@ static void intel_lvds_destroy(struct drm_connector *connector) { struct intel_output *intel_output = to_intel_output(connector); - intel_i2c_destroy(intel_output->ddc_bus); + if (intel_output->ddc_bus) + intel_i2c_destroy(intel_output->ddc_bus); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); kfree(connector); @@ -425,8 +426,7 @@ void intel_lvds_init(struct drm_device *dev) if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); - intel_lvds_destroy(connector); - return; + goto failed; } /* @@ -470,19 +470,18 @@ void intel_lvds_init(struct drm_device *dev) if (!dev_priv->panel_fixed_mode) goto failed; -#if 0 /* FIXME: detect aopen & mac mini type stuff automatically? */ /* * Blacklist machines with BIOSes that list an LVDS panel without * actually having one. */ - if (dev_priv->PciInfo->chipType == PCI_CHIP_I945_GM) { + if (IS_I945GM(dev)) { /* aopen mini pc */ - if (dev_priv->PciInfo->subsysVendor == 0xa0a0) - goto disable_exit; + if (dev->pdev->subsystem_vendor == 0xa0a0) + goto failed; - if ((dev_priv->PciInfo->subsysVendor == 0x8086) && - (dev_priv->PciInfo->subsysCard == 0x7270)) { + if ((dev->pdev->subsystem_vendor == 0x8086) && + (dev->pdev->subsystem_device == 0x7270)) { /* It's a Mac Mini or Macbook Pro. * * Apple hardware is out to get us. The macbook pro @@ -494,23 +493,23 @@ void intel_lvds_init(struct drm_device *dev) */ if (dev_priv->panel_fixed_mode != NULL && - dev_priv->panel_fixed_mode->HDisplay == 800 && - dev_priv->panel_fixed_mode->VDisplay == 600) - { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Suspected Mac Mini, ignoring the LVDS\n"); - goto disable_exit; + dev_priv->panel_fixed_mode->hdisplay == 800 && + dev_priv->panel_fixed_mode->vdisplay == 600) { + DRM_DEBUG("Suspected Mac Mini, ignoring the LVDS\n"); + goto failed; } } } -#endif out: drm_sysfs_connector_add(connector); return; failed: - DRM_DEBUG("No LVDS modes found, disabling.\n"); - intel_lvds_destroy(connector); + DRM_DEBUG("No LVDS modes found, disabling.\n"); + if (intel_output->ddc_bus) + intel_i2c_destroy(intel_output->ddc_bus); + drm_connector_cleanup(connector); + kfree(connector); } diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index ef67ef9b..f0a47e2e 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -1036,10 +1036,8 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) else i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); - if (i2cbus == NULL) { - intel_sdvo_destroy(connector); - return; - } + if (!i2cbus) + goto err_connector; sdvo_priv->i2c_bus = i2cbus; @@ -1061,8 +1059,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { DRM_DEBUG("No SDVO device found on SDVO%c\n", output_device == SDVOB ? 'B' : 'C'); - intel_sdvo_destroy(connector); - return; + goto err_i2c; } } @@ -1107,8 +1104,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", SDVO_NAME(sdvo_priv), bytes[0], bytes[1]); - intel_sdvo_destroy(connector); - return; + goto err_i2c; } drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); @@ -1143,6 +1139,15 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) sdvo_priv->caps.output_flags & (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); - intel_output->ddc_bus = i2cbus; + intel_output->ddc_bus = i2cbus; + + return; +err_i2c: + intel_i2c_destroy(intel_output->i2c_bus); +err_connector: + drm_connector_cleanup(connector); + kfree(intel_output); + + return; } -- cgit v1.2.3 From 5f94172f81120c56ba07843ff860a9e265dac1f8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 10:31:36 +1000 Subject: intel: if no spare crtc exists don't just take one. --- linux-core/intel_display.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index e1d9d4d0..e2d2a5fb 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1167,13 +1167,10 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, } /* - * If we didn't find an unused CRTC, use the first available one - * that can drive this connector. + * If we didn't find an unused CRTC, don't use any. */ if (!crtc) { - crtc = supported_crtc; - if (!crtc) - return NULL; + return NULL; } encoder->crtc = crtc; -- cgit v1.2.3 From 25c1bb334f3a32e3e635e9d5de1abf8abdcc87f0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 10:38:35 +1000 Subject: drm/intel: make hotplug just be an event --- linux-core/drm_crtc_helper.c | 3 +- linux-core/drm_crtc_helper.h | 3 +- shared-core/i915_irq.c | 135 +------------------------------------------ 3 files changed, 3 insertions(+), 138 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index edb739f5..777820d7 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -690,8 +690,7 @@ EXPORT_SYMBOL(drm_helper_initial_config); * RETURNS: * Zero on success, errno on failure. */ -int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, - bool connected) +int drm_helper_hotplug_stage_two(struct drm_device *dev) { dev->mode_config.hotplug_counter++; diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 7b7f23dc..45a67f98 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -65,8 +65,7 @@ struct drm_connector_helper_funcs { extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); extern void drm_helper_disable_unused_functions(struct drm_device *dev); -extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, - bool connected); +extern int drm_helper_hotplug_stage_two(struct drm_device *dev); extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); extern int drm_crtc_helper_set_config(struct drm_mode_set *set); extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4c147a08..2d355688 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -441,93 +441,8 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) return count; } -#define HOTPLUG_CMD_CRT 1 -#define HOTPLUG_CMD_CRT_DIS 2 -#define HOTPLUG_CMD_SDVOB 4 -#define HOTPLUG_CMD_SDVOC 8 -#define HOTPLUG_CMD_TV 16 - static struct drm_device *hotplug_dev; -static int hotplug_cmd = 0; -static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; - -static void i915_hotplug_tv(struct drm_device *dev) -{ - struct drm_connector *connector; - struct intel_output *iout; - enum drm_connector_status status; - - mutex_lock(&dev->mode_config.mutex); - - /* find the crt output */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - iout = to_intel_output(connector); - if (iout->type == INTEL_OUTPUT_TVOUT) - break; - else - iout = 0; - } - - if (iout == 0) - goto unlock; - - status = connector->funcs->detect(connector); - drm_helper_hotplug_stage_two(dev, connector, - status == connector_status_connected ? 1 : 0); - -unlock: - mutex_unlock(&dev->mode_config.mutex); -} - -static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) -{ - struct drm_connector *connector; - struct intel_output *iout; - - mutex_lock(&dev->mode_config.mutex); - - /* find the crt output */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - iout = to_intel_output(connector); - if (iout->type == INTEL_OUTPUT_ANALOG) - break; - else - iout = 0; - } - - if (iout == 0) - goto unlock; - - drm_helper_hotplug_stage_two(dev, connector, isconnected); -unlock: - mutex_unlock(&dev->mode_config.mutex); -} - -static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) -{ - struct drm_connector *connector = 0; - enum drm_connector_status status; - - mutex_lock(&dev->mode_config.mutex); - - connector = intel_sdvo_find(dev, sdvoB); - - if (!connector) - goto unlock; - - status = connector->funcs->detect(connector); - - if (status != connector_status_connected) - drm_helper_hotplug_stage_two(dev, connector, false); - else - drm_helper_hotplug_stage_two(dev, connector, true); - - intel_sdvo_set_hotplug(connector, 1); - -unlock: - mutex_unlock(&dev->mode_config.mutex); -} /* * This code is called in a more safe envirmoent to handle the hotplugs. * Add code here for hotplug love to userspace. @@ -539,34 +454,8 @@ static void i915_hotplug_work_func(struct work_struct *work) #endif { struct drm_device *dev = hotplug_dev; - int crt; - int crtDis; - int sdvoB; - int sdvoC; - int tv; - - spin_lock(&hotplug_lock); - tv = hotplug_cmd & HOTPLUG_CMD_TV; - crt = hotplug_cmd & HOTPLUG_CMD_CRT; - crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS; - sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; - sdvoC = hotplug_cmd & HOTPLUG_CMD_SDVOC; - hotplug_cmd = 0; - spin_unlock(&hotplug_lock); - - if (tv) - i915_hotplug_tv(dev); - if (crt) - i915_hotplug_crt(dev, true); - if (crtDis) - i915_hotplug_crt(dev, false); - - if (sdvoB) - i915_hotplug_sdvo(dev, 1); - - if (sdvoC) - i915_hotplug_sdvo(dev, 0); + drm_helper_hotplug_stage_two(dev); drm_handle_hotplug(dev); } @@ -583,40 +472,18 @@ static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) if (stat & TV_HOTPLUG_INT_STATUS) { DRM_DEBUG("TV event\n"); - - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_TV; - spin_unlock(&hotplug_lock); } if (stat & CRT_HOTPLUG_INT_STATUS) { DRM_DEBUG("CRT event\n"); - - if (stat & CRT_HOTPLUG_MONITOR_MASK) { - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_CRT; - spin_unlock(&hotplug_lock); - } else { - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_CRT_DIS; - spin_unlock(&hotplug_lock); - } } if (stat & SDVOB_HOTPLUG_INT_STATUS) { DRM_DEBUG("sDVOB event\n"); - - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_SDVOB; - spin_unlock(&hotplug_lock); } if (stat & SDVOC_HOTPLUG_INT_STATUS) { DRM_DEBUG("sDVOC event\n"); - - spin_lock(&hotplug_lock); - hotplug_cmd |= HOTPLUG_CMD_SDVOC; - spin_unlock(&hotplug_lock); } queue_work(dev_priv->wq, &hotplug); -- cgit v1.2.3 From 8387a232a3305d10c4ac4cd08f9ebd0888944e55 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 12:02:51 +1000 Subject: intelfb: move mode sets into the intel crtcs better place to store them. --- linux-core/intel_display.c | 6 ++- linux-core/intel_drv.h | 4 ++ linux-core/intel_fb.c | 119 ++++++++++++++++++++++----------------------- 3 files changed, 67 insertions(+), 62 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index e2d2a5fb..0081b5be 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1363,7 +1363,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) struct intel_crtc *intel_crtc; int i; - intel_crtc = kzalloc(sizeof(struct intel_crtc), GFP_KERNEL); + intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); if (intel_crtc == NULL) return; @@ -1381,6 +1381,10 @@ void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->dpms_mode = DPMSModeOff; drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); + intel_crtc->mode_set.crtc = &intel_crtc->base; + intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1); + intel_crtc->mode_set.num_connectors = 0; + if (i915_fbpercrtc) { diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 25e2a652..1008e271 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -20,6 +20,8 @@ /* The i830->i865 use multiple DVOs with multiple i2cs */ /* the i915, i945 have a single sDVO i2c bus - which is different */ #define MAX_OUTPUTS 6 +/* maximum connectors per crtcs in the mode set */ +#define INTELFB_CONN_LIMIT 4 #define INTEL_I2C_BUS_DVO 1 #define INTEL_I2C_BUS_SDVO 2 @@ -72,6 +74,8 @@ struct intel_crtc { u8 lut_r[256], lut_g[256], lut_b[256]; int dpms_mode; struct intel_framebuffer *fbdev_fb; + /* a mode_set for fbdev users on this crtc */ + struct drm_mode_set mode_set; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 5ec5bb8f..71f71a0d 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -50,7 +50,8 @@ struct intelfb_par { struct drm_display_mode *our_mode; struct intel_framebuffer *intel_fb; int crtc_count; - struct list_head mode_set_list; + /* crtc currently bound to this */ + uint32_t crtc_ids[2]; }; /* static int @@ -69,12 +70,23 @@ static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, struct fb_info *info) { struct intelfb_par *par = info->par; - struct drm_mode_set *modeset; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + int i; - list_for_each_entry(modeset, &par->mode_set_list, head) { - struct drm_crtc *crtc = modeset->crtc; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_mode_set *modeset = &intel_crtc->mode_set; struct drm_framebuffer *fb = modeset->fb; + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + if (regno > 255) return 1; @@ -200,7 +212,9 @@ static int intelfb_check_var(struct fb_var_screeninfo *var, static int intelfb_set_par(struct fb_info *info) { struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; struct fb_var_screeninfo *var = &info->var; + int i; DRM_DEBUG("%d %d\n", var->xres, var->pixclock); @@ -305,11 +319,20 @@ static int intelfb_set_par(struct fb_info *info) #endif return -EINVAL; } else { - struct drm_mode_set *modeset; + struct drm_crtc *crtc; int ret; - list_for_each_entry(modeset, &par->mode_set_list, head) { - ret = modeset->crtc->funcs->set_config(modeset); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + ret = crtc->funcs->set_config(&intel_crtc->mode_set); if (ret) return ret; } @@ -466,15 +489,30 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; struct drm_mode_set *modeset; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; int ret = 0; + int i; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + intel_crtc = to_intel_crtc(crtc); + modeset = &intel_crtc->mode_set; - list_for_each_entry(modeset, &par->mode_set_list, head) { modeset->x = var->xoffset; modeset->y = var->yoffset; if (modeset->num_connectors) { - ret = modeset->crtc->funcs->set_config(modeset); + ret = crtc->funcs->set_config(modeset); if (!ret) { info->var.xoffset = var->xoffset; @@ -711,9 +749,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height fb->fbdev = info; - INIT_LIST_HEAD(&par->mode_set_list); - par->intel_fb = intel_fb; + par->dev = dev; /* To allow resizeing without swapping buffers */ printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, @@ -724,48 +761,6 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height #define INTELFB_CONN_LIMIT 4 -static int intelfb_create_crtcmodesets(struct intel_framebuffer *intel_fb, int num_sets, int crtc_base) -{ - int i,j; - struct drm_device *dev = intel_fb->base.dev; - struct intelfb_par *par; - struct drm_mode_set *modeset; - struct drm_crtc *crtc; - struct fb_info *info; - - info = intel_fb->base.fbdev; - par = info->par; - - for (i = 0; i < num_sets; i++) { - modeset = kzalloc(sizeof(struct drm_mode_set) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); - if (!modeset) - goto fail; - - /* attach a CRTC to the modeset */ - j = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (j == i + crtc_base) { - modeset->crtc = crtc; - break; - } - j++; - } - modeset->fb = &intel_fb->base; - - modeset->connectors = (struct drm_connector **)(modeset + 1); - list_add_tail(&modeset->head, &par->mode_set_list); - } - return 0; - -fail: - list_for_each_entry(modeset, &par->mode_set_list, head) { - list_del(&modeset->head); - kfree(modeset); - } - - return -ENOMEM; -} - static int intelfb_single_fb_probe(struct drm_device *dev) { struct drm_crtc *crtc; @@ -795,7 +790,8 @@ static int intelfb_single_fb_probe(struct drm_device *dev) surface_width = crtc->desired_mode->hdisplay; if (crtc->desired_mode->vdisplay > surface_height) - surface_height = crtc->desired_mode->vdisplay; + surface_height = crtc->desired_mode->vdisplay; + } crtc_count++; } @@ -813,11 +809,6 @@ static int intelfb_single_fb_probe(struct drm_device *dev) ret = intelfb_create(dev, fb_width, fb_height, surface_width, surface_height, &intel_fb); if (ret) return -EINVAL; - - /* create a set per crtc connected to this fb */ - ret = intelfb_create_crtcmodesets(intel_fb, dev->mode_config.num_crtc, 0); - if (ret) - return ret; new_fb = 1; } else { struct drm_framebuffer *fb; @@ -835,9 +826,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev) info = intel_fb->base.fbdev; par = info->par; + crtc_count = 0; /* okay we need to setup new connector sets in the crtcs */ - list_for_each_entry(modeset, &par->mode_set_list, head) { - + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + modeset = &intel_crtc->mode_set; + modeset->fb = &intel_fb->base; conn_count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder) @@ -852,10 +846,13 @@ static int intelfb_single_fb_probe(struct drm_device *dev) for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) modeset->connectors[i] = NULL; + par->crtc_ids[crtc_count++] = crtc->base.id; + modeset->num_connectors = conn_count; if (modeset->mode != modeset->crtc->desired_mode) modeset->mode = modeset->crtc->desired_mode; } + par->crtc_count = crtc_count; if (new_fb) { info->var.pixclock = -1; -- cgit v1.2.3 From fc08877b1759f569890665b9d24ea35d11352158 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 14:53:34 +1000 Subject: intelfb: admit fbdev is crap and punt on trying to resize to a larger fbdev. --- linux-core/intel_fb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 71f71a0d..9967f913 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -815,10 +815,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev) fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); intel_fb = to_intel_framebuffer(fb); - /* check if we are going to have a size issue */ - /* do a surface compare */ + /* if someone hotplugs something bigger than we have already allocated, we are pwned. + As really we can't resize an fbdev that is in the wild currently due to fbdev + not really being designed for the lower layers moving stuff around under it. + - so in the grand style of things - punt. */ if ((fb->width < surface_width) || (fb->height < surface_height)) { - DRM_ERROR("NEED BIGGER SURFACE DUDE\n"); + DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); return -EINVAL; } } -- cgit v1.2.3 From e6a3a1fdadd162e3cf12e88ad13c4342f9ee23a1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 14:55:03 +1000 Subject: intelfb: remove duplicate define --- linux-core/intel_fb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 9967f913..d202649f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -759,8 +759,6 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height return 0; } -#define INTELFB_CONN_LIMIT 4 - static int intelfb_single_fb_probe(struct drm_device *dev) { struct drm_crtc *crtc; -- cgit v1.2.3 From be501f00a3c91a8ae78189577873d8a6b8ea1c67 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 15:21:22 +1000 Subject: intelfb: add multi fb paths --- linux-core/intel_fb.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index d202649f..85a173e1 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -759,6 +759,94 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height return 0; } +static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; + struct drm_framebuffer *fb; + struct drm_connector *connector; + struct fb_info *info; + struct intelfb_par *par; + struct drm_mode_set *modeset; + unsigned int width, height; + int new_fb = 0; + int ret, i, conn_count; + + if (!drm_helper_crtc_in_use(crtc)) + return 0; + + if (!crtc->desired_mode) + return 0; + + width = crtc->desired_mode->hdisplay; + height = crtc->desired_mode->vdisplay; + + /* is there an fb bound to this crtc already */ + if (!intel_crtc->mode_set.fb) { + ret = intelfb_create(dev, width, height, width, height, &intel_fb); + if (ret) + return -EINVAL; + new_fb = 1; + } else { + fb = intel_crtc->mode_set.fb; + intel_fb = to_intel_framebuffer(fb); + if ((intel_fb->base.width < width) || (intel_fb->base.height < height)) + return -EINVAL; + } + + info = intel_fb->base.fbdev; + par = info->par; + + modeset = &intel_crtc->mode_set; + modeset->fb = &intel_fb->base; + conn_count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; + conn_count++; + if (conn_count > INTELFB_CONN_LIMIT) + BUG(); + } + } + + for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; + + par->crtc_ids[0] = crtc->base.id; + + modeset->num_connectors = conn_count; + if (modeset->mode != modeset->crtc->desired_mode) + modeset->mode = modeset->crtc->desired_mode; + + par->crtc_count = 1; + + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } else + intelfb_set_par(info); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + return 0; +} + +static int intelfb_multi_fb_probe(struct drm_device *dev) +{ + + struct drm_crtc *crtc; + int ret = 0; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + ret = intelfb_multi_fb_probe_crtc(dev, crtc); + if (ret) + return ret; + } + return ret; +} + static int intelfb_single_fb_probe(struct drm_device *dev) { struct drm_crtc *crtc; @@ -891,12 +979,11 @@ int intelfb_probe(struct drm_device *dev) /* mode a first */ /* search for an fb */ if (i915_fbpercrtc == 1) { - ret = -EINVAL; - goto fail; + ret = intelfb_multi_fb_probe(dev); + } else { + ret = intelfb_single_fb_probe(dev); } - ret = intelfb_single_fb_probe(dev); - fail: /* TODO */ return ret; -- cgit v1.2.3 From 00bb548c6129ee712742d0e893aaa50fc65e49fc Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 15:38:53 +1000 Subject: intel: don't set the mode on the framebuffer if isn't set to scanout our framebuffer --- linux-core/intel_fb.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 85a173e1..856ec868 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -218,7 +218,6 @@ static int intelfb_set_par(struct fb_info *info) DRM_DEBUG("%d %d\n", var->xres, var->pixclock); - if (var->pixclock != -1) { DRM_ERROR("PIXEL CLCOK SET\n"); @@ -332,9 +331,11 @@ static int intelfb_set_par(struct fb_info *info) if (i == par->crtc_count) continue; - ret = crtc->funcs->set_config(&intel_crtc->mode_set); - if (ret) - return ret; + if (crtc->fb == intel_crtc->mode_set.fb) { + ret = crtc->funcs->set_config(&intel_crtc->mode_set); + if (ret) + return ret; + } } return 0; } @@ -984,8 +985,6 @@ int intelfb_probe(struct drm_device *dev) ret = intelfb_single_fb_probe(dev); } -fail: - /* TODO */ return ret; } EXPORT_SYMBOL(intelfb_probe); -- cgit v1.2.3 From 6d4ffd12cd8d3713067adf5fa3bdcb023b0745f1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 16:24:27 +1000 Subject: drm: fix up fb resize again --- linux-core/drm_crtc.c | 19 ++----------------- linux-core/drm_crtc.h | 4 ++-- linux-core/drm_crtc_helper.c | 1 + linux-core/intel_display.c | 32 +++++++++++++++++++++++++++++++- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index d49834b9..e1b371cc 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2055,25 +2055,10 @@ int drm_mode_replacefb(struct drm_device *dev, goto out; } - fb->width = r->width; - fb->height = r->height; - fb->pitch = r->pitch; - fb->bits_per_pixel = r->bpp; - fb->depth = r->depth; - fb->mm_handle = r->handle; - if (dev->mode_config.funcs->resize_fb) - dev->mode_config.funcs->resize_fb(dev, fb); + ret = dev->mode_config.funcs->resize_fb(dev, file_priv, fb, r); else - ret = -EINVAL; -#if 0 - /* find all crtcs connected to this fb */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb->base.id == r->buffer_id) { - crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); - } - } -#endif + ret = -EINVAL; out: mutex_unlock(&dev->mode_config.mutex); return ret; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 043b4a57..5f5f195a 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -522,9 +522,9 @@ struct drm_mode_set { * the CRTC<->connector mappings as needed and update its view of the screen. */ struct drm_mode_config_funcs { - bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); + int (*resize_fb)(struct drm_device *dev, struct drm_file *file_priv, struct drm_framebuffer *fb, struct drm_mode_fb_cmd *mode_cmd); struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); - void (*fb_changed)(struct drm_device *dev); + int (*fb_changed)(struct drm_device *dev); }; struct drm_mode_group { diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 777820d7..bfddab99 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -758,3 +758,4 @@ out_err: return ret; } EXPORT_SYMBOL(drm_get_buffer_object); + diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 0081b5be..0a2854a2 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1517,8 +1517,38 @@ struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, return &intel_fb->base; } +static int intel_insert_new_fb(struct drm_device *dev, struct drm_file *file_priv, + struct drm_framebuffer *fb, struct drm_mode_fb_cmd *mode_cmd) +{ + struct intel_framebuffer *intel_fb; + struct drm_buffer_object *bo; + struct drm_crtc *crtc; + + intel_fb = to_intel_framebuffer(fb); + + mutex_lock(&dev->struct_mutex); + bo = drm_lookup_buffer_object(file_priv, mode_cmd->handle, 0); + mutex_unlock(&dev->struct_mutex); + + if (!bo) + return -EINVAL; + drm_helper_mode_fill_fb_struct(fb, mode_cmd); + + drm_bo_usage_deref_unlocked(&intel_fb->bo); + + intel_fb->bo = bo; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->fb == fb) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y); + } + } + return 0; +} + static const struct drm_mode_config_funcs intel_mode_funcs = { - .resize_fb = NULL, + .resize_fb = intel_insert_new_fb, .fb_create = intel_user_framebuffer_create, .fb_changed = intelfb_probe, }; -- cgit v1.2.3 From c2fc142ea7e9dd651702773efbc9c3366f977aa6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 6 Jun 2008 21:54:38 +0100 Subject: [intel] remove settable use_mi_batchbuffer_start The driver can know what hardware requires MI_BATCH_BUFFER vs MI_BATCH_BUFFER_START; there's no reason to let user mode configure this. --- shared-core/i915_dma.c | 22 ++++++++-------------- shared-core/i915_drv.h | 1 - shared-core/i915_init.c | 7 ------- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 5e06fa6d..db857fbd 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -232,9 +232,6 @@ static int i915_initialize(struct drm_device * dev, /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. */ - dev_priv->use_mi_batchbuffer_start = 0; - if (IS_I965G(dev)) /* 965 doesn't support older method */ - dev_priv->use_mi_batchbuffer_start = 1; /* Allow hardware batchbuffers unless told otherwise. */ @@ -610,7 +607,14 @@ int i915_dispatch_batchbuffer(struct drm_device * dev, return ret; } - if (dev_priv->use_mi_batchbuffer_start) { + if (IS_I830(dev) || IS_845G(dev)) { + BEGIN_LP_RING(4); + OUT_RING(MI_BATCH_BUFFER); + OUT_RING(batch->start | MI_BATCH_NON_SECURE); + OUT_RING(batch->start + batch->used - 4); + OUT_RING(0); + ADVANCE_LP_RING(); + } else { BEGIN_LP_RING(2); if (IS_I965G(dev)) { OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965); @@ -620,14 +624,6 @@ int i915_dispatch_batchbuffer(struct drm_device * dev, OUT_RING(batch->start | MI_BATCH_NON_SECURE); } ADVANCE_LP_RING(); - - } else { - BEGIN_LP_RING(4); - OUT_RING(MI_BATCH_BUFFER); - OUT_RING(batch->start | MI_BATCH_NON_SECURE); - OUT_RING(batch->start + batch->used - 4); - OUT_RING(0); - ADVANCE_LP_RING(); } } @@ -896,8 +892,6 @@ static int i915_setparam(struct drm_device *dev, void *data, switch (param->param) { case I915_SETPARAM_USE_MI_BATCHBUFFER_START: - if (!IS_I965G(dev)) - dev_priv->use_mi_batchbuffer_start = param->value; break; case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: dev_priv->tex_lru_log_granularity = param->value; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 34e81ad5..6d72c051 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -132,7 +132,6 @@ struct drm_i915_private { struct drm_buffer_object *hws_bo; unsigned int cpp; - int use_mi_batchbuffer_start; wait_queue_head_t irq_queue; atomic_t irq_received; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index f03f8949..f2c07fc6 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -151,13 +151,6 @@ int i915_load_modeset_init(struct drm_device *dev) I915_WRITE(PRB0_CTL, ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) | (RING_NO_REPORT | RING_VALID)); - /* We are using separate values as placeholders for mechanisms for - * private backbuffer/depthbuffer usage. - */ - dev_priv->use_mi_batchbuffer_start = 0; - if (IS_I965G(dev)) /* 965 doesn't support older method */ - dev_priv->use_mi_batchbuffer_start = 1; - /* Allow hardware batchbuffers unless told otherwise. */ dev_priv->allow_batchbuffer = 1; -- cgit v1.2.3 From c987e76d953b6aecbfb69058fc4c387aa3fb33c9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 9 Jun 2008 16:20:45 -0700 Subject: Add EDID quirk handling Port over EDID quirks from X.Org so we can handle more monitors. This meant adding size info to the drm_display_mode struct, but other than that the changes were isolated to the DRM EDID handling code (as they should be). --- linux-core/drm_crtc.h | 6 +- linux-core/drm_edid.c | 260 +++++++++++++++++++++++++++++++++++++++++++++----- linux-core/drm_edid.h | 6 +- 3 files changed, 245 insertions(+), 27 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 5f5f195a..2b577b93 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -115,6 +115,10 @@ struct drm_display_mode { int vscan; unsigned int flags; + /* Addressable image size (may be 0 for projectors, etc.) */ + int width_mm; + int height_mm; + /* Actual mode we give to hw */ int clock_index; int synth_clock; @@ -246,8 +250,6 @@ struct drm_display_info { enum subpixel_order subpixel_order; - /* Preferred mode (if any) */ - struct drm_display_mode *preferred_mode; char *raw_edid; /* if any */ }; diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 69906ed9..0d600396 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -1,28 +1,120 @@ /* + * Copyright (c) 2006 Luc Verhaegen (quirks list) * Copyright (c) 2007 Intel Corporation * Jesse Barnes * * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from * FB layer. * Copyright (C) 2006 Dennis Munsie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ +#include #include #include #include "drmP.h" #include "drm_edid.h" +/* + * TODO: + * - support EDID 1.4 + * - port quirks from X server code + */ + +/* + * EDID blocks out in the wild have a variety of bugs, try to collect + * them here (note that userspace may work around broken monitors first, + * but fixes should make their way here so that the kernel "just works" + * on as many displays as possible). + */ + +/* First detailed mode wrong, use largest 60Hz mode */ +#define EDID_QUIRK_PREFER_LARGE_60 (1 << 0) +/* Reported 135MHz pixel clock is too high, needs adjustment */ +#define EDID_QUIRK_135_CLOCK_TOO_HIGH (1 << 1) +/* Prefer the largest mode at 75 Hz */ +#define EDID_QUIRK_PREFER_LARGE_75 (1 << 2) +/* Detail timing is in cm not mm */ +#define EDID_QUIRK_DETAILED_IN_CM (1 << 3) +/* Detailed timing descriptors have bogus size values, so just take the + * maximum size and use that. + */ +#define EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE (1 << 4) +/* Monitor forgot to set the first detailed is preferred bit. */ +#define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) +/* use +hsync +vsync for detailed mode */ +#define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) + +static struct edid_quirk { + char *vendor; + int product_id; + u32 quirks; +} edid_quirk_list[] = { + /* Acer AL1706 */ + { "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 }, + /* Acer F51 */ + { "API", 0x7602, EDID_QUIRK_PREFER_LARGE_60 }, + /* Unknown Acer */ + { "ACR", 2423, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, + + /* Belinea 10 15 55 */ + { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, + { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, + + /* Envision Peripherals, Inc. EN-7100e */ + { "EPI", 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH }, + + /* Funai Electronics PM36B */ + { "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 | + EDID_QUIRK_DETAILED_IN_CM }, + + /* LG Philips LCD LP154W01-A5 */ + { "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, + { "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE }, + + /* Philips 107p5 CRT */ + { "PHL", 57364, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, + + /* Proview AY765C */ + { "PTS", 765, EDID_QUIRK_FIRST_DETAILED_PREFERRED }, + + /* Samsung SyncMaster 205BW. Note: irony */ + { "SAM", 541, EDID_QUIRK_DETAILED_SYNC_PP }, + /* Samsung SyncMaster 22[5-6]BW */ + { "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 }, + { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 }, +}; + + /* Valid EDID header has these bytes */ static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; /** - * edid_valid - sanity check EDID data + * edid_is_valid - sanity check EDID data * @edid: EDID data * * 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 * valid. */ -static bool edid_valid(struct edid *edid) +static bool edid_is_valid(struct edid *edid) { int i; u8 csum = 0; @@ -46,6 +138,97 @@ bad: return 0; } +/** + * edid_vendor - match a string against EDID's obfuscated vendor field + * @edid: EDID to match + * @vendor: vendor string + * + * Returns true if @vendor is in @edid, false otherwise + */ +static bool edid_vendor(struct edid *edid, char *vendor) +{ + char edid_vendor[3]; + + edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@'; + edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) | + ((edid->mfg_id[1] & 0xe0) >> 5)) + '@'; + edid_vendor[2] = (edid->mfg_id[2] & 0x1f) + '@'; + + return !strncmp(edid_vendor, vendor, 3); +} + +/** + * edid_get_quirks - return quirk flags for a given EDID + * @edid: EDID to process + * + * This tells subsequent routines what fixes they need to apply. + */ +static u32 edid_get_quirks(struct edid *edid) +{ + struct edid_quirk *quirk; + int i; + + for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) { + quirk = &edid_quirk_list[i]; + + if (edid_vendor(edid, quirk->vendor) && + (EDID_PRODUCT_ID(edid) == quirk->product_id)) + return quirk->quirks; + } + + return 0; +} + +#define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay) +#define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh)) + + +/** + * edid_fixup_preferred - set preferred modes based on quirk list + * @connector: has mode list to fix up + * @quirks: quirks list + * + * Walk the mode list for @connector, clearing the preferred status + * on existing modes and setting it anew for the right mode ala @quirks. + */ +static void edid_fixup_preferred(struct drm_connector *connector, + u32 quirks) +{ + struct drm_display_mode *t, *cur_mode, *preferred_mode; + int target_refresh; + + if (list_empty(&connector->probed_modes)) + return; + + if (quirks & EDID_QUIRK_PREFER_LARGE_60) + target_refresh = 60; + if (quirks & EDID_QUIRK_PREFER_LARGE_75) + target_refresh = 75; + + preferred_mode = list_first_entry(&connector->probed_modes, + struct drm_display_mode, head); + + list_for_each_entry_safe(cur_mode, t, &connector->probed_modes, head) { + cur_mode->type &= ~DRM_MODE_TYPE_PREFERRED; + + if (cur_mode == preferred_mode) + continue; + + /* Largest mode is preferred */ + if (MODE_SIZE(cur_mode) > MODE_SIZE(preferred_mode)) + preferred_mode = cur_mode; + + /* At a given size, try to get closest to target refresh */ + if ((MODE_SIZE(cur_mode) == MODE_SIZE(preferred_mode)) && + MODE_REFRESH_DIFF(cur_mode, target_refresh) < + MODE_REFRESH_DIFF(preferred_mode, target_refresh)) { + preferred_mode = cur_mode; + } + } + + preferred_mode->type |= DRM_MODE_TYPE_PREFERRED; +} + /** * drm_mode_std - convert standard mode info (width, height, refresh) into mode * @t: standard timing params @@ -86,16 +269,18 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, /** * drm_mode_detailed - create a new mode from an EDID detailed timing section + * @dev: DRM device (needed to create new mode) + * @edid: EDID block * @timing: EDID detailed timing info - * @preferred: is this a preferred mode? + * @quirks: quirks to apply * * An EDID detailed timing block contains enough info for us to create and - * return a new struct drm_display_mode. The @preferred flag will be set - * if this is the display's preferred timing, and we'll use it to indicate - * to the other layers that this mode is desired. + * return a new struct drm_display_mode. */ -struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, - struct detailed_timing *timing) +static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, + struct edid *edid, + struct detailed_timing *timing, + u32 quirks) { struct drm_display_mode *mode; struct detailed_pixel_timing *pt = &timing->data.pixel_data; @@ -114,6 +299,10 @@ struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, return NULL; mode->type = DRM_MODE_TYPE_DRIVER; + + if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH) + timing->pixel_clock = 1088; + mode->clock = timing->pixel_clock * 10; mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo; @@ -137,9 +326,27 @@ struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, if (pt->interlaced) mode->flags |= V_INTERLACE; + if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { + pt->hsync_positive = 1; + pt->vsync_positive = 1; + } + mode->flags |= pt->hsync_positive ? V_PHSYNC : V_NHSYNC; mode->flags |= pt->vsync_positive ? V_PVSYNC : V_NVSYNC; + mode->width_mm = pt->width_mm_lo | (pt->width_mm_hi << 8); + mode->height_mm = pt->height_mm_lo | (pt->height_mm_hi << 8); + + if (quirks & EDID_QUIRK_DETAILED_IN_CM) { + mode->width_mm *= 10; + mode->height_mm *= 10; + } + + if (quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) { + mode->width_mm = edid->width_cm * 10; + mode->height_mm = edid->height_cm * 10; + } + return mode; } @@ -264,12 +471,15 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid /** * add_detailed_modes - get detailed mode info from EDID data + * @connector: attached connector * @edid: EDID block to scan + * @quirks: quirks to apply * * Some of the detailed timing sections may contain mode information. Grab * it and add it to the list. */ -static int add_detailed_info(struct drm_connector *connector, struct edid *edid) +static int add_detailed_info(struct drm_connector *connector, + struct edid *edid, u32 quirks) { struct drm_device *dev = connector->dev; int i, j, modes = 0; @@ -285,19 +495,16 @@ static int add_detailed_info(struct drm_connector *connector, struct edid *edid) /* Detailed mode timing */ if (timing->pixel_clock) { - newmode = drm_mode_detailed(dev, timing); + newmode = drm_mode_detailed(dev, edid, timing, quirks); + if (!newmode) + continue; + /* First detailed mode is preferred */ - if (newmode) { - if (i == 0 && edid->preferred_timing) - newmode->type |= DRM_MODE_TYPE_PREFERRED; - drm_mode_probed_add(connector, newmode); + if (i == 0 && edid->preferred_timing) + newmode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, newmode); - /* Use first one for connector's preferred mode */ - if (!connector->display_info.preferred_mode) - connector->display_info.preferred_mode = - newmode; - modes++; - } + modes++; continue; } @@ -458,7 +665,7 @@ struct edid *drm_get_edid(struct drm_connector *connector, drm_get_connector_name(connector)); return NULL; } - if (!edid_valid(edid)) { + if (!edid_is_valid(edid)) { dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", drm_get_connector_name(connector)); kfree(edid); @@ -483,18 +690,25 @@ EXPORT_SYMBOL(drm_get_edid); int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) { int num_modes = 0; + u32 quirks; if (edid == NULL) { return 0; } - if (!edid_valid(edid)) { + if (!edid_is_valid(edid)) { dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", drm_get_connector_name(connector)); return 0; } + + quirks = edid_get_quirks(edid); + num_modes += add_established_modes(connector, edid); num_modes += add_standard_modes(connector, edid); - num_modes += add_detailed_info(connector, edid); + num_modes += add_detailed_info(connector, edid, quirks); + + if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) + edid_fixup_preferred(connector, quirks); connector->display_info.serration_vsync = edid->serration_vsync; connector->display_info.sync_on_green = edid->sync_on_green; diff --git a/linux-core/drm_edid.h b/linux-core/drm_edid.h index 0d2eeaa1..dccfba91 100644 --- a/linux-core/drm_edid.h +++ b/linux-core/drm_edid.h @@ -122,8 +122,8 @@ struct detailed_timing { struct edid { u8 header[8]; /* Vendor & product info */ - u16 mfg_id; /* FIXME: byte order */ - u16 prod_code; /* FIXME: byte order */ + u8 mfg_id[2]; + u8 prod_code[2]; u32 serial; /* FIXME: byte order */ u8 mfg_week; u8 mfg_year; @@ -173,4 +173,6 @@ struct edid { u8 checksum; } __attribute__((packed)); +#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) + #endif /* __DRM_EDID_H__ */ -- cgit v1.2.3 From 4a2e29bf9982165deeeabb5c585fc0a8a659f380 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Jun 2008 15:59:01 -0700 Subject: Use GEM in modesetting Use GEM for ring buffer setup and framebuffer allocation. This means reworking the hardware status page stuff a bit (just use the basic range allocator for vram for now) and #ifdef'ing out the TTM & DRI2 code. Works well enough to load/unload several times and display fbcon on my T61 (though there's still some unexplained console corruption). --- linux-core/i915_drv.c | 10 +-- linux-core/i915_gem.c | 52 ++++++------ linux-core/intel_display.c | 34 ++++---- linux-core/intel_drv.h | 3 +- linux-core/intel_fb.c | 79 +++++++++++-------- shared-core/i915_dma.c | 39 ++++----- shared-core/i915_drv.h | 41 ++++------ shared-core/i915_init.c | 193 +++++++++++++++++++++------------------------ 8 files changed, 231 insertions(+), 220 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 8718bd10..574282b2 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -48,11 +48,11 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); unsigned int i915_rightof = 1; module_param_named(i915_rightof, i915_rightof, int, 0400); -#ifdef I915_HAVE_FENCE +#if defined(I915_HAVE_FENCE) && defined(I915_TTM) extern struct drm_fence_driver i915_fence_driver; #endif -#ifdef I915_HAVE_BUFFER +#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; @@ -71,7 +71,7 @@ static struct drm_bo_driver i915_bo_driver = { .ttm_cache_flush = i915_flush_ttm, .command_stream_barrier = NULL, }; -#endif +#endif /* ttm */ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) { @@ -619,10 +619,10 @@ static struct drm_driver driver = { .probe = probe, .remove = __devexit_p(drm_cleanup_pci), }, -#ifdef I915_HAVE_FENCE +#if defined(I915_HAVE_FENCE) && defined(I915_TTM) .fence_driver = &i915_fence_driver, #endif -#ifdef I915_HAVE_BUFFER +#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) .bo_driver = &i915_bo_driver, #endif .name = DRIVER_NAME, diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c index 961831c6..47745010 100644 --- a/linux-core/i915_gem.c +++ b/linux-core/i915_gem.c @@ -41,28 +41,35 @@ i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uint32_t write_domain); -int -i915_gem_init_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int i915_gem_do_init(struct drm_device *dev, unsigned long start, + unsigned long end) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_init *args = data; - - mutex_lock(&dev->struct_mutex); - if (args->gtt_start >= args->gtt_end || - (args->gtt_start & (PAGE_SIZE - 1)) != 0 || - (args->gtt_end & (PAGE_SIZE - 1)) != 0) { - mutex_unlock(&dev->struct_mutex); + if (start >= end || + (start & (PAGE_SIZE - 1)) != 0 || + (end & (PAGE_SIZE - 1)) != 0) { return -EINVAL; } - drm_memrange_init(&dev_priv->mm.gtt_space, args->gtt_start, - args->gtt_end - args->gtt_start); + drm_memrange_init(&dev_priv->mm.gtt_space, start, + end - start); + + return 0; +} + +int +i915_gem_init_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_i915_gem_init *args = data; + int ret; + mutex_lock(&dev->struct_mutex); + ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end); mutex_unlock(&dev->struct_mutex); - return 0; + return ret; } static void @@ -1834,17 +1841,16 @@ i915_gem_init_ringbuffer(struct drm_device *dev) dev_priv->ring.virtual_start = dev_priv->ring.map.handle; /* Stop the ring if it's running. */ - I915_WRITE(LP_RING + RING_LEN, 0); - I915_WRITE(LP_RING + RING_HEAD, 0); - I915_WRITE(LP_RING + RING_TAIL, 0); - I915_WRITE(LP_RING + RING_START, 0); + I915_WRITE(PRB0_CTL, 0); + I915_WRITE(PRB0_HEAD, 0); + I915_WRITE(PRB0_TAIL, 0); + I915_WRITE(PRB0_START, 0); /* Initialize the ring. */ - I915_WRITE(LP_RING + RING_START, obj_priv->gtt_offset); - I915_WRITE(LP_RING + RING_LEN, - ((obj->size - 4096) & RING_NR_PAGES) | - RING_NO_REPORT | - RING_VALID); + I915_WRITE(PRB0_START, obj_priv->gtt_offset); + I915_WRITE(PRB0_CTL, (((obj->size - 4096) & RING_NR_PAGES) | + RING_NO_REPORT | + RING_VALID)); /* Update our cache of the ring state */ i915_kernel_lost_context(dev); @@ -1852,7 +1858,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev) return 0; } -static void +void i915_gem_cleanup_ringbuffer(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 0a2854a2..50ad1a27 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -369,6 +369,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj_priv; int pipe = intel_crtc->pipe; unsigned long Start, Offset; int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); @@ -385,7 +386,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) intel_fb = to_intel_framebuffer(crtc->fb); - Start = intel_fb->bo->offset; + obj_priv = intel_fb->obj->driver_private; + + Start = obj_priv->gtt_offset; Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); I915_WRITE(dspstride, crtc->fb->pitch); @@ -1493,7 +1496,7 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = { }; struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, - struct drm_file *file_priv, + struct drm_file *filp, struct drm_mode_fb_cmd *mode_cmd) { struct intel_framebuffer *intel_fb; @@ -1505,15 +1508,15 @@ struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); - if (file_priv) { - mutex_lock(&dev->struct_mutex); - intel_fb->bo = drm_lookup_buffer_object(file_priv, intel_fb->base.mm_handle, 0); - mutex_unlock(&dev->struct_mutex); - if (!intel_fb->bo) { + if (filp) { + intel_fb->obj = drm_gem_object_lookup(dev, filp, + mode_cmd->handle); + if (!intel_fb->obj) { kfree(intel_fb); return NULL; } } + drm_gem_object_unreference(intel_fb->obj); return &intel_fb->base; } @@ -1521,22 +1524,25 @@ static int intel_insert_new_fb(struct drm_device *dev, struct drm_file *file_pri struct drm_framebuffer *fb, struct drm_mode_fb_cmd *mode_cmd) { struct intel_framebuffer *intel_fb; - struct drm_buffer_object *bo; + struct drm_gem_object *obj; struct drm_crtc *crtc; intel_fb = to_intel_framebuffer(fb); mutex_lock(&dev->struct_mutex); - bo = drm_lookup_buffer_object(file_priv, mode_cmd->handle, 0); - mutex_unlock(&dev->struct_mutex); + obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); - if (!bo) + if (!obj) { + mutex_unlock(&dev->struct_mutex); return -EINVAL; + } drm_helper_mode_fill_fb_struct(fb, mode_cmd); - - drm_bo_usage_deref_unlocked(&intel_fb->bo); - intel_fb->bo = bo; + drm_gem_object_unreference(intel_fb->obj); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + + intel_fb->obj = obj; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb == fb) { diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 1008e271..bffbeef0 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -50,8 +50,7 @@ struct intel_i2c_chan { struct intel_framebuffer { struct drm_framebuffer base; - struct drm_buffer_object *bo; - struct drm_bo_kmap_obj kmap; + struct drm_gem_object *obj; }; diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 856ec868..d53b22ff 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -590,9 +590,10 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; struct drm_mode_fb_cmd mode_cmd; - struct drm_buffer_object *fbo = NULL; + struct drm_gem_object *fbo = NULL; + struct drm_i915_gem_object *obj_priv; struct device *device = &dev->pdev->dev; - int ret; + int size, aligned_size, ret; mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */ mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */ @@ -601,26 +602,28 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); mode_cmd.depth = 24; - ret = drm_buffer_object_create(dev, mode_cmd.pitch * mode_cmd.height, - drm_bo_type_kernel, - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0, 0, - &fbo); - if (ret || !fbo) { + size = mode_cmd.pitch * mode_cmd.height; + aligned_size = ALIGN(size, PAGE_SIZE); + fbo = drm_gem_object_alloc(dev, aligned_size); + if (!fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); - return -EINVAL; + ret = -ENOMEM; + goto out; + } + obj_priv = fbo->driver_private; + + mutex_lock(&dev->struct_mutex); + ret = i915_gem_object_pin(fbo, PAGE_SIZE); + if (ret) { + DRM_ERROR("failed to pin fb: %d\n", ret); + goto out_unref; } - fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); if (!fb) { - drm_bo_usage_deref_unlocked(&fbo); DRM_ERROR("failed to allocate fb.\n"); - return -EINVAL; + ret = -ENOMEM; + goto out_unref; } list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); @@ -628,11 +631,13 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height intel_fb = to_intel_framebuffer(fb); *intel_fb_p = intel_fb; - intel_fb->bo = fbo; + intel_fb->obj = fbo; info = framebuffer_alloc(sizeof(struct intelfb_par), device); - if (!info) - return -EINVAL; + if (!info) { + ret = -ENOMEM; + goto out_unref; + } par = info->par; @@ -651,19 +656,20 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height info->fbops = &intelfb_ops; info->fix.line_length = fb->pitch; - info->fix.smem_start = intel_fb->bo->offset + dev->mode_config.fb_base; - info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; + info->fix.smem_len = size; info->flags = FBINFO_DEFAULT; - ret = drm_bo_kmap(intel_fb->bo, 0, intel_fb->bo->num_pages, &intel_fb->kmap); - if (ret) - DRM_ERROR("error mapping fb: %d\n", ret); - - info->screen_base = intel_fb->kmap.virtual; - info->screen_size = info->fix.smem_len; /* FIXME */ + info->screen_base = ioremap(dev->agp->base + obj_priv->gtt_offset, + size); + if (!info->screen_base) { + ret = -ENOSPC; + goto out_unref; + } + info->screen_size = size; - memset(intel_fb->kmap.virtual, 0, info->screen_size); + memset(info->screen_base, 0, size); info->pseudo_palette = fb->pseudo_palette; info->var.xres_virtual = fb->width; @@ -754,10 +760,17 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height par->dev = dev; /* To allow resizeing without swapping buffers */ - printk("allocated %dx%d fb: 0x%08lx, bo %p\n", intel_fb->base.width, - intel_fb->base.height, intel_fb->bo->offset, fbo); + printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, + intel_fb->base.height, obj_priv->gtt_offset, fbo); + mutex_unlock(&dev->struct_mutex); return 0; + +out_unref: + drm_gem_object_unreference(fbo); + mutex_unlock(&dev->struct_mutex); +out: + return ret; } static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) @@ -1001,8 +1014,10 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) if (info) { unregister_framebuffer(info); - drm_bo_kunmap(&intel_fb->kmap); - drm_bo_usage_deref_unlocked(&intel_fb->bo); + iounmap(info->screen_base); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(intel_fb->obj); + mutex_unlock(&dev->struct_mutex); framebuffer_release(info); } return 0; diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 1e51e702..0cd920de 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -139,8 +139,8 @@ int i915_dma_cleanup(struct drm_device * dev) I915_WRITE(0x02080, 0x1ffff000); } - if (dev_priv->status_gfx_addr) { - dev_priv->status_gfx_addr = 0; + if (dev_priv->hws_agpoffset) { + dev_priv->hws_agpoffset = 0; drm_core_ioremapfree(&dev_priv->hws_map, dev); I915_WRITE(0x02080, 0x1ffff000); } @@ -148,7 +148,7 @@ int i915_dma_cleanup(struct drm_device * dev) return 0; } -#if defined(I915_HAVE_BUFFER) +#if defined(I915_HAVE_BUFFER) && defined(DRI2) #define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16) #define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff) #define DRI2_SAREA_BLOCK_NEXT(p) \ @@ -276,10 +276,10 @@ static int i915_initialize(struct drm_device * dev, DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->hws_vaddr = dev_priv->status_page_dmah->vaddr; dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + memset(dev_priv->hws_vaddr, 0, PAGE_SIZE); I915_WRITE(0x02080, dev_priv->dma_status_page); } @@ -289,7 +289,7 @@ static int i915_initialize(struct drm_device * dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) { mutex_init(&dev_priv->cmdbuf_mutex); } - +#ifdef DRI2 if (init->func == I915_INIT_DMA2) { int ret = setup_dri2_sarea(dev, file_priv, init); if (ret) { @@ -298,7 +298,8 @@ static int i915_initialize(struct drm_device * dev, return ret; } } -#endif +#endif /* DRI2 */ +#endif /* I915_HAVE_BUFFER */ return 0; } @@ -319,16 +320,16 @@ static int i915_dma_resume(struct drm_device * dev) } /* Program Hardware Status Page */ - if (!dev_priv->hw_status_page) { + if (!dev_priv->hws_vaddr) { DRM_ERROR("Can not find hardware status page\n"); return -EINVAL; } - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hws_vaddr); - if (dev_priv->status_gfx_addr != 0) - I915_WRITE(0x02080, dev_priv->status_gfx_addr); + if (dev_priv->hws_agpoffset != 0) + I915_WRITE(HWS_PGA, dev_priv->hws_agpoffset); else - I915_WRITE(0x02080, dev_priv->dma_status_page); + I915_WRITE(HWS_PGA, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); return 0; @@ -1032,7 +1033,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr); - dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); + dev_priv->hws_agpoffset = hws->addr & (0x1ffff<<12); dev_priv->hws_map.offset = dev->agp->base + hws->addr; dev_priv->hws_map.size = 4*1024; @@ -1043,18 +1044,18 @@ static int i915_set_status_page(struct drm_device *dev, void *data, drm_core_ioremap(&dev_priv->hws_map, dev); if (dev_priv->hws_map.handle == NULL) { i915_dma_cleanup(dev); - dev_priv->status_gfx_addr = 0; + dev_priv->hws_agpoffset = 0; DRM_ERROR("can not ioremap virtual address for" " G33 hw status page\n"); return -ENOMEM; } - dev_priv->hw_status_page = dev_priv->hws_map.handle; + dev_priv->hws_vaddr = dev_priv->hws_map.handle; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); + memset(dev_priv->hws_vaddr, 0, PAGE_SIZE); + I915_WRITE(HWS_PGA, dev_priv->hws_agpoffset); DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n", - dev_priv->status_gfx_addr); - DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); + dev_priv->hws_agpoffset); + DRM_DEBUG("load hws at %p\n", dev_priv->hws_vaddr); return 0; } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index cfb064ff..06aa00ab 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -115,8 +115,6 @@ struct drm_i915_master_private { struct drm_i915_private { struct drm_device *dev; - struct drm_buffer_object *ring_buffer; - drm_local_map_t *mmio_map; unsigned long mmiobase; @@ -125,12 +123,12 @@ struct drm_i915_private { struct drm_i915_ring_buffer ring; struct drm_dma_handle *status_page_dmah; - void *hw_status_page; dma_addr_t dma_status_page; uint32_t counter; - unsigned int status_gfx_addr; + uint32_t hws_agpoffset; drm_local_map_t hws_map; - struct drm_buffer_object *hws_bo; + void *hws_vaddr; + struct drm_memrange_node *hws; unsigned int cpp; @@ -152,6 +150,8 @@ struct drm_i915_private { bool cursor_needs_physical; + struct drm_memrange vram; + #ifdef I915_HAVE_FENCE uint32_t flush_sequence; uint32_t flush_flags; @@ -176,17 +176,17 @@ struct drm_i915_private { struct drm_display_mode *panel_fixed_mode; struct drm_display_mode *vbt_mode; /* if any */ -#if defined(I915_HAVE_BUFFER) +#if defined(I915_HAVE_BUFFER) && defined(DRI2) /* DRI2 sarea */ - struct drm_buffer_object *sarea_bo; - struct drm_bo_kmap_obj sarea_kmap; + struct drm_gem_object *sarea_object; + struct drm_bo_kmap_obj sarea_kmap; +#endif /* Feature bits from the VBIOS */ int int_tv_support:1; int lvds_dither:1; int lvds_vbt:1; int int_crt_support:1; -#endif struct { struct drm_memrange gtt_space; @@ -483,7 +483,7 @@ extern void i915_invalidate_reported_sequence(struct drm_device *dev); #endif -#ifdef I915_HAVE_BUFFER +#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) /* i915_buffer.c */ extern struct drm_ttm_backend *i915_create_ttm_backend_entry(struct drm_device *dev); extern int i915_fence_type(struct drm_buffer_object *bo, uint32_t *fclass, @@ -495,6 +495,8 @@ extern uint64_t i915_evict_flags(struct drm_buffer_object *bo); extern int i915_move(struct drm_buffer_object *bo, int evict, int no_wait, struct drm_bo_mem_reg *new_mem); void i915_flush_ttm(struct drm_ttm *ttm); +#endif /* ttm */ +#ifdef I915_HAVE_BUFFER /* i915_execbuf.c */ int i915_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -530,6 +532,9 @@ void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_timeout(unsigned long data); void i915_gem_retire_handler(struct work_struct *work); int i915_gem_init_ringbuffer(struct drm_device *dev); +void i915_gem_cleanup_ringbuffer(struct drm_device *dev); +int i915_gem_do_init(struct drm_device *dev, unsigned long start, + unsigned long end); #endif extern unsigned int i915_fbpercrtc; @@ -596,12 +601,6 @@ void i915_ring_validate(struct drm_device *dev, const char *func, int line); I915_WRITE(PRB0_TAIL, outring); \ } while(0) -#define BREADCRUMB_BITS 31 -#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) - -#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) -#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) - extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); /* @@ -713,7 +712,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define BREADCRUMB_BITS 31 #define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) -#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) +#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hws_vaddr))[5]) /** * Reads a dword out of the status page, which is written to from the command @@ -728,7 +727,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); * * The area from dword 0x10 to 0x3ff is available for driver usage. */ -#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) +#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hws_vaddr))[reg]) #define I915_GEM_HWS_INDEX 0x10 /* @@ -986,12 +985,6 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define ADPA_DPMS_STANDBY (2<<10) #define ADPA_DPMS_OFF (3<<10) -#define LP_RING 0x2030 -#define HP_RING 0x2040 -/* The binner has its own ring buffer: - */ -#define HWB_RING 0x2400 - #define RING_TAIL 0x00 #define TAIL_ADDR 0x001FFFF8 #define RING_HEAD 0x04 diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index ba02f485..3f310770 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -100,24 +100,11 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, return 0; } -int i915_load_modeset_init(struct drm_device *dev) +static int i915_init_hwstatus(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long agp_size, prealloc_size; - int size, ret = 0; - - i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); - printk("setting up %ld bytes of VRAM space\n", prealloc_size); - printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size)); - ret = i915_gem_init_ringbuffer(dev); - if (ret) - goto out; - - /* Allow hardware batchbuffers unless told otherwise. - */ - dev_priv->allow_batchbuffer = 1; - dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; - mutex_init(&dev_priv->cmdbuf_mutex); + struct drm_memrange_node *free_space; + int ret = 0; /* Program Hardware Status Page */ if (!IS_G33(dev)) { @@ -127,52 +114,105 @@ int i915_load_modeset_init(struct drm_device *dev) if (!dev_priv->status_page_dmah) { DRM_ERROR("Can not allocate hardware status page\n"); ret = -ENOMEM; - goto destroy_ringbuffer; + goto out; } - dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->hws_vaddr = dev_priv->status_page_dmah->vaddr; dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(HWS_PGA, dev_priv->dma_status_page); } else { - size = 4 * 1024; - ret = drm_buffer_object_create(dev, size, - drm_bo_type_kernel, - DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0x1, 0, - &dev_priv->hws_bo); - if (ret < 0) { + free_space = drm_memrange_search_free(&dev_priv->vram, + PAGE_SIZE, + PAGE_SIZE, 0); + if (!free_space) { + DRM_ERROR("No free vram available, aborting\n"); + ret = -ENOMEM; + goto out; + } + + dev_priv->hws = drm_memrange_get_block(free_space, PAGE_SIZE, + PAGE_SIZE); + if (!dev_priv->hws) { DRM_ERROR("Unable to allocate or pin hw status page\n"); ret = -EINVAL; - goto destroy_ringbuffer; + goto out; } - dev_priv->status_gfx_addr = - dev_priv->hws_bo->offset & (0x1ffff << 12); + dev_priv->hws_agpoffset = dev_priv->hws->start; dev_priv->hws_map.offset = dev->agp->base + - dev_priv->hws_bo->offset; - dev_priv->hws_map.size = size; + dev_priv->hws->start; + dev_priv->hws_map.size = PAGE_SIZE; dev_priv->hws_map.type= 0; dev_priv->hws_map.flags= 0; dev_priv->hws_map.mtrr = 0; drm_core_ioremap(&dev_priv->hws_map, dev); if (dev_priv->hws_map.handle == NULL) { - dev_priv->status_gfx_addr = 0; + dev_priv->hws_agpoffset = 0; DRM_ERROR("can not ioremap virtual addr for" "G33 hw status page\n"); ret = -ENOMEM; - goto destroy_hws; + goto out_free; } - dev_priv->hw_status_page = dev_priv->hws_map.handle; - memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); + dev_priv->hws_vaddr = dev_priv->hws_map.handle; + I915_WRITE(HWS_PGA, dev_priv->hws_agpoffset); } + + memset(dev_priv->hws_vaddr, 0, PAGE_SIZE); + DRM_DEBUG("Enabled hardware status page\n"); + return 0; + +out_free: + /* free hws */ +out: + return ret; +} + +static void i915_cleanup_hwstatus(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_G33(dev)) { + if (dev_priv->status_page_dmah) + drm_pci_free(dev, dev_priv->status_page_dmah); + } else { + if (dev_priv->hws_map.handle) + drm_core_ioremapfree(&dev_priv->hws_map, dev); + if (dev_priv->hws) + drm_memrange_put_block(dev_priv->hws); + } + I915_WRITE(HWS_PGA, 0x1ffff000); +} + +static int i915_load_modeset_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long agp_size, prealloc_size; + int ret = 0; + + i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); + + /* Basic memrange allocator for stolen space (aka vram) */ + drm_memrange_init(&dev_priv->vram, 0, prealloc_size); + /* Let GEM Manage from end of prealloc space to end of aperture */ + i915_gem_do_init(dev, prealloc_size, agp_size); + + ret = i915_gem_init_ringbuffer(dev); + if (ret) + goto out; + + ret = i915_init_hwstatus(dev); + if (ret) + goto destroy_ringbuffer; + + /* Allow hardware batchbuffers unless told otherwise. + */ + dev_priv->allow_batchbuffer = 1; + dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; + mutex_init(&dev_priv->cmdbuf_mutex); + dev_priv->wq = create_singlethread_workqueue("i915"); if (dev_priv->wq == 0) { DRM_DEBUG("Error\n"); @@ -208,22 +248,9 @@ modeset_cleanup: destroy_wq: destroy_workqueue(dev_priv->wq); destroy_hws: - if (!IS_G33(dev)) { - if (dev_priv->status_page_dmah) - drm_pci_free(dev, dev_priv->status_page_dmah); - } else { - if (dev_priv->hws_map.handle) - drm_core_ioremapfree(&dev_priv->hws_map, dev); - if (dev_priv->hws_bo) - drm_bo_usage_deref_unlocked(&dev_priv->hws_bo); - } - I915_WRITE(HWS_PGA, 0x1ffff000); + i915_cleanup_hwstatus(dev); destroy_ringbuffer: - if (dev_priv->ring.virtual_start) - drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, - dev_priv->ring.virtual_start); - if (dev_priv->ring_buffer) - drm_bo_usage_deref_unlocked(&dev_priv->ring_buffer); + i915_gem_cleanup_ringbuffer(dev); out: return ret; } @@ -318,26 +345,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) #endif if (drm_core_check_feature(dev, DRIVER_MODESET)) { - /* - * Initialize the memory manager for local and AGP space - */ - ret = drm_bo_driver_init(dev); - if (ret) { - DRM_ERROR("fail to init memory manager for " - "local & AGP space\n"); - goto out_rmmap; - } - ret = i915_load_modeset_init(dev); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); - goto driver_fini; + goto out_rmmap; } } return 0; -driver_fini: - drm_bo_driver_finish(dev); out_rmmap: drm_rmmap(dev, dev_priv->mmio_map); free_priv: @@ -362,6 +377,8 @@ int i915_driver_unload(struct drm_device *dev) drm_core_ioremapfree(&dev_priv->ring.map, dev); } #endif + +#ifdef DRI2 if (dev_priv->sarea_kmap.virtual) { drm_bo_kunmap(&dev_priv->sarea_kmap); dev_priv->sarea_kmap.virtual = NULL; @@ -374,44 +391,17 @@ int i915_driver_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); dev_priv->sarea_bo = NULL; } - - if (dev_priv->status_page_dmah) { - drm_pci_free(dev, dev_priv->status_page_dmah); - dev_priv->status_page_dmah = NULL; - dev_priv->hw_status_page = NULL; - dev_priv->dma_status_page = 0; - /* Need to rewrite hardware status page */ - I915_WRITE(HWS_PGA, 0x1ffff000); - } - - if (dev_priv->status_gfx_addr) { - dev_priv->status_gfx_addr = 0; - drm_core_ioremapfree(&dev_priv->hws_map, dev); - drm_bo_usage_deref_unlocked(&dev_priv->hws_bo); - I915_WRITE(HWS_PGA, 0x1ffff000); - } +#endif + i915_cleanup_hwstatus(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, - dev_priv->ring.virtual_start); - - DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage)); mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(&dev_priv->ring_buffer); - - if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { - DRM_ERROR("Memory manager type 3 not clean. " - "Delaying takedown\n"); - } - if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { - DRM_ERROR("Memory manager type 3 not clean. " - "Delaying takedown\n"); - } + i915_gem_cleanup_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); + drm_memrange_takedown(&dev_priv->vram); + i915_gem_lastclose(dev); } - drm_bo_driver_finish(dev); - #ifdef __linux__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) intel_init_chipset_flush_compat(dev); @@ -493,7 +483,7 @@ void i915_driver_lastclose(struct drm_device * dev) if (dev_priv->agp_heap) i915_mem_takedown(&(dev_priv->agp_heap)); -#if defined(I915_HAVE_BUFFER) +#if defined(DRI2) if (dev_priv->sarea_kmap.virtual) { drm_bo_kunmap(&dev_priv->sarea_kmap); dev_priv->sarea_kmap.virtual = NULL; @@ -516,7 +506,8 @@ int i915_driver_firstopen(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; - +#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) drm_bo_driver_init(dev); +#endif return 0; } -- cgit v1.2.3 From 7010d500072977f63a0bac08f2141d69dbd19595 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Jun 2008 13:57:39 -0700 Subject: i915: switch back to fbcon on panic Normally when X is running, panic messages will be invisible and the machine will just appear to hard hang. This patch adds support for switching back to the fbcon framebuffer on panic (through the use of a panic notifier registration) so we can see what happened. Note that in order to be really useful, X will have to run its VT in something other than KD_GRAPHICS mode. Also, not all kernel errors result in panics, some go through BUG() which may trigger another type of event, not resulting in a switch. --- linux-core/intel_fb.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 856ec868..64a8fc94 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -581,6 +581,22 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) } EXPORT_SYMBOL(intelfb_resize); +static struct drm_mode_set panic_mode; + +int intelfb_panic(struct notifier_block *n, unsigned long ununsed, + void *panic_str) +{ + DRM_ERROR("panic occurred, switching back to text console\n"); + drm_crtc_helper_set_config(&panic_mode); + + return 0; +} +EXPORT_SYMBOL(intelfb_panic); + +static struct notifier_block paniced = { + .notifier_call = intelfb_panic, +}; + int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, uint32_t surface_width, uint32_t surface_height, struct intel_framebuffer **intel_fb_p) @@ -831,6 +847,12 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc * printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); + + /* Switch back to kernel console on panic */ + panic_mode = *modeset; + atomic_notifier_chain_register(&panic_notifier_list, &paniced); + printk(KERN_INFO "registered panic notifier\n"); + return 0; } @@ -952,6 +974,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev) printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); + + /* Switch back to kernel console on panic */ + panic_mode = *modeset; + atomic_notifier_chain_register(&panic_notifier_list, &paniced); + printk(KERN_INFO "registered panic notifier\n"); + return 0; } @@ -1005,6 +1033,9 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) drm_bo_usage_deref_unlocked(&intel_fb->bo); framebuffer_release(info); } + + atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); + memset(&panic_mode, 0, sizeof(struct drm_mode_set)); return 0; } EXPORT_SYMBOL(intelfb_remove); -- cgit v1.2.3 From c843d47b906e57fb3002af4a609d3cb95c5e195d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Jun 2008 14:51:46 -0700 Subject: i915: use WC mapping for framebuffer screen_base --- linux-core/intel_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index b082080c..16788411 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -677,8 +677,8 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height info->flags = FBINFO_DEFAULT; - info->screen_base = ioremap(dev->agp->base + obj_priv->gtt_offset, - size); + info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset, + size); if (!info->screen_base) { ret = -ENOSPC; goto out_unref; -- cgit v1.2.3 From 57b8837b4eb3b4972390680ad8042cd6920bf003 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Jun 2008 15:31:48 -0700 Subject: i915: cleanup PCI state before disabling MSI Core MSI code will BUG() if an interrupt handler is still registered when pci_disable_msi() is called. --- linux-core/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 1817c964..2b8ee774 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -656,9 +656,9 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) } static void remove(struct pci_dev *pdev) { + drm_cleanup_pci(pdev); if (pdev->msi_enabled) pci_disable_msi(pdev); - drm_cleanup_pci(pdev); } static int __init i915_init(void) -- cgit v1.2.3 From f58e21c7d056017340dc0ecac7e53dee2b33fe3b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 18 Jun 2008 16:49:51 -0700 Subject: i915: add blanking support to intelfb Got tired of not having my LCD actually turn off when I left the machine at the console. --- linux-core/intel_fb.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 16788411..0780aae7 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -525,6 +525,92 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, return ret; } +static void intelfb_on(struct fb_info *info) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int i; + + /* + * For each CRTC in this fb, find all associated encoders + * and turn them off, then turn off the CRTC. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + crtc_funcs->dpms(crtc, DPMSModeOn); + + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, DPMSModeOn); + } + } + } +} + +static void intelfb_off(struct fb_info *info, int dpms_mode) +{ + struct intelfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int i; + + /* + * For each CRTC in this fb, find all associated encoders + * and turn them off, then turn off the CRTC. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, dpms_mode); + } + } + if (dpms_mode == DPMSModeOff) + crtc_funcs->dpms(crtc, dpms_mode); + } +} + +int intelfb_blank(int blank, struct fb_info *info) +{ + switch (blank) { + case FB_BLANK_UNBLANK: + intelfb_on(info); + break; + case FB_BLANK_NORMAL: + intelfb_off(info, DPMSModeStandby); + break; + case FB_BLANK_HSYNC_SUSPEND: + intelfb_off(info, DPMSModeStandby); + break; + case FB_BLANK_VSYNC_SUSPEND: + intelfb_off(info, DPMSModeSuspend); + break; + case FB_BLANK_POWERDOWN: + intelfb_off(info, DPMSModeOff); + break; + } + return 0; +} + static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, //.fb_open = intelfb_open, @@ -539,6 +625,7 @@ static struct fb_ops intelfb_ops = { .fb_copyarea = cfb_copyarea, //intelfb_copyarea, .fb_imageblit = cfb_imageblit, //intelfb_imageblit, .fb_pan_display = intelfb_pan_display, + .fb_blank = intelfb_blank, }; /** -- cgit v1.2.3 From 473a1997ace1a9fb545d0457549e50d17eb36175 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 16:29:00 +0200 Subject: NV50: Initial import of kernel modesetting. --- linux-core/Makefile | 2 +- linux-core/Makefile.kernel | 5 +- linux-core/drm_crtc.c | 1 + linux-core/drm_crtc.h | 1 + linux-core/drm_edid.c | 34 +- linux-core/drm_modes.c | 5 +- linux-core/nouveau_bios.c | 815 +++++++++++++++++++++++++++++++ linux-core/nouveau_bios.h | 151 ++++++ linux-core/nouveau_drv.c | 7 + linux-core/nv50_connector.c | 207 ++++++++ linux-core/nv50_connector.h | 60 +++ linux-core/nv50_crtc.c | 515 ++++++++++++++++++++ linux-core/nv50_crtc.h | 67 +++ linux-core/nv50_cursor.c | 177 +++++++ linux-core/nv50_cursor.h | 51 ++ linux-core/nv50_dac.c | 177 +++++++ linux-core/nv50_display.c | 337 +++++++++++++ linux-core/nv50_display.h | 83 ++++ linux-core/nv50_display_commands.h | 196 ++++++++ linux-core/nv50_fb.c | 136 ++++++ linux-core/nv50_fb.h | 55 +++ linux-core/nv50_i2c.c | 356 ++++++++++++++ linux-core/nv50_i2c.h | 47 ++ linux-core/nv50_kms_wrapper.c | 960 +++++++++++++++++++++++++++++++++++++ linux-core/nv50_kms_wrapper.h | 94 ++++ linux-core/nv50_lut.c | 171 +++++++ linux-core/nv50_lut.h | 45 ++ linux-core/nv50_output.c | 33 ++ linux-core/nv50_output.h | 60 +++ linux-core/nv50_sor.c | 204 ++++++++ shared-core/nouveau_dma.h | 5 + shared-core/nouveau_drv.h | 26 + shared-core/nouveau_irq.c | 80 +++- shared-core/nouveau_mem.c | 11 + shared-core/nouveau_reg.h | 298 ++++++++++++ shared-core/nouveau_state.c | 50 +- 36 files changed, 5503 insertions(+), 19 deletions(-) create mode 100644 linux-core/nouveau_bios.c create mode 100644 linux-core/nouveau_bios.h create mode 100644 linux-core/nv50_connector.c create mode 100644 linux-core/nv50_connector.h create mode 100644 linux-core/nv50_crtc.c create mode 100644 linux-core/nv50_crtc.h create mode 100644 linux-core/nv50_cursor.c create mode 100644 linux-core/nv50_cursor.h create mode 100644 linux-core/nv50_dac.c create mode 100644 linux-core/nv50_display.c create mode 100644 linux-core/nv50_display.h create mode 100644 linux-core/nv50_display_commands.h create mode 100644 linux-core/nv50_fb.c create mode 100644 linux-core/nv50_fb.h create mode 100644 linux-core/nv50_i2c.c create mode 100644 linux-core/nv50_i2c.h create mode 100644 linux-core/nv50_kms_wrapper.c create mode 100644 linux-core/nv50_kms_wrapper.h create mode 100644 linux-core/nv50_lut.c create mode 100644 linux-core/nv50_lut.h create mode 100644 linux-core/nv50_output.c create mode 100644 linux-core/nv50_output.h create mode 100644 linux-core/nv50_sor.c diff --git a/linux-core/Makefile b/linux-core/Makefile index b9405bbb..9b288851 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -90,7 +90,7 @@ VIAHEADERS = via_drm.h via_drv.h via_3d_reg.h via_verifier.h $(DRMHEADERS) MACH64HEADERS = mach64_drv.h mach64_drm.h $(DRMHEADERS) NVHEADERS = nv_drv.h $(DRMHEADERS) FFBHEADERS = ffb_drv.h $(DRMHEADERS) -NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS) +NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h nouveau_display.h $(DRMHEADERS) XGIHEADERS = xgi_cmdlist.h xgi_drv.h xgi_misc.h xgi_regs.h $(DRMHEADERS) RADEONMSHEADERS = radeon_ms_driver.h $(DRMHEADERS) diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index ac9baf02..23430140 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -35,7 +35,10 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o \ nv40_graph.o nv50_graph.o \ - nv04_instmem.o nv50_instmem.o + nv04_instmem.o nv50_instmem.o \ + nouveau_bios.o \ + nv50_crtc.o nv50_cursor.o nv50_lut.o nv50_fb.o nv50_output.o nv50_sor.o nv50_dac.o nv50_connector.o nv50_i2c.o nv50_display.o \ + nv50_kms_wrapper.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e1b371cc..c8cfaef4 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -100,6 +100,7 @@ char *drm_get_connector_name(struct drm_connector *connector) connector->connector_type_id); return buf; } +EXPORT_SYMBOL(drm_get_connector_name); char *drm_get_connector_status_name(enum drm_connector_status status) { diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 2b577b93..d6fa4cca 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -619,6 +619,7 @@ extern void drm_fb_release(struct file *filp); extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); +extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter); extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 0d600396..812e64a6 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -122,19 +122,30 @@ static bool edid_is_valid(struct edid *edid) if (memcmp(edid->header, edid_header, sizeof(edid_header))) goto bad; - if (edid->version != 1) + if (edid->version != 1) { + DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); goto bad; - if (edid->revision <= 0 || edid->revision > 3) + } + if (edid->revision <= 0 || edid->revision > 3) { + DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision); goto bad; + } for (i = 0; i < EDID_LENGTH; i++) csum += raw_edid[i]; - if (csum) + if (csum) { + DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum); goto bad; + } return 1; bad: + if (raw_edid) { + DRM_ERROR("Raw EDID:\n"); + print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH); + printk("\n"); + } return 0; } @@ -545,7 +556,7 @@ static int add_detailed_info(struct drm_connector *connector, #define DDC_ADDR 0x50 -static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) +unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) { unsigned char start = 0x0; unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); @@ -576,6 +587,7 @@ static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) kfree(buf); return NULL; } +EXPORT_SYMBOL(drm_do_probe_ddc_edid); static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) { @@ -589,15 +601,15 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) * Then set clock & data low */ algo_data->setscl(algo_data->data, 1); - udelay(550); /* startup delay */ - algo_data->setscl(algo_data->data, 0); - algo_data->setsda(algo_data->data, 0); + //udelay(550); /* startup delay */ + //algo_data->setscl(algo_data->data, 0); + //algo_data->setsda(algo_data->data, 0); for (i = 0; i < 3; i++) { /* For some old monitors we need the * following process to initialize/stop DDC */ - algo_data->setsda(algo_data->data, 0); + algo_data->setsda(algo_data->data, 1); msleep(13); algo_data->setscl(algo_data->data, 1); @@ -632,16 +644,16 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) algo_data->setsda(algo_data->data, 1); msleep(15); algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 0); if (edid) break; } /* Release the DDC lines when done or the Apple Cinema HD display * will switch off */ - algo_data->setsda(algo_data->data, 0); - algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 1); algo_data->setscl(algo_data->data, 1); - + return edid; } diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 3ed427fb..df670c74 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -89,6 +89,7 @@ void drm_mode_list_concat(struct list_head *head, struct list_head *new) list_move_tail(entry, new); } } +EXPORT_SYMBOL(drm_mode_list_concat); /** * drm_mode_width - get the width of a mode @@ -401,6 +402,7 @@ void drm_mode_prune_invalid(struct drm_device *dev, } } } +EXPORT_SYMBOL(drm_mode_prune_invalid); /** * drm_mode_compare - compare modes for favorability @@ -525,7 +527,7 @@ void drm_mode_sort(struct list_head *mode_list) { list_sort(mode_list, drm_mode_compare); } - +EXPORT_SYMBOL(drm_mode_sort); /** * drm_mode_connector_list_update - update the mode list for the connector @@ -564,3 +566,4 @@ void drm_mode_connector_list_update(struct drm_connector *connector) } } } +EXPORT_SYMBOL(drm_mode_connector_list_update); diff --git a/linux-core/nouveau_bios.c b/linux-core/nouveau_bios.c new file mode 100644 index 00000000..83647418 --- /dev/null +++ b/linux-core/nouveau_bios.c @@ -0,0 +1,815 @@ +/* + * Copyright (C) 2005-2006 Erik Waling + * Copyright (C) 2006 Stephane Marchesin + * Copyright (C) 2007-2008 Stuart Bennett + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include "nouveau_bios.h" +#include "nouveau_drv.h" + +/* returns true if it mismatches */ +static bool nv_checksum(const uint8_t *data, unsigned int length) +{ + /* there's a few checksums in the BIOS, so here's a generic checking function */ + int i; + uint8_t sum = 0; + + for (i = 0; i < length; i++) + sum += data[i]; + + if (sum) + return true; + + return false; +} + +static int nv_valid_bios(struct drm_device *dev, uint8_t *data) +{ + /* check for BIOS signature */ + if (!(data[0] == 0x55 && data[1] == 0xAA)) { + DRM_ERROR("BIOS signature not found.\n"); + return 0; + } + + if (nv_checksum(data, data[2] * 512)) { + DRM_ERROR("BIOS checksum invalid.\n"); + return 1; + } + + return 2; +} + +static void nv_shadow_bios_rom(struct drm_device *dev, uint8_t *data) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int i; + + /* enable access to rom */ + NV_WRITE(NV04_PBUS_PCI_NV_20, NV04_PBUS_PCI_NV_20_ROM_SHADOW_DISABLED); + + /* This is also valid for pre-NV50, it just happened to be the only define already present. */ + for (i=0; i < NV50_PROM__ESIZE; i++) { + /* Appearantly needed for a 6600GT/6800LE bug. */ + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + } + + /* disable access to rom */ + NV_WRITE(NV04_PBUS_PCI_NV_20, NV04_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED); +} + +static void nv_shadow_bios_ramin(struct drm_device *dev, uint8_t *data) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t old_bar0_pramin = 0; + int i; + + /* Move the bios copy to the start of ramin? */ + if (dev_priv->card_type >= NV_50) { + uint32_t vbios_vram = (NV_READ(0x619f04) & ~0xff) << 8; + + if (!vbios_vram) + vbios_vram = (NV_READ(0x1700) << 16) + 0xf0000; + + old_bar0_pramin = NV_READ(0x1700); + NV_WRITE(0x1700, vbios_vram >> 16); + } + + for (i=0; i < NV50_PROM__ESIZE; i++) + data[i] = DRM_READ8(dev_priv->mmio, NV04_PRAMIN + i); + + if (dev_priv->card_type >= NV_50) + NV_WRITE(0x1700, old_bar0_pramin); +} + +static bool nv_shadow_bios(struct drm_device *dev, uint8_t *data) +{ + nv_shadow_bios_rom(dev, data); + if (nv_valid_bios(dev, data) == 2) + return true; + + nv_shadow_bios_ramin(dev, data); + if (nv_valid_bios(dev, data)) + return true; + + return false; +} + +struct bit_entry { + uint8_t id[2]; + uint16_t length; + uint16_t offset; +}; + +static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry) +{ + /* offset + 8 (16 bits): PLL limits table pointer + * + * There's more in here, but that's unknown. + */ + + if (bitentry->length < 10) { + DRM_ERROR( "Do not understand BIT C table\n"); + return 0; + } + + bios->pll_limit_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 8]))); + + return 1; +} + +static void parse_bit_structure(struct drm_device *dev, struct bios *bios, const uint16_t bitoffset) +{ + int entries = bios->data[bitoffset + 4]; + /* parse i first, I next (which needs C & M before it), and L before D */ + char parseorder[] = "iCMILDT"; + struct bit_entry bitentry; + int i, j, offset; + + for (i = 0; i < sizeof(parseorder); i++) { + for (j = 0, offset = bitoffset + 6; j < entries; j++, offset += 6) { + bitentry.id[0] = bios->data[offset]; + bitentry.id[1] = bios->data[offset + 1]; + bitentry.length = le16_to_cpu(*((uint16_t *)&bios->data[offset + 2])); + bitentry.offset = le16_to_cpu(*((uint16_t *)&bios->data[offset + 4])); + + if (bitentry.id[0] != parseorder[i]) + continue; + + switch (bitentry.id[0]) { + case 'C': + parse_bit_C_tbl_entry(dev, bios, &bitentry); + break; + } + } + } +} + +static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len) +{ + int i, j; + + for (i = 0; i <= (n - len); i++) { + for (j = 0; j < len; j++) + if (data[i + j] != str[j]) + break; + if (j == len) + return i; + } + + return 0; +} + +static void +read_dcb_i2c_entry(struct drm_device *dev, uint8_t dcb_version, uint16_t i2ctabptr, int index) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct bios *bios = &dev_priv->bios; + uint8_t *i2ctable = &bios->data[i2ctabptr]; + uint8_t headerlen = 0; + int i2c_entries = MAX_NUM_DCB_ENTRIES; + int recordoffset = 0, rdofs = 1, wrofs = 0; + + if (!i2ctabptr) + return; + + if (dcb_version >= 0x30) { + if (i2ctable[0] != dcb_version) /* necessary? */ + DRM_ERROR( + "DCB I2C table version mismatch (%02X vs %02X)\n", + i2ctable[0], dcb_version); + headerlen = i2ctable[1]; + i2c_entries = i2ctable[2]; + + /* same address offset used for read and write for C51 and G80 */ + if (bios->chip_version == 0x51) + rdofs = wrofs = 1; + if (i2ctable[0] >= 0x40) + rdofs = wrofs = 0; + } + /* it's your own fault if you call this function on a DCB 1.1 BIOS -- + * the test below is for DCB 1.2 + */ + if (dcb_version < 0x14) { + recordoffset = 2; + rdofs = 0; + wrofs = 1; + } + + if (index == 0xf) + return; + if (index > i2c_entries) { + DRM_ERROR( + "DCB I2C index too big (%d > %d)\n", + index, i2ctable[2]); + return; + } + if (i2ctable[headerlen + 4 * index + 3] == 0xff) { + DRM_ERROR( + "DCB I2C entry invalid\n"); + return; + } + + if (bios->chip_version == 0x51) { + int port_type = i2ctable[headerlen + 4 * index + 3]; + + if (port_type != 4) + DRM_ERROR( + "DCB I2C table has port type %d\n", port_type); + } + if (i2ctable[0] >= 0x40) { + int port_type = i2ctable[headerlen + 4 * index + 3]; + + if (port_type != 5) + DRM_ERROR( + "DCB I2C table has port type %d\n", port_type); + } + + dev_priv->dcb_table.i2c_read[index] = i2ctable[headerlen + recordoffset + rdofs + 4 * index]; + dev_priv->dcb_table.i2c_write[index] = i2ctable[headerlen + recordoffset + wrofs + 4 * index]; +} + +static bool +parse_dcb_entry(struct drm_device *dev, int index, uint8_t dcb_version, uint16_t i2ctabptr, uint32_t conn, uint32_t conf) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_entry *entry = &dev_priv->dcb_table.entry[index]; + + memset(entry, 0, sizeof (struct dcb_entry)); + + entry->index = index; + /* safe defaults for a crt */ + entry->type = 0; + entry->i2c_index = 0; + entry->heads = 1; + entry->bus = 0; + entry->location = LOC_ON_CHIP; + entry->or = 1; + entry->duallink_possible = false; + + if (dcb_version >= 0x20) { + entry->type = conn & 0xf; + entry->i2c_index = (conn >> 4) & 0xf; + entry->heads = (conn >> 8) & 0xf; + entry->bus = (conn >> 16) & 0xf; + entry->location = (conn >> 20) & 0xf; + entry->or = (conn >> 24) & 0xf; + /* Normal entries consist of a single bit, but dual link has the + * adjacent more significant bit set too + */ + if ((1 << (ffs(entry->or) - 1)) * 3 == entry->or) + entry->duallink_possible = true; + + switch (entry->type) { + case DCB_OUTPUT_LVDS: + { + uint32_t mask; + if (conf & 0x1) + entry->lvdsconf.use_straps_for_mode = true; + if (dcb_version < 0x22) { + mask = ~0xd; + /* both 0x4 and 0x8 show up in v2.0 tables; assume they mean + * the same thing, which is probably wrong, but might work */ + if (conf & 0x4 || conf & 0x8) + entry->lvdsconf.use_power_scripts = true; + } else { + mask = ~0x5; + if (conf & 0x4) + entry->lvdsconf.use_power_scripts = true; + } + if (conf & mask) { + DRM_ERROR( + "Unknown LVDS configuration bits, please report\n"); + /* cause output setting to fail, so message is seen */ + dev_priv->dcb_table.entries = 0; + return false; + } + break; + } + case 0xe: + /* weird type that appears on g80 mobile bios; nv driver treats it as a terminator */ + return false; + } + read_dcb_i2c_entry(dev, dcb_version, i2ctabptr, entry->i2c_index); + } else if (dcb_version >= 0x14 ) { + if (conn != 0xf0003f00 && conn != 0xf2247f10 && conn != 0xf2204001 && conn != 0xf2204301 && conn != 0xf2244311 && conn != 0xf2045f14 && conn != 0xf2205004 && conn != 0xf2208001 && conn != 0xf4204011 && conn != 0xf4208011 && conn != 0xf4248011) { + DRM_ERROR( + "Unknown DCB 1.4 / 1.5 entry, please report\n"); + /* cause output setting to fail, so message is seen */ + dev_priv->dcb_table.entries = 0; + return false; + } + /* most of the below is a "best guess" atm */ + entry->type = conn & 0xf; + if (entry->type == 4) { /* digital */ + if (conn & 0x10) + entry->type = DCB_OUTPUT_LVDS; + else + entry->type = DCB_OUTPUT_TMDS; + } + /* what's in bits 5-13? could be some brooktree/chrontel/philips thing, in tv case */ + entry->i2c_index = (conn >> 14) & 0xf; + /* raw heads field is in range 0-1, so move to 1-2 */ + entry->heads = ((conn >> 18) & 0x7) + 1; + entry->location = (conn >> 21) & 0xf; + entry->bus = (conn >> 25) & 0x7; + /* set or to be same as heads -- hopefully safe enough */ + entry->or = entry->heads; + + switch (entry->type) { + case DCB_OUTPUT_LVDS: + /* this is probably buried in conn's unknown bits */ + entry->lvdsconf.use_power_scripts = true; + break; + case DCB_OUTPUT_TMDS: + /* invent a DVI-A output, by copying the fields of the DVI-D output + * reported to work by math_b on an NV20(!) */ + memcpy(&entry[1], &entry[0], sizeof(struct dcb_entry)); + entry[1].type = DCB_OUTPUT_ANALOG; + dev_priv->dcb_table.entries++; + } + read_dcb_i2c_entry(dev, dcb_version, i2ctabptr, entry->i2c_index); + } else if (dcb_version >= 0x12) { + /* v1.2 tables normally have the same 5 entries, which are not + * specific to the card, so use the defaults for a crt */ + /* DCB v1.2 does have an I2C table that read_dcb_i2c_table can handle, but cards + * exist (seen on nv11) where the pointer to the table points to the wrong + * place, so for now, we rely on the indices parsed in parse_bmp_structure + */ + entry->i2c_index = dev_priv->bios.legacy.i2c_indices.crt; + } else { /* pre DCB / v1.1 - use the safe defaults for a crt */ + DRM_ERROR( + "No information in BIOS output table; assuming a CRT output exists\n"); + entry->i2c_index = dev_priv->bios.legacy.i2c_indices.crt; + } + + if (entry->type == DCB_OUTPUT_LVDS && dev_priv->bios.fp.strapping != 0xff) + entry->lvdsconf.use_straps_for_mode = true; + + dev_priv->dcb_table.entries++; + + return true; +} + +static void merge_like_dcb_entries(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + /* DCB v2.0 lists each output combination separately. + * Here we merge compatible entries to have fewer outputs, with more options + */ + int i, newentries = 0; + + for (i = 0; i < dev_priv->dcb_table.entries; i++) { + struct dcb_entry *ient = &dev_priv->dcb_table.entry[i]; + int j; + + for (j = i + 1; j < dev_priv->dcb_table.entries; j++) { + struct dcb_entry *jent = &dev_priv->dcb_table.entry[j]; + + if (jent->type == 100) /* already merged entry */ + continue; + + /* merge heads field when all other fields the same */ + if (jent->i2c_index == ient->i2c_index && jent->type == ient->type && jent->location == ient->location && jent->or == ient->or) { + DRM_INFO( + "Merging DCB entries %d and %d\n", i, j); + ient->heads |= jent->heads; + jent->type = 100; /* dummy value */ + } + } + } + + /* Compact entries merged into others out of dcb_table */ + for (i = 0; i < dev_priv->dcb_table.entries; i++) { + if ( dev_priv->dcb_table.entry[i].type == 100 ) + continue; + + if (newentries != i) + memcpy(&dev_priv->dcb_table.entry[newentries], &dev_priv->dcb_table.entry[i], sizeof(struct dcb_entry)); + newentries++; + } + + dev_priv->dcb_table.entries = newentries; +} + +static unsigned int parse_dcb_table(struct drm_device *dev, struct bios *bios) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint16_t dcbptr, i2ctabptr = 0; + uint8_t *dcbtable; + uint8_t dcb_version, headerlen = 0x4, entries = MAX_NUM_DCB_ENTRIES; + bool configblock = true; + int recordlength = 8, confofs = 4; + int i; + + dev_priv->dcb_table.entries = 0; + + /* get the offset from 0x36 */ + dcbptr = le16_to_cpu(*(uint16_t *)&bios->data[0x36]); + + if (dcbptr == 0x0) { + DRM_ERROR( + "No Display Configuration Block pointer found\n"); + /* this situation likely means a really old card, pre DCB, so we'll add the safe CRT entry */ + parse_dcb_entry(dev, 0, 0, 0, 0, 0); + return 1; + } + + dcbtable = &bios->data[dcbptr]; + + /* get DCB version */ + dcb_version = dcbtable[0]; + DRM_INFO( + "Display Configuration Block version %d.%d found\n", + dcb_version >> 4, dcb_version & 0xf); + + if (dcb_version >= 0x20) { /* NV17+ */ + uint32_t sig; + + if (dcb_version >= 0x30) { /* NV40+ */ + headerlen = dcbtable[1]; + entries = dcbtable[2]; + recordlength = dcbtable[3]; + i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[4]); + sig = le32_to_cpu(*(uint32_t *)&dcbtable[6]); + + DRM_INFO( + "DCB header length %d, with %d possible entries\n", + headerlen, entries); + } else { + i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]); + sig = le32_to_cpu(*(uint32_t *)&dcbtable[4]); + headerlen = 8; + } + + if (sig != 0x4edcbdcb) { + DRM_ERROR( + "Bad Display Configuration Block signature (%08X)\n", sig); + return 0; + } + } else if (dcb_version >= 0x14) { /* some NV15/16, and NV11+ */ + char sig[8]; + + memset(sig, 0, 8); + strncpy(sig, (char *)&dcbtable[-7], 7); + i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]); + recordlength = 10; + confofs = 6; + + if (strcmp(sig, "DEV_REC")) { + DRM_ERROR( + "Bad Display Configuration Block signature (%s)\n", sig); + return 0; + } + } else if (dcb_version >= 0x12) { /* some NV6/10, and NV15+ */ + i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]); + configblock = false; + } else { /* NV5+, maybe NV4 */ + /* DCB 1.1 seems to be quite unhelpful - we'll just add the safe CRT entry */ + parse_dcb_entry(dev, 0, dcb_version, 0, 0, 0); + return 1; + } + + if (entries >= MAX_NUM_DCB_ENTRIES) + entries = MAX_NUM_DCB_ENTRIES; + + for (i = 0; i < entries; i++) { + uint32_t connection, config = 0; + + connection = le32_to_cpu(*(uint32_t *)&dcbtable[headerlen + recordlength * i]); + if (configblock) + config = le32_to_cpu(*(uint32_t *)&dcbtable[headerlen + confofs + recordlength * i]); + + /* Should we allow discontinuous DCBs? Certainly DCB I2C tables can be discontinuous */ + if ((connection & 0x0000000f) == 0x0000000f) /* end of records */ + break; + if (connection == 0x00000000) /* seen on an NV11 with DCB v1.5 */ + break; + + DRM_INFO("Raw DCB entry %d: %08x %08x\n", i, connection, config); + if (!parse_dcb_entry(dev, dev_priv->dcb_table.entries, dcb_version, i2ctabptr, connection, config)) + break; + } + + merge_like_dcb_entries(dev); + + return dev_priv->dcb_table.entries; +} + +int nouveau_parse_bios(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + const uint8_t bit_signature[] = { 'B', 'I', 'T' }; + int offset; + + dev_priv->bios.data = kzalloc(NV50_PROM__ESIZE, GFP_KERNEL); + + if (!nv_shadow_bios(dev, dev_priv->bios.data)) + return -EINVAL; + + dev_priv->bios.length = dev_priv->bios.data[2] * 512; + if (dev_priv->bios.length > NV50_PROM__ESIZE) + dev_priv->bios.length = NV50_PROM__ESIZE; + + if ((offset = findstr(dev_priv->bios.data, dev_priv->bios.length, bit_signature, sizeof(bit_signature)))) { + DRM_INFO("BIT BIOS found\n"); + parse_bit_structure(dev, &dev_priv->bios, offset + 4); + } else { + DRM_ERROR("BIT BIOS not found\n"); + return -EINVAL; + } + + if (parse_dcb_table(dev, &dev_priv->bios)) + DRM_INFO("Found %d entries in DCB\n", dev_priv->dcb_table.entries); + + return 0; +} + +/* temporary */ +#define NV_RAMDAC_NVPLL 0x00680500 +#define NV_RAMDAC_MPLL 0x00680504 +#define NV_RAMDAC_VPLL 0x00680508 +# define NV_RAMDAC_PLL_COEFF_MDIV 0x000000FF +# define NV_RAMDAC_PLL_COEFF_NDIV 0x0000FF00 +# define NV_RAMDAC_PLL_COEFF_PDIV 0x00070000 +# define NV30_RAMDAC_ENABLE_VCO2 (1 << 7) +#define NV_RAMDAC_VPLL2 0x00680520 + +bool get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim) +{ + /* PLL limits table + * + * Version 0x10: NV31 + * One byte header (version), one record of 24 bytes + * Version 0x11: NV36 - Not implemented + * Seems to have same record style as 0x10, but 3 records rather than 1 + * Version 0x20: Found on Geforce 6 cards + * Trivial 4 byte BIT header. 31 (0x1f) byte record length + * Version 0x21: Found on Geforce 7, 8 and some Geforce 6 cards + * 5 byte header, fifth byte of unknown purpose. 35 (0x23) byte record + * length in general, some (integrated) have an extra configuration byte + */ + + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct bios *bios = &dev_priv->bios; + uint8_t pll_lim_ver = 0, headerlen = 0, recordlen = 0, entries = 0; + int pllindex = 0; + uint32_t crystal_strap_mask, crystal_straps; + + if (!bios->pll_limit_tbl_ptr) { + if (bios->chip_version >= 0x40 || bios->chip_version == 0x31 || bios->chip_version == 0x36) { + DRM_ERROR("Pointer to PLL limits table invalid\n"); + return false; + } + } else { + pll_lim_ver = bios->data[bios->pll_limit_tbl_ptr]; + + DRM_INFO("Found PLL limits table version 0x%X\n", pll_lim_ver); + } + + crystal_strap_mask = 1 << 6; + /* open coded pNv->twoHeads test */ + if (bios->chip_version > 0x10 && bios->chip_version != 0x15 && + bios->chip_version != 0x1a && bios->chip_version != 0x20) + crystal_strap_mask |= 1 << 22; + crystal_straps = NV_READ(NV50_PEXTDEV + 0x0) & crystal_strap_mask; + + switch (pll_lim_ver) { + /* we use version 0 to indicate a pre limit table bios (single stage pll) + * and load the hard coded limits instead */ + case 0: + break; + case 0x10: + case 0x11: /* strictly v0x11 has 3 entries, but the last two don't seem to get used */ + headerlen = 1; + recordlen = 0x18; + entries = 1; + pllindex = 0; + break; + case 0x20: + case 0x21: + headerlen = bios->data[bios->pll_limit_tbl_ptr + 1]; + recordlen = bios->data[bios->pll_limit_tbl_ptr + 2]; + entries = bios->data[bios->pll_limit_tbl_ptr + 3]; + break; + default: + DRM_ERROR("PLL limits table revision not currently supported\n"); + return false; + } + + /* initialize all members to zero */ + memset(pll_lim, 0, sizeof(struct pll_lims)); + + if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) { + uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex; + + pll_lim->vco1.minfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs]))); + pll_lim->vco1.maxfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 4]))); + pll_lim->vco2.minfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 8]))); + pll_lim->vco2.maxfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 12]))); + pll_lim->vco1.min_inputfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 16]))); + pll_lim->vco2.min_inputfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 20]))); + pll_lim->vco1.max_inputfreq = pll_lim->vco2.max_inputfreq = INT_MAX; + + /* these values taken from nv30/31/36 */ + pll_lim->vco1.min_n = 0x1; + if (bios->chip_version == 0x36) + pll_lim->vco1.min_n = 0x5; + pll_lim->vco1.max_n = 0xff; + pll_lim->vco1.min_m = 0x1; + pll_lim->vco1.max_m = 0xd; + pll_lim->vco2.min_n = 0x4; + /* on nv30, 31, 36 (i.e. all cards with two stage PLLs with this + * table version (apart from nv35)), N2 is compared to + * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and + * save a comparison + */ + pll_lim->vco2.max_n = 0x28; + if (bios->chip_version == 0x30 || bios->chip_version == 0x35) + /* only 5 bits available for N2 on nv30/35 */ + pll_lim->vco2.max_n = 0x1f; + pll_lim->vco2.min_m = 0x1; + pll_lim->vco2.max_m = 0x4; + } else if (pll_lim_ver) { /* ver 0x20, 0x21 */ + uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen; + uint32_t reg = 0; /* default match */ + int i; + + /* first entry is default match, if nothing better. warn if reg field nonzero */ + if (le32_to_cpu(*((uint32_t *)&bios->data[plloffs]))) + DRM_ERROR("Default PLL limit entry has non-zero register field\n"); + + if (limit_match > MAX_PLL_TYPES) + /* we've been passed a reg as the match */ + reg = limit_match; + else /* limit match is a pll type */ + for (i = 1; i < entries && !reg; i++) { + uint32_t cmpreg = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + recordlen * i]))); + + if (limit_match == NVPLL && (cmpreg == NV_RAMDAC_NVPLL || cmpreg == 0x4000)) + reg = cmpreg; + if (limit_match == MPLL && (cmpreg == NV_RAMDAC_MPLL || cmpreg == 0x4020)) + reg = cmpreg; + if (limit_match == VPLL1 && (cmpreg == NV_RAMDAC_VPLL || cmpreg == 0x4010)) + reg = cmpreg; + if (limit_match == VPLL2 && (cmpreg == NV_RAMDAC_VPLL2 || cmpreg == 0x4018)) + reg = cmpreg; + } + + for (i = 1; i < entries; i++) + if (le32_to_cpu(*((uint32_t *)&bios->data[plloffs + recordlen * i])) == reg) { + pllindex = i; + break; + } + + plloffs += recordlen * pllindex; + + DRM_INFO("Loading PLL limits for reg 0x%08x\n", pllindex ? reg : 0); + + /* frequencies are stored in tables in MHz, kHz are more useful, so we convert */ + + /* What output frequencies can each VCO generate? */ + pll_lim->vco1.minfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 4]))) * 1000; + pll_lim->vco1.maxfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 6]))) * 1000; + pll_lim->vco2.minfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 8]))) * 1000; + pll_lim->vco2.maxfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 10]))) * 1000; + + /* What input frequencies do they accept (past the m-divider)? */ + pll_lim->vco1.min_inputfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 12]))) * 1000; + pll_lim->vco2.min_inputfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 14]))) * 1000; + pll_lim->vco1.max_inputfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 16]))) * 1000; + pll_lim->vco2.max_inputfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 18]))) * 1000; + + /* What values are accepted as multiplier and divider? */ + pll_lim->vco1.min_n = bios->data[plloffs + 20]; + pll_lim->vco1.max_n = bios->data[plloffs + 21]; + pll_lim->vco1.min_m = bios->data[plloffs + 22]; + pll_lim->vco1.max_m = bios->data[plloffs + 23]; + pll_lim->vco2.min_n = bios->data[plloffs + 24]; + pll_lim->vco2.max_n = bios->data[plloffs + 25]; + pll_lim->vco2.min_m = bios->data[plloffs + 26]; + pll_lim->vco2.max_m = bios->data[plloffs + 27]; + + pll_lim->unk1c = bios->data[plloffs + 28]; + pll_lim->max_log2p_bias = bios->data[plloffs + 29]; + pll_lim->log2p_bias = bios->data[plloffs + 30]; + + if (recordlen > 0x22) + pll_lim->refclk = le32_to_cpu(*((uint32_t *)&bios->data[plloffs + 31])); + + if (recordlen > 0x23) + if (bios->data[plloffs + 35]) + DRM_ERROR("Bits set in PLL configuration byte (%x)\n", bios->data[plloffs + 35]); + + /* C51 special not seen elsewhere */ + /*if (bios->chip_version == 0x51 && !pll_lim->refclk) { + uint32_t sel_clk = nv32_rd(pScrn, NV_RAMDAC_SEL_CLK); + + if (((limit_match == NV_RAMDAC_VPLL || limit_match == VPLL1) && sel_clk & 0x20) || + ((limit_match == NV_RAMDAC_VPLL2 || limit_match == VPLL2) && sel_clk & 0x80)) { + if (nv_idx_port_rd(pScrn, CRTC_INDEX_COLOR, NV_VGA_CRTCX_REVISION) < 0xa3) + pll_lim->refclk = 200000; + else + pll_lim->refclk = 25000; + } + }*/ + } + + /* By now any valid limit table ought to have set a max frequency for + * vco1, so if it's zero it's either a pre limit table bios, or one + * with an empty limit table (seen on nv18) + */ + if (!pll_lim->vco1.maxfreq) { + pll_lim->vco1.minfreq = bios->fminvco; + pll_lim->vco1.maxfreq = bios->fmaxvco; + pll_lim->vco1.min_inputfreq = 0; + pll_lim->vco1.max_inputfreq = INT_MAX; + pll_lim->vco1.min_n = 0x1; + pll_lim->vco1.max_n = 0xff; + pll_lim->vco1.min_m = 0x1; + if (crystal_straps == 0) { + /* nv05 does this, nv11 doesn't, nv10 unknown */ + if (bios->chip_version < 0x11) + pll_lim->vco1.min_m = 0x7; + pll_lim->vco1.max_m = 0xd; + } else { + if (bios->chip_version < 0x11) + pll_lim->vco1.min_m = 0x8; + pll_lim->vco1.max_m = 0xe; + } + } + + if (!pll_lim->refclk) + switch (crystal_straps) { + case 0: + pll_lim->refclk = 13500; + break; + case (1 << 6): + pll_lim->refclk = 14318; + break; + case (1 << 22): + pll_lim->refclk = 27000; + break; + case (1 << 22 | 1 << 6): + pll_lim->refclk = 25000; + break; + } + +#if 1 /* for easy debugging */ + DRM_INFO("pll.vco1.minfreq: %d\n", pll_lim->vco1.minfreq); + DRM_INFO("pll.vco1.maxfreq: %d\n", pll_lim->vco1.maxfreq); + DRM_INFO("pll.vco2.minfreq: %d\n", pll_lim->vco2.minfreq); + DRM_INFO("pll.vco2.maxfreq: %d\n", pll_lim->vco2.maxfreq); + + DRM_INFO("pll.vco1.min_inputfreq: %d\n", pll_lim->vco1.min_inputfreq); + DRM_INFO("pll.vco1.max_inputfreq: %d\n", pll_lim->vco1.max_inputfreq); + DRM_INFO("pll.vco2.min_inputfreq: %d\n", pll_lim->vco2.min_inputfreq); + DRM_INFO("pll.vco2.max_inputfreq: %d\n", pll_lim->vco2.max_inputfreq); + + DRM_INFO("pll.vco1.min_n: %d\n", pll_lim->vco1.min_n); + DRM_INFO("pll.vco1.max_n: %d\n", pll_lim->vco1.max_n); + DRM_INFO("pll.vco1.min_m: %d\n", pll_lim->vco1.min_m); + DRM_INFO("pll.vco1.max_m: %d\n", pll_lim->vco1.max_m); + DRM_INFO("pll.vco2.min_n: %d\n", pll_lim->vco2.min_n); + DRM_INFO("pll.vco2.max_n: %d\n", pll_lim->vco2.max_n); + DRM_INFO("pll.vco2.min_m: %d\n", pll_lim->vco2.min_m); + DRM_INFO("pll.vco2.max_m: %d\n", pll_lim->vco2.max_m); + + DRM_INFO("pll.unk1c: %d\n", pll_lim->unk1c); + DRM_INFO("pll.max_log2p_bias: %d\n", pll_lim->max_log2p_bias); + DRM_INFO("pll.log2p_bias: %d\n", pll_lim->log2p_bias); + + DRM_INFO("pll.refclk: %d\n", pll_lim->refclk); +#endif + + return true; +} diff --git a/linux-core/nouveau_bios.h b/linux-core/nouveau_bios.h new file mode 100644 index 00000000..e33ecd0f --- /dev/null +++ b/linux-core/nouveau_bios.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2005-2006 Erik Waling + * Copyright (C) 2006 Stephane Marchesin + * Copyright (C) 2007-2008 Stuart Bennett + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NOUVEAU_BIOS_H__ +#define __NOUVEAU_BIOS_H__ + +#include "drmP.h" +#include "drm.h" + +#define LOC_ON_CHIP 0 + +enum dcb_output_type {/* matches DCB types */ + DCB_OUTPUT_NONE = 4, + DCB_OUTPUT_ANALOG = 0, + DCB_OUTPUT_TMDS = 2, + DCB_OUTPUT_LVDS = 3, + DCB_OUTPUT_TV = 1, +}; + +struct bios { + uint8_t *data; + unsigned int length; + bool execute; + + uint8_t major_version, chip_version; + uint8_t feature_byte; + + uint32_t fmaxvco, fminvco; + + uint32_t dactestval; + + uint16_t init_script_tbls_ptr; + uint16_t extra_init_script_tbl_ptr; + uint16_t macro_index_tbl_ptr; + uint16_t macro_tbl_ptr; + uint16_t condition_tbl_ptr; + uint16_t io_condition_tbl_ptr; + uint16_t io_flag_condition_tbl_ptr; + uint16_t init_function_tbl_ptr; + + uint16_t pll_limit_tbl_ptr; + uint16_t ram_restrict_tbl_ptr; + + struct { + struct nouveau_hw_mode *native_mode; + uint8_t *edid; + uint16_t lvdsmanufacturerpointer; + uint16_t xlated_entry; + bool power_off_for_reset; + bool reset_after_pclk_change; + bool dual_link; + bool link_c_increment; + bool if_is_24bit; + bool BITbit1; + int duallink_transition_clk; + /* lower nibble stores PEXTDEV_BOOT_0 strap + * upper nibble stores xlated display strap */ + uint8_t strapping; + } fp; + + struct { + uint16_t output0_script_ptr; + uint16_t output1_script_ptr; + } tmds; + + struct { + uint16_t mem_init_tbl_ptr; + uint16_t sdr_seq_tbl_ptr; + uint16_t ddr_seq_tbl_ptr; + + struct { + uint8_t crt, tv, panel; + } i2c_indices; + } legacy; +}; + +struct dcb_entry { + int index; + uint8_t type; + uint8_t i2c_index; + uint8_t heads; + uint8_t bus; + uint8_t location; + uint8_t or; + bool duallink_possible; + union { + struct { + bool use_straps_for_mode; + bool use_power_scripts; + } lvdsconf; + }; +}; + +/* changing these requires matching changes to reg tables in nv_get_clock */ +#define MAX_PLL_TYPES 4 +enum pll_types { + NVPLL, + MPLL, + VPLL1, + VPLL2 +}; + +struct pll_lims { + struct { + int minfreq; + int maxfreq; + int min_inputfreq; + int max_inputfreq; + + uint8_t min_m; + uint8_t max_m; + uint8_t min_n; + uint8_t max_n; + } vco1, vco2; + + uint8_t unk1c; + uint8_t max_log2p_bias; + uint8_t log2p_bias; + int refclk; +}; + +bool get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim); +int nouveau_parse_bios(struct drm_device *dev); + +#endif /* __NOUVEAU_BIOS_H__ */ diff --git a/linux-core/nouveau_drv.c b/linux-core/nouveau_drv.c index c8f57dff..04f002f2 100644 --- a/linux-core/nouveau_drv.c +++ b/linux-core/nouveau_drv.c @@ -28,6 +28,9 @@ #include "drm_pciids.h" +unsigned int nouveau_modeset = 0; /* kms */ +module_param_named(modeset, nouveau_modeset, int, 0400); + static struct pci_device_id pciidlist[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), @@ -104,6 +107,10 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __init nouveau_init(void) { driver.num_ioctls = nouveau_max_ioctl; + + if (nouveau_modeset == 1) + driver.driver_features |= DRIVER_MODESET; + return drm_init(&driver, pciidlist); } diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c new file mode 100644 index 00000000..d13622b7 --- /dev/null +++ b/linux-core/nv50_connector.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_connector.h" + +static struct nv50_output *nv50_connector_to_output(struct nv50_connector *connector, bool digital) +{ + struct nv50_display *display = nv50_get_display(connector->dev); + struct nv50_output *output = NULL; + bool digital_possible = false; + bool analog_possible = false; + + switch (connector->type) { + case CONNECTOR_VGA: + case CONNECTOR_TV: + analog_possible = true; + break; + case CONNECTOR_DVI_I: + analog_possible = true; + digital_possible = true; + break; + case CONNECTOR_DVI_D: + case CONNECTOR_LVDS: + digital_possible = true; + break; + default: + break; + } + + /* Return early on bad situations. */ + if (!analog_possible && !digital_possible) + return NULL; + + if (!analog_possible && !digital) + return NULL; + + if (!digital_possible && digital) + return NULL; + + list_for_each_entry(output, &display->outputs, head) { + if (connector->bus != output->bus) + continue; + if (digital && output->type == OUTPUT_TMDS) + return output; + if (digital && output->type == OUTPUT_LVDS) + return output; + if (!digital && output->type == OUTPUT_DAC) + return output; + if (!digital && output->type == OUTPUT_TV) + return output; + } + + return NULL; +} + +static bool nv50_connector_detect(struct nv50_connector *connector) +{ + /* kindly borrrowed from the intel driver, hope it works. */ + uint8_t out_buf[] = { 0x0, 0x0}; + uint8_t buf[2]; + int ret; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } + }; + + NV50_DEBUG("\n"); + + if (!connector->i2c_chan) + return false; + + ret = i2c_transfer(&connector->i2c_chan->adapter, msgs, 2); + DRM_INFO("I2C detect returned %d\n", ret); + + if (ret == 2) + return true; + + return false; +} + +static int nv50_connector_destroy(struct nv50_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + + NV50_DEBUG("\n"); + + if (!display || !connector) + return -EINVAL; + + list_del(&connector->head); + + if (connector->i2c_chan) + nv50_i2c_channel_destroy(connector->i2c_chan); + + if (dev_priv->free_connector) + dev_priv->free_connector(connector); + + return 0; +} + +int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int type) +{ + struct nv50_connector *connector = NULL; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = NULL; + + NV50_DEBUG("\n"); + + /* This allows the public layer to do it's thing. */ + if (dev_priv->alloc_connector) + connector = dev_priv->alloc_connector(dev); + + if (!connector) + return -ENOMEM; + + connector->dev = dev; + + display = nv50_get_display(dev); + if (!display) + goto out; + + if (type == CONNECTOR_UNKNOWN) + goto out; + + list_add_tail(&connector->head, &display->connectors); + + connector->bus = bus; + connector->type = type; + + switch (type) { + case CONNECTOR_VGA: + DRM_INFO("Detected a VGA connector\n"); + break; + case CONNECTOR_DVI_D: + DRM_INFO("Detected a DVI-D connector\n"); + break; + case CONNECTOR_DVI_I: + DRM_INFO("Detected a DVI-I connector\n"); + break; + case CONNECTOR_LVDS: + DRM_INFO("Detected a LVDS connector\n"); + break; + case CONNECTOR_TV: + DRM_INFO("Detected a TV connector\n"); + break; + default: + DRM_ERROR("Unknown connector, this is not good.\n"); + break; + } + + /* some reasonable defaults */ + if (type == CONNECTOR_DVI_D || type == CONNECTOR_LVDS) + connector->scaling_mode = SCALE_FULLSCREEN; + else + connector->scaling_mode = SCALE_PANEL; + + if (i2c_index < 0xf) + connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index); + + /* set function pointers */ + connector->detect = nv50_connector_detect; + connector->destroy = nv50_connector_destroy; + connector->to_output = nv50_connector_to_output; + + return 0; + +out: + if (dev_priv->free_connector) + dev_priv->free_connector(connector); + + return -EINVAL; +} diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h new file mode 100644 index 00000000..c70d6ef4 --- /dev/null +++ b/linux-core/nv50_connector.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_CONNECTOR_H__ +#define __NV50_CONNECTOR_H__ + +#include "nv50_output.h" +#include "nv50_i2c.h" + +#define CONNECTOR_UNKNOWN 0 +#define CONNECTOR_VGA 1 +#define CONNECTOR_DVI_D 2 +#define CONNECTOR_DVI_I 3 +#define CONNECTOR_LVDS 4 +#define CONNECTOR_TV 5 + +struct nv50_connector { + struct list_head head; + + struct drm_device *dev; + int type; + + int bus; + struct nv50_i2c_channel *i2c_chan; + struct nv50_output *output; + + int scaling_mode; + bool digital; /* last connected output, this has to be set from the outside*/ + + bool (*detect) (struct nv50_connector *connector); + int (*destroy) (struct nv50_connector *connector); + struct nv50_output *(*to_output) (struct nv50_connector *connector, bool digital); +}; + +int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int type); + +#endif /* __NV50_CONNECTOR_H__ */ diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c new file mode 100644 index 00000000..974f5202 --- /dev/null +++ b/linux-core/nv50_crtc.c @@ -0,0 +1,515 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_crtc.h" +#include "nv50_cursor.h" +#include "nv50_lut.h" +#include "nv50_fb.h" + +static int nv50_crtc_validate_mode(struct nv50_crtc *crtc, struct nouveau_hw_mode *mode) +{ + NV50_DEBUG("\n"); + + if (mode->clock > 400000) + return MODE_CLOCK_HIGH; + + if (mode->clock < 25000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static int nv50_crtc_set_mode(struct nv50_crtc *crtc, struct nouveau_hw_mode *mode) +{ + struct nouveau_hw_mode *hw_mode = crtc->mode; + uint8_t rval; + + NV50_DEBUG("index %d\n", crtc->index); + + if (!mode) { + DRM_ERROR("No mode\n"); + return MODE_NOMODE; + } + + if ((rval = crtc->validate_mode(crtc, mode))) { + DRM_ERROR("Mode invalid\n"); + return rval; + } + + /* copy values to mode */ + *hw_mode = *mode; + + return 0; +} + +static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct nouveau_hw_mode *hw_mode; + uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end; + uint32_t hunk1, vunk1, vunk2a, vunk2b; + uint32_t offset = crtc->index * 0x400; + uint32_t pitch; + + NV50_DEBUG("index %d\n", crtc->index); + NV50_DEBUG("%s native mode\n", crtc->use_native_mode ? "using" : "not using"); + + if (crtc->use_native_mode) + hw_mode = crtc->native_mode; + else + hw_mode = crtc->mode; + + hsync_dur = hw_mode->hsync_end - hw_mode->hsync_start; + vsync_dur = hw_mode->vsync_end - hw_mode->vsync_start; + hsync_start_to_end = hw_mode->hblank_end - hw_mode->hsync_start; + vsync_start_to_end = hw_mode->vblank_end - hw_mode->vsync_start; + /* I can't give this a proper name, anyone else can? */ + hunk1 = hw_mode->htotal - hw_mode->hsync_start + hw_mode->hblank_start; + vunk1 = hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_start; + /* Another strange value, this time only for interlaced modes. */ + vunk2a = 2*hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_start; + vunk2b = hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_end; + + if (hw_mode->flags & V_INTERLACE) { + vsync_dur /= 2; + vsync_start_to_end /= 2; + vunk1 /= 2; + vunk2a /= 2; + vunk2b /= 2; + /* magic */ + if (hw_mode->flags & V_DBLSCAN) { + vsync_start_to_end -= 1; + vunk1 -= 1; + vunk2a -= 1; + vunk2b -= 1; + } + } + + OUT_MODE(NV50_CRTC0_CLOCK + offset, hw_mode->clock | 0x800000); + OUT_MODE(NV50_CRTC0_INTERLACE + offset, (hw_mode->flags & V_INTERLACE) ? 2 : 0); + OUT_MODE(NV50_CRTC0_DISPLAY_START + offset, 0); + OUT_MODE(NV50_CRTC0_UNK82C + offset, 0); + OUT_MODE(NV50_CRTC0_DISPLAY_TOTAL + offset, hw_mode->vtotal << 16 | hw_mode->htotal); + OUT_MODE(NV50_CRTC0_SYNC_DURATION + offset, (vsync_dur - 1) << 16 | (hsync_dur - 1)); + OUT_MODE(NV50_CRTC0_SYNC_START_TO_BLANK_END + offset, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1)); + OUT_MODE(NV50_CRTC0_MODE_UNK1 + offset, (vunk1 - 1) << 16 | (hunk1 - 1)); + if (hw_mode->flags & V_INTERLACE) { + OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset, (vunk2b - 1) << 16 | (vunk2a - 1)); + } + OUT_MODE(NV50_CRTC0_FB_SIZE + offset, crtc->fb->height << 16 | crtc->fb->width); + + /* I suspect this flag indicates a linear fb. */ + pitch = ((crtc->fb->width + 63) & ~63) * (crtc->fb->bpp)/8; + NV50_DEBUG("fb_pitch %d\n", pitch); + OUT_MODE(NV50_CRTC0_FB_PITCH + offset, pitch | 0x100000); + + switch (crtc->fb->depth) { + case 8: + OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_8BPP); + break; + case 15: + OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_15BPP); + break; + case 16: + OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_16BPP); + break; + case 24: + OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_24BPP); + break; + } + crtc->set_dither(crtc); + OUT_MODE(NV50_CRTC0_COLOR_CTRL + offset, NV50_CRTC_COLOR_CTRL_MODE_COLOR); + OUT_MODE(NV50_CRTC0_FB_POS + offset, (crtc->fb->y << 16) | (crtc->fb->x)); + /* This is the actual resolution of the mode. */ + OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay); + OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0)); + + /* Maybe move this as well? */ + crtc->blank(crtc, FALSE); + + return 0; +} + +static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("index %d\n", crtc->index); + NV50_DEBUG("%s\n", blanked ? "blanked" : "unblanked"); + + /* We really need a framebuffer. */ + if (!crtc->fb->block && !blanked) { + DRM_ERROR("No framebuffer available on crtc %d\n", crtc->index); + return -EINVAL; + } + + if (blanked) { + crtc->cursor->hide(crtc); + + OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, NV50_CRTC0_CLUT_MODE_BLANK); + OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, 0); + if (dev_priv->chipset != 0x50) + OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset, NV84_CRTC0_BLANK_UNK1_BLANK); + OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_BLANK); + if (dev_priv->chipset != 0x50) + OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_BLANK); + } else { + uint32_t ram_amount; + + OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8); + OUT_MODE(0x864 + offset, 0); + /* maybe this needs to be moved. */ + NV_WRITE(NV50_PDISPLAY_UNK_380, 0); + /* RAM is clamped to 256 MiB. */ + ram_amount = nouveau_mem_fb_amount(crtc->dev); + NV50_DEBUG("ram_amount %d\n", ram_amount); + if (ram_amount > 256*1024*1024) + ram_amount = 256*1024*1024; + NV_WRITE(NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); + NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000); + NV_WRITE(NV50_PDISPLAY_UNK_38C, 0); + if (crtc->cursor->block) + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8); + else + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, 0); + if (dev_priv->chipset != 0x50) + OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_UNBLANK); + + if (crtc->cursor->visible) + crtc->cursor->show(crtc); + else + crtc->cursor->hide(crtc); + + OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, + crtc->fb->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON); + OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, crtc->lut->block->start >> 8); + if (dev_priv->chipset != 0x50) + OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset, NV84_CRTC0_BLANK_UNK1_UNBLANK); + OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_UNBLANK); + } + + return 0; +} + +static int nv50_crtc_set_dither(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("\n"); + + OUT_MODE(NV50_CRTC0_DITHERING_CTRL + offset, crtc->use_dithering ? + NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF); + + return 0; +} + +static void nv50_crtc_calc_scale(struct nv50_crtc *crtc, uint32_t *outX, uint32_t *outY) +{ + float hor_scale, ver_scale; + + hor_scale = (float)crtc->native_mode->hdisplay/(float)crtc->mode->hdisplay; + ver_scale = (float)crtc->native_mode->vdisplay/(float)crtc->mode->vdisplay; + + if (ver_scale > hor_scale) { + *outX = crtc->mode->hdisplay * hor_scale; + *outY = crtc->mode->vdisplay * hor_scale; + } else { + *outX = crtc->mode->hdisplay * ver_scale; + *outY = crtc->mode->vdisplay * ver_scale; + } +} + +static int nv50_crtc_set_scale(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + uint32_t outX, outY; + + NV50_DEBUG("\n"); + + switch (crtc->scaling_mode) { + case SCALE_ASPECT: + nv50_crtc_calc_scale(crtc, &outX, &outY); + break; + case SCALE_FULLSCREEN: + outX = crtc->native_mode->hdisplay; + outY = crtc->native_mode->vdisplay; + break; + case SCALE_NOSCALE: + case SCALE_PANEL: + default: + outX = crtc->mode->hdisplay; + outY = crtc->mode->vdisplay; + break; + } + + /* Got a better name for SCALER_ACTIVE? */ + /* One day i've got to really figure out why this is needed. */ + if ((crtc->mode->flags & V_DBLSCAN) || (crtc->mode->flags & V_INTERLACE) || + crtc->mode->hdisplay != outX || crtc->mode->vdisplay != outY) { + OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE); + } else { + OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE); + } + + OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX); + OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX); + + return 0; +} + +static int nv50_crtc_calc_clock(struct nv50_crtc *crtc, + uint32_t *bestN1, uint32_t *bestN2, uint32_t *bestM1, uint32_t *bestM2, uint32_t *bestlog2P) +{ + struct nouveau_hw_mode *hw_mode; + struct pll_lims limits; + int clk, vco2, crystal; + int minvco1, minvco2, minU1, maxU1, minU2, maxU2, minM1, maxM1; + int maxvco1, maxvco2, minN1, maxN1, minM2, maxM2, minN2, maxN2; + bool fixedgain2; + int M1, N1, M2, N2, log2P; + int clkP, calcclk1, calcclk2, calcclkout; + int delta, bestdelta = INT_MAX; + int bestclk = 0; + + NV50_DEBUG("\n"); + + if (crtc->use_native_mode) + hw_mode = crtc->native_mode; + else + hw_mode = crtc->mode; + + clk = hw_mode->clock; + + /* These are in the g80 bios tables, at least in mine. */ + if (!get_pll_limits(crtc->dev, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index), &limits)) + return -EINVAL; + + minvco1 = limits.vco1.minfreq, maxvco1 = limits.vco1.maxfreq; + minvco2 = limits.vco2.minfreq, maxvco2 = limits.vco2.maxfreq; + minU1 = limits.vco1.min_inputfreq, minU2 = limits.vco2.min_inputfreq; + maxU1 = limits.vco1.max_inputfreq, maxU2 = limits.vco2.max_inputfreq; + minM1 = limits.vco1.min_m, maxM1 = limits.vco1.max_m; + minN1 = limits.vco1.min_n, maxN1 = limits.vco1.max_n; + minM2 = limits.vco2.min_m, maxM2 = limits.vco2.max_m; + minN2 = limits.vco2.min_n, maxN2 = limits.vco2.max_n; + crystal = limits.refclk; + fixedgain2 = (minM2 == maxM2 && minN2 == maxN2); + + vco2 = (maxvco2 - maxvco2/200) / 2; + for (log2P = 0; clk && log2P < 6 && clk <= (vco2 >> log2P); log2P++) /* log2P is maximum of 6 */ + ; + clkP = clk << log2P; + + if (maxvco2 < clk + clk/200) /* +0.5% */ + maxvco2 = clk + clk/200; + + for (M1 = minM1; M1 <= maxM1; M1++) { + if (crystal/M1 < minU1) + return bestclk; + if (crystal/M1 > maxU1) + continue; + + for (N1 = minN1; N1 <= maxN1; N1++) { + calcclk1 = crystal * N1 / M1; + if (calcclk1 < minvco1) + continue; + if (calcclk1 > maxvco1) + break; + + for (M2 = minM2; M2 <= maxM2; M2++) { + if (calcclk1/M2 < minU2) + break; + if (calcclk1/M2 > maxU2) + continue; + + /* add calcclk1/2 to round better */ + N2 = (clkP * M2 + calcclk1/2) / calcclk1; + if (N2 < minN2) + continue; + if (N2 > maxN2) + break; + + if (!fixedgain2) { + calcclk2 = calcclk1 * N2 / M2; + if (calcclk2 < minvco2) + break; + if (calcclk2 > maxvco2) + continue; + } else + calcclk2 = calcclk1; + + calcclkout = calcclk2 >> log2P; + delta = abs(calcclkout - clk); + /* we do an exhaustive search rather than terminating + * on an optimality condition... + */ + if (delta < bestdelta) { + bestdelta = delta; + bestclk = calcclkout; + *bestN1 = N1; + *bestN2 = N2; + *bestM1 = M1; + *bestM2 = M2; + *bestlog2P = log2P; + if (delta == 0) /* except this one */ + return bestclk; + } + } + } + } + + return bestclk; +} + +static int nv50_crtc_set_clock(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index); + + uint32_t N1 = 0, N2 = 0, M1 = 0, M2 = 0, log2P = 0; + + uint32_t reg1 = NV_READ(pll_reg + 4); + uint32_t reg2 = NV_READ(pll_reg + 8); + + NV50_DEBUG("\n"); + + NV_WRITE(pll_reg, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED | 0x10000011); + + /* The other bits are typically empty, but let's be on the safe side. */ + reg1 &= 0xff00ff00; + reg2 &= 0x8000ff00; + + if (!nv50_crtc_calc_clock(crtc, &N1, &N2, &M1, &M2, &log2P)) + return -EINVAL; + + NV50_DEBUG("N1 %d N2 %d M1 %d M2 %d log2P %d\n", N1, N2, M1, M2, log2P); + + reg1 |= (M1 << 16) | N1; + reg2 |= (log2P << 28) | (M2 << 16) | N2; + + NV_WRITE(pll_reg + 4, reg1); + NV_WRITE(pll_reg + 8, reg2); + + return 0; +} + +static int nv50_crtc_set_clock_mode(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + /* This acknowledges a clock request. */ + NV_WRITE(NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(crtc->index), 0); + + return 0; +} + +static int nv50_crtc_destroy(struct nv50_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + + NV50_DEBUG("\n"); + + if (!display || !crtc) + return -EINVAL; + + list_del(&crtc->head); + + nv50_fb_destroy(crtc); + nv50_lut_destroy(crtc); + nv50_cursor_destroy(crtc); + + kfree(crtc->mode); + kfree(crtc->native_mode); + + if (dev_priv->free_crtc) + dev_priv->free_crtc(crtc); + + return 0; +} + +int nv50_crtc_create(struct drm_device *dev, int index) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = NULL; + + NV50_DEBUG("\n"); + + /* This allows the public layer to do it's thing. */ + if (dev_priv->alloc_crtc) + crtc = dev_priv->alloc_crtc(dev); + + if (!crtc) + return -ENOMEM; + + crtc->dev = dev; + + display = nv50_get_display(dev); + if (!display) + goto out; + + list_add_tail(&crtc->head, &display->crtcs); + + crtc->index = index; + + crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + + nv50_fb_create(crtc); + nv50_lut_create(crtc); + nv50_cursor_create(crtc); + + /* set function pointers */ + crtc->validate_mode = nv50_crtc_validate_mode; + crtc->set_mode = nv50_crtc_set_mode; + crtc->execute_mode = nv50_crtc_execute_mode; + crtc->blank = nv50_crtc_blank; + crtc->set_dither = nv50_crtc_set_dither; + crtc->set_scale = nv50_crtc_set_scale; + crtc->set_clock = nv50_crtc_set_clock; + crtc->set_clock_mode = nv50_crtc_set_clock_mode; + crtc->destroy = nv50_crtc_destroy; + + return 0; + +out: + if (crtc->mode) + kfree(crtc->mode); + if (crtc->native_mode) + kfree(crtc->native_mode); + if (dev_priv->free_crtc) + dev_priv->free_crtc(crtc); + + return -EINVAL; +} diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h new file mode 100644 index 00000000..5eb815a5 --- /dev/null +++ b/linux-core/nv50_crtc.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_CRTC_H__ +#define __NV50_CRTC_H__ + +#include "nv50_display.h" + +struct nv50_cursor; +struct nv50_lut; +struct nv50_fb; + +struct nv50_crtc { + struct list_head head; + + struct drm_device *dev; + int index; + bool active; + + struct nouveau_hw_mode *mode; + struct nouveau_hw_mode *native_mode; + + bool use_native_mode; + bool use_dithering; + int scaling_mode; + + struct nv50_cursor *cursor; + struct nv50_lut *lut; + struct nv50_fb *fb; + + int (*validate_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode); + int (*set_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode); + int (*execute_mode) (struct nv50_crtc *crtc); + int (*blank) (struct nv50_crtc *crtc, bool blanked); + int (*set_dither) (struct nv50_crtc *crtc); + int (*set_scale) (struct nv50_crtc *crtc); + int (*set_clock) (struct nv50_crtc *crtc); + int (*set_clock_mode) (struct nv50_crtc *crtc); + int (*destroy) (struct nv50_crtc *crtc); +}; + +int nv50_crtc_create(struct drm_device *dev, int index); + +#endif /* __NV50_CRTC_H__ */ diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c new file mode 100644 index 00000000..3d35b936 --- /dev/null +++ b/linux-core/nv50_cursor.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_cursor.h" +#include "nv50_crtc.h" +#include "nv50_display.h" + +static int nv50_cursor_enable(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), 0x2000); + while(NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK); + + NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON); + while((NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK) + != NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE); + + crtc->cursor->enabled = true; + + return 0; +} + +static int nv50_cursor_disable(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), 0); + while(NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK); + + crtc->cursor->enabled = false; + + return 0; +} + +/* Calling update or changing the stored cursor state is left to the higher level ioctl's. */ +static int nv50_cursor_show(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("\n"); + + /* Better not show the cursor when we have none. */ + /* TODO: is cursor offset actually set? */ + if (!crtc->cursor->block) { + DRM_ERROR("No cursor available on crtc %d\n", crtc->index); + return -EINVAL; + } + + OUT_MODE(NV50_CRTC0_CURSOR_CTRL + offset, NV50_CRTC0_CURSOR_CTRL_SHOW); + + return 0; +} + +static int nv50_cursor_hide(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("\n"); + + OUT_MODE(NV50_CRTC0_CURSOR_CTRL + offset, NV50_CRTC0_CURSOR_CTRL_HIDE); + + return 0; +} + +static int nv50_cursor_set_pos(struct nv50_crtc *crtc, int x, int y) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV_WRITE(NV50_HW_CURSOR_POS(crtc->index), ((y & 0xFFFF) << 16) | (x & 0xFFFF)); + /* Needed to make the cursor move. */ + NV_WRITE(NV50_HW_CURSOR_POS_CTRL(crtc->index), 0); + + return 0; +} + +static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle) +{ + struct mem_block *block = NULL; + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + block = find_block_by_handle(dev_priv->fb_heap, handle); + + if (block) { + bool first_time = false; + if (!crtc->cursor->block) + first_time = true; + + crtc->cursor->block = block; + + /* set the cursor offset cursor */ + if (first_time) { + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8); + if (crtc->cursor->visible) + crtc->cursor->show(crtc); + } + } else { + return -EINVAL; + } + + return 0; +} + +int nv50_cursor_create(struct nv50_crtc *crtc) +{ + NV50_DEBUG("\n"); + + if (!crtc) + return -EINVAL; + + crtc->cursor = kzalloc(sizeof(struct nv50_cursor), GFP_KERNEL); + + /* function pointers */ + crtc->cursor->show = nv50_cursor_show; + crtc->cursor->hide = nv50_cursor_hide; + crtc->cursor->set_pos = nv50_cursor_set_pos; + crtc->cursor->set_bo = nv50_cursor_set_bo; + crtc->cursor->enable = nv50_cursor_enable; + crtc->cursor->disable = nv50_cursor_disable; + + /* defaults */ + crtc->cursor->visible = true; /* won't happen until there is a cursor bo */ + + return 0; +} + +int nv50_cursor_destroy(struct nv50_crtc *crtc) +{ + int rval = 0; + + NV50_DEBUG("\n"); + + if (!crtc) + return -EINVAL; + + if (crtc->cursor->enabled) { + rval = crtc->cursor->disable(crtc); + if (rval != 0) + return rval; + } + + kfree(crtc->cursor); + crtc->cursor = NULL; + + return 0; +} diff --git a/linux-core/nv50_cursor.h b/linux-core/nv50_cursor.h new file mode 100644 index 00000000..a2e4632c --- /dev/null +++ b/linux-core/nv50_cursor.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_CURSOR_H__ +#define __NV50_CURSOR_H__ + +#include "nv50_display.h" + +struct nv50_crtc; + +struct nv50_cursor { + struct mem_block *block; + int x, y; + bool visible; + bool enabled; + + int (*show) (struct nv50_crtc *crtc); + int (*hide) (struct nv50_crtc *crtc); + int (*set_pos) (struct nv50_crtc *crtc, int x, int y); + int (*set_bo) (struct nv50_crtc *crtc, drm_handle_t handle); + int (*enable) (struct nv50_crtc *crtc); + int (*disable) (struct nv50_crtc *crtc); +}; + +int nv50_cursor_create(struct nv50_crtc *crtc); +int nv50_cursor_destroy(struct nv50_crtc *crtc); + +#endif /* __NV50_CURSOR_H__ */ diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c new file mode 100644 index 00000000..f827fed4 --- /dev/null +++ b/linux-core/nv50_dac.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_output.h" + +static int nv50_dac_validate_mode(struct nv50_output *output, struct nouveau_hw_mode *mode) +{ + NV50_DEBUG("\n"); + + if (mode->clock > 400000) + return MODE_CLOCK_HIGH; + + if (mode->clock < 25000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static int nv50_dac_execute_mode(struct nv50_output *output, bool disconnect) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + struct nv50_crtc *crtc = output->crtc; + struct nouveau_hw_mode *desired_mode = NULL; + + uint32_t offset = nv50_output_or_offset(output) * 0x80; + + uint32_t mode_ctl = NV50_DAC_MODE_CTRL_OFF; + uint32_t mode_ctl2 = 0; + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + if (disconnect) { + NV50_DEBUG("Disconnecting DAC\n"); + OUT_MODE(NV50_DAC0_MODE_CTRL + offset, mode_ctl); + return 0; + } + + desired_mode = (crtc->use_native_mode ? crtc->native_mode : + crtc->mode); + + if (crtc->index == 1) + mode_ctl |= NV50_DAC_MODE_CTRL_CRTC1; + else + mode_ctl |= NV50_DAC_MODE_CTRL_CRTC0; + + /* Lacking a working tv-out, this is not a 100% sure. */ + if (output->type == OUTPUT_DAC) { + mode_ctl |= 0x40; + } else if (output->type == OUTPUT_TV) { + mode_ctl |= 0x100; + } + + if (desired_mode->flags & V_NHSYNC) + mode_ctl2 |= NV50_DAC_MODE_CTRL2_NHSYNC; + + if (desired_mode->flags & V_NVSYNC) + mode_ctl2 |= NV50_DAC_MODE_CTRL2_NVSYNC; + + OUT_MODE(NV50_DAC0_MODE_CTRL + offset, mode_ctl); + OUT_MODE(NV50_DAC0_MODE_CTRL2 + offset, mode_ctl2); + + return 0; +} + +static int nv50_dac_set_clock_mode(struct nv50_output *output) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + NV_WRITE(NV50_PDISPLAY_DAC_CLK_CLK_CTRL2(nv50_output_or_offset(output)), 0); + + return 0; +} + +static int nv50_dac_destroy(struct nv50_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + + NV50_DEBUG("\n"); + + if (!display || !output) + return -EINVAL; + + list_del(&output->head); + + kfree(output->native_mode); + if (dev_priv->free_output) + dev_priv->free_output(output); + + return 0; +} + +int nv50_dac_create(struct drm_device *dev, int dcb_entry) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_output *output = NULL; + struct nv50_display *display = NULL; + struct dcb_entry *entry = NULL; + + NV50_DEBUG("\n"); + + /* This allows the public layer to do it's thing. */ + if (dev_priv->alloc_output) + output = dev_priv->alloc_output(dev); + + if (!output) + return -ENOMEM; + + output->dev = dev; + + display = nv50_get_display(dev); + if (!display) + goto out; + + entry = &dev_priv->dcb_table.entry[dcb_entry]; + if (!entry) + goto out; + + switch (entry->type) { + case DCB_OUTPUT_ANALOG: + output->type = OUTPUT_DAC; + DRM_INFO("Detected a DAC output\n"); + break; + default: + goto out; + } + + output->dcb_entry = dcb_entry; + output->bus = entry->bus; + + list_add_tail(&output->head, &display->outputs); + + output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + + /* Set function pointers. */ + output->validate_mode = nv50_dac_validate_mode; + output->execute_mode = nv50_dac_execute_mode; + output->set_clock_mode = nv50_dac_set_clock_mode; + output->detect = NULL; /* TODO */ + output->destroy = nv50_dac_destroy; + + return 0; + +out: + if (output->native_mode) + kfree(output->native_mode); + if (dev_priv->free_output) + dev_priv->free_output(output); + return -EINVAL; +} + diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c new file mode 100644 index 00000000..56ddeb97 --- /dev/null +++ b/linux-core/nv50_display.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_display.h" +#include "nv50_crtc.h" +#include "nv50_output.h" +#include "nv50_connector.h" + +static int nv50_display_pre_init(struct nv50_display *display) +{ + struct drm_device *dev = display->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + int i; + + NV50_DEBUG("\n"); + + NV_WRITE(0x00610184, NV_READ(0x00614004)); + /* + * I think the 0x006101XX range is some kind of main control area that enables things. + */ + /* CRTC? */ + NV_WRITE(0x00610190 + 0 * 0x10, NV_READ(0x00616100 + 0 * 0x800)); + NV_WRITE(0x00610190 + 1 * 0x10, NV_READ(0x00616100 + 1 * 0x800)); + NV_WRITE(0x00610194 + 0 * 0x10, NV_READ(0x00616104 + 0 * 0x800)); + NV_WRITE(0x00610194 + 1 * 0x10, NV_READ(0x00616104 + 1 * 0x800)); + NV_WRITE(0x00610198 + 0 * 0x10, NV_READ(0x00616108 + 0 * 0x800)); + NV_WRITE(0x00610198 + 1 * 0x10, NV_READ(0x00616108 + 1 * 0x800)); + NV_WRITE(0x0061019c + 0 * 0x10, NV_READ(0x0061610c + 0 * 0x800)); + NV_WRITE(0x0061019c + 1 * 0x10, NV_READ(0x0061610c + 1 * 0x800)); + /* DAC */ + NV_WRITE(0x006101d0 + 0 * 0x4, NV_READ(0x0061a000 + 0 * 0x800)); + NV_WRITE(0x006101d0 + 1 * 0x4, NV_READ(0x0061a000 + 1 * 0x800)); + NV_WRITE(0x006101d0 + 2 * 0x4, NV_READ(0x0061a000 + 2 * 0x800)); + /* SOR */ + NV_WRITE(0x006101e0 + 0 * 0x4, NV_READ(0x0061c000 + 0 * 0x800)); + NV_WRITE(0x006101e0 + 1 * 0x4, NV_READ(0x0061c000 + 1 * 0x800)); + /* Something not yet in use, tv-out maybe. */ + NV_WRITE(0x006101f0 + 0 * 0x4, NV_READ(0x0061e000 + 0 * 0x800)); + NV_WRITE(0x006101f0 + 1 * 0x4, NV_READ(0x0061e000 + 1 * 0x800)); + NV_WRITE(0x006101f0 + 2 * 0x4, NV_READ(0x0061e000 + 2 * 0x800)); + + for (i = 0; i < 3; i++) { + NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(i), 0x00550000 | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + NV_WRITE(NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i), 0x00000001); + } + + display->preinit_done = TRUE; + + return 0; +} + +static int nv50_display_init(struct nv50_display *display) +{ + struct drm_device *dev = display->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t val; + + NV50_DEBUG("\n"); + + /* The precise purpose is unknown, i suspect it has something to do with text mode. */ + if (NV_READ(NV50_PDISPLAY_SUPERVISOR) & 0x100) { + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, 0x100); + NV_WRITE(0x006194e8, NV_READ(0x006194e8) & ~1); + while (NV_READ(0x006194e8) & 2); + } + + /* taken from nv bug #12637 */ + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, 0x2b00); + do { + val = NV_READ(NV50_PDISPLAY_UNK200_CTRL); + if ((val & 0x9f0000) == 0x20000) + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, val | 0x800000); + + if ((val & 0x3f0000) == 0x30000) + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, val | 0x200000); + } while (val & 0x1e0000); + + NV_WRITE(NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE); + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, 0x1000b03); + while (!(NV_READ(NV50_PDISPLAY_UNK200_CTRL) & 0x40000000)); + + /* For the moment this is just a wrapper, which should be replaced with a real fifo at some point. */ + OUT_MODE(NV50_UNK84, 0); + OUT_MODE(NV50_UNK88, 0); + OUT_MODE(NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK); + OUT_MODE(NV50_CRTC0_UNK800, 0); + OUT_MODE(NV50_CRTC0_DISPLAY_START, 0); + OUT_MODE(NV50_CRTC0_UNK82C, 0); + + /* enable clock change interrupts. */ + NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) | 0x70); + + display->init_done = TRUE; + + return 0; +} + +static int nv50_display_disable(struct nv50_display *display) +{ + struct drm_device *dev = display->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_crtc *crtc = NULL; + int i; + + NV50_DEBUG("\n"); + + list_for_each_entry(crtc, &display->crtcs, head) { + crtc->blank(crtc, TRUE); + } + + display->update(display); + + /* Almost like ack'ing a vblank interrupt, maybe in the spirit of cleaning up? */ + list_for_each_entry(crtc, &display->crtcs, head) { + if (crtc->active) { + uint32_t mask; + + if (crtc->index == 1) + mask = NV50_PDISPLAY_SUPERVISOR_CRTC1; + else + mask = NV50_PDISPLAY_SUPERVISOR_CRTC0; + + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, mask); + while (!(NV_READ(NV50_PDISPLAY_SUPERVISOR) & mask)); + } + } + + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, 0); + NV_WRITE(NV50_PDISPLAY_CTRL_STATE, 0); + while ((NV_READ(NV50_PDISPLAY_UNK200_CTRL) & 0x1e0000) != 0); + + for (i = 0; i < 2; i++) { + while (NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_STATE(i)) & NV50_PDISPLAY_SOR_REGS_DPMS_STATE_WAIT); + } + + /* disable clock change interrupts. */ + NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) & ~0x70); + + display->init_done = FALSE; + + return 0; +} + +static int nv50_display_update(struct nv50_display *display) +{ + struct drm_device *dev = display->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + + NV50_DEBUG("\n"); + + OUT_MODE(NV50_UPDATE_DISPLAY, 0); + + return 0; +} + +int nv50_display_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = kzalloc(sizeof(struct nv50_display), GFP_KERNEL); + int i, type, output_index, bus; + /* DAC0, DAC1, DAC2, SOR0, SOR1*/ + int or_counter[5] = {0, 0, 0, 0, 0}; + int i2c_index[5] = {0, 0, 0, 0, 0}; + uint32_t bus_mask = 0; + uint32_t bus_digital = 0, bus_analog = 0; + + NV50_DEBUG("\n"); + + INIT_LIST_HEAD(&display->crtcs); + INIT_LIST_HEAD(&display->outputs); + INIT_LIST_HEAD(&display->connectors); + + dev_priv->display_priv = display; + + for (i = 0; i < 2; i++) { + nv50_crtc_create(dev, i); + } + + /* we setup the outputs up from the BIOS table */ + for (i = 0 ; i < dev_priv->dcb_table.entries; i++) { + type = dev_priv->dcb_table.entry[i].type; + output_index = ffs(dev_priv->dcb_table.entry[i].or) - 1; + bus = dev_priv->dcb_table.entry[i].bus; + + switch (type) { + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_LVDS: + or_counter[output_index + 3] += 1; + i2c_index[output_index + 3] = dev_priv->dcb_table.entry[i].i2c_index; + bus_digital |= (1 << bus); + nv50_sor_create(dev, i); + break; + case DCB_OUTPUT_ANALOG: + or_counter[output_index] += 1; + i2c_index[output_index] = dev_priv->dcb_table.entry[i].i2c_index; + bus_analog |= (1 << bus); + nv50_dac_create(dev, i); + break; + default: + break; + } + + } + + /* setup the connectors based on the output tables. */ + for (i = 0 ; i < dev_priv->dcb_table.entries; i++) { + int connector_type = 0; + type = dev_priv->dcb_table.entry[i].type; + bus = dev_priv->dcb_table.entry[i].bus; + + /* already done? */ + if (bus_mask & (1 << bus)) + continue; + + /* only do it for supported outputs */ + if (type != DCB_OUTPUT_ANALOG && type != DCB_OUTPUT_TMDS + && type != DCB_OUTPUT_LVDS) + continue; + + switch (type) { + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_ANALOG: + if ((bus_digital & (1 << bus)) && (bus_analog & (1 << bus))) + connector_type = CONNECTOR_DVI_I; + else if (bus_digital & (1 << bus)) + connector_type = CONNECTOR_DVI_D; + else if (bus_analog & (1 << bus)) + connector_type = CONNECTOR_VGA; + break; + case DCB_OUTPUT_LVDS: + connector_type = CONNECTOR_LVDS; + break; + default: + connector_type = CONNECTOR_UNKNOWN; + break; + } + + if (connector_type == CONNECTOR_UNKNOWN) + continue; + + nv50_connector_create(dev, bus, dev_priv->dcb_table.entry[i].i2c_index, connector_type); + + bus_mask |= (1 << bus); + } + + display->dev = dev; + + /* function pointers */ + display->init = nv50_display_init; + display->pre_init = nv50_display_pre_init; + display->disable = nv50_display_disable; + display->update = nv50_display_update; + + return 0; +} + +int nv50_display_destroy(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + struct nv50_crtc *crtc = NULL; + struct nv50_output *output = NULL; + struct nv50_connector *connector = NULL; + + NV50_DEBUG("\n"); + + if (display->init_done) + display->disable(display); + + list_for_each_entry(connector, &display->connectors, head) { + connector->destroy(connector); + } + + list_for_each_entry(output, &display->outputs, head) { + output->destroy(output); + } + + list_for_each_entry(crtc, &display->crtcs, head) { + crtc->destroy(crtc); + } + + kfree(display); + dev_priv->display_priv = NULL; + + return 0; +} + +/* This can be replaced with a real fifo in the future. */ +void nv50_display_command(struct drm_nouveau_private *dev_priv, uint32_t mthd, uint32_t val) +{ + uint32_t counter = 0; + +#if 1 + DRM_INFO("mthd 0x%03X val 0x%08X\n", mthd, val); +#endif + + NV_WRITE(NV50_PDISPLAY_CTRL_VAL, val); + NV_WRITE(NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_PENDING | 0x10000 | mthd | NV50_PDISPLAY_CTRL_STATE_ENABLE); + + while (NV_READ(NV50_PDISPLAY_CTRL_STATE) & NV50_PDISPLAY_CTRL_STATE_PENDING) { + counter++; + if (counter > 25000) { + DRM_ERROR("You probably need a reboot now\n"); + break; + } + } +} + +struct nv50_display *nv50_get_display(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + return (struct nv50_display *) dev_priv->display_priv; +} diff --git a/linux-core/nv50_display.h b/linux-core/nv50_display.h new file mode 100644 index 00000000..f20e67da --- /dev/null +++ b/linux-core/nv50_display.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_DISPLAY_H__ +#define __NV50_DISPLAY_H__ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_dma.h" +#include "nouveau_drv.h" +#include "nouveau_reg.h" +#include "nv50_display_commands.h" + +/* for convience, so you can see through the trees. */ +#define NV50_DEBUG DRM_ERROR + +struct nouveau_hw_mode { + unsigned int clock; + unsigned short hdisplay, hblank_start, hsync_start, hsync_end, hblank_end, htotal; + unsigned short vdisplay, vblank_start, vsync_start, vsync_end, vblank_end, vtotal; + + unsigned int flags; +}; + +struct nv50_crtc; +struct nv50_output; +struct nv50_connector; + +struct nv50_display { + struct drm_device *dev; + + bool preinit_done; + bool init_done; + + int last_crtc; /* crtc used for last mode set */ + + int (*pre_init) (struct nv50_display *display); + int (*init) (struct nv50_display *display); + int (*disable) (struct nv50_display *display); + int (*update) (struct nv50_display *display); + + struct list_head crtcs; + struct list_head outputs; + struct list_head connectors; +}; + +enum scaling_modes { + SCALE_PANEL, + SCALE_FULLSCREEN, + SCALE_ASPECT, + SCALE_NOSCALE, + SCALE_INVALID +}; + +void nv50_display_command(struct drm_nouveau_private *dev_priv, uint32_t mthd, uint32_t val); +struct nv50_display *nv50_get_display(struct drm_device *dev); +int nv50_display_create(struct drm_device *dev); +int nv50_display_destroy(struct drm_device *dev); + +#endif /* __NV50_DISPLAY_H__ */ diff --git a/linux-core/nv50_display_commands.h b/linux-core/nv50_display_commands.h new file mode 100644 index 00000000..97b3d3c1 --- /dev/null +++ b/linux-core/nv50_display_commands.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +/* copied from ddx definitions, until rules-ng can handle this */ + +#define NV50_UPDATE_DISPLAY 0x80 +#define NV50_UNK84 0x84 +#define NV50_UNK88 0x88 + +#define NV50_DAC0_MODE_CTRL 0x400 + #define NV50_DAC_MODE_CTRL_OFF (0 << 0) + #define NV50_DAC_MODE_CTRL_CRTC0 (1 << 0) + #define NV50_DAC_MODE_CTRL_CRTC1 (1 << 1) +#define NV50_DAC1_MODE_CTRL 0x480 +#define NV50_DAC2_MODE_CTRL 0x500 + +#define NV50_DAC0_MODE_CTRL2 0x404 + #define NV50_DAC_MODE_CTRL2_NHSYNC (1 << 0) + #define NV50_DAC_MODE_CTRL2_NVSYNC (2 << 0) +#define NV50_DAC1_MODE_CTRL2 0x484 +#define NV50_DAC2_MODE_CTRL2 0x504 + +#define NV50_SOR0_MODE_CTRL 0x600 + #define NV50_SOR_MODE_CTRL_OFF (0 << 0) + #define NV50_SOR_MODE_CTRL_CRTC0 (1 << 0) + #define NV50_SOR_MODE_CTRL_CRTC1 (1 << 1) + #define NV50_SOR_MODE_CTRL_LVDS (0 << 8) + #define NV50_SOR_MODE_CTRL_TMDS (1 << 8) + #define NV50_SOR_MODE_CTRL_TMDS_DUAL_LINK (4 << 8) + #define NV50_SOR_MODE_CTRL_NHSYNC (1 << 12) + #define NV50_SOR_MODE_CTRL_NVSYNC (2 << 12) +#define NV50_SOR1_MODE_CTRL 0x640 + +#define NV50_CRTC0_UNK800 0x800 +#define NV50_CRTC0_CLOCK 0x804 +#define NV50_CRTC0_INTERLACE 0x808 + +/* 0x810 is a reasonable guess, nothing more. */ +#define NV50_CRTC0_DISPLAY_START 0x810 +#define NV50_CRTC0_DISPLAY_TOTAL 0x814 +#define NV50_CRTC0_SYNC_DURATION 0x818 +#define NV50_CRTC0_SYNC_START_TO_BLANK_END 0x81C +#define NV50_CRTC0_MODE_UNK1 0x820 +#define NV50_CRTC0_MODE_UNK2 0x824 + +#define NV50_CRTC0_UNK82C 0x82C + +/* You can't have a palette in 8 bit mode (=OFF) */ +#define NV50_CRTC0_CLUT_MODE 0x840 + #define NV50_CRTC0_CLUT_MODE_BLANK 0x00000000 + #define NV50_CRTC0_CLUT_MODE_OFF 0x80000000 + #define NV50_CRTC0_CLUT_MODE_ON 0xC0000000 +#define NV50_CRTC0_CLUT_OFFSET 0x844 + +/* Anyone know what part of the chip is triggered here precisely? */ +#define NV84_CRTC0_BLANK_UNK1 0x85C + #define NV84_CRTC0_BLANK_UNK1_BLANK 0x0 + #define NV84_CRTC0_BLANK_UNK1_UNBLANK 0x1 + +#define NV50_CRTC0_FB_OFFSET 0x860 + +#define NV50_CRTC0_FB_SIZE 0x868 +#define NV50_CRTC0_FB_PITCH 0x86C + +#define NV50_CRTC0_DEPTH 0x870 + #define NV50_CRTC0_DEPTH_8BPP 0x1E00 + #define NV50_CRTC0_DEPTH_15BPP 0xE900 + #define NV50_CRTC0_DEPTH_16BPP 0xE800 + #define NV50_CRTC0_DEPTH_24BPP 0xCF00 + +/* I'm openminded to better interpretations. */ +/* This is an educated guess. */ +/* NV50 has RAMDAC and TMDS offchip, so it's unlikely to be that. */ +#define NV50_CRTC0_BLANK_CTRL 0x874 + #define NV50_CRTC0_BLANK_CTRL_BLANK 0x0 + #define NV50_CRTC0_BLANK_CTRL_UNBLANK 0x1 + +#define NV50_CRTC0_CURSOR_CTRL 0x880 + #define NV50_CRTC0_CURSOR_CTRL_SHOW 0x85000000 + #define NV50_CRTC0_CURSOR_CTRL_HIDE 0x05000000 + +#define NV50_CRTC0_CURSOR_OFFSET 0x884 + +/* Anyone know what part of the chip is triggered here precisely? */ +#define NV84_CRTC0_BLANK_UNK2 0x89C + #define NV84_CRTC0_BLANK_UNK2_BLANK 0x0 + #define NV84_CRTC0_BLANK_UNK2_UNBLANK 0x1 + +#define NV50_CRTC0_DITHERING_CTRL 0x8A0 + #define NV50_CRTC0_DITHERING_CTRL_ON 0x11 + #define NV50_CRTC0_DITHERING_CTRL_OFF 0x0 + +#define NV50_CRTC0_SCALE_CTRL 0x8A4 + #define NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE (0 << 0) + /* It doesn't seem to be needed, hence i wonder what it does precisely. */ + #define NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE (9 << 0) +#define NV50_CRTC0_COLOR_CTRL 0x8A8 + #define NV50_CRTC_COLOR_CTRL_MODE_COLOR (4 << 16) + +#define NV50_CRTC0_FB_POS 0x8C0 +#define NV50_CRTC0_REAL_RES 0x8C8 + +/* Added a macro, because the signed stuff can cause you problems very quickly. */ +#define NV50_CRTC0_SCALE_CENTER_OFFSET 0x8D4 + #define NV50_CRTC_SCALE_CENTER_OFFSET_VAL(x, y) ((((unsigned)y << 16) & 0xFFFF0000) | (((unsigned)x) & 0x0000FFFF)) +/* Both of these are needed, otherwise nothing happens. */ +#define NV50_CRTC0_SCALE_RES1 0x8D8 +#define NV50_CRTC0_SCALE_RES2 0x8DC + +#define NV50_CRTC1_UNK800 0xC00 +#define NV50_CRTC1_CLOCK 0xC04 +#define NV50_CRTC1_INTERLACE 0xC08 + +/* 0xC10 is a reasonable guess, nothing more. */ +#define NV50_CRTC1_DISPLAY_START 0xC10 +#define NV50_CRTC1_DISPLAY_TOTAL 0xC14 +#define NV50_CRTC1_SYNC_DURATION 0xC18 +#define NV50_CRTC1_SYNC_START_TO_BLANK_END 0xC1C +#define NV50_CRTC1_MODE_UNK1 0xC20 +#define NV50_CRTC1_MODE_UNK2 0xC24 + +#define NV50_CRTC1_CLUT_MODE 0xC40 + #define NV50_CRTC1_CLUT_MODE_BLANK 0x00000000 + #define NV50_CRTC1_CLUT_MODE_OFF 0x80000000 + #define NV50_CRTC1_CLUT_MODE_ON 0xC0000000 +#define NV50_CRTC1_CLUT_OFFSET 0xC44 + +/* Anyone know what part of the chip is triggered here precisely? */ +#define NV84_CRTC1_BLANK_UNK1 0xC5C + #define NV84_CRTC1_BLANK_UNK1_BLANK 0x0 + #define NV84_CRTC1_BLANK_UNK1_UNBLANK 0x1 + +#define NV50_CRTC1_FB_OFFSET 0xC60 + +#define NV50_CRTC1_FB_SIZE 0xC68 +#define NV50_CRTC1_FB_PITCH 0xC6C + +#define NV50_CRTC1_DEPTH 0xC70 + #define NV50_CRTC1_DEPTH_8BPP 0x1E00 + #define NV50_CRTC1_DEPTH_15BPP 0xE900 + #define NV50_CRTC1_DEPTH_16BPP 0xE800 + #define NV50_CRTC1_DEPTH_24BPP 0xCF00 + +/* I'm openminded to better interpretations. */ +#define NV50_CRTC1_BLANK_CTRL 0xC74 + #define NV50_CRTC1_BLANK_CTRL_BLANK 0x0 + #define NV50_CRTC1_BLANK_CTRL_UNBLANK 0x1 + +#define NV50_CRTC1_CURSOR_CTRL 0xC80 + #define NV50_CRTC1_CURSOR_CTRL_SHOW 0x85000000 + #define NV50_CRTC1_CURSOR_CTRL_HIDE 0x05000000 + +#define NV50_CRTC1_CURSOR_OFFSET 0xC84 + +/* Anyone know what part of the chip is triggered here precisely? */ +#define NV84_CRTC1_BLANK_UNK2 0xC9C + #define NV84_CRTC1_BLANK_UNK2_BLANK 0x0 + #define NV84_CRTC1_BLANK_UNK2_UNBLANK 0x1 + +#define NV50_CRTC1_DITHERING_CTRL 0xCA0 + #define NV50_CRTC1_DITHERING_CTRL_ON 0x11 + #define NV50_CRTC1_DITHERING_CTRL_OFF 0x0 + +#define NV50_CRTC1_SCALE_CTRL 0xCA4 +#define NV50_CRTC1_COLOR_CTRL 0xCA8 + +#define NV50_CRTC1_FB_POS 0xCC0 +#define NV50_CRTC1_REAL_RES 0xCC8 + +#define NV50_CRTC1_SCALE_CENTER_OFFSET 0xCD4 +/* Both of these are needed, otherwise nothing happens. */ +#define NV50_CRTC1_SCALE_RES1 0xCD8 +#define NV50_CRTC1_SCALE_RES2 0xCDC diff --git a/linux-core/nv50_fb.c b/linux-core/nv50_fb.c new file mode 100644 index 00000000..b44b48ab --- /dev/null +++ b/linux-core/nv50_fb.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_fb.h" +#include "nv50_lut.h" +#include "nv50_crtc.h" +#include "nv50_display.h" + +static int nv50_fb_bind(struct nv50_crtc *crtc, struct nv50_fb_info *info) +{ + int rval = 0; + + NV50_DEBUG("\n"); + + if (!crtc || !info) { + DRM_ERROR("crtc %p info %p\n",crtc, info); + return -EINVAL; + } + + if (!info->block || !info->width || !info->height || !info->depth || !info->bpp) { + DRM_ERROR("block %p width %d height %d depth %d bpp %d\n", info->block, info->width, info->height, info->depth, info->bpp); + return -EINVAL; + } + + crtc->fb->block = info->block; + crtc->fb->width = info->width; + crtc->fb->height = info->height; + + crtc->fb->y = info->x; + crtc->fb->x = info->y; + + crtc->fb->depth = info->depth; + crtc->fb->bpp = info->bpp; + + /* update lut if needed */ + if (crtc->fb->depth != crtc->lut->depth) { + int r_size = 0, g_size = 0, b_size = 0; + uint16_t *r_val, *g_val, *b_val; + int i; + + switch (crtc->fb->depth) { + case 15: + r_size = 32; + g_size = 32; + b_size = 32; + break; + case 16: + r_size = 32; + g_size = 64; + b_size = 32; + break; + case 24: + default: + r_size = 256; + g_size = 256; + b_size = 256; + break; + } + + r_val = kmalloc(r_size * sizeof(uint16_t), GFP_KERNEL); + g_val = kmalloc(g_size * sizeof(uint16_t), GFP_KERNEL); + b_val = kmalloc(b_size * sizeof(uint16_t), GFP_KERNEL); + + if (!r_val || !g_val || !b_val) + return -ENOMEM; + + /* Set the color indices. */ + for (i = 0; i < r_size; i++) { + r_val[i] = i << 8; + } + for (i = 0; i < g_size; i++) { + g_val[i] = i << 8; + } + for (i = 0; i < b_size; i++) { + b_val[i] = i << 8; + } + + rval = crtc->lut->set(crtc, r_val, g_val, b_val); + + /* free before returning */ + kfree(r_val); + kfree(g_val); + kfree(b_val); + + if (rval != 0) + return rval; + } + + return 0; +} + +int nv50_fb_create(struct nv50_crtc *crtc) +{ + if (!crtc) + return -EINVAL; + + crtc->fb = kzalloc(sizeof(struct nv50_fb), GFP_KERNEL); + + crtc->fb->bind = nv50_fb_bind; + + return 0; +} + +int nv50_fb_destroy(struct nv50_crtc *crtc) +{ + if (!crtc) + return -EINVAL; + + kfree(crtc->fb); + crtc->fb = NULL; + + return 0; +} diff --git a/linux-core/nv50_fb.h b/linux-core/nv50_fb.h new file mode 100644 index 00000000..6b286315 --- /dev/null +++ b/linux-core/nv50_fb.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_FB_H__ +#define __NV50_FB_H__ + +#include "nv50_display.h" + +struct nv50_crtc; + +struct nv50_fb_info { + struct mem_block *block; + int width, height; + int bpp, depth; + int x,y; +}; + +struct nv50_fb { + struct mem_block *block; + int width, height; + int bpp, depth; + + int x,y; + + /* function points */ + int (*bind) (struct nv50_crtc *crtc, struct nv50_fb_info *info); +}; + +int nv50_fb_create(struct nv50_crtc *crtc); +int nv50_fb_destroy(struct nv50_crtc *crtc); + +#endif /* __NV50_FB_H__ */ diff --git a/linux-core/nv50_i2c.c b/linux-core/nv50_i2c.c new file mode 100644 index 00000000..cf55645b --- /dev/null +++ b/linux-core/nv50_i2c.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +/* This is largely a clone from xorg i2c functions, as i had serious trouble getting an i2c_bit_algo adaptor running. */ + +#include "nv50_i2c.h" + +static void nv50_i2c_set_bits(struct nv50_i2c_channel *chan, int clock_high, int data_high) +{ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + + NV_WRITE(NV50_PCONNECTOR_I2C_PORT(chan->index), 4 | (data_high << 1) | clock_high); +} + +static void nv50_i2c_get_bits(struct nv50_i2c_channel *chan, int *clock_high, int *data_high) +{ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + + uint32_t val = NV_READ(NV50_PCONNECTOR_I2C_PORT(chan->index)); + + if (val & 1) + *clock_high = 1; + else + *clock_high = 0; + + if (val & 2) + *data_high = 1; + else + *data_high = 0; +} + +static bool nv50_i2c_raise_clock(struct nv50_i2c_channel *chan, int data) +{ + int i, clock; + + nv50_i2c_set_bits(chan, 1, data); + udelay(2); + + for (i = 2200; i > 0; i -= 2) { + nv50_i2c_get_bits(chan, &clock, &data); + if (clock) + return TRUE; + udelay(2); + } + + printk("a timeout occured in nv50_i2c_raise_clock\n"); + + return FALSE; +} + +static bool nv50_i2c_start(struct nv50_i2c_channel *chan) +{ + if (!nv50_i2c_raise_clock(chan, 1)) + return FALSE; + + nv50_i2c_set_bits(chan, 1, 0); + udelay(5); + + nv50_i2c_set_bits(chan, 0, 0); + udelay(5); + + return TRUE; +} + +static void nv50_i2c_stop(struct nv50_i2c_channel *chan) +{ + nv50_i2c_set_bits(chan, 0, 0); + udelay(2); + + nv50_i2c_set_bits(chan, 1, 0); + udelay(5); + + nv50_i2c_set_bits(chan, 1, 1); + udelay(5); +} + +static bool nv50_i2c_write_bit(struct nv50_i2c_channel *chan, int data) +{ + bool rval; + + nv50_i2c_set_bits(chan, 0, data); + udelay(2); + + rval = nv50_i2c_raise_clock(chan, data); + udelay(5); + + nv50_i2c_set_bits(chan, 0, data); + udelay(5); + + return rval; +} + +static bool nv50_i2c_read_bit(struct nv50_i2c_channel *chan, int *data) +{ + bool rval; + int clock; + + rval = nv50_i2c_raise_clock(chan, 1); + udelay(5); + + nv50_i2c_get_bits(chan, &clock, data); + udelay(5); + + nv50_i2c_set_bits(chan, 0, 1); + udelay(5); + + return rval; +} + +static bool nv50_i2c_write_byte(struct nv50_i2c_channel *chan, uint8_t byte) +{ + bool rval; + int i, clock, data; + + for (i = 7; i >= 0; i--) + if (!nv50_i2c_write_bit(chan, (byte >> i) & 1)) + return FALSE; + + nv50_i2c_set_bits(chan, 0, 1); + udelay(5); + + rval = nv50_i2c_raise_clock(chan, 1); + + if (rval) { + for (i = 40; i > 0; i -= 2) { + udelay(2); + nv50_i2c_get_bits(chan, &clock, &data); + if (data == 0) + break; + } + + if (i <= 0) { + printk("a timeout occured in nv50_i2c_write_byte\n"); + rval = FALSE; + } + } + + nv50_i2c_set_bits(chan, 0, 1); + udelay(5); + + return rval; +} + +static bool nv50_i2c_read_byte(struct nv50_i2c_channel *chan, uint8_t *byte, bool last) +{ + int i, bit; + + nv50_i2c_set_bits(chan, 0, 1); + udelay(5); + + *byte = 0; + + for (i = 7; i >= 0; i--) { + if (nv50_i2c_read_bit(chan, &bit)) { + if (bit) + *byte |= (1 << i); + } else { + return FALSE; + } + } + + if (!nv50_i2c_write_bit(chan, last ? 1 : 0)) + return FALSE; + + return TRUE; +} + +/* only 7 bits addresses. */ +static bool nv50_i2c_address(struct nv50_i2c_channel *chan, uint8_t address, bool write) +{ + if (nv50_i2c_start(chan)) { + uint8_t real_addr = (address << 1); + if (!write) + real_addr |= 1; + + if (nv50_i2c_write_byte(chan, real_addr)) + return TRUE; + + /* failure, so issue stop */ + nv50_i2c_stop(chan); + } + + return FALSE; +} + +static bool nv50_i2c_read(struct nv50_i2c_channel *chan, uint8_t address, uint8_t *buffer, uint32_t length) +{ + int i, j; + bool rval, last; + + /* retries */ + for (i = 0; i < 4; i++) { + rval = nv50_i2c_address(chan, address, FALSE); + if (!rval) + return FALSE; + + for (j = 0; j < length; j++) { + last = false; + if (j == (length - 1)) + last = true; + rval = nv50_i2c_read_byte(chan, &buffer[j], last); + if (!rval) { + nv50_i2c_stop(chan); + break; + } + } + + nv50_i2c_stop(chan); + + /* done */ + if (rval) + break; + } + + if (!rval) + printk("nv50_i2c_read failed\n"); + + return rval; +} + +static bool nv50_i2c_write(struct nv50_i2c_channel *chan, uint8_t address, uint8_t *buffer, uint32_t length) +{ + int i, j; + bool rval; + + /* retries */ + for (i = 0; i < 4; i++) { + rval = nv50_i2c_address(chan, address, TRUE); + if (!rval) + return FALSE; + + for (j = 0; j < length; j++) { + rval = nv50_i2c_write_byte(chan, buffer[j]); + if (!rval) { + break; + } + } + + nv50_i2c_stop(chan); + + /* done */ + if (rval) + break; + } + + if (!rval) + printk("nv50_i2c_write failed\n"); + + return rval; +} + +static int nv50_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct nv50_i2c_channel *chan = i2c_get_adapdata(i2c_adap); + bool rval; + int i; + + for (i = 0; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) { /* read */ + rval = nv50_i2c_read(chan, msgs[i].addr, msgs[i].buf, msgs[i].len); + } else { /* write */ + rval = nv50_i2c_write(chan, msgs[i].addr, msgs[i].buf, msgs[i].len); + } + + if (!rval) + break; + } + + if (rval) + return i; + else + return -EINVAL; +} + +static u32 nv50_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static const struct i2c_algorithm nv50_i2c_algo = { + .master_xfer = nv50_i2c_xfer, + .functionality = nv50_i2c_functionality, +}; + +static int nv50_i2c_register_bus(struct i2c_adapter *adap) +{ + adap->algo = &nv50_i2c_algo; + + adap->timeout = 40; + adap->retries = 4; + + return i2c_add_adapter(adap); +} + +#define I2C_HW_B_NOUVEAU 0x010030 +struct nv50_i2c_channel *nv50_i2c_channel_create(struct drm_device *dev, uint32_t index) +{ + struct nv50_i2c_channel *chan; + + chan = kzalloc(sizeof(struct nv50_i2c_channel), GFP_KERNEL); + + if (!chan) + goto out; + + DRM_INFO("Creating i2c bus with index %d\n", index); + + chan->dev = dev; + chan->index = index; + snprintf(chan->adapter.name, I2C_NAME_SIZE, "nv50 i2c %d", index); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_HW_B_NOUVEAU; + chan->adapter.dev.parent = &dev->pdev->dev; + + i2c_set_adapdata(&chan->adapter, chan); + + if (nv50_i2c_register_bus(&chan->adapter)) + goto out; + + return chan; + +out: + kfree(chan); + return NULL; +} + +void nv50_i2c_channel_destroy(struct nv50_i2c_channel *chan) +{ + if (!chan) + return; + + i2c_del_adapter(&chan->adapter); + kfree(chan); +} diff --git a/linux-core/nv50_i2c.h b/linux-core/nv50_i2c.h new file mode 100644 index 00000000..1740f8ec --- /dev/null +++ b/linux-core/nv50_i2c.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_I2C_H__ +#define __NV50_I2C_H__ + +#include +#include +#include +#include "drmP.h" +#include "drm.h" +#include "nv50_display.h" + +struct nv50_i2c_channel { + struct drm_device *dev; + + uint32_t index; + struct i2c_adapter adapter; +}; + +struct nv50_i2c_channel *nv50_i2c_channel_create(struct drm_device *dev, uint32_t index); +void nv50_i2c_channel_destroy(struct nv50_i2c_channel *chan); + +#endif /* __NV50_I2C_H__ */ diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c new file mode 100644 index 00000000..01d4bc9a --- /dev/null +++ b/linux-core/nv50_kms_wrapper.c @@ -0,0 +1,960 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_kms_wrapper.h" +#include "drm_crtc_helper.h" /* be careful what you use from this */ + +/* This file serves as the interface between the common kernel modesetting code and the device dependent implementation. */ + +/* + * Get private functions. + */ + +struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + return dev_priv->kms_priv; +} + +/* + * Allocation functions. + */ + +static void *nv50_kms_alloc_crtc(struct drm_device *dev) +{ + struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); + struct nv50_kms_crtc *crtc = kzalloc(sizeof(struct nv50_kms_crtc), GFP_KERNEL); + + list_add_tail(&crtc->head, &kms_priv->crtcs); + + return &(crtc->priv); +} + +static void *nv50_kms_alloc_output(struct drm_device *dev) +{ + struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); + struct nv50_kms_encoder *encoder = kzalloc(sizeof(struct nv50_kms_encoder), GFP_KERNEL); + + list_add_tail(&encoder->head, &kms_priv->encoders); + + return &(encoder->priv); +} + +static void *nv50_kms_alloc_connector(struct drm_device *dev) +{ + struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); + struct nv50_kms_connector *connector = kzalloc(sizeof(struct nv50_kms_connector), GFP_KERNEL); + + list_add_tail(&connector->head, &kms_priv->connectors); + + return &(connector->priv); +} + +static void nv50_kms_free_crtc(void *crtc) +{ + struct nv50_kms_crtc *kms_crtc = from_nv50_crtc(crtc); + + list_del(&kms_crtc->head); + + kfree(kms_crtc); +} + +static void nv50_kms_free_output(void *output) +{ + struct nv50_kms_encoder *kms_encoder = from_nv50_output(output); + + list_del(&kms_encoder->head); + + kfree(kms_encoder); +} + +static void nv50_kms_free_connector(void *connector) +{ + struct nv50_kms_connector *kms_connector = from_nv50_connector(connector); + + list_del(&kms_connector->head); + + kfree(kms_connector); +} + +/* + * Mode conversion functions. + */ + +static struct nouveau_hw_mode *nv50_kms_to_hw_mode(struct drm_display_mode *mode) +{ + struct nouveau_hw_mode *hw_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + + /* create hw values. */ + hw_mode->clock = mode->clock; + hw_mode->flags = hw_mode->flags; + + hw_mode->hdisplay = mode->hdisplay; + hw_mode->hsync_start = mode->hsync_start; + hw_mode->hsync_end = mode->hsync_end; + hw_mode->htotal = mode->htotal; + + hw_mode->hblank_start = mode->hdisplay + 1; + hw_mode->hblank_end = mode->htotal; + + hw_mode->vdisplay = mode->vdisplay; + hw_mode->vsync_start = mode->vsync_start; + hw_mode->vsync_end = mode->vsync_end; + hw_mode->vtotal = mode->vtotal; + + hw_mode->vblank_start = mode->vdisplay + 1; + hw_mode->vblank_end = mode->vtotal; + + return hw_mode; +} + +/* + * State mirroring functions. + */ + +static void nv50_kms_mirror_routing(struct drm_device *dev) +{ + struct nv50_display *display = nv50_get_display(dev); + struct nv50_crtc *crtc = NULL; + struct nv50_output *output = NULL; + struct nv50_connector *connector = NULL; + struct drm_connector *drm_connector = NULL; + + /* Wipe all previous connections. */ + list_for_each_entry(connector, &display->connectors, head) { + connector->output = NULL; + } + + list_for_each_entry(output, &display->outputs, head) { + output->crtc = NULL; + } + + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder) { + output = to_nv50_output(drm_connector->encoder); + connector = to_nv50_connector(drm_connector); + + /* hook up output to connector. */ + connector->output = output; + + if (drm_connector->encoder->crtc) { + crtc = to_nv50_crtc(drm_connector->encoder->crtc); + + /* hook up output to crtc. */ + output->crtc = crtc; + } + } + } +} + +/* + * FB functions. + */ + +static void nv50_kms_framebuffer_destroy(struct drm_framebuffer *drm_framebuffer) +{ + drm_framebuffer_cleanup(drm_framebuffer); + + kfree(drm_framebuffer); +} + +static const struct drm_framebuffer_funcs nv50_kms_fb_funcs = { + .destroy = nv50_kms_framebuffer_destroy, +}; + +/* + * Mode config functions. + */ + +static struct drm_framebuffer *nv50_kms_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd) +{ + struct drm_framebuffer *drm_framebuffer = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); + if (!drm_framebuffer) + return NULL; + + drm_framebuffer_init(dev, drm_framebuffer, &nv50_kms_fb_funcs); + drm_helper_mode_fill_fb_struct(drm_framebuffer, mode_cmd); + + return drm_framebuffer; +} + +static int nv50_kms_fb_changed(struct drm_device *dev) +{ + return 0; /* not needed until nouveaufb? */ +} + +static const struct drm_mode_config_funcs nv50_kms_mode_funcs = { + .resize_fb = NULL, + .fb_create = nv50_kms_framebuffer_create, + .fb_changed = nv50_kms_fb_changed, +}; + +/* + * CRTC functions. + */ + +static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_handle, + uint32_t width, uint32_t height) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + struct nv50_display *display = nv50_get_display(crtc->dev); + int rval; + + if (width != 64 || height != 64) + return -EINVAL; + + rval = crtc->cursor->set_bo(crtc, (drm_handle_t) buffer_handle); + + if (rval != 0) + return rval; + + /* in case this triggers any other cursor changes */ + display->update(display); + + return 0; +} + +static int nv50_kms_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + + return crtc->cursor->set_pos(crtc, x, y); +} + +void nv50_kms_crtc_gamma_set(struct drm_crtc *drm_crtc, u16 *r, u16 *g, u16 *b, + uint32_t size) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + + if (size != 256) + return; + + crtc->lut->set(crtc, (uint16_t *)r, (uint16_t *)g, (uint16_t *)b); +} + +int nv50_kms_crtc_set_config(struct drm_mode_set *set) +{ + int rval = 0, i; + uint32_t crtc_mask = 0; + struct drm_device *dev = NULL; + struct drm_nouveau_private *dev_priv = NULL; + struct nv50_display *display = NULL; + struct drm_connector *drm_connector = NULL; + struct drm_encoder *drm_encoder = NULL; + struct drm_crtc *drm_crtc = NULL; + + struct nv50_crtc *crtc = NULL; + struct nv50_output *output = NULL; + struct nv50_connector *connector = NULL; + struct nouveau_hw_mode *hw_mode = NULL; + struct nv50_fb_info fb_info; + + NV50_DEBUG("\n"); + + /* + * Initial approach is very simple, always set a mode. + * Always bail out completely if something is wrong. + * Later this could be extended to be more smart. + */ + + /* Sanity checking */ + if (!set) { + NV50_DEBUG("Sanity check failed\n"); + goto out; + } + + if (!set->crtc || !set->fb || !set->mode || !set->connectors) { + NV50_DEBUG("Sanity check failed\n"); + goto out; + } + + /* Basic variable setting */ + dev = set->crtc->dev; + dev_priv = dev->dev_private; + display = nv50_get_display(dev); + crtc = to_nv50_crtc(set->crtc); + + /* Mode validation */ + hw_mode = nv50_kms_to_hw_mode(set->mode); + + rval = crtc->validate_mode(crtc, hw_mode); + + if (rval != MODE_OK) { + NV50_DEBUG("Mode not ok\n"); + goto out; + } + + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } + connector = to_nv50_connector(drm_connector); + + output = connector->to_output(connector, connector->digital); + if (!output) { + NV50_DEBUG("No output\n"); + goto out; + } + + rval = output->validate_mode(output, hw_mode); + if (rval != MODE_OK) { + NV50_DEBUG("Mode not ok\n"); + goto out; + } + } + + /* Validation done, move on to cleaning of existing structures. */ + + /* find encoders that use this crtc. */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + /* find the connector that goes with it */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder == drm_encoder) { + drm_connector->encoder = NULL; + break; + } + } + drm_encoder->crtc = NULL; + } + } + + /* now find if our desired encoders or connectors are in use already. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } + + if (!drm_connector->encoder) + continue; + + drm_encoder = drm_connector->encoder; + drm_connector->encoder = NULL; + + if (!drm_encoder->crtc) + continue; + + drm_crtc = drm_encoder->crtc; + drm_encoder->crtc = NULL; + + crtc = to_nv50_crtc(drm_crtc); + crtc->active = false; + drm_crtc->enabled = false; + } + + /* set framebuffer */ + set->crtc->fb = set->fb; + + /* Time to wire up the public encoder, the private one will be handled later. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } + + output = connector->to_output(connector, connector->digital); + if (!output) { + NV50_DEBUG("No output\n"); + goto out; + } + + /* find the encoder public structure that matches out output structure. */ + drm_encoder = to_nv50_kms_encoder(output); + + if (!drm_encoder) { + NV50_DEBUG("No encoder\n"); + goto out; + } + + + drm_encoder->crtc = set->crtc; + drm_connector->encoder = drm_encoder; + } + + /* mirror everything to the private structs */ + nv50_kms_mirror_routing(dev); + + /* set private framebuffer */ + crtc = to_nv50_crtc(set->crtc); + fb_info.block = find_block_by_handle(dev_priv->fb_heap, set->fb->mm_handle); + fb_info.width = set->fb->width; + fb_info.height = set->fb->height; + fb_info.depth = set->fb->depth; + fb_info.bpp = set->fb->bits_per_pixel; + fb_info.x = set->x; + fb_info.y = set->y; + + rval = crtc->fb->bind(crtc, &fb_info); + if (rval != 0) { + NV50_DEBUG("fb_bind failed\n"); + goto out; + } + + if (!crtc->cursor->enabled) { + rval = crtc->cursor->enable(crtc); + if (rval != 0) { + NV50_DEBUG("cursor_enable failed\n"); + goto out; + } + } + + /* modeset time, finally */ + + /* disconnect unused outputs */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc) + crtc_mask |= 1 << output->crtc->index; + else + output->execute_mode(output, TRUE); + } + + rval = crtc->set_mode(crtc, hw_mode); + if (rval != 0) { + NV50_DEBUG("crtc mode set failed\n"); + goto out; + } + + /* find native mode. */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; + + *crtc->native_mode = *output->native_mode; + list_for_each_entry(connector, &display->connectors, head) { + if (connector->output != output) + continue; + + crtc->scaling_mode = connector->scaling_mode; + break; + } + + if (crtc->scaling_mode == SCALE_PANEL) + crtc->use_native_mode = false; + else + crtc->use_native_mode = true; + + break; /* no use in finding more than one mode */ + } + + rval = crtc->execute_mode(crtc); + if (rval != 0) { + NV50_DEBUG("crtc execute mode failed\n"); + goto out; + } + + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; + + rval = output->execute_mode(output, FALSE); + if (rval != 0) { + NV50_DEBUG("output execute mode failed\n"); + goto out; + } + } + + rval = crtc->set_scale(crtc); + if (rval != 0) { + NV50_DEBUG("crtc set scale failed\n"); + goto out; + } + + /* next line changes crtc, so putting it here is important */ + display->last_crtc = crtc->index; + + /* blank any unused crtcs */ + list_for_each_entry(crtc, &display->crtcs, head) { + if (!(crtc_mask & (1 << crtc->index))) + crtc->blank(crtc, TRUE); + } + + display->update(display); + + kfree(hw_mode); + + return 0; + +out: + display->update(display); + + kfree(hw_mode); + + if (rval != 0) + return rval; + else + return -EINVAL; +} + +static void nv50_kms_crtc_destroy(struct drm_crtc *drm_crtc) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + + drm_crtc_cleanup(drm_crtc); + + /* this will even destroy the public structure. */ + crtc->destroy(crtc); +} + +static const struct drm_crtc_funcs nv50_kms_crtc_funcs = { + .save = NULL, + .restore = NULL, + .cursor_set = nv50_kms_crtc_cursor_set, + .cursor_move = nv50_kms_crtc_cursor_move, + .gamma_set = nv50_kms_crtc_gamma_set, + .set_config = nv50_kms_crtc_set_config, + .destroy = nv50_kms_crtc_destroy, +}; + +static int nv50_kms_crtcs_init(struct drm_device *dev) +{ + struct nv50_display *display = nv50_get_display(dev); + struct nv50_crtc *crtc = NULL; + + /* + * This may look a bit confusing, but: + * The internal structure is already allocated and so is the public one. + * Just a matter of getting to the memory and register it. + */ + list_for_each_entry(crtc, &display->crtcs, head) { + struct drm_crtc *drm_crtc = to_nv50_kms_crtc(crtc); + + drm_crtc_init(dev, drm_crtc, &nv50_kms_crtc_funcs); + } + + return 0; +} + +/* + * Encoder functions + */ + +static void nv50_kms_encoder_destroy(struct drm_encoder *drm_encoder) +{ + struct nv50_output *output = to_nv50_output(drm_encoder); + + drm_encoder_cleanup(drm_encoder); + + /* this will even destroy the public structure. */ + output->destroy(output); +} + +static const struct drm_encoder_funcs nv50_kms_encoder_funcs = { + .destroy = nv50_kms_encoder_destroy, +}; + +static int nv50_kms_encoders_init(struct drm_device *dev) +{ + struct nv50_display *display = nv50_get_display(dev); + struct nv50_output *output = NULL; + + list_for_each_entry(output, &display->outputs, head) { + struct drm_encoder *drm_encoder = to_nv50_kms_encoder(output); + uint32_t type = DRM_MODE_ENCODER_NONE; + + switch (output->type) { + case OUTPUT_DAC: + type = DRM_MODE_ENCODER_DAC; + break; + case OUTPUT_TMDS: + type = DRM_MODE_ENCODER_TMDS; + break; + case OUTPUT_LVDS: + type = DRM_MODE_ENCODER_LVDS; + break; + case OUTPUT_TV: + type = DRM_MODE_ENCODER_TVDAC; + break; + default: + type = DRM_MODE_ENCODER_NONE; + break; + } + + if (type == DRM_MODE_ENCODER_NONE) { + DRM_ERROR("DRM_MODE_ENCODER_NONE encountered\n"); + continue; + } + + drm_encoder_init(dev, drm_encoder, &nv50_kms_encoder_funcs, type); + + /* I've never seen possible crtc's restricted. */ + drm_encoder->possible_crtcs = 3; + drm_encoder->possible_clones = 0; + } + + return 0; +} + +/* + * Connector functions + */ + +void nv50_kms_connector_detect_all(struct drm_device *dev) +{ + struct drm_connector *drm_connector = NULL; + enum drm_connector_status old, new; + bool notify = false; + + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + old = drm_connector->status; + new = drm_connector->funcs->detect(drm_connector); + + if (new != old) { + notify = true; + drm_connector->funcs->fill_modes(drm_connector, 0, 0); + } + } + + /* I think this is the hook that notifies of changes. */ + if (notify) + dev->mode_config.funcs->fb_changed(dev); +} + +static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector) +{ + struct nv50_connector *connector = to_nv50_connector(drm_connector); + bool connected; + + connected = connector->detect(connector); + + if (connected) + drm_connector->status = connector_status_connected; + else + drm_connector->status = connector_status_disconnected; + + return drm_connector->status; +} + +static void nv50_kms_connector_destroy(struct drm_connector *drm_connector) +{ + struct nv50_connector *connector = to_nv50_connector(drm_connector); + + drm_sysfs_connector_remove(drm_connector); + drm_connector_cleanup(drm_connector); + + /* this will even destroy the public structure. */ + connector->destroy(connector); +} + +/* + * Detailed mode info for a standard 640x480@60Hz monitor + */ +static struct drm_display_mode std_mode[] = { + /*{ DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + V_NHSYNC | V_NVSYNC) },*/ /* 640x480@60Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DEFAULT, 135000, 1280, 1296, + 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, + V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */ +}; + +static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, uint32_t maxX, uint32_t maxY) +{ + struct nv50_connector *connector = to_nv50_connector(drm_connector); + int ret = 0; + bool connected; + struct drm_display_mode *mode, *t; + struct edid *edid = NULL; + + DRM_DEBUG("%s\n", drm_get_connector_name(drm_connector)); + /* set all modes to the unverified state */ + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) + mode->status = MODE_UNVERIFIED; + + connected = connector->detect(connector); + + if (connected) + drm_connector->status = connector_status_connected; + else + drm_connector->status = connector_status_disconnected; + + if (!connected) { + DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); + /* TODO set EDID to NULL */ + return; + } + + /* Not all connnectors have an i2c channel. */ + if (connector->i2c_chan) + edid = (struct edid *) drm_do_probe_ddc_edid(&connector->i2c_chan->adapter); + + if (edid) { + drm_mode_connector_update_edid_property(drm_connector, edid); + ret = drm_add_edid_modes(drm_connector, edid); + connector->digital = edid->digital; /* cache */ + } + + if (ret) /* number of modes > 1 */ + drm_mode_connector_list_update(drm_connector); + + if (maxX && maxY) + drm_mode_validate_size(drm_connector->dev, &drm_connector->modes, maxX, maxY, 0); + + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { + if (mode->status == MODE_OK) { + struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); + struct nv50_output *output = connector->to_output(connector, connector->digital); + + mode->status = output->validate_mode(output, hw_mode); + /* find native mode, TODO: also check if we actually found one */ + if (mode->status == MODE_OK) { + if (mode->type & DRM_MODE_TYPE_PREFERRED) + *output->native_mode = *hw_mode; + } + kfree(hw_mode); + } + } + + /* revalidate now that we have native mode */ + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { + if (mode->status == MODE_OK) { + struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); + struct nv50_output *output = connector->to_output(connector, connector->digital); + + mode->status = output->validate_mode(output, hw_mode); + kfree(hw_mode); + } + } + + drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, TRUE); + + if (list_empty(&drm_connector->modes)) { + struct drm_display_mode *stdmode; + struct nouveau_hw_mode *hw_mode; + struct nv50_output *output; + + DRM_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector)); + + /* Should we do this here ??? + * When no valid EDID modes are available we end up + * here and bailed in the past, now we add a standard + * 640x480@60Hz mode and carry on. + */ + stdmode = drm_mode_duplicate(drm_connector->dev, &std_mode[0]); + drm_mode_probed_add(drm_connector, stdmode); + drm_mode_list_concat(&drm_connector->probed_modes, + &drm_connector->modes); + + /* also add it as native mode */ + hw_mode = nv50_kms_to_hw_mode(mode); + output = connector->to_output(connector, connector->digital); + + if (hw_mode) + *output->native_mode = *hw_mode; + + DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", + drm_get_connector_name(drm_connector)); + } + + drm_mode_sort(&drm_connector->modes); + + DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(drm_connector)); + + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { + mode->vrefresh = drm_mode_vrefresh(mode); + + /* is this needed, as it's unused by the driver? */ + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + drm_mode_debug_printmodeline(mode); + } +} + +static const struct drm_connector_funcs nv50_kms_connector_funcs = { + .save = NULL, + .restore = NULL, + .detect = nv50_kms_connector_detect, + .destroy = nv50_kms_connector_destroy, + .fill_modes = nv50_kms_connector_fill_modes, +}; + +static int nv50_kms_connectors_init(struct drm_device *dev) +{ + struct nv50_display *display = nv50_get_display(dev); + struct nv50_connector *connector = NULL; + int i; + + list_for_each_entry(connector, &display->connectors, head) { + struct drm_connector *drm_connector = to_nv50_kms_connector(connector); + uint32_t type = DRM_MODE_CONNECTOR_Unknown; + + switch (connector->type) { + case CONNECTOR_VGA: + type = DRM_MODE_CONNECTOR_VGA; + break; + case CONNECTOR_DVI_D: + type = DRM_MODE_CONNECTOR_DVID; + break; + case CONNECTOR_DVI_I: + type = DRM_MODE_CONNECTOR_DVII; + break; + case CONNECTOR_LVDS: + type = DRM_MODE_CONNECTOR_LVDS; + break; + case CONNECTOR_TV: + type = DRM_MODE_CONNECTOR_SVIDEO; + break; + default: + type = DRM_MODE_CONNECTOR_Unknown; + break; + } + + if (type == DRM_MODE_CONNECTOR_Unknown) { + DRM_ERROR("DRM_MODE_CONNECTOR_Unknown encountered\n"); + continue; + } + + /* It should be allowed sometimes, but let's be safe for the moment. */ + drm_connector->interlace_allowed = false; + drm_connector->doublescan_allowed = false; + + drm_connector_init(dev, drm_connector, &nv50_kms_connector_funcs, type); + + /* attach encoders, possibilities are analog + digital */ + for (i = 0; i < 2; i++) { + struct drm_encoder *drm_encoder = NULL; + struct nv50_output *output = connector->to_output(connector, i); + if (!output) + continue; + + drm_encoder = to_nv50_kms_encoder(output); + if (!drm_encoder) { + DRM_ERROR("No struct drm_connector to match struct nv50_output\n"); + continue; + } + + drm_mode_connector_attach_encoder(drm_connector, drm_encoder); + } + + drm_sysfs_connector_add(drm_connector); + } + + return 0; +} + +/* + * Main functions + */ + +int nv50_kms_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_kms_priv *kms_priv = kzalloc(sizeof(struct nv50_kms_priv), GFP_KERNEL); + struct nv50_display *display = NULL; + int rval = 0; + + dev_priv->kms_priv = kms_priv; + + /* function pointers */ + /* an allocation interface that deals with the outside world, without polluting the core. */ + dev_priv->alloc_crtc = nv50_kms_alloc_crtc; + dev_priv->alloc_output = nv50_kms_alloc_output; + dev_priv->alloc_connector = nv50_kms_alloc_connector; + + dev_priv->free_crtc = nv50_kms_free_crtc; + dev_priv->free_output = nv50_kms_free_output; + dev_priv->free_connector = nv50_kms_free_connector; + + /* bios is needed for tables. */ + rval = nouveau_parse_bios(dev); + if (rval != 0) + goto out; + + /* init basic kernel modesetting */ + drm_mode_config_init(dev); + + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + + dev->mode_config.funcs = (void *)&nv50_kms_mode_funcs; + + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; + + dev->mode_config.fb_base = dev_priv->fb_phys; + + /* init kms lists */ + INIT_LIST_HEAD(&kms_priv->crtcs); + INIT_LIST_HEAD(&kms_priv->encoders); + INIT_LIST_HEAD(&kms_priv->connectors); + + /* init the internal core, must be done first. */ + rval = nv50_display_create(dev); + if (rval != 0) + goto out; + + display = nv50_get_display(dev); + if (!display) { + rval = -EINVAL; + goto out; + } + + /* pre-init now */ + rval = display->pre_init(display); + if (rval != 0) + goto out; + + /* init external layer */ + rval = nv50_kms_crtcs_init(dev); + if (rval != 0) + goto out; + + rval = nv50_kms_encoders_init(dev); + if (rval != 0) + goto out; + + rval = nv50_kms_connectors_init(dev); + if (rval != 0) + goto out; + + /* init now, this'll kill the textmode */ + rval = display->init(display); + if (rval != 0) + goto out; + + /* process cmdbuffer */ + display->update(display); + + return 0; + +out: + kfree(kms_priv); + dev_priv->kms_priv = NULL; + + return rval; +} + +int nv50_kms_destroy(struct drm_device *dev) +{ + drm_mode_config_cleanup(dev); + + return 0; +} + diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h new file mode 100644 index 00000000..3847d510 --- /dev/null +++ b/linux-core/nv50_kms_wrapper.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_KMS_WRAPPER_H__ +#define __NV50_KMS_WRAPPER_H__ + +#include "drmP.h" +#include "drm.h" + +#include "nv50_display.h" +#include "nv50_crtc.h" +#include "nv50_cursor.h" +#include "nv50_lut.h" +#include "nv50_fb.h" +#include "nv50_output.h" +#include "nv50_connector.h" + +#include "drm_crtc.h" +#include "drm_edid.h" + +/* Link internal modesetting structure to interface. */ + +struct nv50_kms_crtc { + struct list_head head; + + struct nv50_crtc priv; + struct drm_crtc pub; +}; + +struct nv50_kms_encoder { + struct list_head head; + + struct nv50_output priv; + struct drm_encoder pub; +}; + +struct nv50_kms_connector { + struct list_head head; + + struct nv50_connector priv; + struct drm_connector pub; +}; + +struct nv50_kms_priv { + struct list_head crtcs; + struct list_head encoders; + struct list_head connectors; +}; + +/* Get private functions. */ +#define from_nv50_kms_crtc(x) container_of(x, struct nv50_kms_crtc, pub) +#define from_nv50_crtc(x) container_of(x, struct nv50_kms_crtc, priv) +#define from_nv50_kms_encoder(x) container_of(x, struct nv50_kms_encoder, pub) +#define from_nv50_output(x) container_of(x, struct nv50_kms_encoder, priv) +#define from_nv50_kms_connector(x) container_of(x, struct nv50_kms_connector, pub) +#define from_nv50_connector(x) container_of(x, struct nv50_kms_connector, priv) + +#define to_nv50_crtc(x) (&(from_nv50_kms_crtc(x)->priv)) +#define to_nv50_kms_crtc(x) (&(from_nv50_crtc(x)->pub)) +#define to_nv50_output(x) (&(from_nv50_kms_encoder(x)->priv)) +#define to_nv50_kms_encoder(x) (&(from_nv50_output(x)->pub)) +#define to_nv50_connector(x) (&(from_nv50_kms_connector(x)->priv)) +#define to_nv50_kms_connector(x) (&(from_nv50_connector(x)->pub)) + +struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev); +void nv50_kms_connector_detect_all(struct drm_device *dev); + +int nv50_kms_init(struct drm_device *dev); +int nv50_kms_destroy(struct drm_device *dev); + +#endif /* __NV50_KMS_WRAPPER_H__ */ diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c new file mode 100644 index 00000000..570900ba --- /dev/null +++ b/linux-core/nv50_lut.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_lut.h" +#include "nv50_fb.h" +#include "nv50_crtc.h" +#include "nv50_display.h" + +static int nv50_lut_alloc(struct nv50_crtc *crtc) +{ + struct mem_block *block; + struct drm_file *file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL); + uint32_t flags = NOUVEAU_MEM_INTERNAL | NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; + + NV50_DEBUG("\n"); + + /* Any file_priv should do as it's pointer is used as identification. */ + block = nouveau_mem_alloc(crtc->dev, 0, 4096, flags, file_priv); + + if (!block) + return -ENOMEM; + + crtc->lut->block = block; + + return 0; +} + +static int nv50_lut_free(struct nv50_crtc *crtc) +{ + struct drm_file *file_priv = crtc->lut->block->file_priv; + + NV50_DEBUG("\n"); + + nouveau_mem_free(crtc->dev, crtc->lut->block); + + kfree(file_priv); + + return 0; +} + +#define NV50_LUT_INDEX(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8))) +static int nv50_lut_set(struct nv50_crtc *crtc, uint16_t *red, uint16_t *green, uint16_t *blue) +{ + uint32_t index = 0, i; + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + void __iomem *lut = NULL; + + NV50_DEBUG("\n"); + + if (!crtc->lut || !crtc->lut->block) { + DRM_ERROR("Something wrong with the LUT\n"); + return -EINVAL; + } + + /* 16 bits, red, green, blue, unused, total of 64 bits per index */ + /* maybe switch to ioremap_wc once it becomes available. */ + lut = ioremap(dev_priv->fb_phys + crtc->lut->block->start, crtc->lut->block->size); + if (!lut) { + DRM_ERROR("ioremap failed on LUT\n"); + return -EINVAL; + } + + /* 10 bits lut, with 14 bits values. */ + switch (crtc->fb->depth) { + case 15: + /* R5G5B5 */ + for (i = 0; i < 32; i++) { + index = NV50_LUT_INDEX(i, 5); + writew(red[i] >> 2, lut + 8*index + 0); + writew(green[i] >> 2, lut + 8*index + 2); + writew(blue[i] >> 2, lut + 8*index + 4); + } + break; + case 16: + /* R5G6B5 */ + for (i = 0; i < 32; i++) { + index = NV50_LUT_INDEX(i, 5); + writew(red[i] >> 2, lut + 8*index + 0); + writew(blue[i] >> 2, lut + 8*index + 4); + } + + /* Green has an extra bit. */ + for (i = 0; i < 64; i++) { + index = NV50_LUT_INDEX(i, 6); + writew(green[i] >> 2, lut + 8*index + 2); + } + break; + default: + /* R8G8B8 */ + for (i = 0; i < 256; i++) { + writew(red[i] >> 2, lut + 8*i + 0); + writew(green[i] >> 2, lut + 8*i + 2); + writew(blue[i] >> 2, lut + 8*i + 4); + } + break; + } + + crtc->lut->depth = crtc->fb->depth; + + /* Cleaning time. */ + iounmap(lut); + + return 0; +} + +int nv50_lut_create(struct nv50_crtc *crtc) +{ + int rval = 0; + + NV50_DEBUG("\n"); + + if (!crtc) + return -EINVAL; + + crtc->lut = kzalloc(sizeof(struct nv50_lut), GFP_KERNEL); + + rval = nv50_lut_alloc(crtc); + if (rval != 0) + return rval; + + /* lut will be inited when fb is bound */ + crtc->lut->depth = 0; + + /* function pointers */ + crtc->lut->set = nv50_lut_set; + + return 0; +} + +int nv50_lut_destroy(struct nv50_crtc *crtc) +{ + int rval = 0; + + NV50_DEBUG("\n"); + + if (!crtc) + return -EINVAL; + + rval = nv50_lut_free(crtc); + + kfree(crtc->lut); + crtc->lut = NULL; + + if (rval != 0) + return rval; + + return 0; +} diff --git a/linux-core/nv50_lut.h b/linux-core/nv50_lut.h new file mode 100644 index 00000000..06704830 --- /dev/null +++ b/linux-core/nv50_lut.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_LUT_H__ +#define __NV50_LUT_H__ + +#include "nv50_display.h" + +struct nv50_crtc; + +struct nv50_lut { + struct mem_block *block; + + int depth; /* check against fb to see if it needs to be reuploaded */ + + int (*set) (struct nv50_crtc *crtc, uint16_t *red, uint16_t *green, uint16_t *blue); +}; + +int nv50_lut_create(struct nv50_crtc *crtc); +int nv50_lut_destroy(struct nv50_crtc *crtc); + +#endif /* __NV50_LUT_H__ */ diff --git a/linux-core/nv50_output.c b/linux-core/nv50_output.c new file mode 100644 index 00000000..de0017b9 --- /dev/null +++ b/linux-core/nv50_output.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_output.h" + +int nv50_output_or_offset(struct nv50_output *output) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + return ffs(dev_priv->dcb_table.entry[output->dcb_entry].or) - 1; +} diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h new file mode 100644 index 00000000..bdee2826 --- /dev/null +++ b/linux-core/nv50_output.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_OUTPUT_H__ +#define __NV50_OUTPUT_H__ + +#include "nv50_crtc.h" + +#define OUTPUT_UNKNOWN 0 +#define OUTPUT_DAC 1 +#define OUTPUT_TMDS 2 +#define OUTPUT_LVDS 3 +#define OUTPUT_TV 4 + +struct nv50_output { + struct list_head head; + + struct drm_device *dev; + int bus; + int dcb_entry; + int type; + + struct nv50_crtc *crtc; + struct nouveau_hw_mode *native_mode; + + int (*validate_mode) (struct nv50_output *output, struct nouveau_hw_mode *mode); + int (*execute_mode) (struct nv50_output *output, bool disconnect); + int (*set_clock_mode) (struct nv50_output *output); + bool (*detect) (struct nv50_output *output); + int (*destroy) (struct nv50_output *output); +}; + +int nv50_output_or_offset(struct nv50_output *output); +int nv50_sor_create(struct drm_device *dev, int dcb_entry); +int nv50_dac_create(struct drm_device *dev, int dcb_entry); + +#endif /* __NV50_OUTPUT_H__ */ diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c new file mode 100644 index 00000000..430c1e83 --- /dev/null +++ b/linux-core/nv50_sor.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "nv50_output.h" + +static int nv50_sor_validate_mode(struct nv50_output *output, struct nouveau_hw_mode *mode) +{ + NV50_DEBUG("\n"); + + if (mode->clock > 165000) /* no dual link until we figure it out completely */ + return MODE_CLOCK_HIGH; + + if (mode->clock < 25000) + return MODE_CLOCK_LOW; + + if (output->native_mode->hdisplay > 0 && output->native_mode->vdisplay > 0) { + if (mode->hdisplay > output->native_mode->hdisplay || mode->vdisplay > output->native_mode->vdisplay) + return MODE_PANEL; + } + + return MODE_OK; +} + +static int nv50_sor_execute_mode(struct nv50_output *output, bool disconnect) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + struct nv50_crtc *crtc = output->crtc; + struct nouveau_hw_mode *desired_mode = NULL; + + uint32_t offset = nv50_output_or_offset(output) * 0x40; + + uint32_t mode_ctl = NV50_SOR_MODE_CTRL_OFF; + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + if (disconnect) { + NV50_DEBUG("Disconnecting SOR\n"); + OUT_MODE(NV50_SOR0_MODE_CTRL + offset, mode_ctl); + return 0; + } + + desired_mode = (crtc->use_native_mode ? crtc->native_mode : crtc->mode); + + if (output->type == OUTPUT_LVDS) { + mode_ctl |= NV50_SOR_MODE_CTRL_LVDS; + } else { + mode_ctl |= NV50_SOR_MODE_CTRL_TMDS; + if (desired_mode->clock > 165000) + mode_ctl |= NV50_SOR_MODE_CTRL_TMDS_DUAL_LINK; + } + + if (crtc->index == 1) + mode_ctl |= NV50_SOR_MODE_CTRL_CRTC1; + else + mode_ctl |= NV50_SOR_MODE_CTRL_CRTC0; + + if (desired_mode->flags & V_NHSYNC) + mode_ctl |= NV50_SOR_MODE_CTRL_NHSYNC; + + if (desired_mode->flags & V_NVSYNC) + mode_ctl |= NV50_SOR_MODE_CTRL_NVSYNC; + + /* TODO: DPMS ?????? */ + + OUT_MODE(NV50_SOR0_MODE_CTRL + offset, mode_ctl); + + return 0; +} + +static int nv50_sor_set_clock_mode(struct nv50_output *output) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + struct nv50_crtc *crtc = output->crtc; + + uint32_t limit = 165000; + struct nouveau_hw_mode *hw_mode; + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + if (crtc->use_native_mode) + hw_mode = crtc->native_mode; + else + hw_mode = crtc->mode; + + /* 0x70000 was a late addition to nv, mentioned as fixing tmds initialisation on certain gpu's. */ + /* I presume it's some kind of clock setting, but what precisely i do not know. */ + NV_WRITE(NV50_PDISPLAY_SOR_CLK_CLK_CTRL2(nv50_output_or_offset(output)), 0x70000 | ((hw_mode->clock > limit) ? 0x101 : 0)); + + return 0; +} + +static int nv50_sor_destroy(struct nv50_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + + NV50_DEBUG("\n"); + + if (!display || !output) + return -EINVAL; + + list_del(&output->head); + + kfree(output->native_mode); + if (dev_priv->free_output) + dev_priv->free_output(output); + + return 0; +} + +int nv50_sor_create(struct drm_device *dev, int dcb_entry) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_output *output = NULL; + struct nv50_display *display = NULL; + struct dcb_entry *entry = NULL; + + NV50_DEBUG("\n"); + + /* This allows the public layer to do it's thing. */ + if (dev_priv->alloc_output) + output = dev_priv->alloc_output(dev); + + if (!output) + return -ENOMEM; + + output->dev = dev; + + display = nv50_get_display(dev); + if (!display) + goto out; + + entry = &dev_priv->dcb_table.entry[dcb_entry]; + if (!entry) + goto out; + + switch (entry->type) { + case DCB_OUTPUT_TMDS: + output->type = OUTPUT_TMDS; + DRM_INFO("Detected a TMDS output\n"); + break; + case DCB_OUTPUT_LVDS: + output->type = OUTPUT_LVDS; + DRM_INFO("Detected a LVDS output\n"); + break; + default: + goto out; + } + + output->dcb_entry = dcb_entry; + output->bus = entry->bus; + + list_add_tail(&output->head, &display->outputs); + + output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + + /* Set function pointers. */ + output->validate_mode = nv50_sor_validate_mode; + output->execute_mode = nv50_sor_execute_mode; + output->set_clock_mode = nv50_sor_set_clock_mode; + output->detect = NULL; + output->destroy = nv50_sor_destroy; + + /* Some default state, unknown what it precisely means. */ + if (output->type == OUTPUT_TMDS) { + NV_WRITE(NV50_PDISPLAY_SOR_REGS_UNK_00C(nv50_output_or_offset(output)), 0x03010700); + NV_WRITE(NV50_PDISPLAY_SOR_REGS_UNK_010(nv50_output_or_offset(output)), 0x0000152f); + NV_WRITE(NV50_PDISPLAY_SOR_REGS_UNK_014(nv50_output_or_offset(output)), 0x00000000); + NV_WRITE(NV50_PDISPLAY_SOR_REGS_UNK_018(nv50_output_or_offset(output)), 0x00245af8); + } + + return 0; + +out: + if (output->native_mode) + kfree(output->native_mode); + if (dev_priv->free_output) + dev_priv->free_output(output); + return -EINVAL; +} diff --git a/shared-core/nouveau_dma.h b/shared-core/nouveau_dma.h index ce3c58cb..07652c2b 100644 --- a/shared-core/nouveau_dma.h +++ b/shared-core/nouveau_dma.h @@ -93,4 +93,9 @@ typedef enum { } \ } while(0) +/* This should allow easy switching to a real fifo in the future. */ +#define OUT_MODE(mthd, val) do { \ + nv50_display_command(dev_priv, mthd, val); \ +} while(0) + #endif diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index a51e552c..20aa6b86 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -41,6 +41,9 @@ #include "nouveau_drm.h" #include "nouveau_reg.h" +#include "nouveau_bios.h" + +#define MAX_NUM_DCB_ENTRIES 16 struct mem_block { struct mem_block *next; @@ -310,6 +313,28 @@ struct drm_nouveau_private { struct nouveau_config config; struct list_head gpuobj_list; + + void *display_priv; /* internal modesetting */ + void *kms_priv; /* related to public interface */ + + /* Hook these up to the "public interface" to accomodate a certain allocation style. */ + /* This is to avoid polluting the internal interface. */ + void *(*alloc_crtc) (struct drm_device *dev); + void *(*alloc_output) (struct drm_device *dev); + void *(*alloc_connector) (struct drm_device *dev); + + void (*free_crtc) (void *crtc); + void (*free_output) (void *output); + void (*free_connector) (void *connector); + + struct bios bios; + + struct { + int entries; + struct dcb_entry entry[MAX_NUM_DCB_ENTRIES]; + unsigned char i2c_read[MAX_NUM_DCB_ENTRIES]; + unsigned char i2c_write[MAX_NUM_DCB_ENTRIES]; + } dcb_table; }; #define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \ @@ -353,6 +378,7 @@ extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, struct drm_file *); extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); +extern struct mem_block* find_block_by_handle(struct mem_block *heap, drm_handle_t handle); extern uint64_t nouveau_mem_fb_amount(struct drm_device *); extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data, diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 2a3d8a0b..e68b755f 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -37,6 +37,11 @@ #include "nouveau_reg.h" #include "nouveau_swmthd.h" +/* needed for interrupt based vpll changes */ +#include "nv50_display.h" +#include "nv50_crtc.h" +#include "nv50_output.h" + void nouveau_irq_preinstall(struct drm_device *dev) { @@ -503,11 +508,82 @@ static void nouveau_nv50_display_irq_handler(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t val = NV_READ(NV50_DISPLAY_SUPERVISOR); + uint32_t val = NV_READ(NV50_PDISPLAY_SUPERVISOR); DRM_INFO("NV50_DISPLAY_INTR - 0x%08X\n", val); - NV_WRITE(NV50_DISPLAY_SUPERVISOR, val); + /* vblank interrupts */ + if (val & NV50_PDISPLAY_SUPERVISOR_CRTCn) { + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val & NV50_PDISPLAY_SUPERVISOR_CRTCn); + val &= ~NV50_PDISPLAY_SUPERVISOR_CRTCn; + } + + /* clock setting amongst other things. */ + if (val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK) { + uint32_t state = (val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK) >> NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT; + + NV50_DEBUG("state %d\n", state); + + /* Set pll */ + if (state == 2) { + struct nv50_display *display = nv50_get_display(dev); + struct nv50_output *output = NULL; + struct nv50_crtc *crtc = NULL; + int crtc_index; + + uint32_t unk30 = NV_READ(NV50_PDISPLAY_UNK30_CTRL); + + for (crtc_index = 0; crtc_index < 2; crtc_index++) { + bool clock_change = false; + bool clock_ack = false; + + if (crtc_index == 0 && (unk30 & NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0)) + clock_change = true; + + if (crtc_index == 1 && (unk30 & NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1)) + clock_change = true; + + if (clock_change) + clock_ack = true; + + if (display->last_crtc == crtc_index) + clock_ack = true; + + list_for_each_entry(crtc, &display->crtcs, head) { + if (crtc->index == crtc_index) + break; + } + + if (clock_change) + crtc->set_clock(crtc); + + NV50_DEBUG("index %d clock_change %d clock_ack %d\n", crtc_index, clock_change, clock_ack); + + if (!clock_ack) + continue; + + crtc->set_clock_mode(crtc); + + list_for_each_entry(output, &display->outputs, head) { + if (!output->crtc) + continue; + + if (output->crtc == crtc) + output->set_clock_mode(output); + } + } + } + + NV_WRITE(NV50_PDISPLAY_UNK30_CTRL, NV50_PDISPLAY_UNK30_CTRL_PENDING); + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK); + + val &= ~NV50_PDISPLAY_SUPERVISOR_CLK_MASK; + } + + if (val) + DRM_ERROR("unsupported NV50_DISPLAY_INTR - 0x%08X\n", val); + + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val); } static void diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 2cf8807d..810eaf9e 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -108,6 +108,17 @@ static struct mem_block *find_block(struct mem_block *heap, uint64_t start) return NULL; } +struct mem_block *find_block_by_handle(struct mem_block *heap, drm_handle_t handle) +{ + struct mem_block *p; + + list_for_each(p, heap) + if (p->map_handle == handle) + return p; + + return NULL; +} + void nouveau_mem_free_block(struct mem_block *p) { p->file_priv = NULL; diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 1ae0177c..8cf7f889 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -116,6 +116,9 @@ #define NV04_PBUS_PCI_NV_1 0x00001804 #define NV04_PBUS_PCI_NV_19 0x0000184C +#define NV04_PBUS_PCI_NV_20 0x00001850 +# define NV04_PBUS_PCI_NV_20_ROM_SHADOW_DISABLED (0 << 0) +# define NV04_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED (1 << 0) #define NV04_PTIMER_INTR_0 0x00009100 #define NV04_PTIMER_INTR_EN_0 0x00009140 @@ -542,6 +545,8 @@ /* This name is a partial guess. */ #define NV50_DISPLAY_SUPERVISOR 0x00610024 +#define NV04_PRAMIN 0x00700000 + /* Fifo commands. These are not regs, neither masks */ #define NV03_FIFO_CMD_JUMP 0x20000000 #define NV03_FIFO_CMD_JUMP_OFFSET_MASK 0x1ffffffc @@ -591,3 +596,296 @@ #define NV40_RAMFC_UNK_48 0x48 #define NV40_RAMFC_UNK_4C 0x4C #define NV40_RAMFC_UNK_50 0x50 + +/* This is a partial import from rules-ng, a few things may be duplicated. + * Eventually we should completely import everything from rules-ng. + * For the moment check rules-ng for docs. + */ + +#define NV50_PMC 0x00000000 +#define NV50_PMC__LEN 0x1 +#define NV50_PMC__ESIZE 0x2000 +# define NV50_PMC_BOOT_0 0x00000000 +# define NV50_PMC_BOOT_0_REVISION 0x000000ff +# define NV50_PMC_BOOT_0_REVISION__SHIFT 0 +# define NV50_PMC_BOOT_0_ARCH 0x0ff00000 +# define NV50_PMC_BOOT_0_ARCH__SHIFT 20 +# define NV50_PMC_INTR_0 0x00000100 +# define NV50_PMC_INTR_0_PFIFO (1<<8) +# define NV50_PMC_INTR_0_PGRAPH (1<<12) +# define NV50_PMC_INTR_0_PTIMER (1<<20) +# define NV50_PMC_INTR_0_HOTPLUG (1<<21) +# define NV50_PMC_INTR_0_DISPLAY (1<<26) +# define NV50_PMC_INTR_EN_0 0x00000140 +# define NV50_PMC_INTR_EN_0_MASTER (1<<0) +# define NV50_PMC_INTR_EN_0_MASTER_DISABLED (0<<0) +# define NV50_PMC_INTR_EN_0_MASTER_ENABLED (1<<0) +# define NV50_PMC_ENABLE 0x00000200 +# define NV50_PMC_ENABLE_PFIFO (1<<8) +# define NV50_PMC_ENABLE_PGRAPH (1<<12) + +#define NV50_PCONNECTOR 0x0000e000 +#define NV50_PCONNECTOR__LEN 0x1 +#define NV50_PCONNECTOR__ESIZE 0x1000 +# define NV50_PCONNECTOR_HOTPLUG_INTR 0x0000e050 +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C0 (1<<0) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C1 (1<<1) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C2 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C3 (1<<3) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C4 (1<<4) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C5 (1<<5) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C6 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C7 (1<<7) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C8 (1<<8) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C9 (1<<9) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C10 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C11 (1<<11) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C12 (1<<12) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C13 (1<<13) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C14 (1<<14) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C15 (1<<15) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C0 (1<<16) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C1 (1<<17) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C2 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C3 (1<<19) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C4 (1<<20) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C5 (1<<21) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C6 (1<<22) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C7 (1<<23) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C8 (1<<24) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C9 (1<<25) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C10 (1<<26) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C11 (1<<27) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C12 (1<<28) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C13 (1<<29) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C14 (1<<30) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C15 (1<<31) +# define NV50_PCONNECTOR_HOTPLUG_CTRL 0x0000e054 +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C0 (1<<0) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C1 (1<<1) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C2 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C3 (1<<3) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C4 (1<<4) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C5 (1<<5) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C6 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C7 (1<<7) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C8 (1<<8) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C9 (1<<9) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C10 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C11 (1<<11) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C12 (1<<12) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C13 (1<<13) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C14 (1<<14) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C15 (1<<15) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C0 (1<<16) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C1 (1<<17) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C2 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C3 (1<<19) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C4 (1<<20) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C5 (1<<21) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C6 (1<<22) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C7 (1<<23) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C8 (1<<24) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C9 (1<<25) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C10 (1<<26) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C11 (1<<27) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C12 (1<<28) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C13 (1<<29) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C14 (1<<30) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C15 (1<<31) +# define NV50_PCONNECTOR_HOTPLUG_STATE1 0x0000e104 +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C0 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C1 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C2 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C3 (1<<14) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C4 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C5 (1<<22) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C6 (1<<26) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C7 (1<<30) +# define NV50_PCONNECTOR_HOTPLUG_STATE2 0x0000e108 +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C8 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C9 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C10 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C11 (1<<14) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C12 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C13 (1<<22) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C14 (1<<26) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C15 (1<<30) +# define NV50_PCONNECTOR_I2C 0x0000e138 +# define NV50_PCONNECTOR_I2C__LEN 0x10 +# define NV50_PCONNECTOR_I2C__ESIZE 0x18 +# define NV50_PCONNECTOR_I2C_PORT(i) (0x0000e138+(i)*0x18) + + +#define NV50_PBUS 0x00088000 +#define NV50_PBUS__LEN 0x1 +#define NV50_PBUS__ESIZE 0x1000 +# define NV50_PBUS_PCI_ID 0x00088000 +# define NV50_PBUS_PCI_ID_VENDOR_ID 0x0000ffff +# define NV50_PBUS_PCI_ID_VENDOR_ID__SHIFT 0 +# define NV50_PBUS_PCI_ID_DEVICE_ID 0xffff0000 +# define NV50_PBUS_PCI_ID_DEVICE_ID__SHIFT 16 + +#define NV50_PFB 0x00100000 +#define NV50_PFB__LEN 0x1 +#define NV50_PFB__ESIZE 0x1000 + +#define NV50_PEXTDEV 0x00101000 +#define NV50_PEXTDEV__LEN 0x1 +#define NV50_PEXTDEV__ESIZE 0x1000 + +#define NV50_PROM 0x00300000 +#define NV50_PROM__LEN 0x1 +#define NV50_PROM__ESIZE 0x10000 + +#define NV50_PGRAPH 0x00400000 +#define NV50_PGRAPH__LEN 0x1 +#define NV50_PGRAPH__ESIZE 0x10000 + +#define NV50_PDISPLAY 0x00610000 +#define NV50_PDISPLAY__LEN 0x1 +#define NV50_PDISPLAY__ESIZE 0x10000 +# define NV50_PDISPLAY_SUPERVISOR 0x00610024 +# define NV50_PDISPLAY_SUPERVISOR_CRTCn 0x0000000c +# define NV50_PDISPLAY_SUPERVISOR_CRTCn__SHIFT 2 +# define NV50_PDISPLAY_SUPERVISOR_CRTC0 (1<<2) +# define NV50_PDISPLAY_SUPERVISOR_CRTC1 (1<<3) +# define NV50_PDISPLAY_SUPERVISOR_CLK_MASK 0x00000070 +# define NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT 4 +# define NV50_PDISPLAY_SUPERVISOR_CLK_UPDATE (1<<5) +# define NV50_PDISPLAY_SUPERVISOR_INTR 0x0061002c +# define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC0 (1<<2) +# define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC1 (1<<3) +# define NV50_PDISPLAY_SUPERVISOR_INTR_UNK1 (1<<4) +# define NV50_PDISPLAY_SUPERVISOR_INTR_CLK_UPDATE (1<<5) +# define NV50_PDISPLAY_SUPERVISOR_INTR_UNK4 (1<<6) +# define NV50_PDISPLAY_UNK30_CTRL 0x00610030 +# define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0 (1<<9) +# define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1 (1<<10) +# define NV50_PDISPLAY_UNK30_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_UNK50_CTRL 0x00610050 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE (1<<1) +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE_MASK 0x00000003 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE_MASK__SHIFT 0 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE (1<<9) +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE_MASK 0x00000300 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE_MASK__SHIFT 8 +# define NV50_PDISPLAY_UNK200_CTRL 0x00610200 +# define NV50_PDISPLAY_CURSOR 0x00610270 +# define NV50_PDISPLAY_CURSOR__LEN 0x2 +# define NV50_PDISPLAY_CURSOR__ESIZE 0x10 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i) (0x00610270+(i)*0x10) +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON (1<<0) +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK 0x00030000 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK__SHIFT 16 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE (1<<16) + +# define NV50_PDISPLAY_CTRL_STATE 0x00610300 +# define NV50_PDISPLAY_CTRL_STATE_ENABLE (1<<0) +# define NV50_PDISPLAY_CTRL_STATE_PENDING (1<<31) +# define NV50_PDISPLAY_CTRL_VAL 0x00610304 +# define NV50_PDISPLAY_UNK_380 0x00610380 +# define NV50_PDISPLAY_RAM_AMOUNT 0x00610384 +# define NV50_PDISPLAY_UNK_388 0x00610388 +# define NV50_PDISPLAY_UNK_38C 0x0061038c +# define NV50_PDISPLAY_CRTC_VAL 0x00610a00 +# define NV50_PDISPLAY_CRTC_VAL__LEN 0x2 +# define NV50_PDISPLAY_CRTC_VAL_UNK_900(i,j) (0x00610a18+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CLUT_MODE(i,j) (0x00610a24+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_INTERLACE(i,j) (0x00610a48+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_CTRL(i,j) (0x00610a50+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CURSOR_CTRL(i,j) (0x00610a58+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_UNK_904(i,j) (0x00610ab8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_DEPTH(i,j) (0x00610ac8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CLOCK(i,j) (0x00610ad0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_COLOR_CTRL(i,j) (0x00610ae0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SYNC_START_TO_BLANK_END(i,j) (0x00610ae8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_MODE_UNK1(i,j) (0x00610af0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_DISPLAY_TOTAL(i,j) (0x00610af8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SYNC_DURATION(i,j) (0x00610b00+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_MODE_UNK2(i,j) (0x00610b08+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_UNK_828(i,j) (0x00610b10+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_SIZE(i,j) (0x00610b18+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_PITCH(i,j) (0x00610b20+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_PITCH_LINEAR_FB (1<<20) +# define NV50_PDISPLAY_CRTC_VAL_FB_POS(i,j) (0x00610b28+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_CENTER_OFFSET(i,j) (0x00610b38+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_REAL_RES(i,j) (0x00610b40+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_RES1(i,j) (0x00610b48+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_RES2(i,j) (0x00610b50+(i)*0x540+(j)*0x4) + + +# define NV50_PDISPLAY_DAC_VAL_MODE_CTRL(i,j) (0x00610b58+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_SOR_VAL_MODE_CTRL(i,j) (0x00610b70+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_DAC_VAL_MODE_CTRL2(i,j) (0x00610bdc+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_CRTC_CLK 0x00614000 +# define NV50_PDISPLAY_CRTC_CLK__LEN 0x2 +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(i) (0x00614100+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED__SHIFT 9 +# define NV50_PDISPLAY_CRTC_CLK_VPLL_A(i) (0x00614104+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_VPLL_B(i) (0x00614108+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(i) (0x00614200+(i)*0x800) + +# define NV50_PDISPLAY_DAC_CLK 0x00614000 +# define NV50_PDISPLAY_DAC_CLK__LEN 0x3 +# define NV50_PDISPLAY_DAC_CLK_CLK_CTRL2(i) (0x00614280+(i)*0x800) + +# define NV50_PDISPLAY_SOR_CLK 0x00614000 +# define NV50_PDISPLAY_SOR_CLK__LEN 0x3 +# define NV50_PDISPLAY_SOR_CLK_CLK_CTRL2(i) (0x00614300+(i)*0x800) + +# define NV50_PDISPLAY_DAC_REGS 0x0061a000 +# define NV50_PDISPLAY_DAC_REGS__LEN 0x3 +# define NV50_PDISPLAY_DAC_REGS__ESIZE 0x800 +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(i) (0x0061a004+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF (1<<0) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF (1<<2) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED (1<<4) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF (1<<6) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(i) (0x0061a00c+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE (1<<20) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT 0x38000000 +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT__SHIFT 29 +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_DONE (1<<31) +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i) (0x0061a010+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1_CONNECTED__SHIFT 9 + +# define NV50_PDISPLAY_SOR_REGS 0x0061c000 +# define NV50_PDISPLAY_SOR_REGS__LEN 0x2 +# define NV50_PDISPLAY_SOR_REGS__ESIZE 0x800 +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(i) (0x0061c004+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON (1<<0) +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1(i) (0x0061c008+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1_CONNECTED__SHIFT 9 +# define NV50_PDISPLAY_SOR_REGS_UNK_00C(i) (0x0061c00c+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_010(i) (0x0061c010+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_014(i) (0x0061c014+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_018(i) (0x0061c018+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE(i) (0x0061c030+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_ACTIVE 0x00030000 +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_ACTIVE__SHIFT 16 +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_BLANKED (1<<19) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_WAIT (1<<28) + + +#define NV50_UNK640000 0x00640000 +#define NV50_UNK640000__LEN 0x6 +#define NV50_UNK640000__ESIZE 0x1000 +# define NV50_UNK640000_UNK_000(i) (0x00640000+(i)*0x1000) + +#define NV50_HW_CURSOR 0x00647000 +#define NV50_HW_CURSOR__LEN 0x2 +#define NV50_HW_CURSOR__ESIZE 0x1000 +# define NV50_HW_CURSOR_POS_CTRL(i) (0x00647080+(i)*0x1000) +# define NV50_HW_CURSOR_POS(i) (0x00647084+(i)*0x1000) diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index d9c6efe7..82591c64 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -27,6 +27,7 @@ #include "drm_sarea.h" #include "nouveau_drv.h" #include "nouveau_drm.h" +#include "nv50_kms_wrapper.h" static int nouveau_init_card_mappings(struct drm_device *dev) { @@ -362,6 +363,13 @@ nouveau_card_init(struct drm_device *dev) if (ret) return ret; dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + if (dev_priv->card_type >= NV_50) { + nv50_kms_init(dev); + nv50_kms_connector_detect_all(dev); + } + return 0; } @@ -410,8 +418,7 @@ void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv) nouveau_mem_release(file_priv,dev_priv->pci_heap); } -/* first module load, setup the mmio/fb mapping */ -int nouveau_firstopen(struct drm_device *dev) +int nouveau_setup_mappings(struct drm_device *dev) { #if defined(__powerpc__) struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -457,6 +464,16 @@ int nouveau_firstopen(struct drm_device *dev) return 0; } +/* first module load, setup the mmio/fb mapping */ +/* KMS: we need mmio at load time, not when the first drm client opens. */ +int nouveau_firstopen(struct drm_device *dev) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + return nouveau_setup_mappings(dev); +} + #define NV40_CHIPSET_MASK 0x00000baf #define NV44_CHIPSET_MASK 0x00005450 @@ -549,10 +566,23 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)dev_priv; + /* init card now, otherwise bad things happen */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + int rval = 0; + + rval = nouveau_setup_mappings(dev); + if (rval != 0) + return rval; + + rval = nouveau_card_init(dev); + if (rval != 0) + return rval; + } + return 0; } -void nouveau_lastclose(struct drm_device *dev) +void nouveau_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -568,8 +598,22 @@ void nouveau_lastclose(struct drm_device *dev) } } +/* KMS: we need mmio at load time, not when the first drm client opens. */ +void nouveau_lastclose(struct drm_device *dev) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + nouveau_close(dev); +} + int nouveau_unload(struct drm_device *dev) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + nv50_kms_destroy(dev); + nouveau_close(dev); + } + drm_free(dev->dev_private, sizeof(*dev->dev_private), DRM_MEM_DRIVER); dev->dev_private = NULL; return 0; -- cgit v1.2.3 From 3809209349ccf12aa71c7848f0b21d77fa0a5f03 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 17:01:30 +0200 Subject: Undo something i didn't want to change. - I made it consistent with recent kernel fb code (maybe this is older bugged code?) - Still i don't use this and i should leave it to others. --- linux-core/drm_edid.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 812e64a6..22c6e3bf 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -601,15 +601,15 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) * Then set clock & data low */ algo_data->setscl(algo_data->data, 1); - //udelay(550); /* startup delay */ - //algo_data->setscl(algo_data->data, 0); - //algo_data->setsda(algo_data->data, 0); + udelay(550); /* startup delay */ + algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 0); for (i = 0; i < 3; i++) { /* For some old monitors we need the * following process to initialize/stop DDC */ - algo_data->setsda(algo_data->data, 1); + algo_data->setsda(algo_data->data, 0); msleep(13); algo_data->setscl(algo_data->data, 1); @@ -644,7 +644,6 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) algo_data->setsda(algo_data->data, 1); msleep(15); algo_data->setscl(algo_data->data, 0); - algo_data->setsda(algo_data->data, 0); if (edid) break; } -- cgit v1.2.3 From e67cd7dda9d7d6d82f4026f246d07bf4c4021a57 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 18:47:51 +0200 Subject: NV50: A few minor added safeties + cleanup. --- linux-core/nouveau_bios.c | 2 ++ linux-core/nv50_crtc.c | 12 ++++++++++-- linux-core/nv50_cursor.c | 2 ++ linux-core/nv50_dac.c | 16 +++++++++++++--- linux-core/nv50_display.c | 3 +++ linux-core/nv50_fb.c | 3 +++ linux-core/nv50_kms_wrapper.c | 26 ++++++++++++++++++++------ linux-core/nv50_kms_wrapper.h | 6 +++--- linux-core/nv50_lut.c | 6 ++++++ linux-core/nv50_sor.c | 16 +++++++++++++--- 10 files changed, 75 insertions(+), 17 deletions(-) diff --git a/linux-core/nouveau_bios.c b/linux-core/nouveau_bios.c index 83647418..3e7fe23f 100644 --- a/linux-core/nouveau_bios.c +++ b/linux-core/nouveau_bios.c @@ -532,6 +532,8 @@ int nouveau_parse_bios(struct drm_device *dev) int offset; dev_priv->bios.data = kzalloc(NV50_PROM__ESIZE, GFP_KERNEL); + if (!dev_priv->bios.data) + return -ENOMEM; if (!nv_shadow_bios(dev, dev_priv->bios.data)) return -EINVAL; diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 974f5202..f34e7279 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -463,6 +463,7 @@ int nv50_crtc_create(struct drm_device *dev, int index) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_crtc *crtc = NULL; struct nv50_display *display = NULL; + int rval = 0; NV50_DEBUG("\n"); @@ -476,8 +477,10 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->dev = dev; display = nv50_get_display(dev); - if (!display) + if (!display) { + rval = -EINVAL; goto out; + } list_add_tail(&crtc->head, &display->crtcs); @@ -486,6 +489,11 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!crtc->mode || crtc->native_mode) { + rval = -ENOMEM; + goto out; + } + nv50_fb_create(crtc); nv50_lut_create(crtc); nv50_cursor_create(crtc); @@ -511,5 +519,5 @@ out: if (dev_priv->free_crtc) dev_priv->free_crtc(crtc); - return -EINVAL; + return rval; } diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c index 3d35b936..4196df6b 100644 --- a/linux-core/nv50_cursor.c +++ b/linux-core/nv50_cursor.c @@ -140,6 +140,8 @@ int nv50_cursor_create(struct nv50_crtc *crtc) return -EINVAL; crtc->cursor = kzalloc(sizeof(struct nv50_cursor), GFP_KERNEL); + if (!crtc->cursor) + return -ENOMEM; /* function pointers */ crtc->cursor->show = nv50_cursor_show; diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index f827fed4..b237241e 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -122,6 +122,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) struct nv50_output *output = NULL; struct nv50_display *display = NULL; struct dcb_entry *entry = NULL; + int rval = 0; NV50_DEBUG("\n"); @@ -135,12 +136,16 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) output->dev = dev; display = nv50_get_display(dev); - if (!display) + if (!display) { + rval = -EINVAL; goto out; + } entry = &dev_priv->dcb_table.entry[dcb_entry]; - if (!entry) + if (!entry) { + rval = -EINVAL; goto out; + } switch (entry->type) { case DCB_OUTPUT_ANALOG: @@ -148,6 +153,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) DRM_INFO("Detected a DAC output\n"); break; default: + rval = -EINVAL; goto out; } @@ -157,6 +163,10 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) list_add_tail(&output->head, &display->outputs); output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!output->native_mode) { + rval = -ENOMEM; + goto out; + } /* Set function pointers. */ output->validate_mode = nv50_dac_validate_mode; @@ -172,6 +182,6 @@ out: kfree(output->native_mode); if (dev_priv->free_output) dev_priv->free_output(output); - return -EINVAL; + return rval; } diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 56ddeb97..05ff72f8 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -189,6 +189,9 @@ int nv50_display_create(struct drm_device *dev) NV50_DEBUG("\n"); + if (!display) + return -ENOMEM; + INIT_LIST_HEAD(&display->crtcs); INIT_LIST_HEAD(&display->outputs); INIT_LIST_HEAD(&display->connectors); diff --git a/linux-core/nv50_fb.c b/linux-core/nv50_fb.c index b44b48ab..f57a9fad 100644 --- a/linux-core/nv50_fb.c +++ b/linux-core/nv50_fb.c @@ -119,6 +119,9 @@ int nv50_fb_create(struct nv50_crtc *crtc) crtc->fb = kzalloc(sizeof(struct nv50_fb), GFP_KERNEL); + if (!crtc->fb) + return -ENOMEM; + crtc->fb->bind = nv50_fb_bind; return 0; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 01d4bc9a..a63cb7df 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -48,7 +48,10 @@ static void *nv50_kms_alloc_crtc(struct drm_device *dev) struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); struct nv50_kms_crtc *crtc = kzalloc(sizeof(struct nv50_kms_crtc), GFP_KERNEL); - list_add_tail(&crtc->head, &kms_priv->crtcs); + if (!crtc) + return NULL; + + list_add_tail(&crtc->item, &kms_priv->crtcs); return &(crtc->priv); } @@ -58,7 +61,10 @@ static void *nv50_kms_alloc_output(struct drm_device *dev) struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); struct nv50_kms_encoder *encoder = kzalloc(sizeof(struct nv50_kms_encoder), GFP_KERNEL); - list_add_tail(&encoder->head, &kms_priv->encoders); + if (!encoder) + return NULL; + + list_add_tail(&encoder->item, &kms_priv->encoders); return &(encoder->priv); } @@ -68,7 +74,10 @@ static void *nv50_kms_alloc_connector(struct drm_device *dev) struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); struct nv50_kms_connector *connector = kzalloc(sizeof(struct nv50_kms_connector), GFP_KERNEL); - list_add_tail(&connector->head, &kms_priv->connectors); + if (!connector) + return NULL; + + list_add_tail(&connector->item, &kms_priv->connectors); return &(connector->priv); } @@ -77,7 +86,7 @@ static void nv50_kms_free_crtc(void *crtc) { struct nv50_kms_crtc *kms_crtc = from_nv50_crtc(crtc); - list_del(&kms_crtc->head); + list_del(&kms_crtc->item); kfree(kms_crtc); } @@ -86,7 +95,7 @@ static void nv50_kms_free_output(void *output) { struct nv50_kms_encoder *kms_encoder = from_nv50_output(output); - list_del(&kms_encoder->head); + list_del(&kms_encoder->item); kfree(kms_encoder); } @@ -95,7 +104,7 @@ static void nv50_kms_free_connector(void *connector) { struct nv50_kms_connector *kms_connector = from_nv50_connector(connector); - list_del(&kms_connector->head); + list_del(&kms_connector->item); kfree(kms_connector); } @@ -107,6 +116,8 @@ static void nv50_kms_free_connector(void *connector) static struct nouveau_hw_mode *nv50_kms_to_hw_mode(struct drm_display_mode *mode) { struct nouveau_hw_mode *hw_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!hw_mode) + return NULL; /* create hw values. */ hw_mode->clock = mode->clock; @@ -870,6 +881,9 @@ int nv50_kms_init(struct drm_device *dev) struct nv50_display *display = NULL; int rval = 0; + if (!kms_priv) + return -ENOMEM; + dev_priv->kms_priv = kms_priv; /* function pointers */ diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h index 3847d510..f224f1bb 100644 --- a/linux-core/nv50_kms_wrapper.h +++ b/linux-core/nv50_kms_wrapper.h @@ -44,21 +44,21 @@ /* Link internal modesetting structure to interface. */ struct nv50_kms_crtc { - struct list_head head; + struct list_head item; struct nv50_crtc priv; struct drm_crtc pub; }; struct nv50_kms_encoder { - struct list_head head; + struct list_head item; struct nv50_output priv; struct drm_encoder pub; }; struct nv50_kms_connector { - struct list_head head; + struct list_head item; struct nv50_connector priv; struct drm_connector pub; diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c index 570900ba..cb52f27f 100644 --- a/linux-core/nv50_lut.c +++ b/linux-core/nv50_lut.c @@ -37,6 +37,9 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) NV50_DEBUG("\n"); + if (!file_priv) + return -ENOMEM; + /* Any file_priv should do as it's pointer is used as identification. */ block = nouveau_mem_alloc(crtc->dev, 0, 4096, flags, file_priv); @@ -137,6 +140,9 @@ int nv50_lut_create(struct nv50_crtc *crtc) crtc->lut = kzalloc(sizeof(struct nv50_lut), GFP_KERNEL); + if (!crtc->lut) + return -ENOMEM; + rval = nv50_lut_alloc(crtc); if (rval != 0) return rval; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 430c1e83..49f29fd3 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -138,6 +138,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) struct nv50_output *output = NULL; struct nv50_display *display = NULL; struct dcb_entry *entry = NULL; + int rval = 0; NV50_DEBUG("\n"); @@ -151,12 +152,16 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) output->dev = dev; display = nv50_get_display(dev); - if (!display) + if (!display) { + rval = -EINVAL; goto out; + } entry = &dev_priv->dcb_table.entry[dcb_entry]; - if (!entry) + if (!entry) { + rval = -EINVAL; goto out; + } switch (entry->type) { case DCB_OUTPUT_TMDS: @@ -168,6 +173,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) DRM_INFO("Detected a LVDS output\n"); break; default: + rval = -EINVAL; goto out; } @@ -177,6 +183,10 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) list_add_tail(&output->head, &display->outputs); output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!output->native_mode) { + rval = -ENOMEM; + goto out; + } /* Set function pointers. */ output->validate_mode = nv50_sor_validate_mode; @@ -200,5 +210,5 @@ out: kfree(output->native_mode); if (dev_priv->free_output) dev_priv->free_output(output); - return -EINVAL; + return rval; } -- cgit v1.2.3 From 7c9551a464e168279224139b70a439f985b601c9 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 18:58:04 +0200 Subject: fix typo --- linux-core/nv50_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index f34e7279..887d6ec2 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -489,7 +489,7 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); - if (!crtc->mode || crtc->native_mode) { + if (!crtc->mode || !crtc->native_mode) { rval = -ENOMEM; goto out; } -- cgit v1.2.3 From b0b0f374432ecf84b5115130caa4697d6d1ca789 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 19:04:22 +0200 Subject: NV50: Fix a few more possible leaks. --- linux-core/nv50_lut.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c index cb52f27f..5cdf6b5d 100644 --- a/linux-core/nv50_lut.c +++ b/linux-core/nv50_lut.c @@ -34,6 +34,7 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) struct mem_block *block; struct drm_file *file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL); uint32_t flags = NOUVEAU_MEM_INTERNAL | NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; + int rval = 0; NV50_DEBUG("\n"); @@ -43,12 +44,20 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) /* Any file_priv should do as it's pointer is used as identification. */ block = nouveau_mem_alloc(crtc->dev, 0, 4096, flags, file_priv); - if (!block) - return -ENOMEM; + if (!block) { + rval = -ENOMEM; + goto out; + } crtc->lut->block = block; return 0; + +out: + if (file_priv) + kfree(file_priv); + + return rval; } static int nv50_lut_free(struct nv50_crtc *crtc) @@ -144,8 +153,9 @@ int nv50_lut_create(struct nv50_crtc *crtc) return -ENOMEM; rval = nv50_lut_alloc(crtc); - if (rval != 0) - return rval; + if (rval != 0) { + goto out; + } /* lut will be inited when fb is bound */ crtc->lut->depth = 0; @@ -154,6 +164,12 @@ int nv50_lut_create(struct nv50_crtc *crtc) crtc->lut->set = nv50_lut_set; return 0; + +out: + if (crtc->lut) + kfree(crtc->lut); + + return rval; } int nv50_lut_destroy(struct nv50_crtc *crtc) -- cgit v1.2.3 From 30f153a7c2a9bc69e615b7fff3fb060af0e3ed83 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 19:31:55 +0200 Subject: nouveau: disable KMS for pre-NV50 even when specifically enabled --- shared-core/nouveau_state.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 82591c64..9f8fc43d 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -557,6 +557,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) return -EINVAL; } + /* For those who think they want to be funny. */ + if (dev_priv->card_type < NV_50) + dev->driver->driver_features &= ~DRIVER_MODESET; + /* Special flags */ if (dev->pci_device == 0x01a0) { dev_priv->flags |= NV_NFORCE; -- cgit v1.2.3 From 0a45f150669eaa2737d7485c9b68ea4c483f3048 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 23 Jun 2008 20:33:32 +0200 Subject: NV50: Improve set_config and fix some minor bugs. --- linux-core/nv50_crtc.c | 47 ++--- linux-core/nv50_crtc.h | 1 + linux-core/nv50_display.c | 12 ++ linux-core/nv50_fb.c | 7 +- linux-core/nv50_fb.h | 2 + linux-core/nv50_kms_wrapper.c | 427 ++++++++++++++++++++++++++---------------- linux-core/nv50_sor.c | 4 + 7 files changed, 317 insertions(+), 183 deletions(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 887d6ec2..0bcf3058 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -72,7 +72,6 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end; uint32_t hunk1, vunk1, vunk2a, vunk2b; uint32_t offset = crtc->index * 0x400; - uint32_t pitch; NV50_DEBUG("index %d\n", crtc->index); NV50_DEBUG("%s native mode\n", crtc->use_native_mode ? "using" : "not using"); @@ -119,12 +118,31 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) if (hw_mode->flags & V_INTERLACE) { OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset, (vunk2b - 1) << 16 | (vunk2a - 1)); } + + crtc->set_fb(crtc); + crtc->set_dither(crtc); + + /* This is the actual resolution of the mode. */ + OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay); + OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0)); + + /* Maybe move this as well? */ + crtc->blank(crtc, FALSE); + + return 0; +} + +static int nv50_crtc_set_fb(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("\n"); + OUT_MODE(NV50_CRTC0_FB_SIZE + offset, crtc->fb->height << 16 | crtc->fb->width); /* I suspect this flag indicates a linear fb. */ - pitch = ((crtc->fb->width + 63) & ~63) * (crtc->fb->bpp)/8; - NV50_DEBUG("fb_pitch %d\n", pitch); - OUT_MODE(NV50_CRTC0_FB_PITCH + offset, pitch | 0x100000); + OUT_MODE(NV50_CRTC0_FB_PITCH + offset, crtc->fb->pitch | 0x100000); switch (crtc->fb->depth) { case 8: @@ -140,15 +158,9 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_24BPP); break; } - crtc->set_dither(crtc); + OUT_MODE(NV50_CRTC0_COLOR_CTRL + offset, NV50_CRTC_COLOR_CTRL_MODE_COLOR); OUT_MODE(NV50_CRTC0_FB_POS + offset, (crtc->fb->y << 16) | (crtc->fb->x)); - /* This is the actual resolution of the mode. */ - OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay); - OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0)); - - /* Maybe move this as well? */ - crtc->blank(crtc, FALSE); return 0; } @@ -178,20 +190,8 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) if (dev_priv->chipset != 0x50) OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_BLANK); } else { - uint32_t ram_amount; - OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8); OUT_MODE(0x864 + offset, 0); - /* maybe this needs to be moved. */ - NV_WRITE(NV50_PDISPLAY_UNK_380, 0); - /* RAM is clamped to 256 MiB. */ - ram_amount = nouveau_mem_fb_amount(crtc->dev); - NV50_DEBUG("ram_amount %d\n", ram_amount); - if (ram_amount > 256*1024*1024) - ram_amount = 256*1024*1024; - NV_WRITE(NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); - NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000); - NV_WRITE(NV50_PDISPLAY_UNK_38C, 0); if (crtc->cursor->block) OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8); else @@ -502,6 +502,7 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->validate_mode = nv50_crtc_validate_mode; crtc->set_mode = nv50_crtc_set_mode; crtc->execute_mode = nv50_crtc_execute_mode; + crtc->set_fb = nv50_crtc_set_fb; crtc->blank = nv50_crtc_blank; crtc->set_dither = nv50_crtc_set_dither; crtc->set_scale = nv50_crtc_set_scale; diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index 5eb815a5..0eadc3d4 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -54,6 +54,7 @@ struct nv50_crtc { int (*validate_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode); int (*set_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode); int (*execute_mode) (struct nv50_crtc *crtc); + int (*set_fb) (struct nv50_crtc *crtc); int (*blank) (struct nv50_crtc *crtc, bool blanked); int (*set_dither) (struct nv50_crtc *crtc); int (*set_scale) (struct nv50_crtc *crtc); diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 05ff72f8..0c82ff8f 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -34,6 +34,7 @@ static int nv50_display_pre_init(struct nv50_display *display) struct drm_device *dev = display->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; int i; + uint32_t ram_amount; NV50_DEBUG("\n"); @@ -67,6 +68,17 @@ static int nv50_display_pre_init(struct nv50_display *display) NV_WRITE(NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i), 0x00000001); } + /* This used to be in crtc unblank, but seems out of place there. */ + NV_WRITE(NV50_PDISPLAY_UNK_380, 0); + /* RAM is clamped to 256 MiB. */ + ram_amount = nouveau_mem_fb_amount(display->dev); + NV50_DEBUG("ram_amount %d\n", ram_amount); + if (ram_amount > 256*1024*1024) + ram_amount = 256*1024*1024; + NV_WRITE(NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); + NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000); + NV_WRITE(NV50_PDISPLAY_UNK_38C, 0); + display->preinit_done = TRUE; return 0; diff --git a/linux-core/nv50_fb.c b/linux-core/nv50_fb.c index f57a9fad..153899da 100644 --- a/linux-core/nv50_fb.c +++ b/linux-core/nv50_fb.c @@ -40,8 +40,9 @@ static int nv50_fb_bind(struct nv50_crtc *crtc, struct nv50_fb_info *info) return -EINVAL; } - if (!info->block || !info->width || !info->height || !info->depth || !info->bpp) { - DRM_ERROR("block %p width %d height %d depth %d bpp %d\n", info->block, info->width, info->height, info->depth, info->bpp); + if (!info->block || !info->width || !info->height || !info->depth || !info->bpp || !info->pitch) { + DRM_ERROR("block %p width %d height %d depth %d bpp %d pitch %d\n", info->block, info->width, + info->height, info->depth, info->bpp, info->pitch); return -EINVAL; } @@ -55,6 +56,8 @@ static int nv50_fb_bind(struct nv50_crtc *crtc, struct nv50_fb_info *info) crtc->fb->depth = info->depth; crtc->fb->bpp = info->bpp; + crtc->fb->pitch = info->pitch; + /* update lut if needed */ if (crtc->fb->depth != crtc->lut->depth) { int r_size = 0, g_size = 0, b_size = 0; diff --git a/linux-core/nv50_fb.h b/linux-core/nv50_fb.h index 6b286315..3051dc5c 100644 --- a/linux-core/nv50_fb.h +++ b/linux-core/nv50_fb.h @@ -35,6 +35,7 @@ struct nv50_fb_info { struct mem_block *block; int width, height; int bpp, depth; + int pitch; int x,y; }; @@ -42,6 +43,7 @@ struct nv50_fb { struct mem_block *block; int width, height; int bpp, depth; + int pitch; int x,y; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index a63cb7df..e93a2668 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -284,12 +284,17 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) struct nouveau_hw_mode *hw_mode = NULL; struct nv50_fb_info fb_info; + bool blank = false; + bool switch_fb = false; + bool modeset = false; + NV50_DEBUG("\n"); /* - * Initial approach is very simple, always set a mode. - * Always bail out completely if something is wrong. - * Later this could be extended to be more smart. + * Supported operations: + * - Switch mode. + * - Switch framebuffer. + * - Blank screen. */ /* Sanity checking */ @@ -298,138 +303,200 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - if (!set->crtc || !set->fb || !set->mode || !set->connectors) { + if (!set->crtc || !set->connectors) { NV50_DEBUG("Sanity check failed\n"); goto out; } + if (set->mode) { + if (set->fb) { + if (!drm_mode_equal(set->mode, &set->crtc->mode)) + modeset = true; + + if (set->fb != set->crtc->fb) + switch_fb = true; + + if (set->x != set->crtc->x || set->y != set->crtc->y) + switch_fb = true; + } + } else { + blank = true; + } + + if (!modeset && !switch_fb && !blank) { + DRM_ERROR("There is nothing to do, bad input.\n"); + goto out; + } + /* Basic variable setting */ dev = set->crtc->dev; dev_priv = dev->dev_private; display = nv50_get_display(dev); crtc = to_nv50_crtc(set->crtc); - /* Mode validation */ - hw_mode = nv50_kms_to_hw_mode(set->mode); - - rval = crtc->validate_mode(crtc, hw_mode); - - if (rval != MODE_OK) { - NV50_DEBUG("Mode not ok\n"); - goto out; - } + /** + * Wiring up the encoders and connectors. + */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - NV50_DEBUG("No connector\n"); - goto out; - } - connector = to_nv50_connector(drm_connector); + if (modeset) { + /* Mode validation */ + hw_mode = nv50_kms_to_hw_mode(set->mode); - output = connector->to_output(connector, connector->digital); - if (!output) { - NV50_DEBUG("No output\n"); - goto out; - } + rval = crtc->validate_mode(crtc, hw_mode); - rval = output->validate_mode(output, hw_mode); if (rval != MODE_OK) { NV50_DEBUG("Mode not ok\n"); goto out; } - } - /* Validation done, move on to cleaning of existing structures. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } + connector = to_nv50_connector(drm_connector); - /* find encoders that use this crtc. */ - list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (drm_encoder->crtc == set->crtc) { - /* find the connector that goes with it */ - list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { - if (drm_connector->encoder == drm_encoder) { - drm_connector->encoder = NULL; - break; - } + output = connector->to_output(connector, connector->digital); + if (!output) { + NV50_DEBUG("No output\n"); + goto out; } - drm_encoder->crtc = NULL; - } - } - /* now find if our desired encoders or connectors are in use already. */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - NV50_DEBUG("No connector\n"); - goto out; + rval = output->validate_mode(output, hw_mode); + if (rval != MODE_OK) { + NV50_DEBUG("Mode not ok\n"); + goto out; + } } - if (!drm_connector->encoder) - continue; + /* Validation done, move on to cleaning of existing structures. */ + + /* find encoders that use this crtc. */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + /* find the connector that goes with it */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder == drm_encoder) { + drm_connector->encoder = NULL; + break; + } + } + drm_encoder->crtc = NULL; + } + } - drm_encoder = drm_connector->encoder; - drm_connector->encoder = NULL; + /* now find if our desired encoders or connectors are in use already. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } - if (!drm_encoder->crtc) - continue; + if (!drm_connector->encoder) + continue; - drm_crtc = drm_encoder->crtc; - drm_encoder->crtc = NULL; + drm_encoder = drm_connector->encoder; + drm_connector->encoder = NULL; - crtc = to_nv50_crtc(drm_crtc); - crtc->active = false; - drm_crtc->enabled = false; - } + if (!drm_encoder->crtc) + continue; - /* set framebuffer */ - set->crtc->fb = set->fb; + drm_crtc = drm_encoder->crtc; + drm_encoder->crtc = NULL; - /* Time to wire up the public encoder, the private one will be handled later. */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - NV50_DEBUG("No connector\n"); - goto out; + crtc = to_nv50_crtc(drm_crtc); + crtc->active = false; + drm_crtc->enabled = false; } - output = connector->to_output(connector, connector->digital); - if (!output) { - NV50_DEBUG("No output\n"); - goto out; - } + /* Time to wire up the public encoder, the private one will be handled later. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } - /* find the encoder public structure that matches out output structure. */ - drm_encoder = to_nv50_kms_encoder(output); + output = connector->to_output(connector, connector->digital); + if (!output) { + NV50_DEBUG("No output\n"); + goto out; + } - if (!drm_encoder) { - NV50_DEBUG("No encoder\n"); - goto out; + /* find the encoder public structure that matches out output structure. */ + drm_encoder = to_nv50_kms_encoder(output); + + if (!drm_encoder) { + NV50_DEBUG("No encoder\n"); + goto out; + } + + drm_encoder->crtc = set->crtc; + drm_connector->encoder = drm_encoder; } + } + + /** + * Unwire encoders and connectors, etc. + */ + if (blank) { + crtc = to_nv50_crtc(drm_crtc); - drm_encoder->crtc = set->crtc; - drm_connector->encoder = drm_encoder; + crtc->active = false; + set->crtc->enabled = false; + + /* find encoders that use this crtc. */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + /* find the connector that goes with it */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder == drm_encoder) { + drm_connector->encoder = NULL; + break; + } + } + drm_encoder->crtc = NULL; + } + } } + /** + * All state should now be updated, now onto the real work. + */ + /* mirror everything to the private structs */ nv50_kms_mirror_routing(dev); - /* set private framebuffer */ - crtc = to_nv50_crtc(set->crtc); - fb_info.block = find_block_by_handle(dev_priv->fb_heap, set->fb->mm_handle); - fb_info.width = set->fb->width; - fb_info.height = set->fb->height; - fb_info.depth = set->fb->depth; - fb_info.bpp = set->fb->bits_per_pixel; - fb_info.x = set->x; - fb_info.y = set->y; - - rval = crtc->fb->bind(crtc, &fb_info); - if (rval != 0) { - NV50_DEBUG("fb_bind failed\n"); - goto out; + /** + * Bind framebuffer. + */ + + if (switch_fb) { + /* set framebuffer */ + set->crtc->fb = set->fb; + + /* set private framebuffer */ + crtc = to_nv50_crtc(set->crtc); + fb_info.block = find_block_by_handle(dev_priv->fb_heap, set->fb->mm_handle); + fb_info.width = set->fb->width; + fb_info.height = set->fb->height; + fb_info.depth = set->fb->depth; + fb_info.bpp = set->fb->bits_per_pixel; + fb_info.pitch = set->fb->pitch; + fb_info.x = set->x; + fb_info.y = set->y; + + rval = crtc->fb->bind(crtc, &fb_info); + if (rval != 0) { + NV50_DEBUG("fb_bind failed\n"); + goto out; + } } + /* this is !cursor_show */ if (!crtc->cursor->enabled) { rval = crtc->cursor->enable(crtc); if (rval != 0) { @@ -438,74 +505,119 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } } - /* modeset time, finally */ + /** + * Blanking. + */ - /* disconnect unused outputs */ - list_for_each_entry(output, &display->outputs, head) { - if (output->crtc) - crtc_mask |= 1 << output->crtc->index; - else - output->execute_mode(output, TRUE); - } + if (blank) { + crtc = to_nv50_crtc(set->crtc); - rval = crtc->set_mode(crtc, hw_mode); - if (rval != 0) { - NV50_DEBUG("crtc mode set failed\n"); - goto out; + rval = crtc->blank(crtc, TRUE); + if (rval != 0) { + DRM_ERROR("blanking failed\n"); + goto out; + } } - /* find native mode. */ - list_for_each_entry(output, &display->outputs, head) { - if (output->crtc != crtc) - continue; + /** + * Change framebuffer, without changing mode. + */ - *crtc->native_mode = *output->native_mode; - list_for_each_entry(connector, &display->connectors, head) { - if (connector->output != output) - continue; + if (switch_fb && !modeset) { + crtc = to_nv50_crtc(set->crtc); - crtc->scaling_mode = connector->scaling_mode; - break; + rval = crtc->blank(crtc, TRUE); + if (rval != 0) { + DRM_ERROR("blanking failed\n"); + goto out; } - if (crtc->scaling_mode == SCALE_PANEL) - crtc->use_native_mode = false; - else - crtc->use_native_mode = true; + rval = crtc->set_fb(crtc); + if (rval != 0) { + DRM_ERROR("set_fb failed\n"); + goto out; + } - break; /* no use in finding more than one mode */ + /* this also sets the fb offset */ + rval = crtc->blank(crtc, FALSE); + if (rval != 0) { + DRM_ERROR("unblanking failed\n"); + goto out; + } } - rval = crtc->execute_mode(crtc); - if (rval != 0) { - NV50_DEBUG("crtc execute mode failed\n"); - goto out; - } + /** + * Normal modesetting. + */ - list_for_each_entry(output, &display->outputs, head) { - if (output->crtc != crtc) - continue; + if (modeset) { + /* disconnect unused outputs */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc) + crtc_mask |= 1 << output->crtc->index; + else + output->execute_mode(output, TRUE); + } - rval = output->execute_mode(output, FALSE); + rval = crtc->set_mode(crtc, hw_mode); if (rval != 0) { - NV50_DEBUG("output execute mode failed\n"); + NV50_DEBUG("crtc mode set failed\n"); goto out; } - } - rval = crtc->set_scale(crtc); - if (rval != 0) { - NV50_DEBUG("crtc set scale failed\n"); - goto out; - } + /* find native mode. */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; - /* next line changes crtc, so putting it here is important */ - display->last_crtc = crtc->index; + *crtc->native_mode = *output->native_mode; + list_for_each_entry(connector, &display->connectors, head) { + if (connector->output != output) + continue; - /* blank any unused crtcs */ - list_for_each_entry(crtc, &display->crtcs, head) { - if (!(crtc_mask & (1 << crtc->index))) - crtc->blank(crtc, TRUE); + crtc->scaling_mode = connector->scaling_mode; + break; + } + + if (crtc->scaling_mode == SCALE_PANEL) + crtc->use_native_mode = false; + else + crtc->use_native_mode = true; + + break; /* no use in finding more than one mode */ + } + + rval = crtc->execute_mode(crtc); + if (rval != 0) { + NV50_DEBUG("crtc execute mode failed\n"); + goto out; + } + + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; + + rval = output->execute_mode(output, FALSE); + if (rval != 0) { + NV50_DEBUG("output execute mode failed\n"); + goto out; + } + } + + rval = crtc->set_scale(crtc); + if (rval != 0) { + NV50_DEBUG("crtc set scale failed\n"); + goto out; + } + + /* next line changes crtc, so putting it here is important */ + display->last_crtc = crtc->index; + + /* blank any unused crtcs */ + list_for_each_entry(crtc, &display->crtcs, head) { + if (!(crtc_mask & (1 << crtc->index))) + crtc->blank(crtc, TRUE); + } } display->update(display); @@ -631,36 +743,35 @@ static int nv50_kms_encoders_init(struct drm_device *dev) void nv50_kms_connector_detect_all(struct drm_device *dev) { struct drm_connector *drm_connector = NULL; - enum drm_connector_status old, new; - bool notify = false; list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { - old = drm_connector->status; - new = drm_connector->funcs->detect(drm_connector); - - if (new != old) { - notify = true; - drm_connector->funcs->fill_modes(drm_connector, 0, 0); - } + drm_connector->funcs->detect(drm_connector); } - - /* I think this is the hook that notifies of changes. */ - if (notify) - dev->mode_config.funcs->fb_changed(dev); } static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector) { struct nv50_connector *connector = to_nv50_connector(drm_connector); + struct drm_device *dev = drm_connector->dev; bool connected; + int old_status; connected = connector->detect(connector); + old_status = drm_connector->status; + if (connected) drm_connector->status = connector_status_connected; else drm_connector->status = connector_status_disconnected; + /* update our modes whenever there is reason to */ + if (old_status != drm_connector->status) { + drm_connector->funcs->fill_modes(drm_connector, 0, 0); + /* notify fb of changes */ + dev->mode_config.funcs->fb_changed(dev); + } + return drm_connector->status; } @@ -695,7 +806,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u struct drm_display_mode *mode, *t; struct edid *edid = NULL; - DRM_DEBUG("%s\n", drm_get_connector_name(drm_connector)); + NV50_DEBUG("%s\n", drm_get_connector_name(drm_connector)); /* set all modes to the unverified state */ list_for_each_entry_safe(mode, t, &drm_connector->modes, head) mode->status = MODE_UNVERIFIED; @@ -708,7 +819,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_connector->status = connector_status_disconnected; if (!connected) { - DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); + NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); /* TODO set EDID to NULL */ return; } @@ -762,7 +873,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u struct nouveau_hw_mode *hw_mode; struct nv50_output *output; - DRM_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector)); + NV50_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector)); /* Should we do this here ??? * When no valid EDID modes are available we end up @@ -787,7 +898,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_mode_sort(&drm_connector->modes); - DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(drm_connector)); + NV50_DEBUG("Probed modes for %s\n", drm_get_connector_name(drm_connector)); list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { mode->vrefresh = drm_mode_vrefresh(mode); diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 49f29fd3..75909c82 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -100,6 +100,10 @@ static int nv50_sor_set_clock_mode(struct nv50_output *output) NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + /* We don't yet know what to do, if anything at all. */ + if (output->type == OUTPUT_LVDS) + return 0; + if (crtc->use_native_mode) hw_mode = crtc->native_mode; else -- cgit v1.2.3 From f9dad8cc22994e0e4671d14b3ee721e4b5777a68 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 23 Jun 2008 21:15:54 +0200 Subject: libdrm: check for allocation failure --- libdrm/xf86drmMode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index a393f965..df865415 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -419,6 +419,9 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) r->connector_type = conn.connector_type; r->connector_type_id = conn.connector_type_id; + if (!r->props || !r->prop_values || !r->modes || !r->encoders) + goto err_allocs; + err_allocs: drmFree(U642VOID(conn.prop_values_ptr)); drmFree(U642VOID(conn.props_ptr)); -- cgit v1.2.3 From 246b41fea462a3b1669c0e3f9fe7f6077a479832 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 23 Jun 2008 22:59:17 +0200 Subject: [modesetting-101] update mode count after fill_modes. - This avoids returning with a mode count of 0, thus not allocating space for the 2nd ioctl. --- linux-core/drm_crtc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c8cfaef4..aab936c2 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1018,9 +1018,6 @@ int drm_mode_getconnector(struct drm_device *dev, } connector = obj_to_connector(obj); - list_for_each_entry(mode, &connector->modes, head) - mode_count++; - for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { if (connector->property_ids[i] != 0) { props_count++; @@ -1037,6 +1034,10 @@ int drm_mode_getconnector(struct drm_device *dev, connector->funcs->fill_modes(connector, dev->mode_config.max_width, dev->mode_config.max_height); } + /* delayed so we get modes regardless of pre-fill_modes state */ + list_for_each_entry(mode, &connector->modes, head) + mode_count++; + out_resp->generation = dev->mode_config.current_generation; out_resp->connector_type = connector->connector_type; out_resp->connector_type_id = connector->connector_type_id; @@ -1049,6 +1050,7 @@ int drm_mode_getconnector(struct drm_device *dev, else out_resp->encoder = 0; + /* this ioctl is called twice, once to determine how much space is needed, and the 2nd time to fill it */ if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr; @@ -1060,7 +1062,6 @@ int drm_mode_getconnector(struct drm_device *dev, goto out; } copied++; - } } out_resp->count_modes = mode_count; -- cgit v1.2.3 From 5072a2911e134bb3fec06a6d7011a92e714a9953 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 00:00:02 +0200 Subject: NV50: fix some misc bugs --- linux-core/nv50_kms_wrapper.c | 55 ++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index e93a2668..739704b5 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -303,7 +303,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - if (!set->crtc || !set->connectors) { + if (!set->crtc) { NV50_DEBUG("Sanity check failed\n"); goto out; } @@ -323,6 +323,11 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) blank = true; } + if (!set->connectors && modeset) { + NV50_DEBUG("Sanity check failed\n"); + goto out; + } + if (!modeset && !switch_fb && !blank) { DRM_ERROR("There is nothing to do, bad input.\n"); goto out; @@ -439,28 +444,15 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /** - * Unwire encoders and connectors, etc. + * Disable crtc. */ if (blank) { - crtc = to_nv50_crtc(drm_crtc); + crtc = to_nv50_crtc(set->crtc); + /* keeping the encoders and connectors attached, so they can be tracked */ crtc->active = false; set->crtc->enabled = false; - - /* find encoders that use this crtc. */ - list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (drm_encoder->crtc == set->crtc) { - /* find the connector that goes with it */ - list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { - if (drm_connector->encoder == drm_encoder) { - drm_connector->encoder = NULL; - break; - } - } - drm_encoder->crtc = NULL; - } - } } /** @@ -517,13 +509,26 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) DRM_ERROR("blanking failed\n"); goto out; } + + /* detach any outputs that are currently running on this crtc */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + output = to_nv50_output(drm_encoder); + + rval = output->execute_mode(output, TRUE); + if (rval != 0) { + DRM_ERROR("detaching output failed\n"); + goto out; + } + } + } } /** * Change framebuffer, without changing mode. */ - if (switch_fb && !modeset) { + if (switch_fb && !modeset && !blank) { crtc = to_nv50_crtc(set->crtc); rval = crtc->blank(crtc, TRUE); @@ -553,10 +558,15 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (modeset) { /* disconnect unused outputs */ list_for_each_entry(output, &display->outputs, head) { - if (output->crtc) + if (output->crtc) { crtc_mask |= 1 << output->crtc->index; - else - output->execute_mode(output, TRUE); + } else { + rval = output->execute_mode(output, TRUE); + if (rval != 0) { + DRM_ERROR("detaching output failed\n"); + goto out; + } + } } rval = crtc->set_mode(crtc, hw_mode); @@ -627,7 +637,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) return 0; out: - display->update(display); + if (display) + display->update(display); kfree(hw_mode); -- cgit v1.2.3 From e7582cfff6cb561d8bdfcd640d6843cdbb6b3391 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 09:41:13 +0200 Subject: NV50: These are actually errors. --- linux-core/nv50_kms_wrapper.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 739704b5..529a9055 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -299,12 +299,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* Sanity checking */ if (!set) { - NV50_DEBUG("Sanity check failed\n"); + DRM_ERROR("Sanity check failed\n"); goto out; } if (!set->crtc) { - NV50_DEBUG("Sanity check failed\n"); + DRM_ERROR("Sanity check failed\n"); goto out; } @@ -324,7 +324,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } if (!set->connectors && modeset) { - NV50_DEBUG("Sanity check failed\n"); + DRM_ERROR("Sanity check failed\n"); goto out; } @@ -350,27 +350,27 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = crtc->validate_mode(crtc, hw_mode); if (rval != MODE_OK) { - NV50_DEBUG("Mode not ok\n"); + DRM_ERROR("Mode not ok\n"); goto out; } for (i = 0; i < set->num_connectors; i++) { drm_connector = set->connectors[i]; if (!drm_connector) { - NV50_DEBUG("No connector\n"); + DRM_ERROR("No connector\n"); goto out; } connector = to_nv50_connector(drm_connector); output = connector->to_output(connector, connector->digital); if (!output) { - NV50_DEBUG("No output\n"); + DRM_ERROR("No output\n"); goto out; } rval = output->validate_mode(output, hw_mode); if (rval != MODE_OK) { - NV50_DEBUG("Mode not ok\n"); + DRM_ERROR("Mode not ok\n"); goto out; } } @@ -395,7 +395,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) for (i = 0; i < set->num_connectors; i++) { drm_connector = set->connectors[i]; if (!drm_connector) { - NV50_DEBUG("No connector\n"); + DRM_ERROR("No connector\n"); goto out; } @@ -420,13 +420,13 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) for (i = 0; i < set->num_connectors; i++) { drm_connector = set->connectors[i]; if (!drm_connector) { - NV50_DEBUG("No connector\n"); + DRM_ERROR("No connector\n"); goto out; } output = connector->to_output(connector, connector->digital); if (!output) { - NV50_DEBUG("No output\n"); + DRM_ERROR("No output\n"); goto out; } @@ -434,7 +434,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) drm_encoder = to_nv50_kms_encoder(output); if (!drm_encoder) { - NV50_DEBUG("No encoder\n"); + DRM_ERROR("No encoder\n"); goto out; } @@ -483,7 +483,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = crtc->fb->bind(crtc, &fb_info); if (rval != 0) { - NV50_DEBUG("fb_bind failed\n"); + DRM_ERROR("fb_bind failed\n"); goto out; } } @@ -492,7 +492,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (!crtc->cursor->enabled) { rval = crtc->cursor->enable(crtc); if (rval != 0) { - NV50_DEBUG("cursor_enable failed\n"); + DRM_ERROR("cursor_enable failed\n"); goto out; } } @@ -571,7 +571,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = crtc->set_mode(crtc, hw_mode); if (rval != 0) { - NV50_DEBUG("crtc mode set failed\n"); + DRM_ERROR("crtc mode set failed\n"); goto out; } @@ -599,7 +599,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = crtc->execute_mode(crtc); if (rval != 0) { - NV50_DEBUG("crtc execute mode failed\n"); + DRM_ERROR("crtc execute mode failed\n"); goto out; } @@ -609,14 +609,14 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = output->execute_mode(output, FALSE); if (rval != 0) { - NV50_DEBUG("output execute mode failed\n"); + DRM_ERROR("output execute mode failed\n"); goto out; } } rval = crtc->set_scale(crtc); if (rval != 0) { - NV50_DEBUG("crtc set scale failed\n"); + DRM_ERROR("crtc set scale failed\n"); goto out; } -- cgit v1.2.3 From 315fef7ee44f9ca565f158a6a84fd29b34e69fd8 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 10:16:52 +0200 Subject: NV50: fix cursor hide/show --- linux-core/nv50_cursor.c | 4 +--- linux-core/nv50_kms_wrapper.c | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c index 4196df6b..47ae11bb 100644 --- a/linux-core/nv50_cursor.c +++ b/linux-core/nv50_cursor.c @@ -126,6 +126,7 @@ static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle) crtc->cursor->show(crtc); } } else { + DRM_ERROR("Unable to find cursor bo with handle 0x%X\n", handle); return -EINVAL; } @@ -151,9 +152,6 @@ int nv50_cursor_create(struct nv50_crtc *crtc) crtc->cursor->enable = nv50_cursor_enable; crtc->cursor->disable = nv50_cursor_disable; - /* defaults */ - crtc->cursor->visible = true; /* won't happen until there is a cursor bo */ - return 0; } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 529a9055..b3d5ce65 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -233,20 +233,35 @@ static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_h { struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); struct nv50_display *display = nv50_get_display(crtc->dev); - int rval; + int rval = 0; if (width != 64 || height != 64) return -EINVAL; - rval = crtc->cursor->set_bo(crtc, (drm_handle_t) buffer_handle); + /* set bo before doing show cursor */ + if (buffer_handle) { + rval = crtc->cursor->set_bo(crtc, (drm_handle_t) buffer_handle); + if (rval != 0) + goto out; + } + + if (buffer_handle) { + rval = crtc->cursor->show(crtc); + if (rval != 0) + goto out; + } else { /* no handle implies hiding the cursor */ + rval = crtc->cursor->hide(crtc); + goto out; + } if (rval != 0) return rval; +out: /* in case this triggers any other cursor changes */ display->update(display); - return 0; + return rval; } static int nv50_kms_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y) -- cgit v1.2.3 From 14522b3e1bd1129333af7f1a16a436a5f90388ea Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 12:38:57 +0200 Subject: NV50: fix a few misc things --- linux-core/nv50_kms_wrapper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index b3d5ce65..8b97882a 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -245,6 +245,8 @@ static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_h goto out; } + crtc->cursor->visible = buffer_handle ? true : false; + if (buffer_handle) { rval = crtc->cursor->show(crtc); if (rval != 0) @@ -858,6 +860,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_mode_connector_update_edid_property(drm_connector, edid); ret = drm_add_edid_modes(drm_connector, edid); connector->digital = edid->digital; /* cache */ + kfree(edid); } if (ret) /* number of modes > 1 */ -- cgit v1.2.3 From 5dbcb7551ff0b2c759f34ca85c30cfa95f33ba09 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 20:29:08 +0200 Subject: NV50: minor change --- linux-core/nv50_connector.c | 2 +- linux-core/nv50_sor.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index d13622b7..a13f8e59 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -184,7 +184,7 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty } /* some reasonable defaults */ - if (type == CONNECTOR_DVI_D || type == CONNECTOR_LVDS) + if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS) connector->scaling_mode = SCALE_FULLSCREEN; else connector->scaling_mode = SCALE_PANEL; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 75909c82..fca9612f 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -83,8 +83,6 @@ static int nv50_sor_execute_mode(struct nv50_output *output, bool disconnect) if (desired_mode->flags & V_NVSYNC) mode_ctl |= NV50_SOR_MODE_CTRL_NVSYNC; - /* TODO: DPMS ?????? */ - OUT_MODE(NV50_SOR0_MODE_CTRL + offset, mode_ctl); return 0; -- cgit v1.2.3 From d55629a13d0f287e186e93a4828ef86b36678eba Mon Sep 17 00:00:00 2001 From: root Date: Tue, 24 Jun 2008 23:18:29 +0100 Subject: silence warning --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 64a8fc94..cbd22ba6 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -882,7 +882,7 @@ static int intelfb_single_fb_probe(struct drm_device *dev) struct intel_framebuffer *intel_fb; struct fb_info *info; struct intelfb_par *par; - struct drm_mode_set *modeset; + struct drm_mode_set *modeset = NULL; DRM_DEBUG("\n"); /* first up get a count of crtcs now in use and new min/maxes width/heights */ -- cgit v1.2.3 From 5a0164d1e1799b68b3131efd7b9fcaf20c578257 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Jun 2008 01:00:42 +1000 Subject: nouveau: allocate drm-use vram buffers from end of vram. This avoids seeing garbage from engine setup etc before X gets around to pointing the CRTCs at a new scanout buffer. Not actually a noticable problem before G80 as PRAMIN is forced to the end of VRAM by the hardware already. --- shared-core/nouveau_drm.h | 4 ++- shared-core/nouveau_drv.h | 2 +- shared-core/nouveau_mem.c | 58 ++++++++++++++++++++++++++---------------- shared-core/nouveau_notifier.c | 2 +- shared-core/nouveau_object.c | 2 +- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index cf762052..bbb51bc4 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -88,9 +88,11 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */ #define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */ #define NOUVEAU_MEM_NOVM 0x00000800 /* internal */ +#define NOUVEAU_MEM_USER 0x00001000 /* internal */ #define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \ NOUVEAU_MEM_NOTIFIER | \ - NOUVEAU_MEM_NOVM) + NOUVEAU_MEM_NOVM | \ + NOUVEAU_MEM_USER) struct drm_nouveau_mem_alloc { int flags; diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 20aa6b86..33e2a5b6 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -375,7 +375,7 @@ extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start, uint64_t size); extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, uint64_t size, int align2, - struct drm_file *); + struct drm_file *, int tail); extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); extern struct mem_block* find_block_by_handle(struct mem_block *heap, drm_handle_t handle); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 810eaf9e..51ac48dd 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -35,8 +35,9 @@ #include "drm_sarea.h" #include "nouveau_drv.h" -static struct mem_block *split_block(struct mem_block *p, uint64_t start, uint64_t size, - struct drm_file *file_priv) +static struct mem_block * +split_block(struct mem_block *p, uint64_t start, uint64_t size, + struct drm_file *file_priv) { /* Maybe cut off the start of an existing block */ if (start > p->start) { @@ -77,10 +78,9 @@ out: return p; } -struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, - uint64_t size, - int align2, - struct drm_file *file_priv) +struct mem_block * +nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size, + int align2, struct drm_file *file_priv, int tail) { struct mem_block *p; uint64_t mask = (1 << align2) - 1; @@ -88,10 +88,22 @@ struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, if (!heap) return NULL; - list_for_each(p, heap) { - uint64_t start = (p->start + mask) & ~mask; - if (p->file_priv == 0 && start + size <= p->start + p->size) - return split_block(p, start, size, file_priv); + if (tail) { + list_for_each_prev(p, heap) { + uint64_t start = ((p->start + p->size) - size) & ~mask; + + if (p->file_priv == 0 && start >= p->start && + start + size <= p->start + p->size) + return split_block(p, start, size, file_priv); + } + } else { + list_for_each(p, heap) { + uint64_t start = (p->start + mask) & ~mask; + + if (p->file_priv == 0 && + start + size <= p->start + p->size) + return split_block(p, start, size, file_priv); + } } return NULL; @@ -574,13 +586,13 @@ int nouveau_mem_init(struct drm_device *dev) return 0; } -struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, - uint64_t size, int flags, - struct drm_file *file_priv) +struct mem_block * +nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size, + int flags, struct drm_file *file_priv) { - struct mem_block *block; - int type; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct mem_block *block; + int type, tail = !(flags & NOUVEAU_MEM_USER); /* * Make things easier on ourselves: all allocations are page-aligned. @@ -611,14 +623,14 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, #define NOUVEAU_MEM_ALLOC_AGP {\ type=NOUVEAU_MEM_AGP;\ block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,\ - alignment, file_priv); \ + alignment, file_priv, tail); \ if (block) goto alloc_ok;\ } #define NOUVEAU_MEM_ALLOC_PCI {\ type = NOUVEAU_MEM_PCI;\ block = nouveau_mem_alloc_block(dev_priv->pci_heap, size, \ - alignment, file_priv); \ + alignment, file_priv, tail); \ if ( block ) goto alloc_ok;\ } @@ -627,11 +639,11 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, if (!(flags&NOUVEAU_MEM_MAPPED)) {\ block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,\ size, alignment, \ - file_priv); \ + file_priv, tail); \ if (block) goto alloc_ok;\ }\ block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,\ - alignment, file_priv);\ + alignment, file_priv, tail);\ if (block) goto alloc_ok;\ } @@ -749,7 +761,9 @@ out_free: * Ioctls */ -int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_nouveau_mem_alloc *alloc = data; struct mem_block *block; @@ -759,8 +773,8 @@ int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file if (alloc->flags & NOUVEAU_MEM_INTERNAL) return -EINVAL; - block=nouveau_mem_alloc(dev, alloc->alignment, alloc->size, - alloc->flags, file_priv); + block = nouveau_mem_alloc(dev, alloc->alignment, alloc->size, + alloc->flags | NOUVEAU_MEM_USER, file_priv); if (!block) return -ENOMEM; alloc->map_handle=block->map_handle; diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 82c8ab7d..edece4da 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -94,7 +94,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, } mem = nouveau_mem_alloc_block(chan->notifier_heap, count*32, 0, - (struct drm_file *)-2); + (struct drm_file *)-2, 0); if (!mem) { DRM_ERROR("Channel %d notifier block full\n", chan->id); return -ENOMEM; diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 09f9027a..5664bfc8 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -248,7 +248,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, /* Allocate a chunk of the PRAMIN aperture */ gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, drm_order(align), - (struct drm_file *)-2); + (struct drm_file *)-2, 0); if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); return -ENOMEM; -- cgit v1.2.3 From be7276281694145e7c947b91a1c8e6e347de666c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 25 Jun 2008 16:45:41 +1000 Subject: nv50: when destroying a channel make sure it's not still current on PFIFO We won't get a PFIFO context switch when the same channel ID is recreated if the hw still thinks the channel is already active, which causes fun issues. Should allow X to be stopped and started without tearing down the entire card state in lastclose(). --- shared-core/nv50_fifo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c index edf4edbf..d6810666 100644 --- a/shared-core/nv50_fifo.c +++ b/shared-core/nv50_fifo.c @@ -289,6 +289,7 @@ void nv50_fifo_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; DRM_DEBUG("ch%d\n", chan->id); @@ -298,6 +299,9 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) if (chan->id == 0) nv50_fifo_channel_disable(dev, 127, 0); + if ((NV_READ(NV03_PFIFO_CACHE1_PUSH1) & 0xffff) == chan->id) + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, 127); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } -- cgit v1.2.3 From 09b67dda0bc040860aedce4a2d28bce1c80e56d6 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Wed, 25 Jun 2008 15:16:38 +0200 Subject: NV50: Some cleanup and fixes. --- linux-core/nv50_crtc.c | 10 ++++++---- linux-core/nv50_crtc.h | 1 + linux-core/nv50_cursor.c | 18 +++++++++++++++++- linux-core/nv50_cursor.h | 1 + shared-core/nouveau_mem.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 0bcf3058..af2f03d8 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -192,10 +192,9 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) } else { OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8); OUT_MODE(0x864 + offset, 0); - if (crtc->cursor->block) - OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8); - else - OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, 0); + + crtc->cursor->set_offset(crtc); + if (dev_priv->chipset != 0x50) OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_UNBLANK); @@ -212,6 +211,9 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_UNBLANK); } + /* sometimes you need to know if a screen is already blanked. */ + crtc->blanked = blanked; + return 0; } diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index 0eadc3d4..b63c5a22 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -39,6 +39,7 @@ struct nv50_crtc { struct drm_device *dev; int index; bool active; + bool blanked; struct nouveau_hw_mode *mode; struct nouveau_hw_mode *native_mode; diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c index 47ae11bb..091c94fe 100644 --- a/linux-core/nv50_cursor.c +++ b/linux-core/nv50_cursor.c @@ -103,6 +103,21 @@ static int nv50_cursor_set_pos(struct nv50_crtc *crtc, int x, int y) return 0; } +static int nv50_cursor_set_offset(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + if (crtc->cursor->block) { + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8); + } else { + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, 0); + } + + return 0; +} + static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle) { struct mem_block *block = NULL; @@ -121,7 +136,7 @@ static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle) /* set the cursor offset cursor */ if (first_time) { - OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8); + crtc->cursor->set_offset(crtc); if (crtc->cursor->visible) crtc->cursor->show(crtc); } @@ -148,6 +163,7 @@ int nv50_cursor_create(struct nv50_crtc *crtc) crtc->cursor->show = nv50_cursor_show; crtc->cursor->hide = nv50_cursor_hide; crtc->cursor->set_pos = nv50_cursor_set_pos; + crtc->cursor->set_offset = nv50_cursor_set_offset; crtc->cursor->set_bo = nv50_cursor_set_bo; crtc->cursor->enable = nv50_cursor_enable; crtc->cursor->disable = nv50_cursor_disable; diff --git a/linux-core/nv50_cursor.h b/linux-core/nv50_cursor.h index a2e4632c..4fd0d39a 100644 --- a/linux-core/nv50_cursor.h +++ b/linux-core/nv50_cursor.h @@ -40,6 +40,7 @@ struct nv50_cursor { int (*show) (struct nv50_crtc *crtc); int (*hide) (struct nv50_crtc *crtc); int (*set_pos) (struct nv50_crtc *crtc, int x, int y); + int (*set_offset) (struct nv50_crtc *crtc); int (*set_bo) (struct nv50_crtc *crtc, drm_handle_t handle); int (*enable) (struct nv50_crtc *crtc); int (*disable) (struct nv50_crtc *crtc); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 51ac48dd..4acd6bd6 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -34,6 +34,8 @@ #include "drm.h" #include "drm_sarea.h" #include "nouveau_drv.h" +#include "nv50_kms_wrapper.h" + static struct mem_block * split_block(struct mem_block *p, uint64_t start, uint64_t size, @@ -730,6 +732,33 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) DRM_DEBUG("freeing 0x%llx type=0x%08x\n", block->start, block->flags); + /* Check if the deallocations cause problems for our modesetting system. */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + if (dev_priv->card_type >= NV_50) { + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = nv50_get_display(dev); + + list_for_each_entry(crtc, &display->crtcs, head) { + if (crtc->fb->block == block) { + crtc->fb->block = NULL; + + /* this will force a lut change next time a fb is loaded */ + crtc->lut->depth = 0; + + if (!crtc->blanked) + crtc->blank(crtc, TRUE); + } + + if (crtc->cursor->block == block) { + crtc->cursor->block = NULL; + + if (crtc->cursor->visible) + crtc->cursor->hide(crtc); + } + } + } + } + if (block->flags&NOUVEAU_MEM_MAPPED) drm_rmmap(dev, block->map); -- cgit v1.2.3 From 4d85d5d25116304e476849ee64c206ffb3a7f372 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Wed, 25 Jun 2008 15:27:07 +0200 Subject: NV50: i misunderstood NOUVEAU_MEM_INTERNAL, so remove it --- linux-core/nv50_lut.c | 2 +- shared-core/nouveau_mem.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c index 5cdf6b5d..7982a926 100644 --- a/linux-core/nv50_lut.c +++ b/linux-core/nv50_lut.c @@ -33,7 +33,7 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) { struct mem_block *block; struct drm_file *file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL); - uint32_t flags = NOUVEAU_MEM_INTERNAL | NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; + uint32_t flags = NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; int rval = 0; NV50_DEBUG("\n"); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 4acd6bd6..46b6e4d6 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -742,9 +742,6 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) if (crtc->fb->block == block) { crtc->fb->block = NULL; - /* this will force a lut change next time a fb is loaded */ - crtc->lut->depth = 0; - if (!crtc->blanked) crtc->blank(crtc, TRUE); } -- cgit v1.2.3 From 13943fe5823c45759091c1a1f487a4abe377421e Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 26 Jun 2008 21:28:29 +0200 Subject: modesetting-101: Make dpms property optional + misc cleanup. - intel_crt seems the only one to provide it, so init it there. --- linux-core/drm_crtc.c | 77 +++++++++++++++++++++++++++++++------------------- linux-core/drm_crtc.h | 3 +- linux-core/intel_crt.c | 4 +++ linux-core/intel_tv.c | 2 +- 4 files changed, 55 insertions(+), 31 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index aab936c2..b6e636e0 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -43,10 +43,10 @@ struct drm_prop_enum_list { * Global properties */ static struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DPMSModeOn, "On" }, - { DPMSModeStandby, "Standby" }, - { DPMSModeSuspend, "Suspend" }, - { DPMSModeOff, "Off" } +{ { DPMSModeOn, "On" }, + { DPMSModeStandby, "Standby" }, + { DPMSModeSuspend, "Suspend" }, + { DPMSModeOff, "Off" } }; char *drm_get_dpms_name(int val) @@ -61,26 +61,26 @@ char *drm_get_dpms_name(int val) } static struct drm_prop_enum_list drm_connector_enum_list[] = -{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, - { DRM_MODE_CONNECTOR_VGA, "VGA" }, - { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, - { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, - { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, - { DRM_MODE_CONNECTOR_Composite, "Composite" }, - { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, - { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { DRM_MODE_CONNECTOR_Component, "Component" }, - { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, - { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, +{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "Composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "Component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = -{ { DRM_MODE_ENCODER_NONE, "None" }, - { DRM_MODE_ENCODER_DAC, "DAC" }, - { DRM_MODE_ENCODER_TMDS, "TMDS" }, - { DRM_MODE_ENCODER_LVDS, "LVDS" }, - { DRM_MODE_ENCODER_TVDAC, "TV" }, +{ { DRM_MODE_ENCODER_NONE, "None" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TV" }, }; char *drm_get_encoder_name(struct drm_encoder *encoder) @@ -164,7 +164,7 @@ static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object * static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj; - + obj = idr_find(&dev->mode_config.crtc_idr, id); if (!obj || (obj->type != type) || (obj->id != id)) return NULL; @@ -369,8 +369,6 @@ void drm_connector_init(struct drm_device *dev, drm_connector_attach_property(connector, dev->mode_config.edid_property, 0); - drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); - mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_connector_init); @@ -479,8 +477,6 @@ EXPORT_SYMBOL(drm_mode_destroy); static int drm_mode_create_standard_connector_properties(struct drm_device *dev) { - int i; - /* * Standard properties (apply to all connectors) */ @@ -488,6 +484,24 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, "EDID", 0); + return 0; +} + +/** + * drm_mode_create_dpms_property - create dpms connector property + * @dev: DRM device + * + * Called by a driver wanting to support the dpms property. + * Caller is responsible for attaching it to the appropriate connector. + */ +bool drm_mode_create_dpms_property(struct drm_device *dev) +{ + int i; + + /* already allocated */ + if (dev->mode_config.dpms_property) + return 0; + dev->mode_config.dpms_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, "DPMS", ARRAY_SIZE(drm_dpms_enum_list)); @@ -496,6 +510,7 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) return 0; } +EXPORT_SYMBOL(drm_mode_create_dpms_property); /** * drm_create_tv_properties - create TV specific connector properties @@ -508,11 +523,15 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) * responsible for allocating a list of format names and passing them to * this routine. */ -bool drm_create_tv_properties(struct drm_device *dev, int num_modes, +bool drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, char *modes[]) { int i; + /* already allocated */ + if (dev->mode_config.tv_mode_property) + return 0; + dev->mode_config.tv_left_margin_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, @@ -547,7 +566,7 @@ bool drm_create_tv_properties(struct drm_device *dev, int num_modes, return 0; } -EXPORT_SYMBOL(drm_create_tv_properties); +EXPORT_SYMBOL(drm_mode_create_tv_properties); /** * drm_mode_config_init - initialize DRM mode_configuration structure diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d6fa4cca..b94e91a1 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -677,7 +677,8 @@ extern struct drm_property *drm_property_create(struct drm_device *dev, int flag extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); -extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, +extern bool drm_mode_create_dpms_property(struct drm_device *dev); +extern bool drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); extern char *drm_get_encoder_name(struct drm_encoder *encoder); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index b9e8ee63..c7509d5e 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -292,5 +292,9 @@ void intel_crt_init(struct drm_device *dev) drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); + /* create dpms property */ + drm_mode_create_dpms_property(dev); + drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); + drm_sysfs_connector_add(connector); } diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 39f33d6c..f564fa91 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1713,7 +1713,7 @@ intel_tv_init(struct drm_device *dev) goto out; for (i = 0; i < NUM_TV_MODES; i++) tv_format_names[i] = tv_modes[i].name; - drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); -- cgit v1.2.3 From 087e3f577d795bcd007619514bb2977eede70c16 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 26 Jun 2008 23:12:04 +0200 Subject: Revert "modesetting-101: Make dpms property optional + misc cleanup." This reverts commit 13943fe5823c45759091c1a1f487a4abe377421e. --- linux-core/drm_crtc.c | 77 +++++++++++++++++++------------------------------- linux-core/drm_crtc.h | 3 +- linux-core/intel_crt.c | 4 --- linux-core/intel_tv.c | 2 +- 4 files changed, 31 insertions(+), 55 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index b6e636e0..aab936c2 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -43,10 +43,10 @@ struct drm_prop_enum_list { * Global properties */ static struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DPMSModeOn, "On" }, - { DPMSModeStandby, "Standby" }, - { DPMSModeSuspend, "Suspend" }, - { DPMSModeOff, "Off" } +{ { DPMSModeOn, "On" }, + { DPMSModeStandby, "Standby" }, + { DPMSModeSuspend, "Suspend" }, + { DPMSModeOff, "Off" } }; char *drm_get_dpms_name(int val) @@ -61,26 +61,26 @@ char *drm_get_dpms_name(int val) } static struct drm_prop_enum_list drm_connector_enum_list[] = -{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, - { DRM_MODE_CONNECTOR_VGA, "VGA" }, - { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, - { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, - { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, - { DRM_MODE_CONNECTOR_Composite, "Composite" }, - { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, - { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { DRM_MODE_CONNECTOR_Component, "Component" }, - { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, - { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, +{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "Composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "Component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = -{ { DRM_MODE_ENCODER_NONE, "None" }, - { DRM_MODE_ENCODER_DAC, "DAC" }, - { DRM_MODE_ENCODER_TMDS, "TMDS" }, - { DRM_MODE_ENCODER_LVDS, "LVDS" }, - { DRM_MODE_ENCODER_TVDAC, "TV" }, +{ { DRM_MODE_ENCODER_NONE, "None" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TV" }, }; char *drm_get_encoder_name(struct drm_encoder *encoder) @@ -164,7 +164,7 @@ static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object * static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj; - + obj = idr_find(&dev->mode_config.crtc_idr, id); if (!obj || (obj->type != type) || (obj->id != id)) return NULL; @@ -369,6 +369,8 @@ void drm_connector_init(struct drm_device *dev, drm_connector_attach_property(connector, dev->mode_config.edid_property, 0); + drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); + mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_connector_init); @@ -477,6 +479,8 @@ EXPORT_SYMBOL(drm_mode_destroy); static int drm_mode_create_standard_connector_properties(struct drm_device *dev) { + int i; + /* * Standard properties (apply to all connectors) */ @@ -484,24 +488,6 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, "EDID", 0); - return 0; -} - -/** - * drm_mode_create_dpms_property - create dpms connector property - * @dev: DRM device - * - * Called by a driver wanting to support the dpms property. - * Caller is responsible for attaching it to the appropriate connector. - */ -bool drm_mode_create_dpms_property(struct drm_device *dev) -{ - int i; - - /* already allocated */ - if (dev->mode_config.dpms_property) - return 0; - dev->mode_config.dpms_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, "DPMS", ARRAY_SIZE(drm_dpms_enum_list)); @@ -510,7 +496,6 @@ bool drm_mode_create_dpms_property(struct drm_device *dev) return 0; } -EXPORT_SYMBOL(drm_mode_create_dpms_property); /** * drm_create_tv_properties - create TV specific connector properties @@ -523,15 +508,11 @@ EXPORT_SYMBOL(drm_mode_create_dpms_property); * responsible for allocating a list of format names and passing them to * this routine. */ -bool drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, +bool drm_create_tv_properties(struct drm_device *dev, int num_modes, char *modes[]) { int i; - /* already allocated */ - if (dev->mode_config.tv_mode_property) - return 0; - dev->mode_config.tv_left_margin_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, @@ -566,7 +547,7 @@ bool drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, return 0; } -EXPORT_SYMBOL(drm_mode_create_tv_properties); +EXPORT_SYMBOL(drm_create_tv_properties); /** * drm_mode_config_init - initialize DRM mode_configuration structure diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index b94e91a1..d6fa4cca 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -677,8 +677,7 @@ extern struct drm_property *drm_property_create(struct drm_device *dev, int flag extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); -extern bool drm_mode_create_dpms_property(struct drm_device *dev); -extern bool drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, +extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); extern char *drm_get_encoder_name(struct drm_encoder *encoder); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index c7509d5e..b9e8ee63 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -292,9 +292,5 @@ void intel_crt_init(struct drm_device *dev) drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); - /* create dpms property */ - drm_mode_create_dpms_property(dev); - drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); - drm_sysfs_connector_add(connector); } diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index f564fa91..39f33d6c 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1713,7 +1713,7 @@ intel_tv_init(struct drm_device *dev) goto out; for (i = 0; i < NUM_TV_MODES; i++) tv_format_names[i] = tv_modes[i].name; - drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); -- cgit v1.2.3 From d88616555d2d3abc118f77d5556e14dd1512272b Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 26 Jun 2008 23:21:01 +0200 Subject: [modesetting-101] tab-cleanup --- linux-core/drm_crtc.c | 96 +++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index aab936c2..4f21d09e 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -43,10 +43,10 @@ struct drm_prop_enum_list { * Global properties */ static struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DPMSModeOn, "On" }, - { DPMSModeStandby, "Standby" }, - { DPMSModeSuspend, "Suspend" }, - { DPMSModeOff, "Off" } +{ { DPMSModeOn, "On" }, + { DPMSModeStandby, "Standby" }, + { DPMSModeSuspend, "Suspend" }, + { DPMSModeOff, "Off" } }; char *drm_get_dpms_name(int val) @@ -61,26 +61,26 @@ char *drm_get_dpms_name(int val) } static struct drm_prop_enum_list drm_connector_enum_list[] = -{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, - { DRM_MODE_CONNECTOR_VGA, "VGA" }, - { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, - { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, - { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, - { DRM_MODE_CONNECTOR_Composite, "Composite" }, - { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, - { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { DRM_MODE_CONNECTOR_Component, "Component" }, - { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, - { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, +{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "Composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "Component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = -{ { DRM_MODE_ENCODER_NONE, "None" }, - { DRM_MODE_ENCODER_DAC, "DAC" }, - { DRM_MODE_ENCODER_TMDS, "TMDS" }, - { DRM_MODE_ENCODER_LVDS, "LVDS" }, - { DRM_MODE_ENCODER_TVDAC, "TV" }, +{ { DRM_MODE_ENCODER_NONE, "None" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TV" }, }; char *drm_get_encoder_name(struct drm_encoder *encoder) @@ -139,7 +139,7 @@ again: ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); if (ret == -EAGAIN) - goto again; + goto again; obj->id = new_id; obj->type = obj_type; @@ -164,7 +164,7 @@ static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object * static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj; - + obj = idr_find(&dev->mode_config.crtc_idr, id); if (!obj || (obj->type != type) || (obj->id != id)) return NULL; @@ -411,7 +411,7 @@ void drm_encoder_init(struct drm_device *dev, int encoder_type) { encoder->dev = dev; - + drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); encoder->encoder_type = encoder_type; encoder->funcs = funcs; @@ -590,7 +590,7 @@ int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) total_objects += dev->mode_config.num_crtc; total_objects += dev->mode_config.num_connector; total_objects += dev->mode_config.num_encoder; - + group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); if (!group->id_list) return -ENOMEM; @@ -736,7 +736,7 @@ void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modein strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } - + /** * drm_mode_getresources - get graphics configuration * @inode: inode from the ioctl @@ -795,7 +795,7 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each(lh, &dev->mode_config.encoder_list) encoder_count++; } else { - + crtc_count = mode_group->num_crtcs; connector_count = mode_group->num_connectors; encoder_count = mode_group->num_encoders; @@ -900,13 +900,11 @@ int drm_mode_getresources(struct drm_device *dev, } } card_res->count_connectors = connector_count; - - DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs, card_res->count_connectors, card_res->count_encoders); -out: +out: mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -959,7 +957,7 @@ int drm_mode_getcrtc(struct drm_device *dev, drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); crtc_resp->mode_valid = 1; - + } else { crtc_resp->mode_valid = 0; } @@ -1114,7 +1112,7 @@ int drm_mode_getencoder(struct drm_device *dev, struct drm_mode_object *obj; struct drm_encoder *encoder; int ret = 0; - + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, enc_resp->encoder_id, DRM_MODE_OBJECT_ENCODER); if (!obj) { @@ -1132,7 +1130,7 @@ int drm_mode_getencoder(struct drm_device *dev, enc_resp->encoder_id = encoder->base.id; enc_resp->crtcs = encoder->possible_crtcs; enc_resp->clones = encoder->possible_clones; - + out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1177,7 +1175,7 @@ int drm_mode_setcrtc(struct drm_device *dev, goto out; } crtc = obj_to_crtc(obj); - + if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ @@ -1185,7 +1183,7 @@ int drm_mode_setcrtc(struct drm_device *dev, list_for_each_entry(crtcfb, &dev->mode_config.crtc_list, head) { if (crtcfb == crtc) { DRM_DEBUG("Using current fb for setmode\n"); - fb = crtc->fb; + fb = crtc->fb; } } } else { @@ -1604,7 +1602,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, ret = -ENOMEM; goto out; } - + drm_crtc_convert_umode(mode, umode); ret = drm_mode_attachmode(dev, connector, mode); @@ -1644,7 +1642,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, goto out; } connector = obj_to_connector(obj); - + drm_crtc_convert_umode(&mode, umode); ret = drm_mode_detachmode(dev, connector, &mode); out: @@ -1728,7 +1726,7 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) kfree(property->values); drm_mode_object_put(dev, &property->base); list_del(&property->head); - kfree(property); + kfree(property); } EXPORT_SYMBOL(drm_property_destroy); @@ -1844,12 +1842,12 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, copied = 0; enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr; list_for_each_entry(prop_enum, &property->enum_blob_list, head) { - + if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { ret = -EFAULT; goto done; } - + if (copy_to_user(&enum_ptr[copied].name, &prop_enum->name, DRM_PROP_NAME_LEN)) { ret = -EFAULT; @@ -1866,18 +1864,18 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, copied = 0; blob_id_ptr = (uint32_t *)(unsigned long)out_resp->enum_blob_ptr; blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr; - + list_for_each_entry(prop_blob, &property->enum_blob_list, head) { if (put_user(prop_blob->base.id, blob_id_ptr + copied)) { ret = -EFAULT; goto done; } - + if (put_user(prop_blob->length, blob_length_ptr + copied)) { ret = -EFAULT; goto done; } - + copied++; } } @@ -1906,7 +1904,7 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev memcpy(blob->data, data, length); drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); - + list_add_tail(&blob->head, &dev->mode_config.property_blob_list); return blob; } @@ -1958,7 +1956,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, str drm_property_destroy_blob(dev, connector->edid_blob_ptr); connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); - + ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, connector->edid_blob_ptr->base.id); return ret; } @@ -1990,7 +1988,7 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, if (i == DRM_CONNECTOR_MAX_PROPERTY) { goto out; } - + obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); if (!obj) { goto out; @@ -2129,7 +2127,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, goto out; } crtc = obj_to_crtc(obj); - + /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { ret = -EINVAL; @@ -2180,7 +2178,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, goto out; } crtc = obj_to_crtc(obj); - + /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { ret = -EINVAL; -- cgit v1.2.3 From 701011224c048e064295ee12e8a02f7f66d4175a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 01:16:36 +0200 Subject: NV50: Implement DPMS. --- linux-core/nv50_dac.c | 38 ++++++++++++++++++++++++++++++++++++++ linux-core/nv50_kms_wrapper.c | 34 +++++++++++++++++++++++++++++++--- linux-core/nv50_output.h | 2 ++ linux-core/nv50_sor.c | 24 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index b237241e..f51ecf9d 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -96,6 +96,43 @@ static int nv50_dac_set_clock_mode(struct nv50_output *output) return 0; } +static int nv50_dac_set_power_mode(struct nv50_output *output, int mode) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + uint32_t val; + int or = nv50_output_or_offset(output); + + NV50_DEBUG("or %d\n", or); + + /* wait for it to be done */ + while (NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + + val = NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & ~0x7F; + + if (mode != DPMSModeOn) + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED; + + switch (mode) { + case DPMSModeStandby: + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF; + break; + case DPMSModeSuspend: + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF; + break; + case DPMSModeOff: + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF; + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF; + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF; + break; + default: + break; + } + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), val | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + + return 0; +} + static int nv50_dac_destroy(struct nv50_output *output) { struct drm_device *dev = output->dev; @@ -172,6 +209,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) output->validate_mode = nv50_dac_validate_mode; output->execute_mode = nv50_dac_execute_mode; output->set_clock_mode = nv50_dac_set_clock_mode; + output->set_power_mode = nv50_dac_set_power_mode; output->detect = NULL; /* TODO */ output->destroy = nv50_dac_destroy; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 8b97882a..79eb2964 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -640,6 +640,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* next line changes crtc, so putting it here is important */ display->last_crtc = crtc->index; + /* this is executed immediately */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; + + rval = output->set_power_mode(output, DPMSModeOn); + if (rval != 0) { + DRM_ERROR("output set power mode failed\n"); + goto out; + } + } + /* blank any unused crtcs */ list_for_each_entry(crtc, &display->crtcs, head) { if (!(crtc_mask & (1 << crtc->index))) @@ -654,9 +666,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) return 0; out: - if (display) - display->update(display); - kfree(hw_mode); if (rval != 0) @@ -938,12 +947,31 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u } } +static bool nv50_kms_connector_set_property(struct drm_connector *connector, + struct drm_property *property, + uint64_t value) +{ + struct drm_device *dev = connector->dev; + + if (property == dev->mode_config.dpms_property && connector->encoder) { + struct nv50_output *output = to_nv50_output(connector->encoder); + + if (!output->set_power_mode(output, (int) value)) + return true; + else + return false; + } + + return false; +} + static const struct drm_connector_funcs nv50_kms_connector_funcs = { .save = NULL, .restore = NULL, .detect = nv50_kms_connector_detect, .destroy = nv50_kms_connector_destroy, .fill_modes = nv50_kms_connector_fill_modes, + .set_property = nv50_kms_connector_set_property }; static int nv50_kms_connectors_init(struct drm_device *dev) diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h index bdee2826..7a6f9c7e 100644 --- a/linux-core/nv50_output.h +++ b/linux-core/nv50_output.h @@ -49,6 +49,8 @@ struct nv50_output { int (*validate_mode) (struct nv50_output *output, struct nouveau_hw_mode *mode); int (*execute_mode) (struct nv50_output *output, bool disconnect); int (*set_clock_mode) (struct nv50_output *output); + /* this is not a normal modeset call, it is a direct register write, so it's executed immediately */ + int (*set_power_mode) (struct nv50_output *output, int mode); bool (*detect) (struct nv50_output *output); int (*destroy) (struct nv50_output *output); }; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index fca9612f..84192803 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -114,6 +114,29 @@ static int nv50_sor_set_clock_mode(struct nv50_output *output) return 0; } +static int nv50_sor_set_power_mode(struct nv50_output *output, int mode) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + uint32_t val; + int or = nv50_output_or_offset(output); + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + /* wait for it to be done */ + while (NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING); + + val = NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or)); + + if (mode == DPMSModeOn) + val |= NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON; + else + val &= ~NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON; + + NV_WRITE(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or), val | NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING); + + return 0; +} + static int nv50_sor_destroy(struct nv50_output *output) { struct drm_device *dev = output->dev; @@ -194,6 +217,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) output->validate_mode = nv50_sor_validate_mode; output->execute_mode = nv50_sor_execute_mode; output->set_clock_mode = nv50_sor_set_clock_mode; + output->set_power_mode = nv50_sor_set_power_mode; output->detect = NULL; output->destroy = nv50_sor_destroy; -- cgit v1.2.3 From 01ee5eda9aaff880153223df8bb70a34b1a87cee Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 01:29:30 +0200 Subject: NV50: A minor change. --- linux-core/nv50_kms_wrapper.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 79eb2964..900dfccd 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -484,6 +484,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) */ if (switch_fb) { + crtc = to_nv50_crtc(set->crtc); + /* set framebuffer */ set->crtc->fb = set->fb; @@ -573,6 +575,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) */ if (modeset) { + crtc = to_nv50_crtc(set->crtc); + /* disconnect unused outputs */ list_for_each_entry(output, &display->outputs, head) { if (output->crtc) { @@ -586,6 +590,14 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } } + /* blank any unused crtcs */ + list_for_each_entry(crtc, &display->crtcs, head) { + if (!(crtc_mask & (1 << crtc->index))) + crtc->blank(crtc, TRUE); + } + + crtc = to_nv50_crtc(set->crtc); + rval = crtc->set_mode(crtc, hw_mode); if (rval != 0) { DRM_ERROR("crtc mode set failed\n"); @@ -651,12 +663,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } } - - /* blank any unused crtcs */ - list_for_each_entry(crtc, &display->crtcs, head) { - if (!(crtc_mask & (1 << crtc->index))) - crtc->blank(crtc, TRUE); - } } display->update(display); -- cgit v1.2.3 From 71906e86e81440037aa08b6f23f36e9fd3835639 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 16:30:25 +0200 Subject: [modesetting-101] Actually store properties when being changed. --- linux-core/drm_crtc.c | 3 +++ linux-core/nv50_kms_wrapper.c | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 4f21d09e..b9276c3a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2017,6 +2017,9 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, } } + /* store the property value */ + drm_connector_property_set_value(connector, property, out_resp->value); + if (connector->funcs->set_property) ret = connector->funcs->set_property(connector, property, out_resp->value); diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 900dfccd..9ece228e 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -663,6 +663,23 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } } + + /* update dpms state to DPMSModeOn */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + DRM_ERROR("No connector\n"); + goto out; + } + + rval = drm_connector_property_set_value(drm_connector, + dev->mode_config.dpms_property, + DPMSModeOn); + if (rval != 0) { + DRM_ERROR("failed to update dpms state\n"); + goto out; + } + } } display->update(display); -- cgit v1.2.3 From 9f28da80f6cc8e45670b217a2483983f2838095d Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 18:45:08 +0200 Subject: Change some obviously wrong things about property blobs, still broken though. - I do not fully understand these blobs, so i'm leaving it at this for the moment. --- libdrm/xf86drmMode.c | 2 +- linux-core/drm_crtc.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index df865415..ca21a961 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -495,7 +495,7 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) if (prop.flags & DRM_MODE_PROP_ENUM) { r->count_enums = prop.count_enum_blobs; r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); - } else if (prop.flags & DRM_MODE_PROP_ENUM) { + } else if (prop.flags & DRM_MODE_PROP_BLOB) { r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t)); r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t)); r->count_blobs = prop.count_enum_blobs; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index b9276c3a..23ae7d83 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1837,7 +1837,6 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, out_resp->count_values = value_count; if (property->flags & DRM_MODE_PROP_ENUM) { - if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { copied = 0; enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr; @@ -1879,7 +1878,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, copied++; } } - out_resp->count_enum_blobs = enum_count; + out_resp->count_enum_blobs = blob_count; } done: mutex_unlock(&dev->mode_config.mutex); -- cgit v1.2.3 From 91c742663a618e81da69ad4f098321d9af56d636 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 18:58:13 +0200 Subject: NV50: use list_head item instead of list_head head to avoid confusion --- linux-core/nv50_connector.c | 6 +++--- linux-core/nv50_connector.h | 2 +- linux-core/nv50_crtc.c | 4 ++-- linux-core/nv50_crtc.h | 2 +- linux-core/nv50_dac.c | 4 ++-- linux-core/nv50_display.c | 10 +++++----- linux-core/nv50_kms_wrapper.c | 22 +++++++++++----------- linux-core/nv50_output.h | 2 +- linux-core/nv50_sor.c | 4 ++-- shared-core/nouveau_irq.c | 4 ++-- shared-core/nouveau_mem.c | 2 +- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index a13f8e59..ac5194c0 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -60,7 +60,7 @@ static struct nv50_output *nv50_connector_to_output(struct nv50_connector *conne if (!digital_possible && digital) return NULL; - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (connector->bus != output->bus) continue; if (digital && output->type == OUTPUT_TMDS) @@ -122,7 +122,7 @@ static int nv50_connector_destroy(struct nv50_connector *connector) if (!display || !connector) return -EINVAL; - list_del(&connector->head); + list_del(&connector->item); if (connector->i2c_chan) nv50_i2c_channel_destroy(connector->i2c_chan); @@ -157,7 +157,7 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty if (type == CONNECTOR_UNKNOWN) goto out; - list_add_tail(&connector->head, &display->connectors); + list_add_tail(&connector->item, &display->connectors); connector->bus = bus; connector->type = type; diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index c70d6ef4..484227a0 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -38,7 +38,7 @@ #define CONNECTOR_TV 5 struct nv50_connector { - struct list_head head; + struct list_head item; struct drm_device *dev; int type; diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index af2f03d8..fd2ad38a 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -445,7 +445,7 @@ static int nv50_crtc_destroy(struct nv50_crtc *crtc) if (!display || !crtc) return -EINVAL; - list_del(&crtc->head); + list_del(&crtc->item); nv50_fb_destroy(crtc); nv50_lut_destroy(crtc); @@ -484,7 +484,7 @@ int nv50_crtc_create(struct drm_device *dev, int index) goto out; } - list_add_tail(&crtc->head, &display->crtcs); + list_add_tail(&crtc->item, &display->crtcs); crtc->index = index; diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index b63c5a22..de9a33f2 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -34,7 +34,7 @@ struct nv50_lut; struct nv50_fb; struct nv50_crtc { - struct list_head head; + struct list_head item; struct drm_device *dev; int index; diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index f51ecf9d..34b54902 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -144,7 +144,7 @@ static int nv50_dac_destroy(struct nv50_output *output) if (!display || !output) return -EINVAL; - list_del(&output->head); + list_del(&output->item); kfree(output->native_mode); if (dev_priv->free_output) @@ -197,7 +197,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) output->dcb_entry = dcb_entry; output->bus = entry->bus; - list_add_tail(&output->head, &display->outputs); + list_add_tail(&output->item, &display->outputs); output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); if (!output->native_mode) { diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 0c82ff8f..1d828552 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -139,14 +139,14 @@ static int nv50_display_disable(struct nv50_display *display) NV50_DEBUG("\n"); - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { crtc->blank(crtc, TRUE); } display->update(display); /* Almost like ack'ing a vblank interrupt, maybe in the spirit of cleaning up? */ - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { if (crtc->active) { uint32_t mask; @@ -305,15 +305,15 @@ int nv50_display_destroy(struct drm_device *dev) if (display->init_done) display->disable(display); - list_for_each_entry(connector, &display->connectors, head) { + list_for_each_entry(connector, &display->connectors, item) { connector->destroy(connector); } - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { output->destroy(output); } - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { crtc->destroy(crtc); } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 9ece228e..7f1a095b 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -155,11 +155,11 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) struct drm_connector *drm_connector = NULL; /* Wipe all previous connections. */ - list_for_each_entry(connector, &display->connectors, head) { + list_for_each_entry(connector, &display->connectors, item) { connector->output = NULL; } - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { output->crtc = NULL; } @@ -578,7 +578,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) crtc = to_nv50_crtc(set->crtc); /* disconnect unused outputs */ - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (output->crtc) { crtc_mask |= 1 << output->crtc->index; } else { @@ -591,7 +591,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /* blank any unused crtcs */ - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { if (!(crtc_mask & (1 << crtc->index))) crtc->blank(crtc, TRUE); } @@ -605,12 +605,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /* find native mode. */ - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) continue; *crtc->native_mode = *output->native_mode; - list_for_each_entry(connector, &display->connectors, head) { + list_for_each_entry(connector, &display->connectors, item) { if (connector->output != output) continue; @@ -632,7 +632,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) continue; @@ -653,7 +653,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) display->last_crtc = crtc->index; /* this is executed immediately */ - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) continue; @@ -727,7 +727,7 @@ static int nv50_kms_crtcs_init(struct drm_device *dev) * The internal structure is already allocated and so is the public one. * Just a matter of getting to the memory and register it. */ - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { struct drm_crtc *drm_crtc = to_nv50_kms_crtc(crtc); drm_crtc_init(dev, drm_crtc, &nv50_kms_crtc_funcs); @@ -759,7 +759,7 @@ static int nv50_kms_encoders_init(struct drm_device *dev) struct nv50_display *display = nv50_get_display(dev); struct nv50_output *output = NULL; - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { struct drm_encoder *drm_encoder = to_nv50_kms_encoder(output); uint32_t type = DRM_MODE_ENCODER_NONE; @@ -1003,7 +1003,7 @@ static int nv50_kms_connectors_init(struct drm_device *dev) struct nv50_connector *connector = NULL; int i; - list_for_each_entry(connector, &display->connectors, head) { + list_for_each_entry(connector, &display->connectors, item) { struct drm_connector *drm_connector = to_nv50_kms_connector(connector); uint32_t type = DRM_MODE_CONNECTOR_Unknown; diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h index 7a6f9c7e..a5faf050 100644 --- a/linux-core/nv50_output.h +++ b/linux-core/nv50_output.h @@ -36,7 +36,7 @@ #define OUTPUT_TV 4 struct nv50_output { - struct list_head head; + struct list_head item; struct drm_device *dev; int bus; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 84192803..4d82697e 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -148,7 +148,7 @@ static int nv50_sor_destroy(struct nv50_output *output) if (!display || !output) return -EINVAL; - list_del(&output->head); + list_del(&output->item); kfree(output->native_mode); if (dev_priv->free_output) @@ -205,7 +205,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) output->dcb_entry = dcb_entry; output->bus = entry->bus; - list_add_tail(&output->head, &display->outputs); + list_add_tail(&output->item, &display->outputs); output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); if (!output->native_mode) { diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index e68b755f..4c46da8d 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -549,7 +549,7 @@ nouveau_nv50_display_irq_handler(struct drm_device *dev) if (display->last_crtc == crtc_index) clock_ack = true; - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { if (crtc->index == crtc_index) break; } @@ -564,7 +564,7 @@ nouveau_nv50_display_irq_handler(struct drm_device *dev) crtc->set_clock_mode(crtc); - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (!output->crtc) continue; diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 46b6e4d6..425cebe2 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -738,7 +738,7 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) struct nv50_crtc *crtc = NULL; struct nv50_display *display = nv50_get_display(dev); - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { if (crtc->fb->block == block) { crtc->fb->block = NULL; -- cgit v1.2.3 From bc32d1798a213d7701b20feb95781eb51a42e945 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 1 Jul 2008 15:14:30 +0200 Subject: NV50: some i2c cleanup --- linux-core/nv50_i2c.c | 48 +++++++++++++++++++++++++-- shared-core/nouveau_reg.h | 82 +++++++---------------------------------------- 2 files changed, 57 insertions(+), 73 deletions(-) diff --git a/linux-core/nv50_i2c.c b/linux-core/nv50_i2c.c index cf55645b..e90a4cee 100644 --- a/linux-core/nv50_i2c.c +++ b/linux-core/nv50_i2c.c @@ -28,18 +28,62 @@ #include "nv50_i2c.h" +static uint32_t nv50_i2c_port(int index) +{ + uint32_t port = 0; + + switch (index) { + case 0: + port = NV50_PCONNECTOR_I2C_PORT_0; + break; + case 1: + port = NV50_PCONNECTOR_I2C_PORT_1; + break; + case 2: + port = NV50_PCONNECTOR_I2C_PORT_2; + break; + case 3: + port = NV50_PCONNECTOR_I2C_PORT_3; + break; + case 4: + port = NV50_PCONNECTOR_I2C_PORT_4; + break; + case 5: + port = NV50_PCONNECTOR_I2C_PORT_5; + break; + default: + break; + } + + if (!port) { + DRM_ERROR("Invalid i2c port, returning 0.\n"); + BUG(); + } + + return port; +} + static void nv50_i2c_set_bits(struct nv50_i2c_channel *chan, int clock_high, int data_high) { struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + uint32_t port = nv50_i2c_port(chan->index); - NV_WRITE(NV50_PCONNECTOR_I2C_PORT(chan->index), 4 | (data_high << 1) | clock_high); + if (!port) + return; + + NV_WRITE(port, 4 | (data_high << 1) | clock_high); } static void nv50_i2c_get_bits(struct nv50_i2c_channel *chan, int *clock_high, int *data_high) { struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + uint32_t port = nv50_i2c_port(chan->index); + uint32_t val; + + if (!port) + return; - uint32_t val = NV_READ(NV50_PCONNECTOR_I2C_PORT(chan->index)); + val = NV_READ(port); if (val & 1) *clock_high = 1; diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 8cf7f889..6ed23e26 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -632,90 +632,30 @@ # define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C1 (1<<1) # define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C2 (1<<2) # define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C3 (1<<3) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C4 (1<<4) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C5 (1<<5) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C6 (1<<6) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C7 (1<<7) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C8 (1<<8) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C9 (1<<9) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C10 (1<<10) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C11 (1<<11) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C12 (1<<12) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C13 (1<<13) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C14 (1<<14) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C15 (1<<15) # define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C0 (1<<16) # define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C1 (1<<17) # define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C2 (1<<18) # define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C3 (1<<19) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C4 (1<<20) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C5 (1<<21) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C6 (1<<22) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C7 (1<<23) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C8 (1<<24) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C9 (1<<25) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C10 (1<<26) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C11 (1<<27) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C12 (1<<28) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C13 (1<<29) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C14 (1<<30) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C15 (1<<31) # define NV50_PCONNECTOR_HOTPLUG_CTRL 0x0000e054 # define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C0 (1<<0) # define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C1 (1<<1) # define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C2 (1<<2) # define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C3 (1<<3) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C4 (1<<4) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C5 (1<<5) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C6 (1<<6) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C7 (1<<7) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C8 (1<<8) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C9 (1<<9) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C10 (1<<10) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C11 (1<<11) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C12 (1<<12) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C13 (1<<13) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C14 (1<<14) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C15 (1<<15) # define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C0 (1<<16) # define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C1 (1<<17) # define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C2 (1<<18) # define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C3 (1<<19) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C4 (1<<20) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C5 (1<<21) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C6 (1<<22) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C7 (1<<23) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C8 (1<<24) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C9 (1<<25) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C10 (1<<26) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C11 (1<<27) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C12 (1<<28) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C13 (1<<29) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C14 (1<<30) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C15 (1<<31) -# define NV50_PCONNECTOR_HOTPLUG_STATE1 0x0000e104 -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C0 (1<<2) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C1 (1<<6) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C2 (1<<10) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C3 (1<<14) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C4 (1<<18) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C5 (1<<22) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C6 (1<<26) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C7 (1<<30) -# define NV50_PCONNECTOR_HOTPLUG_STATE2 0x0000e108 -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C8 (1<<2) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C9 (1<<6) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C10 (1<<10) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C11 (1<<14) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C12 (1<<18) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C13 (1<<22) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C14 (1<<26) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C15 (1<<30) -# define NV50_PCONNECTOR_I2C 0x0000e138 -# define NV50_PCONNECTOR_I2C__LEN 0x10 -# define NV50_PCONNECTOR_I2C__ESIZE 0x18 -# define NV50_PCONNECTOR_I2C_PORT(i) (0x0000e138+(i)*0x18) - +# define NV50_PCONNECTOR_HOTPLUG_STATE 0x0000e104 +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C0 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C1 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C2 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C3 (1<<14) +# define NV50_PCONNECTOR_I2C_PORT_0 0x0000e138 +# define NV50_PCONNECTOR_I2C_PORT_1 0x0000e150 +# define NV50_PCONNECTOR_I2C_PORT_2 0x0000e168 +# define NV50_PCONNECTOR_I2C_PORT_3 0x0000e180 +# define NV50_PCONNECTOR_I2C_PORT_4 0x0000e240 +# define NV50_PCONNECTOR_I2C_PORT_5 0x0000e258 #define NV50_PBUS 0x00088000 #define NV50_PBUS__LEN 0x1 -- cgit v1.2.3 From 2b9c5719c09226a36a4a1e9869e6075b8ec08824 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 1 Jul 2008 16:00:09 +0200 Subject: NV50: switch to fixed point scale factor calculations --- linux-core/nv50_crtc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index fd2ad38a..c9745e08 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -232,17 +232,18 @@ static int nv50_crtc_set_dither(struct nv50_crtc *crtc) static void nv50_crtc_calc_scale(struct nv50_crtc *crtc, uint32_t *outX, uint32_t *outY) { - float hor_scale, ver_scale; + uint32_t hor_scale, ver_scale; - hor_scale = (float)crtc->native_mode->hdisplay/(float)crtc->mode->hdisplay; - ver_scale = (float)crtc->native_mode->vdisplay/(float)crtc->mode->vdisplay; + /* max res is 8192, which is 2^13, which leaves 19 bits */ + hor_scale = (crtc->native_mode->hdisplay << 19)/crtc->mode->hdisplay; + ver_scale = (crtc->native_mode->vdisplay << 19)/crtc->mode->vdisplay; if (ver_scale > hor_scale) { - *outX = crtc->mode->hdisplay * hor_scale; - *outY = crtc->mode->vdisplay * hor_scale; + *outX = (crtc->mode->hdisplay * hor_scale) >> 19; + *outY = (crtc->mode->vdisplay * hor_scale) >> 19; } else { - *outX = crtc->mode->hdisplay * ver_scale; - *outY = crtc->mode->vdisplay * ver_scale; + *outX = (crtc->mode->hdisplay * ver_scale) >> 19; + *outY = (crtc->mode->vdisplay * ver_scale) >> 19; } } -- cgit v1.2.3 From b28d309210475b6f671af7617c779bd1d7a6810a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 2 Jul 2008 13:59:19 +0200 Subject: tests: Improved and renamed the mode app to modeprint --- tests/mode/Makefile | 14 -- tests/mode/modetest.c | 409 --------------------------------------------- tests/mode/test | 1 - tests/modeprint/Makefile | 14 ++ tests/modeprint/modetest.c | 352 ++++++++++++++++++++++++++++++++++++++ tests/modeprint/test | 1 + 6 files changed, 367 insertions(+), 424 deletions(-) delete mode 100644 tests/mode/Makefile delete mode 100644 tests/mode/modetest.c delete mode 100755 tests/mode/test create mode 100644 tests/modeprint/Makefile create mode 100644 tests/modeprint/modetest.c create mode 100755 tests/modeprint/test diff --git a/tests/mode/Makefile b/tests/mode/Makefile deleted file mode 100644 index 7a9c3c24..00000000 --- a/tests/mode/Makefile +++ /dev/null @@ -1,14 +0,0 @@ - -all: app - -#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ -# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ - -app: modetest.c - @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c - -clean: - @rm -f app - -run: app - @sudo ./test diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c deleted file mode 100644 index bb91e832..00000000 --- a/tests/mode/modetest.c +++ /dev/null @@ -1,409 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -#include "xf86drm.h" -#include "xf86drmMode.h" - -int dpms_prop_id = 0; -const char* getConnectionText(drmModeConnection conn) -{ - switch (conn) { - case DRM_MODE_CONNECTED: - return "connected"; - case DRM_MODE_DISCONNECTED: - return "disconnected"; - default: - return "unknown"; - } - -} - -int printMode(struct drm_mode_modeinfo *mode) -{ -#if 1 - printf("Mode: %s\n", mode->name); - printf("\tclock : %i\n", mode->clock); - printf("\thdisplay : %i\n", mode->hdisplay); - printf("\thsync_start : %i\n", mode->hsync_start); - printf("\thsync_end : %i\n", mode->hsync_end); - printf("\thtotal : %i\n", mode->htotal); - printf("\thskew : %i\n", mode->hskew); - printf("\tvdisplay : %i\n", mode->vdisplay); - printf("\tvsync_start : %i\n", mode->vsync_start); - printf("\tvsync_end : %i\n", mode->vsync_end); - printf("\tvtotal : %i\n", mode->vtotal); - printf("\tvscan : %i\n", mode->vscan); - printf("\tvrefresh : %i\n", mode->vrefresh); - printf("\tflags : %i\n", mode->flags); -#else - printf("Mode: \"%s\" %ix%i %.0f\n", mode->name, - mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); -#endif - return 0; -} - -int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id) -{ - int i = 0, j; - struct drm_mode_modeinfo *mode = NULL; - drmModePropertyPtr props; - drmModeEncoderPtr enc; - unsigned char *name = NULL; - - printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); - printf("\tid : %i\n", id); - printf("\tencoder id : %i\n", connector->encoder); - printf("\tconn : %s\n", getConnectionText(connector->connection)); - printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); - printf("\tcount_modes : %i\n", connector->count_modes); - printf("\tcount_props : %i\n", connector->count_props); - printf("\tcount_encs : %i\n", connector->count_encoders); - - for (i = 0; i < connector->count_encoders; i++) { - enc = drmModeGetEncoder(fd, connector->encoders[i]); - if (enc) { - printf("Encoder: %d %d %d %d %d\n", enc->crtc, enc->encoder_id, enc->encoder_type, enc->crtcs, enc->clones); - } - } - - for (i = 0; i < connector->count_props; i++) { - props = drmModeGetProperty(fd, connector->props[i]); - name = NULL; - if (props) { - printf("Property: %s\n", props->name); - printf("\tid: %i\n", props->prop_id); - printf("\tflags: %i\n", props->flags); - printf("\tvalues %d: ", props->count_values); - for (j = 0; j < props->count_values; j++) - printf("%lld ", props->values[j]); - - printf("\n\tenums %d: \n", props->count_enums); - - if (props->flags & DRM_MODE_PROP_BLOB) { - drmModePropertyBlobPtr blob; - - blob = drmModeGetPropertyBlob(fd, connector->prop_values[i]); - if (blob) { - printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); - drmModeFreePropertyBlob(blob); - } - - } else { - if (!strncmp(props->name, "DPMS", 4)) - dpms_prop_id = props->prop_id; - - for (j = 0; j < props->count_enums; j++) { - printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); - if (connector->prop_values[i] == props->enums[j].value) - name = props->enums[j].name; - - } - - if (props->count_enums && name) { - printf("\tconnector property name %s %s\n", props->name, name); - } else { - printf("\tconnector property id %s %lli\n", props->name, connector->prop_values[i]); - } - } - - drmModeFreeProperty(props); - } - } - - for (i = 0; i < connector->count_modes; i++) { - mode = &connector->modes[i]; - if (mode) - printMode(mode); - else - printf("\t\tmode: Invalid mode %p\n", &connector->modes[i]); - } - - return 0; -} - -int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t id) -{ - printf("Encoder\n"); - printf("\tid :%i\n", id); - printf("\ttype :%d\n", encoder->encoder_type); - printf("\tcrtcs :%d\n", encoder->crtcs); - printf("\tclones :%d\n", encoder->clones); - return 0; -} - -int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) -{ - printf("Crtc\n"); - printf("\tid : %i\n", id); - printf("\tx : %i\n", crtc->x); - printf("\ty : %i\n", crtc->y); - printf("\twidth : %i\n", crtc->width); - printf("\theight : %i\n", crtc->height); - printf("\tmode : %p\n", &crtc->mode); - printf("\tgamma size : %d\n", crtc->gamma_size); - printf("\tnum connectors : %i\n", crtc->count_connectors); - printf("\tconnectors : %i\n", crtc->connectors); - printf("\tnum possible : %i\n", crtc->count_possibles); - printf("\tpossibles : %i\n", crtc->possibles); - - return 0; -} - -int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb) -{ - printf("Framebuffer\n"); - printf("\thandle : %i\n", fb->handle); - printf("\twidth : %i\n", fb->width); - printf("\theight : %i\n", fb->height); - printf("\tpitch : %i\n", fb->pitch);; - printf("\tbpp : %i\n", fb->bpp); - printf("\tdepth : %i\n", fb->depth); - printf("\tbuffer_id : %i\n", fb->buffer_id); - - return 0; -} - -int printRes(int fd, drmModeResPtr res) -{ - int i; - drmModeConnectorPtr connector; - drmModeCrtcPtr crtc; - drmModeFBPtr fb; - drmModeEncoderPtr encoder; - - for (i = 0; i < res->count_connectors; i++) { - connector = drmModeGetConnector(fd, res->connectors[i]); - - if (!connector) - printf("Could not get connector %i\n", i); - else { - printConnector(fd, res, connector, res->connectors[i]); - drmModeFreeConnector(connector); - } - } - - for (i = 0; i < res->count_encoders; i++) { - encoder = drmModeGetEncoder(fd, res->encoders[i]); - - if (!encoder) - printf("Could not get encoder %i\n", i); - else { - printEncoder(fd, res, encoder, res->encoders[i]); - drmModeFreeEncoder(encoder); - } - } - - - for (i = 0; i < res->count_crtcs; i++) { - crtc = drmModeGetCrtc(fd, res->crtcs[i]); - - if (!crtc) - printf("Could not get crtc %i\n", i); - else { - printCrtc(fd, res, crtc, res->crtcs[i]); - drmModeFreeCrtc(crtc); - } - } - - for (i = 0; i < res->count_fbs; i++) { - fb = drmModeGetFB(fd, res->fbs[i]); - - if (!fb) - printf("Could not get fb %i\n", res->fbs[i]); - else { - printFrameBuffer(fd, res, fb); - drmModeFreeFB(fb); - } - } - - return 0; -} - -static struct drm_mode_modeinfo mode = { - .name = "Test mode", - .clock = 25200, - .hdisplay = 640, - .hsync_start = 656, - .hsync_end = 752, - .htotal = 800, - .hskew = 0, - .vdisplay = 480, - .vsync_start = 490, - .vsync_end = 492, - .vtotal = 525, - .vscan = 0, - .vrefresh = 60000, /* vertical refresh * 1000 */ - .flags = 10, -}; - -int testMode(int fd, drmModeResPtr res) -{ - uint32_t connector = res->connectors[0]; - uint32_t newMode = 0; - int ret = 0; - int error = 0; - - printf("Test: adding mode to connector %i\n", connector); - - /* printMode(&mode); */ - - printf("\tAttaching mode %i to connector %i\n", newMode, connector); - - ret = drmModeAttachMode(fd, connector, &mode); - - if (ret) - goto err_mode; - - printf("\tDetaching mode %i from connector %i\n", newMode, connector); - ret = drmModeDetachMode(fd, connector, &mode); - - if (ret) - goto err_mode; - return 0; - -err_mode: - - printf("\tFailed\n"); - - if (error) - printf("\tFailed to delete mode %i\n", newMode); - return 1; -} - -/* -int testFrameBufferGet(int fd, uint32_t fb) -{ - drmModeFBPtr frame; - - printf("Test: get framebuffer %i\n", fb); - - frame = drmModeGetFB(fd, fb); - - if (!frame) { - printf("\tFailed\n"); - } else { - printFrameBuffer(fd, frame); - drmModeFreeFB(frame); - } - - return 0; -} -*/ - -int testFrameBufferAdd(int fd, drmModeResPtr res) -{ - uint32_t fb = 0; - int ret = 0; - drmModeFBPtr frame = 0; - drmBO bo; - - printf("Test: adding framebuffer\n"); - - printf("\tCreating BO\n"); - - /* TODO */ - ret = drmBOCreate(fd, 800 * 600 * 4, 0, 0, - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, &bo); - - printf("\tgot %i\n", ret); - if (ret) - goto err; - - printf("\tAdding FB\n"); - ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, bo.handle, &fb); - if (ret) - goto err_bo; - - frame = drmModeGetFB(fd, fb); - - if (!frame) { - printf("Couldn't retrive created framebuffer\n"); - } else { - printFrameBuffer(fd, res, frame); - drmModeFreeFB(frame); - } - - printf("\tRemoveing FB\n"); - - ret = drmModeRmFB(fd, fb); - - if (ret) { - printf("\tFailed this shouldn't happen!\n"); - goto err_bo; - } - - printf("\tRemoveing BO\n"); - - ret = drmBOUnreference(fb, &bo); - - return 0; - -err_bo: - drmBOUnreference(fd, &bo); - -err: - printf("\tFailed\n"); - - return 1; -} - -int testDPMS(int fd, drmModeResPtr res) -{ - int connector_id; - int i; - - for (i = 0; i < res->count_connectors; i++) { - connector_id = res->connectors[i]; - /* turn connector off */ - drmModeConnectorSetProperty(fd, connector_id, dpms_prop_id, 3); - sleep(2); - drmModeConnectorSetProperty(fd, connector_id, dpms_prop_id, 0); - } - return 1; - -} - -int main(int argc, char **argv) -{ - int fd; - drmModeResPtr res; - - printf("Starting test\n"); - - fd = drmOpen("i915", NULL); - - if (fd < 0) { - printf("Failed to open the card fb (%d)\n",fd); - return 1; - } - - res = drmModeGetResources(fd); - if (res == 0) { - printf("Failed to get resources from card\n"); - drmClose(fd); - return 1; - } - - printRes(fd, res); - - testMode(fd, res); - - testFrameBufferAdd(fd, res); - - /* try dpms test */ - testDPMS(fd, res); - drmModeFreeResources(res); - printf("Ok\n"); - - return 0; -} diff --git a/tests/mode/test b/tests/mode/test deleted file mode 100755 index f98e3708..00000000 --- a/tests/mode/test +++ /dev/null @@ -1 +0,0 @@ -LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app diff --git a/tests/modeprint/Makefile b/tests/modeprint/Makefile new file mode 100644 index 00000000..7a9c3c24 --- /dev/null +++ b/tests/modeprint/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: modetest.c + @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c + +clean: + @rm -f app + +run: app + @sudo ./test diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c new file mode 100644 index 00000000..36925a0b --- /dev/null +++ b/tests/modeprint/modetest.c @@ -0,0 +1,352 @@ + +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +int connectors; +int full_props; +int edid; +int modes; +int full_modes; +int encoders; +int crtcs; +int fbs; + +const char* getConnectionText(drmModeConnection conn) +{ + switch (conn) { + case DRM_MODE_CONNECTED: + return "connected"; + case DRM_MODE_DISCONNECTED: + return "disconnected"; + default: + return "unknown"; + } + +} + +int printMode(struct drm_mode_modeinfo *mode) +{ + if (full_modes) { + printf("Mode: %s\n", mode->name); + printf("\tclock : %i\n", mode->clock); + printf("\thdisplay : %i\n", mode->hdisplay); + printf("\thsync_start : %i\n", mode->hsync_start); + printf("\thsync_end : %i\n", mode->hsync_end); + printf("\thtotal : %i\n", mode->htotal); + printf("\thskew : %i\n", mode->hskew); + printf("\tvdisplay : %i\n", mode->vdisplay); + printf("\tvsync_start : %i\n", mode->vsync_start); + printf("\tvsync_end : %i\n", mode->vsync_end); + printf("\tvtotal : %i\n", mode->vtotal); + printf("\tvscan : %i\n", mode->vscan); + printf("\tvrefresh : %i\n", mode->vrefresh); + printf("\tflags : %i\n", mode->flags); + } else { + printf("Mode: \"%s\" %ix%i %.0f\n", mode->name, + mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); + } + return 0; +} + +int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id) +{ + int i = 0, j; + struct drm_mode_modeinfo *mode = NULL; + drmModePropertyPtr props; + unsigned char *name = NULL; + + printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); + printf("\tid : %i\n", id); + printf("\tencoder id : %i\n", connector->encoder); + printf("\tconn : %s\n", getConnectionText(connector->connection)); + printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); + printf("\tcount_modes : %i\n", connector->count_modes); + printf("\tcount_props : %i\n", connector->count_props); + printf("\tcount_encoders : %i\n", connector->count_encoders); + + if (connector->count_encoders) { + printf("\t\tencoders"); + for (i = 0; i < connector->count_encoders; i++) + printf(" %i", connector->encoders[i]); + printf("\n"); + } + + if (full_props) { + for (i = 0; i < connector->count_props; i++) { + props = drmModeGetProperty(fd, connector->props[i]); + name = NULL; + if (props) { + printf("Property: %s\n", props->name); + printf("\tid: %i\n", props->prop_id); + printf("\tflags: %i\n", props->flags); + printf("\tvalues %d: ", props->count_values); + for (j = 0; j < props->count_values; j++) + printf("%lld ", props->values[j]); + + printf("\n\tenums %d: \n", props->count_enums); + + if (props->flags & DRM_MODE_PROP_BLOB) { + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(fd, connector->prop_values[i]); + if (blob) { + printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); + drmModeFreePropertyBlob(blob); + } + + } else { + if (!strncmp(props->name, "DPMS", 4)) + ; + + for (j = 0; j < props->count_enums; j++) { + printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); + if (connector->prop_values[i] == props->enums[j].value) + name = props->enums[j].name; + + } + + if (props->count_enums && name) { + printf("\tconnector property name %s %s\n", props->name, name); + } else { + printf("\tconnector property id %s %lli\n", props->name, connector->prop_values[i]); + } + } + + drmModeFreeProperty(props); + } + } + } else { + if (connector->count_props) { + printf("\t\tprops"); + for (i = 0; i < connector->count_props; i++) + printf(" %i", connector->props[i]); + printf("\n"); + } + } + + if (modes) { + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + printMode(mode); + } + } + + return 0; +} + +int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t id) +{ + printf("Encoder\n"); + printf("\tid :%i\n", id); + printf("\tcrtc :%d\n", encoder->crtc); + printf("\ttype :%d\n", encoder->encoder_type); + printf("\tcrtcs :%d\n", encoder->crtcs); + printf("\tclones :%d\n", encoder->clones); + return 0; +} + +int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) +{ + printf("Crtc\n"); + printf("\tid : %i\n", id); + printf("\tx : %i\n", crtc->x); + printf("\ty : %i\n", crtc->y); + printf("\twidth : %i\n", crtc->width); + printf("\theight : %i\n", crtc->height); + printf("\tmode : %p\n", &crtc->mode); + printf("\tgamma size : %d\n", crtc->gamma_size); + printf("\tnum connectors : %i\n", crtc->count_connectors); + printf("\tconnectors : %i\n", crtc->connectors); + printf("\tnum possible : %i\n", crtc->count_possibles); + printf("\tpossibles : %i\n", crtc->possibles); + + return 0; +} + +int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb) +{ + printf("Framebuffer\n"); + printf("\thandle : %i\n", fb->handle); + printf("\twidth : %i\n", fb->width); + printf("\theight : %i\n", fb->height); + printf("\tpitch : %i\n", fb->pitch);; + printf("\tbpp : %i\n", fb->bpp); + printf("\tdepth : %i\n", fb->depth); + printf("\tbuffer_id : %i\n", fb->buffer_id); + + return 0; +} + +int printRes(int fd, drmModeResPtr res) +{ + int i; + drmModeFBPtr fb; + drmModeCrtcPtr crtc; + drmModeEncoderPtr encoder; + drmModeConnectorPtr connector; + + printf("Resources\n\n"); + + printf("count_connectors : %i\n", res->count_connectors); + printf("count_encoders : %i\n", res->count_encoders); + printf("count_crtcs : %i\n", res->count_crtcs); + printf("count_fbs : %i\n", res->count_fbs); + + printf("\n"); + + if (connectors) { + for (i = 0; i < res->count_connectors; i++) { + connector = drmModeGetConnector(fd, res->connectors[i]); + + if (!connector) + printf("Could not get connector %i\n", i); + else { + printConnector(fd, res, connector, res->connectors[i]); + drmModeFreeConnector(connector); + } + } + printf("\n"); + } + + + if (encoders) { + for (i = 0; i < res->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, res->encoders[i]); + + if (!encoder) + printf("Could not get encoder %i\n", i); + else { + printEncoder(fd, res, encoder, res->encoders[i]); + drmModeFreeEncoder(encoder); + } + } + printf("\n"); + } + + if (crtcs) { + for (i = 0; i < res->count_crtcs; i++) { + crtc = drmModeGetCrtc(fd, res->crtcs[i]); + + if (!crtc) + printf("Could not get crtc %i\n", i); + else { + printCrtc(fd, res, crtc, res->crtcs[i]); + drmModeFreeCrtc(crtc); + } + } + printf("\n"); + } + + if (fbs) { + for (i = 0; i < res->count_fbs; i++) { + fb = drmModeGetFB(fd, res->fbs[i]); + + if (!fb) + printf("Could not get fb %i\n", res->fbs[i]); + else { + printFrameBuffer(fd, res, fb); + drmModeFreeFB(fb); + } + } + } + + return 0; +} + +void args(int argc, char **argv) +{ + int i; + + fbs = 0; + edid = 0; + crtcs = 0; + modes = 0; + encoders = 0; + full_modes = 0; + full_props = 0; + connectors = 0; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-fb") == 0) { + fbs = 1; + } else if (strcmp(argv[i], "-crtcs") == 0) { + crtcs = 1; + } else if (strcmp(argv[i], "-cons") == 0) { + connectors = 1; + modes = 1; + } else if (strcmp(argv[i], "-modes") == 0) { + connectors = 1; + modes = 1; + } else if (strcmp(argv[i], "-full") == 0) { + connectors = 1; + modes = 1; + full_modes = 1; + } else if (strcmp(argv[i], "-props") == 0) { + connectors = 1; + full_props = 1; + } else if (strcmp(argv[i], "-edids") == 0) { + connectors = 1; + edid = 1; + } else if (strcmp(argv[i], "-encoders") == 0) { + encoders = 1; + } else if (strcmp(argv[i], "-v") == 0) { + fbs = 1; + edid = 1; + crtcs = 1; + modes = 1; + encoders = 1; + full_modes = 1; + full_props = 1; + connectors = 1; + } + } + + if (argc == 1) { + fbs = 1; + modes = 1; + full_modes = 0; + encoders = 1; + connectors = 1; + crtcs = 1; + full_props = 0; + edid = 1; + } +} +int main(int argc, char **argv) +{ + int fd; + drmModeResPtr res; + + args(argc, argv); + + printf("Starting test\n"); + + fd = drmOpen("i915", NULL); + + if (fd < 0) { + printf("Failed to open the card fb (%d)\n",fd); + return 1; + } + + res = drmModeGetResources(fd); + if (res == 0) { + printf("Failed to get resources from card\n"); + drmClose(fd); + return 1; + } + + printRes(fd, res); + + drmModeFreeResources(res); + + printf("Ok\n"); + + return 0; +} diff --git a/tests/modeprint/test b/tests/modeprint/test new file mode 100755 index 00000000..bd1952cc --- /dev/null +++ b/tests/modeprint/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app $@ -- cgit v1.2.3 From f1fe9178f1a2aef272c7feeb15c8de42c8c609d5 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Wed, 2 Jul 2008 16:13:54 +0200 Subject: NV50: basic fbcon + misc fixes - There is one fb, used for as many outputs as possible. - Eventually smaller screens will be scaled to see the full console, but for the moment this'll do. --- linux-core/Makefile.kernel | 3 +- linux-core/nv50_display.c | 3 +- linux-core/nv50_fbcon.c | 599 ++++++++++++++++++++++++++++++++++++++++++ linux-core/nv50_fbcon.h | 41 +++ linux-core/nv50_kms_wrapper.c | 12 +- shared-core/nouveau_state.c | 5 +- 6 files changed, 657 insertions(+), 6 deletions(-) create mode 100644 linux-core/nv50_fbcon.c create mode 100644 linux-core/nv50_fbcon.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 23430140..246c0b35 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -38,7 +38,8 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_instmem.o nv50_instmem.o \ nouveau_bios.o \ nv50_crtc.o nv50_cursor.o nv50_lut.o nv50_fb.o nv50_output.o nv50_sor.o nv50_dac.o nv50_connector.o nv50_i2c.o nv50_display.o \ - nv50_kms_wrapper.o + nv50_kms_wrapper.o \ + nv50_fbcon.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \ diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 1d828552..cd527c44 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -337,10 +337,11 @@ void nv50_display_command(struct drm_nouveau_private *dev_priv, uint32_t mthd, u while (NV_READ(NV50_PDISPLAY_CTRL_STATE) & NV50_PDISPLAY_CTRL_STATE_PENDING) { counter++; - if (counter > 25000) { + if (counter > 1000000) { DRM_ERROR("You probably need a reboot now\n"); break; } + udelay(1); } } diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c new file mode 100644 index 00000000..c428ff94 --- /dev/null +++ b/linux-core/nv50_fbcon.c @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nv50_fbcon.h" + +static int nv50_fbcon_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct nv50_fbcon_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_framebuffer *drm_fb; + + list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) { + if (regno > 255) + return 1; + + /* TODO: 8 bit support */ + if (regno < 16) { + switch (drm_fb->depth) { + case 15: + drm_fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + drm_fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + drm_fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + } + return 0; +} + +static int nv50_fbcon_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct nv50_fbcon_par *par = info->par; + struct drm_framebuffer *drm_fb = par->fb; + int depth; + + NV50_DEBUG("\n"); + + if (!var || !drm_fb || !info) { + DRM_ERROR("No var, drm_fb or info\n"); + } + + par->use_preferred_mode = false; + + if (var->pixclock == -1 || !var->pixclock) { + DRM_INFO("Using preferred mode.\n"); + par->use_preferred_mode = true; + } + + /* Need to resize the fb object !!! */ + if (var->xres > drm_fb->width || var->yres > drm_fb->height) { + DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n", var->xres,var->yres, drm_fb->width, drm_fb->height); + DRM_ERROR("Need resizing code.\n"); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + depth = var->bits_per_pixel; + break; + } + + switch (depth) { + case 15: + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.length = 1; + var->transp.offset = 15; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 24; + break; + default: + DRM_ERROR("Invalid depth %d\n", depth); + return -EINVAL; + } + + return 0; +} + +static int nv50_fbcon_set_par(struct fb_info *info) +{ + struct nv50_fbcon_par *par; + struct drm_framebuffer *drm_fb; + struct drm_connector *drm_connector; + struct drm_crtc *drm_crtc; + struct fb_var_screeninfo *var; + struct drm_display_mode *drm_mode = NULL, *t; + struct drm_device *dev; + int rval; + bool crtc_used[2] = {false, false}; + + NV50_DEBUG("\n"); + + if (!info) { + DRM_ERROR("No fb_info\n"); + return -EINVAL; + } + + par = info->par; + + if (!par) { + DRM_ERROR("No nv50_fbcon_par\n"); + return -EINVAL; + } + + drm_fb = par->fb; + var = &info->var; + dev = par->dev; + + if (!drm_fb || !var || !dev) { + DRM_ERROR("No drm_fb, var or dev\n"); + return -EINVAL; + } + + par->use_preferred_mode = false; + + if (var->pixclock == -1 || !var->pixclock) { + DRM_INFO("Using preferred mode.\n"); + par->use_preferred_mode = true; + } + + /* FB setup */ + switch (var->bits_per_pixel) { + case 16: + drm_fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + drm_fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + drm_fb->depth = var->bits_per_pixel; + break; + } + + drm_fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = drm_fb->pitch; + info->fix.smem_len = info->fix.line_length * drm_fb->height; + /* ignoring 8bpp for the moment */ + info->fix.visual = FB_VISUAL_TRUECOLOR; + + info->screen_size = info->fix.smem_len; /* ??? */ + + /* create a drm mode */ + if (!par->use_preferred_mode) { + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode->flags = 0; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + + drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + } + + /* hook up crtc's */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + enum drm_connector_status status; + struct drm_mode_set mode_set; + int crtc_count = 0; + + status = drm_connector->funcs->detect(drm_connector); + + if (status != connector_status_connected) + continue; + + memset(&mode_set, 0, sizeof(struct drm_mode_set)); + + /* set connector */ + mode_set.num_connectors = 1; + mode_set.connectors = kzalloc(sizeof(struct drm_connector *), GFP_KERNEL); + if (!mode_set.connectors) { + rval = -ENOMEM; + goto out; + } + mode_set.connectors[0] = drm_connector; + + /* set fb */ + list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) { + break; /* first entry is the only entry */ + } + mode_set.fb = drm_fb; + + /* set mode */ + if (par->use_preferred_mode) { + /* find preferred mode */ + list_for_each_entry_safe(drm_mode, t, &drm_connector->modes, head) { + if (drm_mode->type & DRM_MODE_TYPE_PREFERRED) + break; + } + } + mode_set.mode = drm_mode; + + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + if (crtc_used[crtc_count]) { + crtc_count++; + continue; + } + + /* found a crtc */ + mode_set.crtc = drm_crtc; + + break; + } + + /* proceed as planned */ + if (mode_set.crtc) { + mode_set.crtc->funcs->set_config(&mode_set); + crtc_used[crtc_count] = true; + } + + kfree(mode_set.connectors); + } + + return 0; + +out: + return rval; +} + +static struct fb_ops nv50_fb_ops = { + .owner = THIS_MODULE, + //.fb_open = nv50_fb_open, + //.fb_read = nv50_fb_read, + //.fb_write = nv50_fb_write, + //.fb_release = nv50_fb_release, + //.fb_ioctl = nv50_fb_ioctl, + .fb_check_var = nv50_fbcon_check_var, + .fb_set_par = nv50_fbcon_set_par, + .fb_setcolreg = nv50_fbcon_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + //.fb_pan_display = nv50_fb_pan_display, +}; + +static int nv50_fbcon_initial_config(struct drm_device *dev) +{ + struct drm_connector *drm_connector; + + struct drm_framebuffer *drm_fb = NULL; + struct drm_mode_fb_cmd drm_fb_cmd; + enum drm_connector_status status; + uint32_t max_width = 0, max_height = 0, pitch = 0; + struct mem_block *block; + struct drm_file *file_priv; + uint32_t flags; + int rval = 0; + + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + status = drm_connector->funcs->detect(drm_connector); + + /* find the framebuffer size */ + if (status == connector_status_connected) { + struct drm_display_mode *mode, *t; + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { + if (mode->type & DRM_MODE_TYPE_PREFERRED) { + if (mode->hdisplay > max_width) + max_width = mode->hdisplay; + if (mode->vdisplay > max_height) + max_height = mode->vdisplay; + } + } + } + } + + /* allocate framebuffer */ + file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL); + if (!file_priv) { + rval = -ENOMEM; + goto out; + } + + pitch = (max_width + 63) & ~63; + pitch *= 4; /* TODO */ + + flags = NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; + + /* Any file_priv should do as it's pointer is used as identification. */ + block = nouveau_mem_alloc(dev, 0, pitch * max_height, flags, file_priv); + if (!block) { + rval = -ENOMEM; + goto out; + } + + memset(&drm_fb_cmd, 0, sizeof(struct drm_mode_fb_cmd)); + + drm_fb_cmd.width = max_width; + drm_fb_cmd.height = max_height; + drm_fb_cmd.pitch = pitch; + drm_fb_cmd.bpp = 32; /* TODO */ + drm_fb_cmd.handle = block->map_handle; + drm_fb_cmd.depth = 24; /* TODO */ + + drm_fb = dev->mode_config.funcs->fb_create(dev, file_priv, &drm_fb_cmd); + if (!drm_fb) { + rval = -EINVAL; + goto out; + } + + list_add(&drm_fb->filp_head, &dev->mode_config.fb_kernel_list); + + return 0; + +out: + if (file_priv) + kfree(file_priv); + if (drm_fb) + drm_fb->funcs->destroy(drm_fb); + + return rval; +} + +/* + * Single framebuffer, ideally operating in clone mode across various connectors. + */ +int nv50_fbcon_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct fb_info *info; + struct nv50_fbcon_par *par; + struct device *device = &dev->pdev->dev; + struct drm_framebuffer *drm_fb; + struct mem_block *block; + void __iomem *fb = NULL; + int rval; + + rval = nv50_fbcon_initial_config(dev); + if (rval != 0) { + DRM_ERROR("nv50_fbcon_initial_config failed\n"); + return rval; + } + + list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) { + break; /* first entry is the only entry */ + } + + if (!drm_fb) { + DRM_ERROR("no drm_fb found\n"); + return -EINVAL; + } + + block = find_block_by_handle(dev_priv->fb_heap, drm_fb->mm_handle); + if (!block) { + DRM_ERROR("can't find mem_block\n"); + return -EINVAL; + } + + info = framebuffer_alloc(sizeof(struct nv50_fbcon_par), device); + if (!info) { + DRM_ERROR("framebuffer_alloc failed\n"); + return -EINVAL; + } + + par = info->par; + + strcpy(info->fix.id, "nv50drmfb"); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.type_aux = 0; + info->fix.xpanstep = 0; /* 1 is doing it in hw */ + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; + info->fix.accel = FB_ACCEL_NONE; + info->fix.type_aux = 0; + + info->flags = FBINFO_DEFAULT; + + info->fbops = &nv50_fb_ops; + + info->fix.line_length = drm_fb->pitch; + info->fix.smem_start = dev_priv->fb_phys + block->start; + info->fix.smem_len = info->fix.line_length * drm_fb->height; + + info->flags = FBINFO_DEFAULT; + + fb = ioremap(dev_priv->fb_phys + block->start, block->size); + if (!fb) { + DRM_ERROR("Unable to ioremap framebuffer\n"); + return -EINVAL; + } + + info->screen_base = fb; + info->screen_size = info->fix.smem_len; /* FIXME */ + + info->pseudo_palette = drm_fb->pseudo_palette; + info->var.xres_virtual = drm_fb->width; + info->var.yres_virtual = drm_fb->height; + info->var.bits_per_pixel = drm_fb->bits_per_pixel; + info->var.xoffset = 0; + info->var.yoffset = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + + /* TODO: improve this */ + info->var.xres = drm_fb->width; + info->var.yres = drm_fb->height; + + info->fix.mmio_start = drm_get_resource_start(dev, 0); + info->fix.mmio_len = drm_get_resource_len(dev, 0); + + DRM_DEBUG("fb depth is %d\n", drm_fb->depth); + DRM_DEBUG(" pitch is %d\n", drm_fb->pitch); + + switch(drm_fb->depth) { + case 15: + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 5; + info->var.blue.length = 5; + info->var.transp.offset = 15; + info->var.transp.length = 1; + break; + case 16: + info->var.red.offset = 11; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 6; + info->var.blue.length = 5; + info->var.transp.offset = 0; + break; + case 24: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; + case 32: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 24; + info->var.transp.length = 8; + break; + default: + break; + } + + drm_fb->fbdev = info; + par->dev = dev; + par->fb = drm_fb; + + register_framebuffer(info); + + DRM_INFO("nv50drmfb initialised\n"); + + return 0; +} + +int nv50_fbcon_destroy(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_framebuffer *drm_fb; + struct fb_info *info; + struct mem_block *block; + struct drm_file *file_priv; + + list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) { + break; /* first entry is the only entry */ + } + + if (!drm_fb) { + DRM_ERROR("No framebuffer to destroy\n"); + return -EINVAL; + } + + info = drm_fb->fbdev; + if (!info) { + DRM_ERROR("No fb_info\n"); + return -EINVAL; + } + + unregister_framebuffer(info); + + block = find_block_by_handle(dev_priv->fb_heap, drm_fb->mm_handle); + if (!block) { + DRM_ERROR("can't find mem_block\n"); + return -EINVAL; + } + + /* we need to free this after memory is freed */ + file_priv = block->file_priv; + + /* free memory */ + nouveau_mem_free(dev, block); + + if (file_priv) { + kfree(file_priv); + file_priv = NULL; + } + + framebuffer_release(info); + + return 0; +} diff --git a/linux-core/nv50_fbcon.h b/linux-core/nv50_fbcon.h new file mode 100644 index 00000000..98e7101a --- /dev/null +++ b/linux-core/nv50_fbcon.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + * + */ + +#ifndef __NV50_FBCON_H__ +#define __NV50_FBCON_H__ + +#include "nv50_kms_wrapper.h" + +struct nv50_fbcon_par { + struct drm_framebuffer *fb; + struct drm_device *dev; + bool use_preferred_mode; +}; + +int nv50_fbcon_init(struct drm_device *dev); +int nv50_fbcon_destroy(struct drm_device *dev); + +#endif /* __NV50_FBCON_H__ */ \ No newline at end of file diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 7f1a095b..2a214f68 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -153,6 +153,7 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) struct nv50_output *output = NULL; struct nv50_connector *connector = NULL; struct drm_connector *drm_connector = NULL; + struct drm_crtc *drm_crtc = NULL; /* Wipe all previous connections. */ list_for_each_entry(connector, &display->connectors, item) { @@ -179,6 +180,13 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) } } } + + /* mirror crtc active state */ + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + crtc = to_nv50_crtc(drm_crtc); + + crtc->active = drm_crtc->enabled; + } } /* @@ -428,8 +436,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) drm_crtc = drm_encoder->crtc; drm_encoder->crtc = NULL; - crtc = to_nv50_crtc(drm_crtc); - crtc->active = false; drm_crtc->enabled = false; } @@ -456,6 +462,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } drm_encoder->crtc = set->crtc; + set->crtc->enabled = true; drm_connector->encoder = drm_encoder; } } @@ -468,7 +475,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) crtc = to_nv50_crtc(set->crtc); /* keeping the encoders and connectors attached, so they can be tracked */ - crtc->active = false; set->crtc->enabled = false; } diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 9f8fc43d..3baae6ad 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -28,6 +28,7 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" #include "nv50_kms_wrapper.h" +#include "nv50_fbcon.h" static int nouveau_init_card_mappings(struct drm_device *dev) { @@ -367,7 +368,8 @@ nouveau_card_init(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) if (dev_priv->card_type >= NV_50) { nv50_kms_init(dev); - nv50_kms_connector_detect_all(dev); + //nv50_kms_connector_detect_all(dev); + nv50_fbcon_init(dev); } return 0; @@ -615,6 +617,7 @@ int nouveau_unload(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_MODESET)) { nv50_kms_destroy(dev); + nv50_fbcon_destroy(dev); nouveau_close(dev); } -- cgit v1.2.3 From 4f233ce61858b94e0c1bd36e331b36d1b59512e5 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 2 Jul 2008 22:46:44 +0200 Subject: tests: Updated modeprint --- tests/modeprint/modetest.c | 132 +++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 59 deletions(-) diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index 36925a0b..3f00922f 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -55,12 +55,63 @@ int printMode(struct drm_mode_modeinfo *mode) return 0; } +int printProperty(int fd, drmModeResPtr res, drmModePropertyPtr props, uint64_t value) +{ + const unsigned char *name = NULL; + int j; + + printf("Property: %s\n", props->name); + printf("\tid : %i\n", props->prop_id); + printf("\tflags : %i\n", props->flags); + printf("\tcount_values : %d\n", props->count_values); + + + if (props->count_values) { + printf("\tvalues :"); + for (j = 0; j < props->count_values; j++) + printf(" %lld", props->values[j]); + printf("\n"); + } + + + printf("\tcount_enums : %d\n", props->count_enums); + + if (props->flags & DRM_MODE_PROP_BLOB) { + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(fd, value); + if (blob) { + printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); + drmModeFreePropertyBlob(blob); + } else { + printf("error getting blob %lld\n", value); + } + + } else { + if (!strncmp(props->name, "DPMS", 4)) + ; + + for (j = 0; j < props->count_enums; j++) { + printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); + if (props->enums[j].value == value) + name = props->enums[j].name; + } + + if (props->count_enums && name) { + printf("\tcon_value : %s\n", name); + } else { + printf("\tcon_value : %lld\n", value); + } + } + + return 0; +} + int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id) { - int i = 0, j; + int i = 0; struct drm_mode_modeinfo *mode = NULL; drmModePropertyPtr props; - unsigned char *name = NULL; printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); printf("\tid : %i\n", id); @@ -69,73 +120,36 @@ int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uin printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); printf("\tcount_modes : %i\n", connector->count_modes); printf("\tcount_props : %i\n", connector->count_props); - printf("\tcount_encoders : %i\n", connector->count_encoders); + if (connector->count_props) { + printf("\tprops :"); + for (i = 0; i < connector->count_props; i++) + printf(" %i", connector->props[i]); + printf("\n"); + } + printf("\tcount_encoders : %i\n", connector->count_encoders); if (connector->count_encoders) { - printf("\t\tencoders"); + printf("\tencoders :"); for (i = 0; i < connector->count_encoders; i++) printf(" %i", connector->encoders[i]); printf("\n"); } + if (modes) { + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + printMode(mode); + } + } + if (full_props) { for (i = 0; i < connector->count_props; i++) { props = drmModeGetProperty(fd, connector->props[i]); - name = NULL; if (props) { - printf("Property: %s\n", props->name); - printf("\tid: %i\n", props->prop_id); - printf("\tflags: %i\n", props->flags); - printf("\tvalues %d: ", props->count_values); - for (j = 0; j < props->count_values; j++) - printf("%lld ", props->values[j]); - - printf("\n\tenums %d: \n", props->count_enums); - - if (props->flags & DRM_MODE_PROP_BLOB) { - drmModePropertyBlobPtr blob; - - blob = drmModeGetPropertyBlob(fd, connector->prop_values[i]); - if (blob) { - printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); - drmModeFreePropertyBlob(blob); - } - - } else { - if (!strncmp(props->name, "DPMS", 4)) - ; - - for (j = 0; j < props->count_enums; j++) { - printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); - if (connector->prop_values[i] == props->enums[j].value) - name = props->enums[j].name; - - } - - if (props->count_enums && name) { - printf("\tconnector property name %s %s\n", props->name, name); - } else { - printf("\tconnector property id %s %lli\n", props->name, connector->prop_values[i]); - } - } - + printProperty(fd, res, props, connector->prop_values[i]); drmModeFreeProperty(props); } } - } else { - if (connector->count_props) { - printf("\t\tprops"); - for (i = 0; i < connector->count_props; i++) - printf(" %i", connector->props[i]); - printf("\n"); - } - } - - if (modes) { - for (i = 0; i < connector->count_modes; i++) { - mode = &connector->modes[i]; - printMode(mode); - } } return 0; @@ -310,13 +324,13 @@ void args(int argc, char **argv) if (argc == 1) { fbs = 1; + edid = 1; + crtcs = 1; modes = 1; - full_modes = 0; encoders = 1; - connectors = 1; - crtcs = 1; + full_modes = 0; full_props = 0; - edid = 1; + connectors = 1; } } int main(int argc, char **argv) -- cgit v1.2.3 From 49e1fa1d503bb66949d825c41c1d97c83cf86361 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 2 Jul 2008 23:12:33 +0200 Subject: tests: modeprint s/fb/fd/ --- tests/modeprint/modetest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index 3f00922f..d8a94709 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -345,7 +345,7 @@ int main(int argc, char **argv) fd = drmOpen("i915", NULL); if (fd < 0) { - printf("Failed to open the card fb (%d)\n",fd); + printf("Failed to open the card fd (%d)\n",fd); return 1; } -- cgit v1.2.3 From 70ba0871916af586b355550184e0782b36e132c9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 3 Jul 2008 08:00:39 +1000 Subject: drm: fix encoders get permissions --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 82e5af57..deb8eb9c 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -142,7 +142,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_WAIT_HOTPLUG, drm_wait_hotplug, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_REPLACEFB, drm_mode_replacefb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER), -- cgit v1.2.3 From aa2d3cfc168481b7637d935af990ce447012ebfe Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 3 Jul 2008 00:03:48 +0200 Subject: tests: Fix faulty error messages in modeprint --- tests/modeprint/modetest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index d8a94709..f0f8abd4 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -220,7 +220,7 @@ int printRes(int fd, drmModeResPtr res) connector = drmModeGetConnector(fd, res->connectors[i]); if (!connector) - printf("Could not get connector %i\n", i); + printf("Could not get connector %i\n", res->connectors[i]); else { printConnector(fd, res, connector, res->connectors[i]); drmModeFreeConnector(connector); @@ -235,7 +235,7 @@ int printRes(int fd, drmModeResPtr res) encoder = drmModeGetEncoder(fd, res->encoders[i]); if (!encoder) - printf("Could not get encoder %i\n", i); + printf("Could not get encoder %i\n", res->encoders[i]); else { printEncoder(fd, res, encoder, res->encoders[i]); drmModeFreeEncoder(encoder); @@ -249,7 +249,7 @@ int printRes(int fd, drmModeResPtr res) crtc = drmModeGetCrtc(fd, res->crtcs[i]); if (!crtc) - printf("Could not get crtc %i\n", i); + printf("Could not get crtc %i\n", res->crtcs[i]); else { printCrtc(fd, res, crtc, res->crtcs[i]); drmModeFreeCrtc(crtc); -- cgit v1.2.3 From 59a9a756e238dd73f3051434545b2d3bf225da87 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 3 Jul 2008 08:05:51 +1000 Subject: modesetting: lookup blob using correct identifier. blob is a blob not a connector --- linux-core/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 23ae7d83..c20dacd8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1926,7 +1926,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, void *blob_ptr; mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_CONNECTOR); + obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); if (!obj) { ret = -EINVAL; goto done; -- cgit v1.2.3 From 5de978905abd6d44ee2ecdc7393194a4950c595c Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 00:25:06 +0200 Subject: [libdrm] count connectors and such has no place in a crtc object --- libdrm/xf86drmMode.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index f1b7c86e..9f1e7a26 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -106,12 +106,6 @@ typedef struct _drmModeCrtc { int mode_valid; struct drm_mode_modeinfo mode; - int count_connectors; - uint32_t connectors; /**< Connectors that are connected */ - - int count_possibles; - uint32_t possibles; /**< Connectors that can be connected */ - int gamma_size; /**< Number of gamma stops */ } drmModeCrtc, *drmModeCrtcPtr; -- cgit v1.2.3 From 94cf07bff1bf9a42ba6360f8feaa441b763b337f Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 00:30:00 +0200 Subject: Forgot to fix the modeprint test. --- tests/modeprint/modetest.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index f0f8abd4..d5cbbc56 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -176,10 +176,6 @@ int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) printf("\theight : %i\n", crtc->height); printf("\tmode : %p\n", &crtc->mode); printf("\tgamma size : %d\n", crtc->gamma_size); - printf("\tnum connectors : %i\n", crtc->count_connectors); - printf("\tconnectors : %i\n", crtc->connectors); - printf("\tnum possible : %i\n", crtc->count_possibles); - printf("\tpossibles : %i\n", crtc->possibles); return 0; } -- cgit v1.2.3 From 02b30739f7676082af4ce92448d910085d1dfc65 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 01:05:07 +0200 Subject: [modeseting-101] add connected field to sysfs --- linux-core/drm_sysfs.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 92371c22..02b08534 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -176,6 +176,19 @@ static ssize_t dpms_show(struct device *device, return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); } +static ssize_t connected_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + + if (connector->encoder) + return snprintf(buf, PAGE_SIZE, "connected"); + else + return snprintf(buf, PAGE_SIZE, "disconnected"); +} + static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { @@ -221,6 +234,7 @@ static ssize_t modes_show(struct device *device, static struct device_attribute connector_attrs[] = { __ATTR_RO(status), + __ATTR_RO(connected), __ATTR_RO(dpms), __ATTR_RO(modes), }; -- cgit v1.2.3 From 47c8f317410976c679aeaee69a372ec45485d442 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 07:18:18 +0200 Subject: NV50: replace active by enabled --- linux-core/nv50_crtc.h | 2 +- linux-core/nv50_display.c | 2 +- linux-core/nv50_kms_wrapper.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index de9a33f2..8235c9d6 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -38,7 +38,7 @@ struct nv50_crtc { struct drm_device *dev; int index; - bool active; + bool enabled; bool blanked; struct nouveau_hw_mode *mode; diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index cd527c44..2d12fb4f 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -147,7 +147,7 @@ static int nv50_display_disable(struct nv50_display *display) /* Almost like ack'ing a vblank interrupt, maybe in the spirit of cleaning up? */ list_for_each_entry(crtc, &display->crtcs, item) { - if (crtc->active) { + if (crtc->enabled) { uint32_t mask; if (crtc->index == 1) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 2a214f68..46edfb34 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -185,7 +185,7 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { crtc = to_nv50_crtc(drm_crtc); - crtc->active = drm_crtc->enabled; + crtc->enabled = drm_crtc->enabled; } } -- cgit v1.2.3 From d5ca5c9cd379438ac303598677f3789adc3687b1 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 08:07:35 +0200 Subject: [drm-sysfs] connected is ambigious in the context of a connector, replace with enabled --- linux-core/drm_sysfs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 02b08534..36b92224 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -176,17 +176,16 @@ static ssize_t dpms_show(struct device *device, return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); } -static ssize_t connected_show(struct device *device, +static ssize_t enabled_show(struct device *device, struct device_attribute *attr, char *buf) { struct drm_connector *connector = container_of(device, struct drm_connector, kdev); - struct drm_device *dev = connector->dev; if (connector->encoder) - return snprintf(buf, PAGE_SIZE, "connected"); + return snprintf(buf, PAGE_SIZE, "enabled"); else - return snprintf(buf, PAGE_SIZE, "disconnected"); + return snprintf(buf, PAGE_SIZE, "disabled"); } static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, @@ -234,7 +233,7 @@ static ssize_t modes_show(struct device *device, static struct device_attribute connector_attrs[] = { __ATTR_RO(status), - __ATTR_RO(connected), + __ATTR_RO(enabled), __ATTR_RO(dpms), __ATTR_RO(modes), }; -- cgit v1.2.3 From 062d85062061199f2326982e27d54955a4ad76dc Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 09:08:01 +0200 Subject: nv50: s/FALSE/false && s/TRUE/true --- linux-core/nv50_display.c | 6 +++--- linux-core/nv50_i2c.c | 30 +++++++++++++++--------------- linux-core/nv50_kms_wrapper.c | 16 ++++++++-------- shared-core/nouveau_mem.c | 2 +- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 2d12fb4f..b68c4e28 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -79,7 +79,7 @@ static int nv50_display_pre_init(struct nv50_display *display) NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000); NV_WRITE(NV50_PDISPLAY_UNK_38C, 0); - display->preinit_done = TRUE; + display->preinit_done = true; return 0; } @@ -125,7 +125,7 @@ static int nv50_display_init(struct nv50_display *display) /* enable clock change interrupts. */ NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) | 0x70); - display->init_done = TRUE; + display->init_done = true; return 0; } @@ -140,7 +140,7 @@ static int nv50_display_disable(struct nv50_display *display) NV50_DEBUG("\n"); list_for_each_entry(crtc, &display->crtcs, item) { - crtc->blank(crtc, TRUE); + crtc->blank(crtc, true); } display->update(display); diff --git a/linux-core/nv50_i2c.c b/linux-core/nv50_i2c.c index e90a4cee..30e317c5 100644 --- a/linux-core/nv50_i2c.c +++ b/linux-core/nv50_i2c.c @@ -106,19 +106,19 @@ static bool nv50_i2c_raise_clock(struct nv50_i2c_channel *chan, int data) for (i = 2200; i > 0; i -= 2) { nv50_i2c_get_bits(chan, &clock, &data); if (clock) - return TRUE; + return true; udelay(2); } printk("a timeout occured in nv50_i2c_raise_clock\n"); - return FALSE; + return false; } static bool nv50_i2c_start(struct nv50_i2c_channel *chan) { if (!nv50_i2c_raise_clock(chan, 1)) - return FALSE; + return false; nv50_i2c_set_bits(chan, 1, 0); udelay(5); @@ -126,7 +126,7 @@ static bool nv50_i2c_start(struct nv50_i2c_channel *chan) nv50_i2c_set_bits(chan, 0, 0); udelay(5); - return TRUE; + return true; } static void nv50_i2c_stop(struct nv50_i2c_channel *chan) @@ -181,7 +181,7 @@ static bool nv50_i2c_write_byte(struct nv50_i2c_channel *chan, uint8_t byte) for (i = 7; i >= 0; i--) if (!nv50_i2c_write_bit(chan, (byte >> i) & 1)) - return FALSE; + return false; nv50_i2c_set_bits(chan, 0, 1); udelay(5); @@ -198,7 +198,7 @@ static bool nv50_i2c_write_byte(struct nv50_i2c_channel *chan, uint8_t byte) if (i <= 0) { printk("a timeout occured in nv50_i2c_write_byte\n"); - rval = FALSE; + rval = false; } } @@ -222,14 +222,14 @@ static bool nv50_i2c_read_byte(struct nv50_i2c_channel *chan, uint8_t *byte, boo if (bit) *byte |= (1 << i); } else { - return FALSE; + return false; } } if (!nv50_i2c_write_bit(chan, last ? 1 : 0)) - return FALSE; + return false; - return TRUE; + return true; } /* only 7 bits addresses. */ @@ -241,13 +241,13 @@ static bool nv50_i2c_address(struct nv50_i2c_channel *chan, uint8_t address, boo real_addr |= 1; if (nv50_i2c_write_byte(chan, real_addr)) - return TRUE; + return true; /* failure, so issue stop */ nv50_i2c_stop(chan); } - return FALSE; + return false; } static bool nv50_i2c_read(struct nv50_i2c_channel *chan, uint8_t address, uint8_t *buffer, uint32_t length) @@ -257,9 +257,9 @@ static bool nv50_i2c_read(struct nv50_i2c_channel *chan, uint8_t address, uint8_ /* retries */ for (i = 0; i < 4; i++) { - rval = nv50_i2c_address(chan, address, FALSE); + rval = nv50_i2c_address(chan, address, false); if (!rval) - return FALSE; + return false; for (j = 0; j < length; j++) { last = false; @@ -292,9 +292,9 @@ static bool nv50_i2c_write(struct nv50_i2c_channel *chan, uint8_t address, uint8 /* retries */ for (i = 0; i < 4; i++) { - rval = nv50_i2c_address(chan, address, TRUE); + rval = nv50_i2c_address(chan, address, true); if (!rval) - return FALSE; + return false; for (j = 0; j < length; j++) { rval = nv50_i2c_write_byte(chan, buffer[j]); diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 46edfb34..f1f5b69f 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -529,7 +529,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (blank) { crtc = to_nv50_crtc(set->crtc); - rval = crtc->blank(crtc, TRUE); + rval = crtc->blank(crtc, true); if (rval != 0) { DRM_ERROR("blanking failed\n"); goto out; @@ -540,7 +540,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (drm_encoder->crtc == set->crtc) { output = to_nv50_output(drm_encoder); - rval = output->execute_mode(output, TRUE); + rval = output->execute_mode(output, true); if (rval != 0) { DRM_ERROR("detaching output failed\n"); goto out; @@ -556,7 +556,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (switch_fb && !modeset && !blank) { crtc = to_nv50_crtc(set->crtc); - rval = crtc->blank(crtc, TRUE); + rval = crtc->blank(crtc, true); if (rval != 0) { DRM_ERROR("blanking failed\n"); goto out; @@ -569,7 +569,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /* this also sets the fb offset */ - rval = crtc->blank(crtc, FALSE); + rval = crtc->blank(crtc, false); if (rval != 0) { DRM_ERROR("unblanking failed\n"); goto out; @@ -588,7 +588,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (output->crtc) { crtc_mask |= 1 << output->crtc->index; } else { - rval = output->execute_mode(output, TRUE); + rval = output->execute_mode(output, true); if (rval != 0) { DRM_ERROR("detaching output failed\n"); goto out; @@ -599,7 +599,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* blank any unused crtcs */ list_for_each_entry(crtc, &display->crtcs, item) { if (!(crtc_mask & (1 << crtc->index))) - crtc->blank(crtc, TRUE); + crtc->blank(crtc, true); } crtc = to_nv50_crtc(set->crtc); @@ -642,7 +642,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (output->crtc != crtc) continue; - rval = output->execute_mode(output, FALSE); + rval = output->execute_mode(output, false); if (rval != 0) { DRM_ERROR("output execute mode failed\n"); goto out; @@ -933,7 +933,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u } } - drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, TRUE); + drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, true); if (list_empty(&drm_connector->modes)) { struct drm_display_mode *stdmode; diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 425cebe2..861d699f 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -743,7 +743,7 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) crtc->fb->block = NULL; if (!crtc->blanked) - crtc->blank(crtc, TRUE); + crtc->blank(crtc, true); } if (crtc->cursor->block == block) { -- cgit v1.2.3 From 11b7a81c8a776aa7761ee03fe55d741a44ba5df7 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 17:25:37 +0200 Subject: libdrm: fix typo in comment --- libdrm/xf86drmMode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 9f1e7a26..7afc71d7 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -98,7 +98,7 @@ typedef struct _drmModeProperty { typedef struct _drmModeCrtc { unsigned int crtc_id; - unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/ + unsigned int buffer_id; /**< FB id to connect to 0 = disconnect */ uint32_t generation; uint32_t x, y; /**< Position on the frameuffer */ @@ -137,7 +137,7 @@ typedef enum { typedef struct _drmModeConnector { uint32_t generation; unsigned int connector_id; - unsigned int encoder; /**< Crtc currently connected to */ + unsigned int encoder; /**< Encoder currently connected to */ unsigned int connector_type; unsigned int connector_type_id; drmModeConnection connection; -- cgit v1.2.3 From 142a309604b65c26ca95594943ee91dde8688697 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 4 Jul 2008 09:34:24 +1000 Subject: modesetting: rip out all of the generation code. not needed, hotplug will work just as well hopefully. --- libdrm/xf86drmMode.h | 11 ----------- linux-core/drm_crtc.c | 5 ----- linux-core/drm_crtc.h | 3 --- shared-core/drm.h | 7 ------- 4 files changed, 26 deletions(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 7afc71d7..3e2f5c0e 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -50,16 +50,8 @@ * buffer object interface. This object needs to be pinned. */ -/* - * generation - these are to be read by userspace, and if it notices - * while calling a get output or get crtc that the generation has changed - * it should re-call the mode resource functions resync its view of the - * outputs with current view. - */ - typedef struct _drmModeRes { - uint32_t generation; int count_fbs; uint32_t *fbs; @@ -99,7 +91,6 @@ typedef struct _drmModeProperty { typedef struct _drmModeCrtc { unsigned int crtc_id; unsigned int buffer_id; /**< FB id to connect to 0 = disconnect */ - uint32_t generation; uint32_t x, y; /**< Position on the frameuffer */ uint32_t width, height; @@ -111,7 +102,6 @@ typedef struct _drmModeCrtc { } drmModeCrtc, *drmModeCrtcPtr; typedef struct _drmModeEncoder { - uint32_t generation; unsigned int encoder_id; unsigned int encoder_type; uint32_t crtc; @@ -135,7 +125,6 @@ typedef enum { } drmModeSubPixel; typedef struct _drmModeConnector { - uint32_t generation; unsigned int connector_id; unsigned int encoder; /**< Encoder currently connected to */ unsigned int connector_type; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c20dacd8..ca5e75a4 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -574,7 +574,6 @@ void drm_mode_config_init(struct drm_device *dev) drm_mode_create_standard_connector_properties(dev); /* Just to be sure */ - dev->mode_config.current_generation = 0; dev->mode_config.num_fb = 0; dev->mode_config.num_connector = 0; dev->mode_config.num_crtc = 0; @@ -805,7 +804,6 @@ int drm_mode_getresources(struct drm_device *dev, card_res->min_height = dev->mode_config.min_height; card_res->max_width = dev->mode_config.max_width; card_res->min_width = dev->mode_config.min_width; - card_res->generation = dev->mode_config.current_generation; /* handle this in 4 parts */ /* FBs */ @@ -946,7 +944,6 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->x = crtc->x; crtc_resp->y = crtc->y; crtc_resp->gamma_size = crtc->gamma_size; - crtc_resp->generation = dev->mode_config.current_generation; if (crtc->fb) crtc_resp->fb_id = crtc->fb->base.id; else @@ -1036,7 +1033,6 @@ int drm_mode_getconnector(struct drm_device *dev, list_for_each_entry(mode, &connector->modes, head) mode_count++; - out_resp->generation = dev->mode_config.current_generation; out_resp->connector_type = connector->connector_type; out_resp->connector_type_id = connector->connector_type_id; out_resp->mm_width = connector->display_info.width_mm; @@ -1125,7 +1121,6 @@ int drm_mode_getencoder(struct drm_device *dev, enc_resp->crtc = encoder->crtc->base.id; else enc_resp->crtc = 0; - enc_resp->generation = dev->mode_config.current_generation; enc_resp->encoder_type = encoder->encoder_type; enc_resp->encoder_id = encoder->base.id; enc_resp->crtcs = encoder->possible_crtcs; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d6fa4cca..65ff3f29 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -561,9 +561,6 @@ struct drm_mode_config { /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */ struct list_head fb_kernel_list; - /* currently in use generation id */ - int current_generation; - int min_width, min_height; int max_width, max_height; struct drm_mode_config_funcs *funcs; diff --git a/shared-core/drm.h b/shared-core/drm.h index 40653b4b..132c7746 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1033,7 +1033,6 @@ struct drm_mode_card_res { int count_encoders; int min_width, max_width; int min_height, max_height; - uint32_t generation; }; struct drm_mode_crtc { @@ -1044,8 +1043,6 @@ struct drm_mode_crtc { int x, y; /**< Position on the frameuffer */ - uint32_t generation; - int count_connectors; unsigned int connectors; /**< Connectors that are connected */ @@ -1058,8 +1055,6 @@ struct drm_mode_crtc { struct drm_mode_get_encoder { - uint32_t generation; - uint32_t encoder_type; uint32_t encoder_id; @@ -1090,8 +1085,6 @@ struct drm_mode_get_connector { unsigned int connector_type; unsigned int connector_type_id; - uint32_t generation; - unsigned int connection; unsigned int mm_width, mm_height; /**< HxW in millimeters */ unsigned int subpixel; -- cgit v1.2.3 From b29578103f57a8d684b4a3a79f220e6cc626605e Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 17:17:11 +0200 Subject: [modesetting-101] Add subconnector and select_subconnector properties. - These facilitate DVI-I and tv-out that can drive multiple types of signals. --- linux-core/drm_crtc.c | 96 +++++++++++++++++++++++++++++++++++++++- linux-core/drm_crtc.h | 19 +++++++- linux-core/drm_sysfs.c | 98 +++++++++++++++++++++++++++++++++++++++++ linux-core/intel_tv.c | 2 +- linux-core/nv50_connector.h | 1 - linux-core/nv50_kms_wrapper.c | 100 +++++++++++++++++++++++++++++++++++++----- linux-core/nv50_kms_wrapper.h | 1 + 7 files changed, 300 insertions(+), 17 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ca5e75a4..1a381abe 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -60,6 +60,48 @@ char *drm_get_dpms_name(int val) return "unknown"; } +static struct drm_prop_enum_list drm_select_subconnector_enum_list[] = +{ + { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ +}; + +char *drm_get_select_subconnector_name(int val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(drm_select_subconnector_enum_list); i++) + if (drm_select_subconnector_enum_list[i].type == val) + return drm_select_subconnector_enum_list[i].name; + + return "unknown"; +} + +static struct drm_prop_enum_list drm_subconnector_enum_list[] = +{ + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ +}; + +char *drm_get_subconnector_name(int val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(drm_subconnector_enum_list); i++) + if (drm_subconnector_enum_list[i].type == val) + return drm_subconnector_enum_list[i].name; + + return "unknown"; +} + static struct drm_prop_enum_list drm_connector_enum_list[] = { { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, { DRM_MODE_CONNECTOR_VGA, "VGA" }, @@ -497,6 +539,38 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) return 0; } +/** + * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties + * @dev: DRM device + * + * Called by a driver the first time a DVI-I connector is made. + */ +int drm_mode_create_dvi_i_properties(struct drm_device *dev) +{ + int i; + + if (dev->mode_config.dvi_i_select_subconnector_property) + return 0; + + dev->mode_config.dvi_i_select_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, + "select subconnector", 3); + /* add enum element 0-2 */ + for (i = 0; i < 3; i++) + drm_property_add_enum(dev->mode_config.dvi_i_select_subconnector_property, i, drm_select_subconnector_enum_list[i].type, + drm_select_subconnector_enum_list[i].name); + + /* This is a property which indicates the most likely thing to be connected. */ + dev->mode_config.dvi_i_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, + "subconnector", 3); + /* add enum element 0-2 */ + for (i = 0; i < 3; i++) + drm_property_add_enum(dev->mode_config.dvi_i_subconnector_property, i, drm_subconnector_enum_list[i].type, + drm_subconnector_enum_list[i].name); + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); + /** * drm_create_tv_properties - create TV specific connector properties * @dev: DRM device @@ -508,11 +582,29 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) * responsible for allocating a list of format names and passing them to * this routine. */ -bool drm_create_tv_properties(struct drm_device *dev, int num_modes, +int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, char *modes[]) { int i; + if (dev->mode_config.tv_select_subconnector_property) /* already done */ + return 0; + + dev->mode_config.tv_select_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, + "select subconnector", 4); + /* add enum element 3-5 */ + for (i = 1; i < 4; i++) + drm_property_add_enum(dev->mode_config.tv_select_subconnector_property, i, drm_select_subconnector_enum_list[i + 2].type, + drm_select_subconnector_enum_list[i + 2].name); + + /* This is a property which indicates the most likely thing to be connected. */ + dev->mode_config.tv_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, + "subconnector", 4); + /* add enum element 3-5 */ + for (i = 1; i < 4; i++) + drm_property_add_enum(dev->mode_config.tv_subconnector_property, i, drm_subconnector_enum_list[i + 2].type, + drm_subconnector_enum_list[i + 2].name); + dev->mode_config.tv_left_margin_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, @@ -547,7 +639,7 @@ bool drm_create_tv_properties(struct drm_device *dev, int num_modes, return 0; } -EXPORT_SYMBOL(drm_create_tv_properties); +EXPORT_SYMBOL(drm_mode_create_tv_properties); /** * drm_mode_config_init - initialize DRM mode_configuration structure diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 65ff3f29..caceb650 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -170,6 +170,14 @@ struct drm_display_mode { #define DPMSModeSuspend 2 #define DPMSModeOff 3 +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 3 +#define DRM_MODE_SUBCONNECTOR_DVIA 4 +#define DRM_MODE_SUBCONNECTOR_Composite 5 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +#define DRM_MODE_SUBCONNECTOR_Component 8 + #define DRM_MODE_CONNECTOR_Unknown 0 #define DRM_MODE_CONNECTOR_VGA 1 #define DRM_MODE_CONNECTOR_DVII 2 @@ -571,7 +579,13 @@ struct drm_mode_config { struct drm_property *edid_property; struct drm_property *dpms_property; + /* optional properties */ + struct drm_property *dvi_i_subconnector_property; + struct drm_property *dvi_i_select_subconnector_property; + /* TV properties */ + struct drm_property *tv_subconnector_property; + struct drm_property *tv_select_subconnector_property; struct drm_property *tv_mode_property; struct drm_property *tv_left_margin_property; struct drm_property *tv_right_margin_property; @@ -612,6 +626,8 @@ extern void drm_encoder_cleanup(struct drm_encoder *encoder); extern char *drm_get_connector_name(struct drm_connector *connector); extern char *drm_get_dpms_name(int val); +extern char *drm_get_select_subconnector_name(int val); +extern char *drm_get_subconnector_name(int val); extern void drm_fb_release(struct file *filp); extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); extern struct edid *drm_get_edid(struct drm_connector *connector, @@ -674,7 +690,8 @@ extern struct drm_property *drm_property_create(struct drm_device *dev, int flag extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); -extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, +extern int drm_mode_create_dvi_i_properties(struct drm_device *dev); +extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); extern char *drm_get_encoder_name(struct drm_encoder *encoder); diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 36b92224..5c384a60 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -231,6 +231,78 @@ static ssize_t modes_show(struct device *device, return written; } +static ssize_t subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + struct drm_property *prop = NULL; + uint64_t subconnector; + int ret; + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + prop = dev->mode_config.dvi_i_subconnector_property; + break; + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Component: + prop = dev->mode_config.tv_subconnector_property; + break; + default: + DRM_ERROR("Wrong connector type for this property\n"); + return 0; + } + + if (!prop) { + DRM_ERROR("Unable to find subconnector property\n"); + return 0; + } + + ret = drm_connector_property_get_value(connector, prop, &subconnector); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", drm_get_subconnector_name((int)subconnector)); +} + +static ssize_t select_subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + struct drm_property *prop = NULL; + uint64_t subconnector; + int ret; + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + prop = dev->mode_config.dvi_i_select_subconnector_property; + break; + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Component: + prop = dev->mode_config.tv_select_subconnector_property; + break; + default: + DRM_ERROR("Wrong connector type for this property\n"); + return 0; + } + + if (!prop) { + DRM_ERROR("Unable to find select subconnector property\n"); + return 0; + } + + ret = drm_connector_property_get_value(connector, prop, &subconnector); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", drm_get_select_subconnector_name((int)subconnector)); +} + static struct device_attribute connector_attrs[] = { __ATTR_RO(status), __ATTR_RO(enabled), @@ -238,6 +310,12 @@ static struct device_attribute connector_attrs[] = { __ATTR_RO(modes), }; +/* These attributes are for both DVI-I connectors and all types of tv-out. */ +static struct device_attribute connector_attrs_opt1[] = { + __ATTR_RO(subconnector), + __ATTR_RO(select_subconnector), +}; + static struct bin_attribute edid_attr = { .attr.name = "edid", .size = 128, @@ -282,12 +360,32 @@ int drm_sysfs_connector_add(struct drm_connector *connector) goto out; } + /* Standard attributes */ + for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) { ret = device_create_file(&connector->kdev, &connector_attrs[i]); if (ret) goto err_out_files; } + /* Optional attributes */ + /* On the long run it maybe a good idea to make one set of optionals per connector type. */ + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Component: + for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) { + ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]); + if (ret) + goto err_out_files; + } + break; + default: + break; + } + ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr); if (ret) goto err_out_files; diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 39f33d6c..f564fa91 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1713,7 +1713,7 @@ intel_tv_init(struct drm_device *dev) goto out; for (i = 0; i < NUM_TV_MODES; i++) tv_format_names[i] = tv_modes[i].name; - drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index 484227a0..ebd6eac6 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -48,7 +48,6 @@ struct nv50_connector { struct nv50_output *output; int scaling_mode; - bool digital; /* last connected output, this has to be set from the outside*/ bool (*detect) (struct nv50_connector *connector); int (*destroy) (struct nv50_connector *connector); diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index f1f5b69f..ee18b36a 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -387,7 +387,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } connector = to_nv50_connector(drm_connector); - output = connector->to_output(connector, connector->digital); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); goto out; @@ -447,7 +447,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - output = connector->to_output(connector, connector->digital); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); goto out; @@ -806,6 +806,63 @@ static int nv50_kms_encoders_init(struct drm_device *dev) * Connector functions */ +bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) +{ + struct drm_device *dev = drm_connector->dev; + + switch (drm_connector->connector_type) { + case DRM_MODE_CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_SVIDEO: + return false; + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_LVDS: + return true; + default: + break; + } + + if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) { + int rval; + uint64_t prop_val; + + rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, &prop_val); + if (!rval) { + DRM_ERROR("Unable to find select subconnector property, defaulting to DVI-D\n"); + return true; + } + + /* Is a subconnector explicitly selected? */ + switch (prop_val) { + case DRM_MODE_SUBCONNECTOR_DVID: + return true; + case DRM_MODE_SUBCONNECTOR_DVIA: + return false; + default: + break; + } + + rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &prop_val); + if (!rval) { + DRM_ERROR("Unable to find subconnector property, defaulting to DVI-D\n"); + return true; + } + + /* Do we know what subconnector we currently have connected? */ + switch (prop_val) { + case DRM_MODE_SUBCONNECTOR_DVID: + return true; + case DRM_MODE_SUBCONNECTOR_DVIA: + return false; + default: + DRM_ERROR("Unknown subconnector value, defaulting to DVI-D\n"); + return true; + } + } + + DRM_ERROR("Unknown connector type, defaulting to analog\n"); + return false; +} + void nv50_kms_connector_detect_all(struct drm_device *dev) { struct drm_connector *drm_connector = NULL; @@ -867,7 +924,8 @@ static struct drm_display_mode std_mode[] = { static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, uint32_t maxX, uint32_t maxY) { struct nv50_connector *connector = to_nv50_connector(drm_connector); - int ret = 0; + struct drm_device *dev = drm_connector->dev; + int rval = 0; bool connected; struct drm_display_mode *mode, *t; struct edid *edid = NULL; @@ -896,21 +954,32 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u if (edid) { drm_mode_connector_update_edid_property(drm_connector, edid); - ret = drm_add_edid_modes(drm_connector, edid); - connector->digital = edid->digital; /* cache */ + rval = drm_add_edid_modes(drm_connector, edid); + + /* 2 encoders per connector */ + /* eventually do this based on load detect and hot plug detect */ + if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) { + uint64_t subtype = 0; + if (edid->digital) + subtype = DRM_MODE_SUBCONNECTOR_DVID; + else + subtype = DRM_MODE_SUBCONNECTOR_DVIA; + drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, subtype); + } + kfree(edid); } - if (ret) /* number of modes > 1 */ + if (rval) /* number of modes > 1 */ drm_mode_connector_list_update(drm_connector); if (maxX && maxY) - drm_mode_validate_size(drm_connector->dev, &drm_connector->modes, maxX, maxY, 0); + drm_mode_validate_size(dev, &drm_connector->modes, maxX, maxY, 0); list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { if (mode->status == MODE_OK) { struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); - struct nv50_output *output = connector->to_output(connector, connector->digital); + struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); mode->status = output->validate_mode(output, hw_mode); /* find native mode, TODO: also check if we actually found one */ @@ -926,14 +995,14 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { if (mode->status == MODE_OK) { struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); - struct nv50_output *output = connector->to_output(connector, connector->digital); + struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); mode->status = output->validate_mode(output, hw_mode); kfree(hw_mode); } } - drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, true); + drm_mode_prune_invalid(dev, &drm_connector->modes, true); if (list_empty(&drm_connector->modes)) { struct drm_display_mode *stdmode; @@ -947,14 +1016,14 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u * here and bailed in the past, now we add a standard * 640x480@60Hz mode and carry on. */ - stdmode = drm_mode_duplicate(drm_connector->dev, &std_mode[0]); + stdmode = drm_mode_duplicate(dev, &std_mode[0]); drm_mode_probed_add(drm_connector, stdmode); drm_mode_list_concat(&drm_connector->probed_modes, &drm_connector->modes); /* also add it as native mode */ hw_mode = nv50_kms_to_hw_mode(mode); - output = connector->to_output(connector, connector->digital); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (hw_mode) *output->native_mode = *hw_mode; @@ -1045,6 +1114,13 @@ static int nv50_kms_connectors_init(struct drm_device *dev) drm_connector_init(dev, drm_connector, &nv50_kms_connector_funcs, type); + /* Init DVI-I specific properties */ + if (type == DRM_MODE_CONNECTOR_DVII) { + drm_mode_create_dvi_i_properties(dev); + drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_subconnector_property, 0); + drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, 0); + } + /* attach encoders, possibilities are analog + digital */ for (i = 0; i < 2; i++) { struct drm_encoder *drm_encoder = NULL; diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h index f224f1bb..5ac66522 100644 --- a/linux-core/nv50_kms_wrapper.h +++ b/linux-core/nv50_kms_wrapper.h @@ -87,6 +87,7 @@ struct nv50_kms_priv { struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev); void nv50_kms_connector_detect_all(struct drm_device *dev); +bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector); int nv50_kms_init(struct drm_device *dev); int nv50_kms_destroy(struct drm_device *dev); -- cgit v1.2.3 From c9915d695dad8e4f75b4f551f9f78ff3d64dc666 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 17:28:04 +0200 Subject: modesetting-101: Move some defines used for enumeration into the public header. - Otherwise userspace has no idea of the meaning. --- linux-core/drm_crtc.h | 47 ++---------------------------------------- shared-core/drm.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index caceb650..d4bb8794 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -90,6 +90,8 @@ enum drm_mode_status { .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ .vscan = (vs), .flags = (f), .vrefresh = 0 +#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ + struct drm_display_mode { /* Header */ struct list_head head; @@ -147,51 +149,6 @@ struct drm_display_mode { float hsync; }; -/* Video mode flags */ -#define V_PHSYNC (1<<0) -#define V_NHSYNC (1<<1) -#define V_PVSYNC (1<<2) -#define V_NVSYNC (1<<3) -#define V_INTERLACE (1<<4) -#define V_DBLSCAN (1<<5) -#define V_CSYNC (1<<6) -#define V_PCSYNC (1<<7) -#define V_NCSYNC (1<<8) -#define V_HSKEW (1<<9) /* hskew provided */ -#define V_BCAST (1<<10) -#define V_PIXMUX (1<<11) -#define V_DBLCLK (1<<12) -#define V_CLKDIV2 (1<<13) - -#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ - -#define DPMSModeOn 0 -#define DPMSModeStandby 1 -#define DPMSModeSuspend 2 -#define DPMSModeOff 3 - -#define DRM_MODE_SUBCONNECTOR_Automatic 0 -#define DRM_MODE_SUBCONNECTOR_Unknown 0 -#define DRM_MODE_SUBCONNECTOR_DVID 3 -#define DRM_MODE_SUBCONNECTOR_DVIA 4 -#define DRM_MODE_SUBCONNECTOR_Composite 5 -#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 -#define DRM_MODE_SUBCONNECTOR_Component 8 - -#define DRM_MODE_CONNECTOR_Unknown 0 -#define DRM_MODE_CONNECTOR_VGA 1 -#define DRM_MODE_CONNECTOR_DVII 2 -#define DRM_MODE_CONNECTOR_DVID 3 -#define DRM_MODE_CONNECTOR_DVIA 4 -#define DRM_MODE_CONNECTOR_Composite 5 -#define DRM_MODE_CONNECTOR_SVIDEO 6 -#define DRM_MODE_CONNECTOR_LVDS 7 -#define DRM_MODE_CONNECTOR_Component 8 -#define DRM_MODE_CONNECTOR_9PinDIN 9 -#define DRM_MODE_CONNECTOR_DisplayPort 10 -#define DRM_MODE_CONNECTOR_HDMIA 11 -#define DRM_MODE_CONNECTOR_HDMIB 12 - enum drm_connector_status { connector_status_connected = 1, connector_status_disconnected = 2, diff --git a/shared-core/drm.h b/shared-core/drm.h index 132c7746..c9b40e78 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1010,6 +1010,28 @@ struct drm_mm_info_arg { #define DRM_MODE_TYPE_USERDEF (1<<5) #define DRM_MODE_TYPE_DRIVER (1<<6) +/* Video mode flags */ +#define V_PHSYNC (1<<0) +#define V_NHSYNC (1<<1) +#define V_PVSYNC (1<<2) +#define V_NVSYNC (1<<3) +#define V_INTERLACE (1<<4) +#define V_DBLSCAN (1<<5) +#define V_CSYNC (1<<6) +#define V_PCSYNC (1<<7) +#define V_NCSYNC (1<<8) +#define V_HSKEW (1<<9) /* hskew provided */ +#define V_BCAST (1<<10) +#define V_PIXMUX (1<<11) +#define V_DBLCLK (1<<12) +#define V_CLKDIV2 (1<<13) + +/* DPMS flags */ +#define DPMSModeOn 0 +#define DPMSModeStandby 1 +#define DPMSModeSuspend 2 +#define DPMSModeOff 3 + struct drm_mode_modeinfo { unsigned int clock; unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; @@ -1053,6 +1075,12 @@ struct drm_mode_crtc { struct drm_mode_modeinfo mode; }; +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 + struct drm_mode_get_encoder { uint32_t encoder_type; @@ -1063,11 +1091,29 @@ struct drm_mode_get_encoder { uint32_t clones; }; -#define DRM_MODE_ENCODER_NONE 0 -#define DRM_MODE_ENCODER_DAC 1 -#define DRM_MODE_ENCODER_TMDS 2 -#define DRM_MODE_ENCODER_LVDS 3 -#define DRM_MODE_ENCODER_TVDAC 4 +/* This is for connectors with multiple signal types. */ +/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 3 +#define DRM_MODE_SUBCONNECTOR_DVIA 4 +#define DRM_MODE_SUBCONNECTOR_Composite 5 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +#define DRM_MODE_SUBCONNECTOR_Component 8 + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 struct drm_mode_get_connector { -- cgit v1.2.3 From 0028ca33e90d3405bd47a554e9398e0c2aa6099b Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 17:37:45 +0200 Subject: Forgot the 0'th element for the tv property. --- linux-core/drm_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1a381abe..095d44fa 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -592,6 +592,9 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, dev->mode_config.tv_select_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, "select subconnector", 4); + /* add enum element 0 */ + drm_property_add_enum(dev->mode_config.tv_select_subconnector_property, 0, drm_select_subconnector_enum_list[0].type, + drm_select_subconnector_enum_list[0].name); /* add enum element 3-5 */ for (i = 1; i < 4; i++) drm_property_add_enum(dev->mode_config.tv_select_subconnector_property, i, drm_select_subconnector_enum_list[i + 2].type, @@ -600,6 +603,9 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, /* This is a property which indicates the most likely thing to be connected. */ dev->mode_config.tv_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, "subconnector", 4); + /* add enum element 0 */ + drm_property_add_enum(dev->mode_config.tv_subconnector_property, 0, drm_subconnector_enum_list[0].type, + drm_subconnector_enum_list[0].name); /* add enum element 3-5 */ for (i = 1; i < 4; i++) drm_property_add_enum(dev->mode_config.tv_subconnector_property, i, drm_subconnector_enum_list[i + 2].type, -- cgit v1.2.3 From be31a0fa73272b9c727668096ba652ea748a9735 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 18:47:59 +0200 Subject: modesetting-101: tv_left_margin_property shouldn't be immutable. --- linux-core/drm_crtc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 095d44fa..3ee0f86c 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -612,8 +612,7 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, drm_subconnector_enum_list[i + 2].name); dev->mode_config.tv_left_margin_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE | - DRM_MODE_PROP_IMMUTABLE, + drm_property_create(dev, DRM_MODE_PROP_RANGE, "left margin", 2); dev->mode_config.tv_left_margin_property->values[0] = 0; dev->mode_config.tv_left_margin_property->values[1] = 100; -- cgit v1.2.3 From 7cbc5f6145046f3775e3b3ca2862bfb71831ec44 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 5 Jul 2008 12:04:07 +0200 Subject: modesetting-101: Make the interface variable names a little more consistent + modeprint changes. - All things are now called _id when they are id's. - modeprint now accepts driver name as first argument. --- libdrm/xf86drmMode.c | 21 ++++++++------------- libdrm/xf86drmMode.h | 10 +++++----- linux-core/drm_crtc.c | 18 +++++++++--------- shared-core/drm.h | 21 +++++++++------------ tests/modeprint/modetest.c | 25 +++++++++++++++++-------- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index ca21a961..c3921ee9 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -284,11 +284,6 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, { struct drm_mode_crtc crtc; - crtc.count_connectors = 0; - crtc.connectors = 0; - crtc.count_possibles = 0; - crtc.possibles = 0; - crtc.x = x; crtc.y = y; crtc.crtc_id = crtcId; @@ -343,8 +338,8 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) enc.encoder_id = encoder_id; enc.encoder_type = 0; - enc.crtcs = 0; - enc.clones = 0; + enc.possible_crtcs = 0; + enc.possible_clones = 0; if (ioctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc)) return 0; @@ -353,10 +348,10 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) return 0; r->encoder_id = enc.encoder_id; - r->crtc = enc.crtc; + r->crtc_id = enc.crtc_id; r->encoder_type = enc.encoder_type; - r->crtcs = enc.crtcs; - r->clones = enc.clones; + r->possible_crtcs = enc.possible_crtcs; + r->possible_clones = enc.possible_clones; return r; } @@ -370,7 +365,7 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) struct drm_mode_get_connector conn; drmModeConnectorPtr r = NULL; - conn.connector = connector_id; + conn.connector_id = connector_id; conn.connector_type_id = 0; conn.connector_type = 0; conn.count_modes = 0; @@ -402,8 +397,8 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) goto err_allocs; } - r->connector_id = conn.connector; - r->encoder = conn.encoder; + r->connector_id = conn.connector_id; + r->encoder_id = conn.encoder_id; r->connection = conn.connection; r->mmWidth = conn.mm_width; r->mmHeight = conn.mm_height; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 3e2f5c0e..59612a94 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -92,7 +92,7 @@ typedef struct _drmModeCrtc { unsigned int crtc_id; unsigned int buffer_id; /**< FB id to connect to 0 = disconnect */ - uint32_t x, y; /**< Position on the frameuffer */ + uint32_t x, y; /**< Position on the framebuffer */ uint32_t width, height; int mode_valid; struct drm_mode_modeinfo mode; @@ -104,9 +104,9 @@ typedef struct _drmModeCrtc { typedef struct _drmModeEncoder { unsigned int encoder_id; unsigned int encoder_type; - uint32_t crtc; - uint32_t crtcs; - uint32_t clones; + unsigned int crtc_id; + uint32_t possible_crtcs; + uint32_t possible_clones; } drmModeEncoder, *drmModeEncoderPtr; typedef enum { @@ -126,7 +126,7 @@ typedef enum { typedef struct _drmModeConnector { unsigned int connector_id; - unsigned int encoder; /**< Encoder currently connected to */ + unsigned int encoder_id; /**< Encoder currently connected to */ unsigned int connector_type; unsigned int connector_type_id; drmModeConnection connection; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 3ee0f86c..f8e09a8c 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1046,7 +1046,6 @@ int drm_mode_getcrtc(struct drm_device *dev, else crtc_resp->fb_id = 0; - crtc_resp->connectors = 0; if (crtc->enabled) { drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); @@ -1099,11 +1098,11 @@ int drm_mode_getconnector(struct drm_device *dev, memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); - DRM_DEBUG("connector id %d:\n", out_resp->connector); + DRM_DEBUG("connector id %d:\n", out_resp->connector_id); mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, out_resp->connector, DRM_MODE_OBJECT_CONNECTOR); + obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); if (!obj) { ret = -EINVAL; goto out; @@ -1130,6 +1129,7 @@ int drm_mode_getconnector(struct drm_device *dev, list_for_each_entry(mode, &connector->modes, head) mode_count++; + out_resp->connector_id = connector->base.id; out_resp->connector_type = connector->connector_type; out_resp->connector_type_id = connector->connector_type_id; out_resp->mm_width = connector->display_info.width_mm; @@ -1137,9 +1137,9 @@ int drm_mode_getconnector(struct drm_device *dev, out_resp->subpixel = connector->display_info.subpixel_order; out_resp->connection = connector->status; if (connector->encoder) - out_resp->encoder = connector->encoder->base.id; + out_resp->encoder_id = connector->encoder->base.id; else - out_resp->encoder = 0; + out_resp->encoder_id = 0; /* this ioctl is called twice, once to determine how much space is needed, and the 2nd time to fill it */ if ((out_resp->count_modes >= mode_count) && mode_count) { @@ -1215,13 +1215,13 @@ int drm_mode_getencoder(struct drm_device *dev, encoder = obj_to_encoder(obj); if (encoder->crtc) - enc_resp->crtc = encoder->crtc->base.id; + enc_resp->crtc_id = encoder->crtc->base.id; else - enc_resp->crtc = 0; + enc_resp->crtc_id = 0; enc_resp->encoder_type = encoder->encoder_type; enc_resp->encoder_id = encoder->base.id; - enc_resp->crtcs = encoder->possible_crtcs; - enc_resp->clones = encoder->possible_clones; + enc_resp->possible_crtcs = encoder->possible_crtcs; + enc_resp->possible_clones = encoder->possible_clones; out: mutex_unlock(&dev->mode_config.mutex); diff --git a/shared-core/drm.h b/shared-core/drm.h index c9b40e78..b64e265d 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1059,17 +1059,13 @@ struct drm_mode_card_res { struct drm_mode_crtc { uint64_t set_connectors_ptr; + int count_connectors; unsigned int crtc_id; /**< Id */ unsigned int fb_id; /**< Id of framebuffer */ int x, y; /**< Position on the frameuffer */ - int count_connectors; - unsigned int connectors; /**< Connectors that are connected */ - - int count_possibles; - unsigned int possibles; /**< Connectors that can be connected */ uint32_t gamma_size; int mode_valid; struct drm_mode_modeinfo mode; @@ -1083,12 +1079,13 @@ struct drm_mode_crtc { struct drm_mode_get_encoder { - uint32_t encoder_type; - uint32_t encoder_id; + unsigned int encoder_type; + unsigned int encoder_id; + + unsigned int crtc_id; /**< Id of crtc */ - unsigned int crtc; /**< Id of crtc */ - uint32_t crtcs; - uint32_t clones; + uint32_t possible_crtcs; + uint32_t possible_clones; }; /* This is for connectors with multiple signal types. */ @@ -1126,8 +1123,8 @@ struct drm_mode_get_connector { int count_props; int count_encoders; - unsigned int encoder; /**< Current Encoder */ - unsigned int connector; /**< Id */ + unsigned int encoder_id; /**< Current Encoder */ + unsigned int connector_id; /**< Id */ unsigned int connector_type; unsigned int connector_type_id; diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index d5cbbc56..cefa5262 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -17,6 +17,7 @@ int full_modes; int encoders; int crtcs; int fbs; +char *module_name; const char* getConnectionText(drmModeConnection conn) { @@ -115,7 +116,7 @@ int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uin printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); printf("\tid : %i\n", id); - printf("\tencoder id : %i\n", connector->encoder); + printf("\tencoder id : %i\n", connector->encoder_id); printf("\tconn : %s\n", getConnectionText(connector->connection)); printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); printf("\tcount_modes : %i\n", connector->count_modes); @@ -159,10 +160,10 @@ int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t { printf("Encoder\n"); printf("\tid :%i\n", id); - printf("\tcrtc :%d\n", encoder->crtc); + printf("\tcrtc_id :%d\n", encoder->crtc_id); printf("\ttype :%d\n", encoder->encoder_type); - printf("\tcrtcs :%d\n", encoder->crtcs); - printf("\tclones :%d\n", encoder->clones); + printf("\tpossible_crtcs :%d\n", encoder->possible_crtcs); + printf("\tpossible_clones :%d\n", encoder->possible_clones); return 0; } @@ -283,7 +284,9 @@ void args(int argc, char **argv) full_props = 0; connectors = 0; - for (i = 1; i < argc; i++) { + module_name = argv[1]; + + for (i = 2; i < argc; i++) { if (strcmp(argv[i], "-fb") == 0) { fbs = 1; } else if (strcmp(argv[i], "-crtcs") == 0) { @@ -316,9 +319,9 @@ void args(int argc, char **argv) full_props = 1; connectors = 1; } - } + } - if (argc == 1) { + if (argc == 2) { fbs = 1; edid = 1; crtcs = 1; @@ -329,16 +332,22 @@ void args(int argc, char **argv) connectors = 1; } } + int main(int argc, char **argv) { int fd; drmModeResPtr res; + if (argc == 1) { + printf("Please add modulename as first argument\n"); + return 1; + } + args(argc, argv); printf("Starting test\n"); - fd = drmOpen("i915", NULL); + fd = drmOpen(module_name, NULL); if (fd < 0) { printf("Failed to open the card fd (%d)\n",fd); -- cgit v1.2.3 From c48cddc7ef984c1e05ed4f64a7fc182b6a5031f5 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 5 Jul 2008 16:54:26 +0200 Subject: NV50: fix switch_fb and connector_is_digital --- linux-core/nv50_kms_wrapper.c | 52 ++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index ee18b36a..520028aa 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -348,7 +348,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) blank = true; } - if (!set->connectors && modeset) { + if (!set->connectors && (modeset || switch_fb)) { DRM_ERROR("Sanity check failed\n"); goto out; } @@ -368,7 +368,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) * Wiring up the encoders and connectors. */ - if (modeset) { + /* for switch_fb we verify if any important changes happened */ + if (modeset || switch_fb) { /* Mode validation */ hw_mode = nv50_kms_to_hw_mode(set->mode); @@ -398,10 +399,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) DRM_ERROR("Mode not ok\n"); goto out; } - } - /* Validation done, move on to cleaning of existing structures. */ + /* verify if any "sneaky" changes happened */ + if (output != connector->output) + modeset = true; + + if (output->crtc != crtc) + modeset = true; + } + } + /* Validation done, move on to cleaning of existing structures. */ + if (modeset) { /* find encoders that use this crtc. */ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { if (drm_encoder->crtc == set->crtc) { @@ -474,8 +483,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (blank) { crtc = to_nv50_crtc(set->crtc); - /* keeping the encoders and connectors attached, so they can be tracked */ set->crtc->enabled = false; + + /* disconnect encoders and connectors */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + + if (!drm_connector->encoder) + continue; + + drm_connector->encoder->crtc = NULL; + drm_connector->encoder = NULL; + } } /** @@ -535,9 +554,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - /* detach any outputs that are currently running on this crtc */ + /* detach any outputs that are currently unused */ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (drm_encoder->crtc == set->crtc) { + if (!drm_encoder->crtc) { output = to_nv50_output(drm_encoder); rval = output->execute_mode(output, true); @@ -556,12 +575,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (switch_fb && !modeset && !blank) { crtc = to_nv50_crtc(set->crtc); - rval = crtc->blank(crtc, true); - if (rval != 0) { - DRM_ERROR("blanking failed\n"); - goto out; - } - rval = crtc->set_fb(crtc); if (rval != 0) { DRM_ERROR("set_fb failed\n"); @@ -657,7 +670,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* next line changes crtc, so putting it here is important */ display->last_crtc = crtc->index; + } + if (switch_fb || modeset) { /* this is executed immediately */ list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) @@ -690,6 +705,13 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) display->update(display); + /* Update the current mode, now that all has gone well. */ + if (modeset) { + set->crtc->mode = *(set->mode); + set->crtc->x = set->x; + set->crtc->y = set->y; + } + kfree(hw_mode); return 0; @@ -826,7 +848,7 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) uint64_t prop_val; rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, &prop_val); - if (!rval) { + if (rval) { DRM_ERROR("Unable to find select subconnector property, defaulting to DVI-D\n"); return true; } @@ -842,7 +864,7 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) } rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &prop_val); - if (!rval) { + if (rval) { DRM_ERROR("Unable to find subconnector property, defaulting to DVI-D\n"); return true; } -- cgit v1.2.3 From e1cd21bcc8747fcc573708bd4d74df39b60c476a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 5 Jul 2008 20:17:49 +0200 Subject: NV50: remove edid when monitor is gone, improve fbcon, misc fixes - This should avoid switching crtc's when going to fbcon. --- linux-core/drm_crtc.c | 7 +++++++ linux-core/nv50_fbcon.c | 46 ++++++++++++++++++++++++++++++++++--------- linux-core/nv50_kms_wrapper.c | 31 ++++++++++++++++++----------- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f8e09a8c..47885a07 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2046,6 +2046,13 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, str if (connector->edid_blob_ptr) drm_property_destroy_blob(dev, connector->edid_blob_ptr); + /* Delete edid, when there is none. */ + if (!edid) { + connector->edid_blob_ptr = NULL; + ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0); + return ret; + } + connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, connector->edid_blob_ptr->base.id); diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c index c428ff94..8969860b 100644 --- a/linux-core/nv50_fbcon.c +++ b/linux-core/nv50_fbcon.c @@ -284,16 +284,21 @@ static int nv50_fbcon_set_par(struct fb_info *info) } mode_set.mode = drm_mode; - list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { - if (crtc_used[crtc_count]) { - crtc_count++; - continue; + /* choose crtc it already has, if possible */ + if (drm_connector->encoder) { + struct drm_encoder *drm_encoder = drm_connector->encoder; + + if (drm_encoder->crtc) { + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + crtc_count++; + + if (drm_crtc == drm_encoder->crtc) { + if (!crtc_used[crtc_count]) /* still available? */ + mode_set.crtc = drm_crtc; + break; + } + } } - - /* found a crtc */ - mode_set.crtc = drm_crtc; - - break; } /* proceed as planned */ @@ -302,6 +307,29 @@ static int nv50_fbcon_set_par(struct fb_info *info) crtc_used[crtc_count] = true; } + if (!mode_set.crtc) { + crtc_count = 0; /* reset */ + + /* choose a "random" crtc */ + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + if (crtc_used[crtc_count]) { + crtc_count++; + continue; + } + + /* found a crtc */ + mode_set.crtc = drm_crtc; + + break; + } + + /* proceed as planned */ + if (mode_set.crtc) { + mode_set.crtc->funcs->set_config(&mode_set); + crtc_used[crtc_count] = true; + } + } + kfree(mode_set.connectors); } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 520028aa..03c60c1f 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -348,16 +348,11 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) blank = true; } - if (!set->connectors && (modeset || switch_fb)) { + if (!set->connectors && !blank) { DRM_ERROR("Sanity check failed\n"); goto out; } - if (!modeset && !switch_fb && !blank) { - DRM_ERROR("There is nothing to do, bad input.\n"); - goto out; - } - /* Basic variable setting */ dev = set->crtc->dev; dev_priv = dev->dev_private; @@ -369,7 +364,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) */ /* for switch_fb we verify if any important changes happened */ - if (modeset || switch_fb) { + if (!blank) { /* Mode validation */ hw_mode = nv50_kms_to_hw_mode(set->mode); @@ -388,6 +383,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } connector = to_nv50_connector(drm_connector); + /* This is to ensure it knows the connector subtype. */ + drm_connector->funcs->fill_modes(drm_connector, 0, 0); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); @@ -409,6 +407,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } } + /* Now we verified if anything changed, fail if nothing has. */ + if (!modeset && !switch_fb && !blank) { + DRM_ERROR("There is nothing to do, bad input.\n"); + goto out; + } + /* Validation done, move on to cleaning of existing structures. */ if (modeset) { /* find encoders that use this crtc. */ @@ -913,6 +917,7 @@ static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector /* update our modes whenever there is reason to */ if (old_status != drm_connector->status) { drm_connector->funcs->fill_modes(drm_connector, 0, 0); + /* notify fb of changes */ dev->mode_config.funcs->fb_changed(dev); } @@ -966,16 +971,16 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u if (!connected) { NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); - /* TODO set EDID to NULL */ - return; } /* Not all connnectors have an i2c channel. */ - if (connector->i2c_chan) + if (connected && connector->i2c_chan) edid = (struct edid *) drm_do_probe_ddc_edid(&connector->i2c_chan->adapter); + /* This will remove edid if needed. */ + drm_mode_connector_update_edid_property(drm_connector, edid); + if (edid) { - drm_mode_connector_update_edid_property(drm_connector, edid); rval = drm_add_edid_modes(drm_connector, edid); /* 2 encoders per connector */ @@ -1026,6 +1031,10 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_mode_prune_invalid(dev, &drm_connector->modes, true); + /* pruning is done, so bail out. */ + if (!connected) + return; + if (list_empty(&drm_connector->modes)) { struct drm_display_mode *stdmode; struct nouveau_hw_mode *hw_mode; -- cgit v1.2.3 From d495a6e28f7fe5428c1ceb75378cad31b51a517a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 10:11:33 +0200 Subject: NV50: minor fix --- linux-core/nv50_kms_wrapper.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 03c60c1f..0954f0e8 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -408,10 +408,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /* Now we verified if anything changed, fail if nothing has. */ - if (!modeset && !switch_fb && !blank) { - DRM_ERROR("There is nothing to do, bad input.\n"); - goto out; - } + if (!modeset && !switch_fb && !blank) + DRM_INFO("A seemingly empty modeset encountered, this could be a bug.\n"); /* Validation done, move on to cleaning of existing structures. */ if (modeset) { @@ -676,7 +674,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) display->last_crtc = crtc->index; } - if (switch_fb || modeset) { + /* always reset dpms, regardless if any other modesetting is done. */ + if (!blank) { /* this is executed immediately */ list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) -- cgit v1.2.3 From e810cb9243fe6c4905182869d9e3272d861a14cb Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 10:52:25 +0200 Subject: modesetting-101: rename modeflags, as to avoid conflicts with the xorg definitions --- linux-core/drm_crtc_helper.c | 2 +- linux-core/drm_edid.c | 40 ++++++++++++++++++++-------------------- linux-core/drm_modes.c | 8 ++++---- linux-core/dvo_ch7xxx.c | 4 ++-- linux-core/intel_crt.c | 6 +++--- linux-core/intel_display.c | 2 +- linux-core/intel_dvo.c | 10 +++++----- linux-core/intel_fb.c | 4 ++-- linux-core/intel_sdvo.c | 6 +++--- linux-core/nv50_crtc.c | 10 +++++----- linux-core/nv50_dac.c | 4 ++-- linux-core/nv50_fbcon.c | 4 ++-- linux-core/nv50_kms_wrapper.c | 4 ++-- linux-core/nv50_sor.c | 4 ++-- shared-core/drm.h | 29 +++++++++++++++-------------- 15 files changed, 69 insertions(+), 68 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index bfddab99..d5a9f279 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -38,7 +38,7 @@ static struct drm_display_mode std_mode[] = { { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */ }; /** diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 22c6e3bf..a3d9861f 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -335,15 +335,15 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, drm_mode_set_name(mode); if (pt->interlaced) - mode->flags |= V_INTERLACE; + mode->flags |= DRM_MODE_FLAG_INTERLACE; if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { pt->hsync_positive = 1; pt->vsync_positive = 1; } - mode->flags |= pt->hsync_positive ? V_PHSYNC : V_NHSYNC; - mode->flags |= pt->vsync_positive ? V_PVSYNC : V_NVSYNC; + mode->flags |= pt->hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + mode->flags |= pt->vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; mode->width_mm = pt->width_mm_lo | (pt->width_mm_hi << 8); mode->height_mm = pt->height_mm_lo | (pt->height_mm_hi << 8); @@ -367,55 +367,55 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, static struct drm_display_mode edid_est_modes[] = { { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, - V_PHSYNC | V_PVSYNC) }, /* 800x600@60Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, - V_PHSYNC | V_PVSYNC) }, /* 800x600@56Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@75Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664, 704, 832, 0, 480, 489, 491, 520, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@72Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@67Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */ { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, - V_NHSYNC | V_NVSYNC) }, /* 720x400@88Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */ { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, - V_NHSYNC | V_PVSYNC) }, /* 720x400@70Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */ { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, - V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, - V_PHSYNC | V_PVSYNC) }, /* 1024x768@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, - V_NHSYNC | V_NVSYNC) }, /* 1024x768@70Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, - V_NHSYNC | V_NVSYNC) }, /* 1024x768@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032, 1208, 1264, 0, 768, 768, 776, 817, 0, - V_PHSYNC | V_PVSYNC | V_INTERLACE) }, /* 1024x768@43Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */ { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, - V_NHSYNC | V_NVSYNC) }, /* 832x624@75Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, - V_PHSYNC | V_PVSYNC) }, /* 800x600@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, - V_PHSYNC | V_PVSYNC) }, /* 800x600@72Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */ { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, - V_PHSYNC | V_PVSYNC) }, /* 1152x864@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */ }; #define EDID_EST_TIMINGS 16 diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index df670c74..4ee00305 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -162,9 +162,9 @@ int drm_mode_vrefresh(struct drm_display_mode *mode) calc_val /= mode->vtotal; refresh = calc_val; - if (mode->flags & V_INTERLACE) + if (mode->flags & DRM_MODE_FLAG_INTERLACE) refresh *= 2; - if (mode->flags & V_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) refresh /= 2; if (mode->vscan > 1) refresh /= mode->vscan; @@ -198,7 +198,7 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) p->crtc_vsync_end = p->vsync_end; p->crtc_vtotal = p->vtotal; - if (p->flags & V_INTERLACE) { + if (p->flags & DRM_MODE_FLAG_INTERLACE) { if (adjust_flags & CRTC_INTERLACE_HALVE_V) { p->crtc_vdisplay /= 2; p->crtc_vsync_start /= 2; @@ -209,7 +209,7 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) p->crtc_vtotal |= 1; } - if (p->flags & V_DBLSCAN) { + if (p->flags & DRM_MODE_FLAG_DBLSCAN) { p->crtc_vdisplay *= 2; p->crtc_vsync_start *= 2; p->crtc_vsync_end *= 2; diff --git a/linux-core/dvo_ch7xxx.c b/linux-core/dvo_ch7xxx.c index 18922556..1fe9eb0f 100644 --- a/linux-core/dvo_ch7xxx.c +++ b/linux-core/dvo_ch7xxx.c @@ -289,10 +289,10 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo, ch7xxx_readb(dvo, CH7xxx_IDF, &idf); idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP); - if (mode->flags & V_PHSYNC) + if (mode->flags & DRM_MODE_FLAG_PHSYNC) idf |= CH7xxx_IDF_HSP; - if (mode->flags & V_PVSYNC) + if (mode->flags & DRM_MODE_FLAG_PVSYNC) idf |= CH7xxx_IDF_HSP; ch7xxx_writeb(dvo, CH7xxx_IDF, idf); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index b9e8ee63..4326aef9 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -74,7 +74,7 @@ static void intel_crt_restore(struct drm_connector *connector) static int intel_crt_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - if (mode->flags & V_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; if (mode->clock > 400000 || mode->clock < 25000) @@ -118,9 +118,9 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, } adpa = 0; - if (adjusted_mode->flags & V_PHSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) adpa |= ADPA_HSYNC_ACTIVE_HIGH; - if (adjusted_mode->flags & V_PVSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) adpa |= ADPA_VSYNC_ACTIVE_HIGH; if (intel_crtc->pipe == 0) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 0a2854a2..b82993fc 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1112,7 +1112,7 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, /* VESA 640x480x72Hz mode to set on the pipe */ static struct drm_display_mode load_detect_mode = { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, - 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC), + 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), }; struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index e6df8fdd..a3842a91 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -139,7 +139,7 @@ static int intel_dvo_mode_valid(struct drm_connector *connector, struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; - if (mode->flags & V_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; /* XXX: Validate clock range */ @@ -225,9 +225,9 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, if (pipe == 1) dvo_val |= DVO_PIPE_B_SELECT; dvo_val |= DVO_PIPE_STALL; - if (adjusted_mode->flags & V_PHSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) dvo_val |= DVO_HSYNC_ACTIVE_HIGH; - if (adjusted_mode->flags & V_PVSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) dvo_val |= DVO_VSYNC_ACTIVE_HIGH; I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED); @@ -387,9 +387,9 @@ intel_dvo_get_current_mode (struct drm_connector *connector) if (mode) { mode->type |= DRM_MODE_TYPE_PREFERRED; if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) - mode->flags |= V_PHSYNC; + mode->flags |= DRM_MODE_FLAG_PHSYNC; if (dvo_val & DVO_VSYNC_ACTIVE_HIGH) - mode->flags |= V_PVSYNC; + mode->flags |= DRM_MODE_FLAG_PVSYNC; } } } diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index cbd22ba6..5637ea2f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -263,8 +263,8 @@ static int intelfb_set_par(struct fb_info *info) drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode->flags = 0; - drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; - drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index f0a47e2e..2143bdc0 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -602,9 +602,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, ((v_sync_len & 0x30) >> 4); output_dtd.part2.dtd_flags = 0x18; - if (mode->flags & V_PHSYNC) + if (mode->flags & DRM_MODE_FLAG_PHSYNC) output_dtd.part2.dtd_flags |= 0x2; - if (mode->flags & V_PVSYNC) + if (mode->flags & DRM_MODE_FLAG_PVSYNC) output_dtd.part2.dtd_flags |= 0x4; output_dtd.part2.sdvo_flags = 0; @@ -825,7 +825,7 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; - if (mode->flags & V_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; if (sdvo_priv->pixel_clock_min > mode->clock) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index c9745e08..6c3d404f 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -92,14 +92,14 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) vunk2a = 2*hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_start; vunk2b = hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_end; - if (hw_mode->flags & V_INTERLACE) { + if (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) { vsync_dur /= 2; vsync_start_to_end /= 2; vunk1 /= 2; vunk2a /= 2; vunk2b /= 2; /* magic */ - if (hw_mode->flags & V_DBLSCAN) { + if (hw_mode->flags & DRM_MODE_FLAG_DBLSCAN) { vsync_start_to_end -= 1; vunk1 -= 1; vunk2a -= 1; @@ -108,14 +108,14 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) } OUT_MODE(NV50_CRTC0_CLOCK + offset, hw_mode->clock | 0x800000); - OUT_MODE(NV50_CRTC0_INTERLACE + offset, (hw_mode->flags & V_INTERLACE) ? 2 : 0); + OUT_MODE(NV50_CRTC0_INTERLACE + offset, (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 0); OUT_MODE(NV50_CRTC0_DISPLAY_START + offset, 0); OUT_MODE(NV50_CRTC0_UNK82C + offset, 0); OUT_MODE(NV50_CRTC0_DISPLAY_TOTAL + offset, hw_mode->vtotal << 16 | hw_mode->htotal); OUT_MODE(NV50_CRTC0_SYNC_DURATION + offset, (vsync_dur - 1) << 16 | (hsync_dur - 1)); OUT_MODE(NV50_CRTC0_SYNC_START_TO_BLANK_END + offset, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1)); OUT_MODE(NV50_CRTC0_MODE_UNK1 + offset, (vunk1 - 1) << 16 | (hunk1 - 1)); - if (hw_mode->flags & V_INTERLACE) { + if (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) { OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset, (vunk2b - 1) << 16 | (vunk2a - 1)); } @@ -273,7 +273,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) /* Got a better name for SCALER_ACTIVE? */ /* One day i've got to really figure out why this is needed. */ - if ((crtc->mode->flags & V_DBLSCAN) || (crtc->mode->flags & V_INTERLACE) || + if ((crtc->mode->flags & DRM_MODE_FLAG_DBLSCAN) || (crtc->mode->flags & DRM_MODE_FLAG_INTERLACE) || crtc->mode->hdisplay != outX || crtc->mode->vdisplay != outY) { OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE); } else { diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index 34b54902..ce01d573 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -73,10 +73,10 @@ static int nv50_dac_execute_mode(struct nv50_output *output, bool disconnect) mode_ctl |= 0x100; } - if (desired_mode->flags & V_NHSYNC) + if (desired_mode->flags & DRM_MODE_FLAG_NHSYNC) mode_ctl2 |= NV50_DAC_MODE_CTRL2_NHSYNC; - if (desired_mode->flags & V_NVSYNC) + if (desired_mode->flags & DRM_MODE_FLAG_NVSYNC) mode_ctl2 |= NV50_DAC_MODE_CTRL2_NVSYNC; OUT_MODE(NV50_DAC0_MODE_CTRL + offset, mode_ctl); diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c index 8969860b..80597a76 100644 --- a/linux-core/nv50_fbcon.c +++ b/linux-core/nv50_fbcon.c @@ -239,8 +239,8 @@ static int nv50_fbcon_set_par(struct fb_info *info) drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode->flags = 0; - drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; - drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 0954f0e8..b7ba7b00 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -941,10 +941,10 @@ static void nv50_kms_connector_destroy(struct drm_connector *drm_connector) static struct drm_display_mode std_mode[] = { /*{ DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, - V_NHSYNC | V_NVSYNC) },*/ /* 640x480@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },*/ /* 640x480@60Hz */ { DRM_MODE("1280x1024", DRM_MODE_TYPE_DEFAULT, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, - V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */ }; static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, uint32_t maxX, uint32_t maxY) diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 4d82697e..021a45bf 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -77,10 +77,10 @@ static int nv50_sor_execute_mode(struct nv50_output *output, bool disconnect) else mode_ctl |= NV50_SOR_MODE_CTRL_CRTC0; - if (desired_mode->flags & V_NHSYNC) + if (desired_mode->flags & DRM_MODE_FLAG_NHSYNC) mode_ctl |= NV50_SOR_MODE_CTRL_NHSYNC; - if (desired_mode->flags & V_NVSYNC) + if (desired_mode->flags & DRM_MODE_FLAG_NVSYNC) mode_ctl |= NV50_SOR_MODE_CTRL_NVSYNC; OUT_MODE(NV50_SOR0_MODE_CTRL + offset, mode_ctl); diff --git a/shared-core/drm.h b/shared-core/drm.h index b64e265d..c7c7f13c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1011,20 +1011,21 @@ struct drm_mm_info_arg { #define DRM_MODE_TYPE_DRIVER (1<<6) /* Video mode flags */ -#define V_PHSYNC (1<<0) -#define V_NHSYNC (1<<1) -#define V_PVSYNC (1<<2) -#define V_NVSYNC (1<<3) -#define V_INTERLACE (1<<4) -#define V_DBLSCAN (1<<5) -#define V_CSYNC (1<<6) -#define V_PCSYNC (1<<7) -#define V_NCSYNC (1<<8) -#define V_HSKEW (1<<9) /* hskew provided */ -#define V_BCAST (1<<10) -#define V_PIXMUX (1<<11) -#define V_DBLCLK (1<<12) -#define V_CLKDIV2 (1<<13) +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_FLAG_PHSYNC (1<<0) +#define DRM_MODE_FLAG_NHSYNC (1<<1) +#define DRM_MODE_FLAG_PVSYNC (1<<2) +#define DRM_MODE_FLAG_NVSYNC (1<<3) +#define DRM_MODE_FLAG_INTERLACE (1<<4) +#define DRM_MODE_FLAG_DBLSCAN (1<<5) +#define DRM_MODE_FLAG_CSYNC (1<<6) +#define DRM_MODE_FLAG_PCSYNC (1<<7) +#define DRM_MODE_FLAG_NCSYNC (1<<8) +#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ +#define DRM_MODE_FLAG_BCAST (1<<10) +#define DRM_MODE_FLAG_PIXMUX (1<<11) +#define DRM_MODE_FLAG_DBLCLK (1<<12) +#define DRM_MODE_FLAG_CLKDIV2 (1<<13) /* DPMS flags */ #define DPMSModeOn 0 -- cgit v1.2.3 From 6738e7b00bf05529303ed690873495db6d83337c Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 11:08:49 +0200 Subject: modesetting-101: Rename DPMS modes to avoid compatibility issues with xorg definitions. --- linux-core/drm_crtc.c | 8 ++++---- linux-core/drm_crtc_helper.c | 4 ++-- linux-core/dvo_ch7017.c | 6 +++--- linux-core/dvo_ch7xxx.c | 2 +- linux-core/dvo_ivch.c | 6 +++--- linux-core/dvo_sil164.c | 2 +- linux-core/dvo_tfp410.c | 2 +- linux-core/intel_crt.c | 8 ++++---- linux-core/intel_display.c | 34 +++++++++++++++++----------------- linux-core/intel_dvo.c | 2 +- linux-core/intel_lvds.c | 2 +- linux-core/intel_sdvo.c | 12 ++++++------ linux-core/intel_tv.c | 8 ++++---- linux-core/nv50_dac.c | 8 ++++---- linux-core/nv50_kms_wrapper.c | 4 ++-- linux-core/nv50_sor.c | 2 +- shared-core/drm.h | 9 +++++---- 17 files changed, 60 insertions(+), 59 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 47885a07..fc8d1fe8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -43,10 +43,10 @@ struct drm_prop_enum_list { * Global properties */ static struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DPMSModeOn, "On" }, - { DPMSModeStandby, "Standby" }, - { DPMSModeSuspend, "Suspend" }, - { DPMSModeOff, "Off" } +{ { DRM_MODE_DPMS_ON, "On" }, + { DRM_MODE_DPMS_STANDBY, "Standby" }, + { DRM_MODE_DPMS_SUSPEND, "Suspend" }, + { DRM_MODE_DPMS_OFF, "Off" } }; char *drm_get_dpms_name(int val) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index d5a9f279..18fc9d98 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -182,14 +182,14 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { encoder_funcs = encoder->helper_private; if (!encoder->crtc) - (*encoder_funcs->dpms)(encoder, DPMSModeOff); + (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) { - crtc_funcs->dpms(crtc, DPMSModeOff); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); crtc->fb = NULL; } } diff --git a/linux-core/dvo_ch7017.c b/linux-core/dvo_ch7017.c index 194a7af1..b10e0388 100644 --- a/linux-core/dvo_ch7017.c +++ b/linux-core/dvo_ch7017.c @@ -327,7 +327,7 @@ static void ch7017_mode_set(struct intel_dvo_device *dvo, lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | (mode->hdisplay & 0x0700) >> 8; - ch7017_dpms(dvo, DPMSModeOff); + ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, horizontal_active_pixel_input); ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, @@ -363,7 +363,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode) CH7017_DAC3_POWER_DOWN | CH7017_TV_POWER_DOWN_EN); - if (mode == DPMSModeOn) { + if (mode == DRM_MODE_DPMS_ON) { /* Turn on the LVDS */ ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, val & ~CH7017_LVDS_POWER_DOWN_EN); @@ -418,7 +418,7 @@ static void ch7017_restore(struct intel_dvo_device *dvo) struct ch7017_priv *priv = dvo->dev_priv; /* Power down before changing mode */ - ch7017_dpms(dvo, DPMSModeOff); + ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi); ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo); diff --git a/linux-core/dvo_ch7xxx.c b/linux-core/dvo_ch7xxx.c index 1fe9eb0f..ebf54bff 100644 --- a/linux-core/dvo_ch7xxx.c +++ b/linux-core/dvo_ch7xxx.c @@ -301,7 +301,7 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo, /* set the CH7xxx power state */ static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode) { - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP); else ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD); diff --git a/linux-core/dvo_ivch.c b/linux-core/dvo_ivch.c index 7ba00b34..3a29ab6a 100644 --- a/linux-core/dvo_ivch.c +++ b/linux-core/dvo_ivch.c @@ -321,13 +321,13 @@ static void ivch_dpms(struct intel_dvo_device *dvo, int mode) if (!ivch_read(dvo, VR01, &vr01)) return; - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) backlight = 1; else backlight = 0; ivch_write(dvo, VR80, backlight); - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; else vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); @@ -339,7 +339,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, int mode) if (!ivch_read(dvo, VR30, &vr30)) break; - if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DPMSModeOn)) + if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DRM_MODE_DPMS_ON)) break; udelay(1000); } diff --git a/linux-core/dvo_sil164.c b/linux-core/dvo_sil164.c index d0fa4913..033a4bb0 100644 --- a/linux-core/dvo_sil164.c +++ b/linux-core/dvo_sil164.c @@ -226,7 +226,7 @@ static void sil164_dpms(struct intel_dvo_device *dvo, int mode) if (ret == false) return; - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) ch |= SIL164_8_PD; else ch &= ~SIL164_8_PD; diff --git a/linux-core/dvo_tfp410.c b/linux-core/dvo_tfp410.c index c1d1aa96..8e26235c 100644 --- a/linux-core/dvo_tfp410.c +++ b/linux-core/dvo_tfp410.c @@ -248,7 +248,7 @@ static void tfp410_dpms(struct intel_dvo_device *dvo, int mode) if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1)) return; - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) ctl1 |= TFP410_CTL_1_PD; else ctl1 &= ~TFP410_CTL_1_PD; diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 4326aef9..1b2b5b7e 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -44,16 +44,16 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) temp &= ~ADPA_DAC_ENABLE; switch(mode) { - case DPMSModeOn: + case DRM_MODE_DPMS_ON: temp |= ADPA_DAC_ENABLE; break; - case DPMSModeStandby: + case DRM_MODE_DPMS_STANDBY: temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; break; - case DPMSModeSuspend: + case DRM_MODE_DPMS_SUSPEND: temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; break; - case DPMSModeOff: + case DRM_MODE_DPMS_OFF: temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; break; } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index b82993fc..29aae169 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -468,12 +468,12 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) bool enabled; /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DPMSModeOff in the CRTC. + * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. */ switch (mode) { - case DPMSModeOn: - case DPMSModeStandby: - case DPMSModeSuspend: + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: /* Enable the DPLL */ temp = I915_READ(dpll_reg); if ((temp & DPLL_VCO_ENABLE) == 0) { @@ -509,7 +509,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) /* Give the overlay scaler a chance to enable if it's on this pipe */ //intel_crtc_dpms_video(crtc, TRUE); TODO break; - case DPMSModeOff: + case DRM_MODE_DPMS_OFF: /* Give the overlay scaler a chance to disable if it's on this pipe */ //intel_crtc_dpms_video(crtc, FALSE); TODO @@ -558,7 +558,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) if (!master_priv->sarea_priv) return; - enabled = crtc->enabled && mode != DPMSModeOff; + enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; switch (pipe) { case 0: @@ -580,27 +580,27 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) static void intel_crtc_prepare (struct drm_crtc *crtc) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DPMSModeOff); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); } static void intel_crtc_commit (struct drm_crtc *crtc) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DPMSModeOn); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); } void intel_encoder_prepare (struct drm_encoder *encoder) { struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; /* lvds has its own version of prepare see intel_lvds_prepare */ - encoder_funcs->dpms(encoder, DPMSModeOff); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); } void intel_encoder_commit (struct drm_encoder *encoder) { struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; /* lvds has its own version of commit see intel_lvds_commit */ - encoder_funcs->dpms(encoder, DPMSModeOn); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, @@ -1145,10 +1145,10 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, /* Make sure the crtc and connector are running */ intel_crtc = to_intel_crtc(crtc); *dpms_mode = intel_crtc->dpms_mode; - if (intel_crtc->dpms_mode != DPMSModeOn) { + if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DPMSModeOn); - encoder_funcs->dpms(encoder, DPMSModeOn); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } return crtc; } @@ -1184,9 +1184,9 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, mode = &load_detect_mode; drm_crtc_helper_set_mode(crtc, mode, 0, 0); } else { - if (intel_crtc->dpms_mode != DPMSModeOn) { + if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DPMSModeOn); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); } /* Add this connector to the crtc */ @@ -1215,7 +1215,7 @@ void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_ } /* Switch crtc and output back off if necessary */ - if (crtc->enabled && dpms_mode != DPMSModeOn) { + if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) { if (encoder->crtc == crtc) encoder_funcs->dpms(encoder, dpms_mode); crtc_funcs->dpms(crtc, dpms_mode); @@ -1378,7 +1378,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) } intel_crtc->cursor_addr = 0; - intel_crtc->dpms_mode = DPMSModeOff; + intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); intel_crtc->mode_set.crtc = &intel_crtc->base; diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index a3842a91..39ec65d2 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -93,7 +93,7 @@ static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) u32 dvo_reg = dvo->dvo_reg; u32 temp = I915_READ(dvo_reg); - if (mode == DPMSModeOn) { + if (mode == DRM_MODE_DPMS_ON) { I915_WRITE(dvo_reg, temp | DVO_ENABLE); I915_READ(dvo_reg); dvo->dev_ops->dpms(dvo, mode); diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 04e110e4..06b99867 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -93,7 +93,7 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) intel_lvds_set_power(dev, true); else intel_lvds_set_power(dev, false); diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 2143bdc0..6624bde2 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -363,16 +363,16 @@ static bool intel_sdvo_set_encoder_power_state(struct intel_output *intel_output u8 status, state = SDVO_ENCODER_STATE_ON; switch (mode) { - case DPMSModeOn: + case DRM_MODE_DPMS_ON: state = SDVO_ENCODER_STATE_ON; break; - case DPMSModeStandby: + case DRM_MODE_DPMS_STANDBY: state = SDVO_ENCODER_STATE_STANDBY; break; - case DPMSModeSuspend: + case DRM_MODE_DPMS_SUSPEND: state = SDVO_ENCODER_STATE_SUSPEND; break; - case DPMSModeOff: + case DRM_MODE_DPMS_OFF: state = SDVO_ENCODER_STATE_OFF; break; } @@ -691,12 +691,12 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u32 temp; - if (mode != DPMSModeOn) { + if (mode != DRM_MODE_DPMS_ON) { intel_sdvo_set_active_outputs(intel_output, 0); if (0) intel_sdvo_set_encoder_power_state(intel_output, mode); - if (mode == DPMSModeOff) { + if (mode == DRM_MODE_DPMS_OFF) { temp = I915_READ(sdvo_priv->output_device); if ((temp & SDVO_ENABLE) != 0) { intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE); diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index f564fa91..389487bb 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -904,12 +904,12 @@ intel_tv_dpms(struct drm_encoder *encoder, int mode) struct drm_i915_private *dev_priv = dev->dev_private; switch(mode) { - case DPMSModeOn: + case DRM_MODE_DPMS_ON: I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE); break; - case DPMSModeStandby: - case DPMSModeSuspend: - case DPMSModeOff: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); break; } diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index ce01d573..ca4bb5e1 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -109,17 +109,17 @@ static int nv50_dac_set_power_mode(struct nv50_output *output, int mode) val = NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & ~0x7F; - if (mode != DPMSModeOn) + if (mode != DRM_MODE_DPMS_ON) val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED; switch (mode) { - case DPMSModeStandby: + case DRM_MODE_DPMS_STANDBY: val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF; break; - case DPMSModeSuspend: + case DRM_MODE_DPMS_SUSPEND: val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF; break; - case DPMSModeOff: + case DRM_MODE_DPMS_OFF: val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF; val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF; val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index b7ba7b00..8f71e649 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -681,7 +681,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (output->crtc != crtc) continue; - rval = output->set_power_mode(output, DPMSModeOn); + rval = output->set_power_mode(output, DRM_MODE_DPMS_ON); if (rval != 0) { DRM_ERROR("output set power mode failed\n"); goto out; @@ -698,7 +698,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = drm_connector_property_set_value(drm_connector, dev->mode_config.dpms_property, - DPMSModeOn); + DRM_MODE_DPMS_ON); if (rval != 0) { DRM_ERROR("failed to update dpms state\n"); goto out; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 021a45bf..41116923 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -127,7 +127,7 @@ static int nv50_sor_set_power_mode(struct nv50_output *output, int mode) val = NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or)); - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) val |= NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON; else val &= ~NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON; diff --git a/shared-core/drm.h b/shared-core/drm.h index c7c7f13c..2e4d2a94 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1028,10 +1028,11 @@ struct drm_mm_info_arg { #define DRM_MODE_FLAG_CLKDIV2 (1<<13) /* DPMS flags */ -#define DPMSModeOn 0 -#define DPMSModeStandby 1 -#define DPMSModeSuspend 2 -#define DPMSModeOff 3 +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_DPMS_ON 0 +#define DRM_MODE_DPMS_STANDBY 1 +#define DRM_MODE_DPMS_SUSPEND 2 +#define DRM_MODE_DPMS_OFF 3 struct drm_mode_modeinfo { unsigned int clock; -- cgit v1.2.3 From 88f668a0b91a9961d599c46392f3acbb5573ed9d Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 11:23:17 +0200 Subject: NV50: fix minor bug in fbcon crtc selection --- linux-core/nv50_fbcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c index 80597a76..3dd73062 100644 --- a/linux-core/nv50_fbcon.c +++ b/linux-core/nv50_fbcon.c @@ -290,13 +290,13 @@ static int nv50_fbcon_set_par(struct fb_info *info) if (drm_encoder->crtc) { list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { - crtc_count++; - if (drm_crtc == drm_encoder->crtc) { if (!crtc_used[crtc_count]) /* still available? */ mode_set.crtc = drm_crtc; break; } + + crtc_count++; } } } -- cgit v1.2.3 From d5d3f31b108c8514a820bb50a5736ba06fc33275 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 12:51:43 +0200 Subject: NV50: init gamma storage --- linux-core/nv50_kms_wrapper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 8f71e649..a7966e9a 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -762,6 +762,9 @@ static int nv50_kms_crtcs_init(struct drm_device *dev) struct drm_crtc *drm_crtc = to_nv50_kms_crtc(crtc); drm_crtc_init(dev, drm_crtc, &nv50_kms_crtc_funcs); + + /* init lut storage */ + drm_mode_crtc_set_gamma_size(drm_crtc, 256); } return 0; -- cgit v1.2.3 From 0b7d9a97bd2383fe4382fc1b1b266542020f0c4e Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 7 Jul 2008 15:11:48 +0100 Subject: Synchronize the DDC EDID read to it's fb_ddc.c counterpart --- linux-core/drm_edid.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index a3d9861f..07894720 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -595,21 +595,13 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) unsigned char *edid = NULL; int i, j; - /* - * Startup the bus: - * Set clock line high (but give it time to come up) - * Then set clock & data low - */ algo_data->setscl(algo_data->data, 1); - udelay(550); /* startup delay */ - algo_data->setscl(algo_data->data, 0); - algo_data->setsda(algo_data->data, 0); for (i = 0; i < 3; i++) { /* For some old monitors we need the * following process to initialize/stop DDC */ - algo_data->setsda(algo_data->data, 0); + algo_data->setsda(algo_data->data, 1); msleep(13); algo_data->setscl(algo_data->data, 1); @@ -644,6 +636,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) algo_data->setsda(algo_data->data, 1); msleep(15); algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 0); if (edid) break; } -- cgit v1.2.3 From 7fd8a5de63781f6faa053509c80e02e8f1cdbb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 7 Jul 2008 11:56:59 -0400 Subject: Use lowercase bool constants. --- linux-core/drmP.h | 1 + linux-core/drm_agpsupport.c | 6 +-- linux-core/drm_crtc_helper.c | 2 +- linux-core/dvo_ch7xxx.c | 2 +- linux-core/dvo_ivch.c | 2 +- linux-core/dvo_tfp410.c | 4 +- linux-core/intel_crt.c | 4 +- linux-core/intel_display.c | 16 +++--- linux-core/intel_lvds.c | 4 +- linux-core/intel_tv.c | 116 +++++++++++++++++++++---------------------- linux-core/xgi_cmdlist.c | 6 +-- linux-core/xgi_drv.c | 4 +- linux-core/xgi_misc.c | 26 +++++----- 13 files changed, 97 insertions(+), 96 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4a9cc761..8c745502 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -54,6 +54,7 @@ #include /* For (un)lock_kernel */ #include #include +#include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index d6594b87..3cc94ff7 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -517,7 +517,7 @@ drm_agp_bind_pages(struct drm_device *dev, mem->memory[i] = phys_to_gart(page_to_phys(pages[i])); mem->page_count = num_pages; - mem->is_flushed = TRUE; + mem->is_flushed = true; ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE); if (ret != 0) { DRM_ERROR("Failed to bind AGP memory: %d\n", ret); @@ -597,7 +597,7 @@ static int drm_agp_bind_ttm(struct drm_ttm_backend *backend, int snooped = (bo_mem->flags & DRM_BO_FLAG_CACHED) && !(bo_mem->flags & DRM_BO_FLAG_CACHED_MAPPED); DRM_DEBUG("drm_agp_bind_ttm\n"); - mem->is_flushed = TRUE; + mem->is_flushed = true; mem->type = AGP_USER_MEMORY; /* CACHED MAPPED implies not snooped memory */ if (snooped) @@ -696,7 +696,7 @@ struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev) agp_be->mem = NULL; agp_be->bridge = dev->agp->bridge; - agp_be->populated = FALSE; + agp_be->populated = false; agp_be->backend.func = &agp_ttm_backend; agp_be->backend.dev = dev; diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index bfddab99..ffd20342 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -95,7 +95,7 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ui } - drm_mode_prune_invalid(dev, &connector->modes, TRUE); + drm_mode_prune_invalid(dev, &connector->modes, true); if (list_empty(&connector->modes)) { struct drm_display_mode *stdmode; diff --git a/linux-core/dvo_ch7xxx.c b/linux-core/dvo_ch7xxx.c index 18922556..f9beac0b 100644 --- a/linux-core/dvo_ch7xxx.c +++ b/linux-core/dvo_ch7xxx.c @@ -221,7 +221,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo, goto out; } - ch7xxx->quiet = FALSE; + ch7xxx->quiet = false; DRM_DEBUG("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n", name, vendor, device); return true; diff --git a/linux-core/dvo_ivch.c b/linux-core/dvo_ivch.c index 7ba00b34..5af7a9b1 100644 --- a/linux-core/dvo_ivch.c +++ b/linux-core/dvo_ivch.c @@ -265,7 +265,7 @@ static bool ivch_init(struct intel_dvo_device *dvo, dvo->i2c_bus = i2cbus; dvo->i2c_bus->slave_addr = dvo->slave_addr; dvo->dev_priv = priv; - priv->quiet = TRUE; + priv->quiet = true; if (!ivch_read(dvo, VR00, &temp)) goto out; diff --git a/linux-core/dvo_tfp410.c b/linux-core/dvo_tfp410.c index c1d1aa96..65b76c86 100644 --- a/linux-core/dvo_tfp410.c +++ b/linux-core/dvo_tfp410.c @@ -187,7 +187,7 @@ static bool tfp410_init(struct intel_dvo_device *dvo, dvo->i2c_bus = i2cbus; dvo->i2c_bus->slave_addr = dvo->slave_addr; dvo->dev_priv = tfp; - tfp->quiet = TRUE; + tfp->quiet = true; if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) { DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n", @@ -200,7 +200,7 @@ static bool tfp410_init(struct intel_dvo_device *dvo, id, i2cbus->adapter.name, i2cbus->slave_addr); goto out; } - tfp->quiet = FALSE; + tfp->quiet = false; return true; out: kfree(tfp); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index b9e8ee63..2e1611e1 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -136,8 +136,8 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, * * Not for i915G/i915GM * - * \return TRUE if CRT is connected. - * \return FALSE if CRT is disconnected. + * \return true if CRT is connected. + * \return false if CRT is disconnected. */ static bool intel_crt_detect_hotplug(struct drm_connector *connector) { diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 50ad1a27..40cbc492 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -510,7 +510,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc_load_lut(crtc); /* Give the overlay scaler a chance to enable if it's on this pipe */ - //intel_crtc_dpms_video(crtc, TRUE); TODO + //intel_crtc_dpms_video(crtc, true); TODO break; case DPMSModeOff: /* Give the overlay scaler a chance to disable if it's on this pipe */ @@ -737,19 +737,19 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc, switch (intel_output->type) { case INTEL_OUTPUT_LVDS: - is_lvds = TRUE; + is_lvds = true; break; case INTEL_OUTPUT_SDVO: - is_sdvo = TRUE; + is_sdvo = true; break; case INTEL_OUTPUT_DVO: - is_dvo = TRUE; + is_dvo = true; break; case INTEL_OUTPUT_TVOUT: - is_tv = TRUE; + is_tv = true; break; case INTEL_OUTPUT_ANALOG: - is_crt = TRUE; + is_crt = true; break; } } @@ -1177,7 +1177,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, } encoder->crtc = crtc; - intel_output->load_detect_temp = TRUE; + intel_output->load_detect_temp = true; intel_crtc = to_intel_crtc(crtc); *dpms_mode = intel_crtc->dpms_mode; @@ -1212,7 +1212,7 @@ void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_ if (intel_output->load_detect_temp) { encoder->crtc = NULL; - intel_output->load_detect_temp = FALSE; + intel_output->load_detect_temp = false; crtc->enabled = drm_helper_crtc_in_use(crtc); drm_helper_disable_unused_functions(dev); } diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 04e110e4..69d88497 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -407,8 +407,8 @@ void intel_lvds_init(struct drm_device *dev) drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs); drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs); connector->display_info.subpixel_order = SubPixelHorizontalRGB; - connector->interlace_allowed = FALSE; - connector->doublescan_allowed = FALSE; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; /* diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 39f33d6c..ba680635 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -422,18 +422,18 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 124, .hblank_start = 836, .htotal = 857, - .progressive = FALSE, .trilevel_sync = FALSE, + .progressive = false, .trilevel_sync = false, .vsync_start_f1 = 6, .vsync_start_f2 = 7, .vsync_len = 6, - .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_ena = true, .veq_start_f1 = 0, .veq_start_f2 = 1, .veq_len = 18, .vi_end_f1 = 20, .vi_end_f2 = 21, .nbr_end = 240, - .burst_ena = TRUE, + .burst_ena = true, .hburst_start = 72, .hburst_len = 34, .vburst_start_f1 = 9, .vburst_end_f1 = 240, .vburst_start_f2 = 10, .vburst_end_f2 = 240, @@ -445,7 +445,7 @@ const static struct tv_mode tv_modes[] = { .dda2_inc = 7624, .dda2_size = 20013, .dda3_inc = 0, .dda3_size = 0, .sc_reset = TV_SC_RESET_EVERY_4, - .pal_burst = FALSE, + .pal_burst = false, .composite_levels = &ntsc_m_levels_composite, .composite_color = &ntsc_m_csc_composite, @@ -464,12 +464,12 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 124, .hblank_start = 836, .htotal = 857, - .progressive = FALSE, .trilevel_sync = FALSE, + .progressive = false, .trilevel_sync = false, .vsync_start_f1 = 6, .vsync_start_f2 = 7, .vsync_len = 6, - .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_ena = true, .veq_start_f1 = 0, .veq_start_f2 = 1, .veq_len = 18, .vi_end_f1 = 20, .vi_end_f2 = 21, @@ -487,7 +487,7 @@ const static struct tv_mode tv_modes[] = { .dda2_inc = 18557, .dda2_size = 20625, .dda3_inc = 0, .dda3_size = 0, .sc_reset = TV_SC_RESET_EVERY_8, - .pal_burst = TRUE, + .pal_burst = true, .composite_levels = &ntsc_m_levels_composite, .composite_color = &ntsc_m_csc_composite, @@ -507,18 +507,18 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 124, .hblank_start = 836, .htotal = 857, - .progressive = FALSE, .trilevel_sync = FALSE, + .progressive = false, .trilevel_sync = false, .vsync_start_f1 = 6, .vsync_start_f2 = 7, .vsync_len = 6, - .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_ena = true, .veq_start_f1 = 0, .veq_start_f2 = 1, .veq_len = 18, .vi_end_f1 = 20, .vi_end_f2 = 21, .nbr_end = 240, - .burst_ena = TRUE, + .burst_ena = true, .hburst_start = 72, .hburst_len = 34, .vburst_start_f1 = 9, .vburst_end_f1 = 240, .vburst_start_f2 = 10, .vburst_end_f2 = 240, @@ -530,7 +530,7 @@ const static struct tv_mode tv_modes[] = { .dda2_inc = 7624, .dda2_size = 20013, .dda3_inc = 0, .dda3_size = 0, .sc_reset = TV_SC_RESET_EVERY_4, - .pal_burst = FALSE, + .pal_burst = false, .composite_levels = &ntsc_j_levels_composite, .composite_color = &ntsc_j_csc_composite, @@ -550,18 +550,18 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 124, .hblank_start = 836, .htotal = 857, - .progressive = FALSE, .trilevel_sync = FALSE, + .progressive = false, .trilevel_sync = false, .vsync_start_f1 = 6, .vsync_start_f2 = 7, .vsync_len = 6, - .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_ena = true, .veq_start_f1 = 0, .veq_start_f2 = 1, .veq_len = 18, .vi_end_f1 = 20, .vi_end_f2 = 21, .nbr_end = 240, - .burst_ena = TRUE, + .burst_ena = true, .hburst_start = 72, .hburst_len = 34, .vburst_start_f1 = 9, .vburst_end_f1 = 240, .vburst_start_f2 = 10, .vburst_end_f2 = 240, @@ -573,7 +573,7 @@ const static struct tv_mode tv_modes[] = { .dda2_inc = 7624, .dda2_size = 20013, .dda3_inc = 0, .dda3_size = 0, .sc_reset = TV_SC_RESET_EVERY_4, - .pal_burst = FALSE, + .pal_burst = false, .composite_levels = &pal_m_levels_composite, .composite_color = &pal_m_csc_composite, @@ -593,19 +593,19 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 128, .hblank_start = 844, .htotal = 863, - .progressive = FALSE, .trilevel_sync = FALSE, + .progressive = false, .trilevel_sync = false, .vsync_start_f1 = 6, .vsync_start_f2 = 7, .vsync_len = 6, - .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_ena = true, .veq_start_f1 = 0, .veq_start_f2 = 1, .veq_len = 18, .vi_end_f1 = 24, .vi_end_f2 = 25, .nbr_end = 286, - .burst_ena = TRUE, + .burst_ena = true, .hburst_start = 73, .hburst_len = 34, .vburst_start_f1 = 8, .vburst_end_f1 = 285, .vburst_start_f2 = 8, .vburst_end_f2 = 286, @@ -618,7 +618,7 @@ const static struct tv_mode tv_modes[] = { .dda2_inc = 18557, .dda2_size = 20625, .dda3_inc = 0, .dda3_size = 0, .sc_reset = TV_SC_RESET_EVERY_8, - .pal_burst = TRUE, + .pal_burst = true, .composite_levels = &pal_n_levels_composite, .composite_color = &pal_n_csc_composite, @@ -638,18 +638,18 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 128, .hblank_start = 844, .htotal = 863, - .progressive = FALSE, .trilevel_sync = FALSE, + .progressive = false, .trilevel_sync = false, .vsync_start_f1 = 5, .vsync_start_f2 = 6, .vsync_len = 5, - .veq_ena = TRUE, .veq_start_f1 = 0, + .veq_ena = true, .veq_start_f1 = 0, .veq_start_f2 = 1, .veq_len = 15, .vi_end_f1 = 24, .vi_end_f2 = 25, .nbr_end = 286, - .burst_ena = TRUE, + .burst_ena = true, .hburst_start = 73, .hburst_len = 32, .vburst_start_f1 = 8, .vburst_end_f1 = 285, .vburst_start_f2 = 8, .vburst_end_f2 = 286, @@ -661,7 +661,7 @@ const static struct tv_mode tv_modes[] = { .dda2_inc = 18557, .dda2_size = 20625, .dda3_inc = 0, .dda3_size = 0, .sc_reset = TV_SC_RESET_EVERY_8, - .pal_burst = TRUE, + .pal_burst = true, .composite_levels = &pal_levels_composite, .composite_color = &pal_csc_composite, @@ -680,17 +680,17 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 122, .hblank_start = 842, .htotal = 857, - .progressive = TRUE,.trilevel_sync = FALSE, + .progressive = true,.trilevel_sync = false, .vsync_start_f1 = 12, .vsync_start_f2 = 12, .vsync_len = 12, - .veq_ena = FALSE, + .veq_ena = false, .vi_end_f1 = 44, .vi_end_f2 = 44, .nbr_end = 496, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, }, @@ -704,17 +704,17 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 122, .hblank_start = 842, .htotal = 856, - .progressive = TRUE,.trilevel_sync = FALSE, + .progressive = true,.trilevel_sync = false, .vsync_start_f1 = 12, .vsync_start_f2 = 12, .vsync_len = 12, - .veq_ena = FALSE, + .veq_ena = false, .vi_end_f1 = 44, .vi_end_f2 = 44, .nbr_end = 496, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, }, @@ -728,17 +728,17 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 64, .hblank_end = 139, .hblank_start = 859, .htotal = 863, - .progressive = TRUE, .trilevel_sync = FALSE, + .progressive = true, .trilevel_sync = false, .vsync_start_f1 = 10, .vsync_start_f2 = 10, .vsync_len = 10, - .veq_ena = FALSE, + .veq_ena = false, .vi_end_f1 = 48, .vi_end_f2 = 48, .nbr_end = 575, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, }, @@ -752,17 +752,17 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 80, .hblank_end = 300, .hblank_start = 1580, .htotal = 1649, - .progressive = TRUE, .trilevel_sync = TRUE, + .progressive = true, .trilevel_sync = true, .vsync_start_f1 = 10, .vsync_start_f2 = 10, .vsync_len = 10, - .veq_ena = FALSE, + .veq_ena = false, .vi_end_f1 = 29, .vi_end_f2 = 29, .nbr_end = 719, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, }, @@ -776,17 +776,17 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 80, .hblank_end = 300, .hblank_start = 1580, .htotal = 1651, - .progressive = TRUE, .trilevel_sync = TRUE, + .progressive = true, .trilevel_sync = true, .vsync_start_f1 = 10, .vsync_start_f2 = 10, .vsync_len = 10, - .veq_ena = FALSE, + .veq_ena = false, .vi_end_f1 = 29, .vi_end_f2 = 29, .nbr_end = 719, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, }, @@ -800,17 +800,17 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 80, .hblank_end = 300, .hblank_start = 1580, .htotal = 1979, - .progressive = TRUE, .trilevel_sync = TRUE, + .progressive = true, .trilevel_sync = true, .vsync_start_f1 = 10, .vsync_start_f2 = 10, .vsync_len = 10, - .veq_ena = FALSE, + .veq_ena = false, .vi_end_f1 = 29, .vi_end_f2 = 29, .nbr_end = 719, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, .max_srcw = 800 @@ -825,19 +825,19 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 88, .hblank_end = 235, .hblank_start = 2155, .htotal = 2639, - .progressive = FALSE, .trilevel_sync = TRUE, + .progressive = false, .trilevel_sync = true, .vsync_start_f1 = 4, .vsync_start_f2 = 5, .vsync_len = 10, - .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_ena = true, .veq_start_f1 = 4, .veq_start_f2 = 4, .veq_len = 10, .vi_end_f1 = 21, .vi_end_f2 = 22, .nbr_end = 539, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, }, @@ -851,19 +851,19 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 88, .hblank_end = 235, .hblank_start = 2155, .htotal = 2199, - .progressive = FALSE, .trilevel_sync = TRUE, + .progressive = false, .trilevel_sync = true, .vsync_start_f1 = 4, .vsync_start_f2 = 5, .vsync_len = 10, - .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_ena = true, .veq_start_f1 = 4, .veq_start_f2 = 4, .veq_len = 10, .vi_end_f1 = 21, .vi_end_f2 = 22, .nbr_end = 539, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, }, @@ -877,19 +877,19 @@ const static struct tv_mode tv_modes[] = { .hsync_end = 88, .hblank_end = 235, .hblank_start = 2155, .htotal = 2200, - .progressive = FALSE, .trilevel_sync = TRUE, + .progressive = false, .trilevel_sync = true, .vsync_start_f1 = 4, .vsync_start_f2 = 5, .vsync_len = 10, - .veq_ena = TRUE, .veq_start_f1 = 4, + .veq_ena = true, .veq_start_f1 = 4, .veq_start_f2 = 4, .veq_len = 10, .vi_end_f1 = 21, .vi_end_f2 = 22, .nbr_end = 539, - .burst_ena = FALSE, + .burst_ena = false, .filter_table = filter_table, }, @@ -1098,17 +1098,17 @@ intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_encoder *other_encoder; if (!tv_mode) - return FALSE; + return false; /* FIXME: lock encoder list */ list_for_each_entry(other_encoder, &drm_config->encoder_list, head) { if (other_encoder != encoder && other_encoder->crtc == encoder->crtc) - return FALSE; + return false; } adjusted_mode->clock = tv_mode->clock; - return TRUE; + return true; } static void @@ -1152,7 +1152,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, color_conversion = &sdtv_csc_yprpb; else color_conversion = &hdtv_csc_yprpb; - burst_ena = FALSE; + burst_ena = false; break; case DRM_MODE_CONNECTOR_SVIDEO: tv_ctl |= TV_ENC_OUTPUT_SVIDEO; @@ -1352,8 +1352,8 @@ static const struct drm_display_mode reported_modes[] = { * * Requires that the current pipe's DPLL is active. - * \return TRUE if TV is connected. - * \return FALSE if TV is disconnected. + * \return true if TV is connected. + * \return false if TV is disconnected. */ static int intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output) @@ -1703,8 +1703,8 @@ intel_tv_init(struct drm_device *dev) drm_encoder_helper_add(&intel_output->enc, &intel_tv_helper_funcs); drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); - connector->interlace_allowed = FALSE; - connector->doublescan_allowed = FALSE; + connector->interlace_allowed = false; + connector->doublescan_allowed = false; /* Create TV properties then attach current values */ tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, diff --git a/linux-core/xgi_cmdlist.c b/linux-core/xgi_cmdlist.c index 64401ae5..b31ac2d4 100644 --- a/linux-core/xgi_cmdlist.c +++ b/linux-core/xgi_cmdlist.c @@ -135,7 +135,7 @@ int xgi_submit_cmdlist(struct drm_device * dev, void * data, DRM_DEBUG("info->cmdring.last_ptr != NULL\n"); if (pCmdInfo->type == BTYPE_3D) { - xgi_emit_flush(info, FALSE); + xgi_emit_flush(info, false); } info->cmdring.last_ptr[1] = cpu_to_le32(begin[1]); @@ -214,7 +214,7 @@ void xgi_cmdlist_cleanup(struct xgi_info * info) * list chain with a flush command. */ if (info->cmdring.last_ptr != NULL) { - xgi_emit_flush(info, FALSE); + xgi_emit_flush(info, false); xgi_emit_nop(info); } @@ -322,5 +322,5 @@ void xgi_emit_irq(struct xgi_info * info) if (info->cmdring.last_ptr == NULL) return; - xgi_emit_flush(info, TRUE); + xgi_emit_flush(info, true); } diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index f0225f89..f8ed7de8 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -307,8 +307,8 @@ void xgi_driver_lastclose(struct drm_device * dev) || info->pcie_heap_initialized) { drm_sman_cleanup(&info->sman); - info->fb_heap_initialized = FALSE; - info->pcie_heap_initialized = FALSE; + info->fb_heap_initialized = false; + info->pcie_heap_initialized = false; } } } diff --git a/linux-core/xgi_misc.c b/linux-core/xgi_misc.c index 2b3a1788..2a9632f6 100644 --- a/linux-core/xgi_misc.c +++ b/linux-core/xgi_misc.c @@ -46,41 +46,41 @@ static bool xgi_validate_signal(struct drm_map * map) check = le16_to_cpu(DRM_READ16(map, 0x2360)); if ((check & 0x3f) != ((check & 0x3f00) >> 8)) { - return FALSE; + return false; } /* Check RO channel */ DRM_WRITE8(map, 0x235c, 0x83); check = le16_to_cpu(DRM_READ16(map, 0x2360)); if ((check & 0x0f) != ((check & 0xf0) >> 4)) { - return FALSE; + return false; } /* Check RW channel */ DRM_WRITE8(map, 0x235c, 0x88); check = le16_to_cpu(DRM_READ16(map, 0x2360)); if ((check & 0x0f) != ((check & 0xf0) >> 4)) { - return FALSE; + return false; } /* Check RO channel outstanding */ DRM_WRITE8(map, 0x235c, 0x8f); check = le16_to_cpu(DRM_READ16(map, 0x2360)); if (0 != (check & 0x3ff)) { - return FALSE; + return false; } /* Check RW channel outstanding */ DRM_WRITE8(map, 0x235c, 0x90); check = le16_to_cpu(DRM_READ16(map, 0x2360)); if (0 != (check & 0x3ff)) { - return FALSE; + return false; } /* No pending PCIE request. GE stall. */ } - return TRUE; + return true; } @@ -138,7 +138,7 @@ static void xgi_ge_hang_reset(struct drm_map * map) bool xgi_ge_irq_handler(struct xgi_info * info) { const u32 int_status = le32_to_cpu(DRM_READ32(info->mmio_map, 0x2810)); - bool is_support_auto_reset = FALSE; + bool is_support_auto_reset = false; /* Check GE on/off */ if (0 == (0xffffc0f0 & int_status)) { @@ -179,15 +179,15 @@ bool xgi_ge_irq_handler(struct xgi_info * info) cpu_to_le32((int_status & ~0x01) | 0x04000000)); } - return TRUE; + return true; } - return FALSE; + return false; } bool xgi_crt_irq_handler(struct xgi_info * info) { - bool ret = FALSE; + bool ret = false; u8 save_3ce = DRM_READ8(info->mmio_map, 0x3ce); /* CRT1 interrupt just happened @@ -205,7 +205,7 @@ bool xgi_crt_irq_handler(struct xgi_info * info) op3cf_3d = IN3CFB(info->mmio_map, 0x3d); OUT3CFB(info->mmio_map, 0x3d, (op3cf_3d | 0x04)); OUT3CFB(info->mmio_map, 0x3d, (op3cf_3d & ~0x04)); - ret = TRUE; + ret = true; } DRM_WRITE8(info->mmio_map, 0x3ce, save_3ce); @@ -214,7 +214,7 @@ bool xgi_crt_irq_handler(struct xgi_info * info) bool xgi_dvi_irq_handler(struct xgi_info * info) { - bool ret = FALSE; + bool ret = false; const u8 save_3ce = DRM_READ8(info->mmio_map, 0x3ce); /* DVI interrupt just happened @@ -242,7 +242,7 @@ bool xgi_dvi_irq_handler(struct xgi_info * info) OUT3C5B(info->mmio_map, 0x39, (op3cf_39 & ~0x01)); OUT3C5B(info->mmio_map, 0x39, (op3cf_39 | 0x01)); - ret = TRUE; + ret = true; } DRM_WRITE8(info->mmio_map, 0x3ce, save_3ce); -- cgit v1.2.3 From 38a5f6686cd38d5204e240f30006538bcf70f5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 7 Jul 2008 18:00:23 -0400 Subject: Add back flink, open and close ioctls. They fell through the cracks in 86accbcb. --- linux-core/drm_drv.c | 4 ++ linux-core/drm_gem.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++ shared-core/drm.h | 29 +++++++--- 3 files changed, 174 insertions(+), 7 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index c47ed12b..555fdcdf 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -175,6 +175,10 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_BO_VERSION, drm_bo_version_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MM_INFO, drm_mm_info_ioctl, 0), + + DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0), + DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), }; #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 76d7aa94..434155b3 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -116,6 +116,45 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) } EXPORT_SYMBOL(drm_gem_object_alloc); +/** + * Removes the mapping from handle to filp for this object. + */ +static int +drm_gem_handle_delete(struct drm_file *filp, int handle) +{ + struct drm_device *dev; + struct drm_gem_object *obj; + + /* This is gross. The idr system doesn't let us try a delete and + * return an error code. It just spews if you fail at deleting. + * So, we have to grab a lock around finding the object and then + * doing the delete on it and dropping the refcount, or the user + * could race us to double-decrement the refcount and cause a + * use-after-free later. Given the frequency of our handle lookups, + * we may want to use ida for number allocation and a hash table + * for the pointers, anyway. + */ + spin_lock(&filp->table_lock); + + /* Check if we currently have a reference on the object */ + obj = idr_find(&filp->object_idr, handle); + if (obj == NULL) { + spin_unlock(&filp->table_lock); + return -EINVAL; + } + dev = obj->dev; + + /* Release reference and decrement refcount. */ + idr_remove(&filp->object_idr, handle); + spin_unlock(&filp->table_lock); + + mutex_lock(&dev->struct_mutex); + drm_gem_object_handle_unreference(obj); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + /** * Create a handle for this object. This adds a handle reference * to the object, which includes a regular reference count. Callers @@ -175,6 +214,115 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, } EXPORT_SYMBOL(drm_gem_object_lookup); +/** + * Releases the handle to an mm object. + */ +int +drm_gem_close_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_close *args = data; + int ret; + + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + + ret = drm_gem_handle_delete(file_priv, args->handle); + + return ret; +} + +/** + * Create a global name for an object, returning the name. + * + * Note that the name does not hold a reference; when the object + * is freed, the name goes away. + */ +int +drm_gem_flink_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_flink *args = data; + struct drm_gem_object *obj; + int ret; + + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + +again: + if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) + return -ENOMEM; + + spin_lock(&dev->object_name_lock); + if (obj->name) { + spin_unlock(&dev->object_name_lock); + return -EEXIST; + } + ret = idr_get_new_above(&dev->object_name_idr, obj, 1, + &obj->name); + spin_unlock(&dev->object_name_lock); + if (ret == -EAGAIN) + goto again; + + if (ret != 0) { + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + return ret; + } + + /* + * Leave the reference from the lookup around as the + * name table now holds one + */ + args->name = (uint64_t) obj->name; + + return 0; +} + +/** + * Open an object using the global name, returning a handle and the size. + * + * This handle (of course) holds a reference to the object, so the object + * will not go away until the handle is deleted. + */ +int +drm_gem_open_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_open *args = data; + struct drm_gem_object *obj; + int ret; + int handle; + + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + + spin_lock(&dev->object_name_lock); + obj = idr_find(&dev->object_name_idr, (int) args->name); + if (obj) + drm_gem_object_reference(obj); + spin_unlock(&dev->object_name_lock); + if (!obj) + return -ENOENT; + + ret = drm_gem_handle_create(file_priv, obj, &handle); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + if (ret) + return ret; + + args->handle = handle; + args->size = obj->size; + + return 0; +} + /** * Called at device open time, sets up the structure for handling refcounting * of mm objects. diff --git a/shared-core/drm.h b/shared-core/drm.h index 2d0f1f4d..382e3fa1 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -993,15 +993,30 @@ struct drm_mm_info_arg { uint64_t p_size; }; -struct drm_gem_set_domain { - /** Handle for the object */ +struct drm_gem_close { + /** Handle of the object to be closed. */ uint32_t handle; - /** New read domains */ - uint32_t read_domains; - /** New write domain */ - uint32_t write_domain; + uint32_t pad; +}; + +struct drm_gem_flink { + /** Handle for the object being named */ + uint32_t handle; + + /** Returned global name */ + uint32_t name; +}; + +struct drm_gem_open { + /** Name of object being opened */ + uint32_t name; + + /** Returned handle for the object */ + uint32_t handle; + + /** Returned size of the object */ + uint64_t size; }; -#define DRM_GEM_DOMAIN_CPU 0x00000001 /* * Drm mode setting -- cgit v1.2.3 From a9089c45570c7b2df9155c2cd73aeea59cc0e34e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 12 Jul 2008 16:32:09 +1000 Subject: modesetting/helper: fix array overrun - count should be reset here --- linux-core/drm_crtc_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 18fc9d98..ec76aa93 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -566,7 +566,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ret = -EINVAL; goto fail_no_encoder; } - + + count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) continue; -- cgit v1.2.3 From 4872ac9c6204c3f212fd622ed292f6fc245020bf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 25 Jun 2008 04:39:32 +1000 Subject: nouveau: interface changes for nv5x 3d --- shared-core/nouveau_drm.h | 20 +++++++++---- shared-core/nouveau_drv.h | 4 ++- shared-core/nouveau_fifo.c | 1 + shared-core/nouveau_mem.c | 71 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 87 insertions(+), 9 deletions(-) diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index bbb51bc4..4b5869ad 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,7 +25,7 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 10 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 11 struct drm_nouveau_channel_alloc { uint32_t fb_ctxdma_handle; @@ -85,10 +85,12 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_MEM_PINNED 0x00000040 #define NOUVEAU_MEM_USER_BACKED 0x00000080 #define NOUVEAU_MEM_MAPPED 0x00000100 -#define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */ -#define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */ -#define NOUVEAU_MEM_NOVM 0x00000800 /* internal */ -#define NOUVEAU_MEM_USER 0x00001000 /* internal */ +#define NOUVEAU_MEM_TILE 0x00000200 +#define NOUVEAU_MEM_TILE_ZETA 0x00000400 +#define NOUVEAU_MEM_INSTANCE 0x01000000 /* internal */ +#define NOUVEAU_MEM_NOTIFIER 0x02000000 /* internal */ +#define NOUVEAU_MEM_NOVM 0x04000000 /* internal */ +#define NOUVEAU_MEM_USER 0x08000000 /* internal */ #define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \ NOUVEAU_MEM_NOTIFIER | \ NOUVEAU_MEM_NOVM | \ @@ -107,6 +109,13 @@ struct drm_nouveau_mem_free { int flags; }; +struct drm_nouveau_mem_tile { + uint64_t offset; + uint64_t delta; + uint64_t size; + int flags; +}; + /* FIXME : maybe unify {GET,SET}PARAMs */ #define NOUVEAU_GETPARAM_PCI_VENDOR 3 #define NOUVEAU_GETPARAM_PCI_DEVICE 4 @@ -168,5 +177,6 @@ struct drm_nouveau_sarea { #define DRM_NOUVEAU_GPUOBJ_FREE 0x07 #define DRM_NOUVEAU_MEM_ALLOC 0x08 #define DRM_NOUVEAU_MEM_FREE 0x09 +#define DRM_NOUVEAU_MEM_TILE 0x0a #endif /* __NOUVEAU_DRM_H__ */ diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 33e2a5b6..03fe2ba7 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -34,7 +34,7 @@ #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 10 +#define DRIVER_PATCHLEVEL 11 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 @@ -385,6 +385,8 @@ extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_mem_free(struct drm_device *, void *data, struct drm_file *); +extern int nouveau_ioctl_mem_tile(struct drm_device *, void *data, + struct drm_file *); extern struct mem_block* nouveau_mem_alloc(struct drm_device *, int alignment, uint64_t size, int flags, struct drm_file *); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index d8fda277..085336af 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -593,6 +593,7 @@ struct drm_ioctl_desc nouveau_ioctls[] = { DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_ALLOC, nouveau_ioctl_mem_alloc, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_FREE, nouveau_ioctl_mem_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_TILE, nouveau_ioctl_mem_tile, DRM_AUTH), }; int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 861d699f..db207e76 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -606,8 +606,11 @@ nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size, /* Align allocation sizes to 64KiB blocks on G8x. We use a 64KiB * page size in the GPU VM. */ - if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) - size = (size + (64 * 1024)) & ~((64 * 1024) - 1); + if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) { + size = (size + 65535) & ~65535; + if (alignment < 16) + alignment = 16; + } /* * Warn about 0 sized allocations, but let it go through. It'll return 1 page @@ -669,6 +672,7 @@ alloc_ok: struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt; unsigned offset = block->start; unsigned count = block->size / 65536; + unsigned tile = 0; if (!pt) { DRM_ERROR("vm alloc without vm pt\n"); @@ -676,11 +680,22 @@ alloc_ok: return NULL; } + /* The tiling stuff is *not* what NVIDIA does - but both the + * 2D and 3D engines seem happy with this simpler method. + * Should look into why NVIDIA do what they do at some point. + */ + if (flags & NOUVEAU_MEM_TILE) { + if (flags & NOUVEAU_MEM_TILE_ZETA) + tile = 0x00002800; + else + tile = 0x00007000; + } + while (count--) { unsigned pte = offset / 65536; INSTANCE_WR(pt, (pte * 2) + 0, offset | 1); - INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000); + INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile); offset += 65536; } } else { @@ -833,3 +848,53 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file * nouveau_mem_free(dev, block); return 0; } + +int +nouveau_ioctl_mem_tile(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_nouveau_mem_tile *memtile = data; + struct mem_block *block = NULL; + + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + + if (dev_priv->card_type < NV_50) + return -EINVAL; + + if (memtile->flags & NOUVEAU_MEM_FB) { + memtile->offset -= 512*1024*1024; + block = find_block(dev_priv->fb_heap, memtile->offset); + } + + if (!block) + return -EINVAL; + + if (block->file_priv != file_priv) + return -EPERM; + + { + struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt; + unsigned offset = block->start + memtile->delta; + unsigned count = memtile->size / 65536; + unsigned tile = 0; + + if (memtile->flags & NOUVEAU_MEM_TILE) { + if (memtile->flags & NOUVEAU_MEM_TILE_ZETA) + tile = 0x00002800; + else + tile = 0x00007000; + } + + while (count--) { + unsigned pte = offset / 65536; + + INSTANCE_WR(pt, (pte * 2) + 0, offset | 1); + INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile); + offset += 65536; + } + } + + return 0; +} + -- cgit v1.2.3 From 0ef097b598433a5756df2bd6a72deba1f0e1d1c7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Jun 2008 01:24:11 +1000 Subject: nv50: use same dma object for fb/tt access We depend on the VM fully now for memory protection, separate DMA objects for VRAM and GART are unneccesary. However, until the next interface break (soon) a client can't depend on the objects being the same and must still call NV_OBJ_SET_DMA_* methods appropriately. --- shared-core/nouveau_mem.c | 11 ++++++++++- shared-core/nouveau_object.c | 6 ++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index db207e76..375463b4 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -806,6 +806,7 @@ int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_mem_alloc *alloc = data; struct mem_block *block; @@ -822,10 +823,15 @@ nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, alloc->offset=block->start; alloc->flags=block->flags; + if (dev_priv->card_type >= NV_50 && alloc->flags & NOUVEAU_MEM_FB) + alloc->offset += 512*1024*1024; + return 0; } -int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +nouveau_ioctl_mem_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_mem_free *memfree = data; @@ -833,6 +839,9 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file * NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + if (dev_priv->card_type >= NV_50 && memfree->flags & NOUVEAU_MEM_FB) + memfree->offset -= 512*1024*1024; + block=NULL; if (memfree->flags & NOUVEAU_MEM_FB) block = find_block(dev_priv->fb_heap, memfree->offset); diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 5664bfc8..894e7336 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -1036,8 +1036,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, /* VRAM ctxdma */ if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - 512*1024*1024, - dev_priv->fb_available_size, + 0, 0x100000000ULL, NV_DMA_ACCESS_RW, NV_DMA_TARGET_AGP, &vram); if (ret) { @@ -1059,6 +1058,9 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, } /* TT memory ctxdma */ + if (dev_priv->card_type >= NV_50) { + tt = vram; + } else if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) { ret = nouveau_gpuobj_gart_dma_new(chan, 0, dev_priv->gart_info.aper_size, -- cgit v1.2.3 From e2ffee839ed7ae6c55a0a8c6bb8ee872ae8a2a70 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 20 Jul 2008 00:09:06 +0200 Subject: drm: As a workaround don't tear down sg with a modesetting driver. - This allows me to maintain a useful prototype driver. --- linux-core/drm_drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index deb8eb9c..4e7c531a 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -242,7 +242,10 @@ int drm_lastclose(struct drm_device * dev) dev->agp->acquired = 0; dev->agp->enabled = 0; } - if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) { + + /* You're supposed to have a real memory manager for modesetting, but this'll suffice as a temporary workaround. */ + /* This assumes sgdma is inited at load time. */ + if (drm_core_check_feature(dev, DRIVER_SG) && !drm_core_check_feature(dev, DRIVER_MODESET) && dev->sg) { drm_sg_cleanup(dev->sg); dev->sg = NULL; } -- cgit v1.2.3 From 65803e53a696347e38d7f6c2c8dc186c6764ff03 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 20 Jul 2008 13:49:18 +0200 Subject: modesetting-101: implement optional scaling and dithering properties --- linux-core/drm_crtc.c | 69 +++++++++++++++++++++++ linux-core/drm_crtc.h | 8 ++- linux-core/nv50_connector.c | 4 +- linux-core/nv50_connector.h | 1 + linux-core/nv50_crtc.c | 2 +- linux-core/nv50_display.h | 2 +- linux-core/nv50_kms_wrapper.c | 128 ++++++++++++++++++++++++++++++++++++++++-- shared-core/drm.h | 10 ++++ 8 files changed, 215 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fc8d1fe8..c984209a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -60,6 +60,26 @@ char *drm_get_dpms_name(int val) return "unknown"; } +/* + * Optional properties + */ +static struct drm_prop_enum_list drm_scaling_mode_enum_list[] = +{ + { DRM_MODE_SCALE_NON_GPU, "Non-GPU" }, + { DRM_MODE_SCALE_FULLSCREEN, "Fullscreen" }, + { DRM_MODE_SCALE_NO_SCALE, "No scale" }, + { DRM_MODE_SCALE_ASPECT, "Aspect" }, +}; + +static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = +{ + { DRM_MODE_DITHERING_OFF, "Off" }, + { DRM_MODE_DITHERING_ON, "On" }, +}; + +/* + * Non-global properties, but "required" for certain connectors. + */ static struct drm_prop_enum_list drm_select_subconnector_enum_list[] = { { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ @@ -102,6 +122,9 @@ char *drm_get_subconnector_name(int val) return "unknown"; } +/* + * Connector and encoder types. + */ static struct drm_prop_enum_list drm_connector_enum_list[] = { { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, { DRM_MODE_CONNECTOR_VGA, "VGA" }, @@ -646,6 +669,52 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, } EXPORT_SYMBOL(drm_mode_create_tv_properties); +/** + * drm_mode_create_scaling_mode_property - create scaling mode property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired connectors. + */ +int drm_mode_create_scaling_mode_property(struct drm_device *dev) +{ + int i; + + if (dev->mode_config.scaling_mode_property) /* already done */ + return 0; + + dev->mode_config.scaling_mode_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "scaling mode", ARRAY_SIZE(drm_scaling_mode_enum_list)); + for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++) + drm_property_add_enum(dev->mode_config.scaling_mode_property, i, drm_scaling_mode_enum_list[i].type, drm_scaling_mode_enum_list[i].name); + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); + +/** + * drm_mode_create_dithering_property - create dithering property + * @dev: DRM device + * + * Called by a driver the first time it's needed, must be attached to desired connectors. + */ +int drm_mode_create_dithering_property(struct drm_device *dev) +{ + int i; + + if (dev->mode_config.dithering_mode_property) /* already done */ + return 0; + + dev->mode_config.dithering_mode_property = + drm_property_create(dev, DRM_MODE_PROP_ENUM, + "dithering", ARRAY_SIZE(drm_dithering_mode_enum_list)); + for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++) + drm_property_add_enum(dev->mode_config.dithering_mode_property, i, drm_dithering_mode_enum_list[i].type, drm_dithering_mode_enum_list[i].name); + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_dithering_property); + /** * drm_mode_config_init - initialize DRM mode_configuration structure * @dev: DRM device diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d4bb8794..d88c6149 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -536,7 +536,7 @@ struct drm_mode_config { struct drm_property *edid_property; struct drm_property *dpms_property; - /* optional properties */ + /* DVI-I properties */ struct drm_property *dvi_i_subconnector_property; struct drm_property *dvi_i_select_subconnector_property; @@ -549,6 +549,10 @@ struct drm_mode_config { struct drm_property *tv_top_margin_property; struct drm_property *tv_bottom_margin_property; + /* Optional properties */ + struct drm_property *scaling_mode_property; + struct drm_property *dithering_mode_property; + /* hotplug */ uint32_t hotplug_counter; }; @@ -650,6 +654,8 @@ extern int drm_property_add_enum(struct drm_property *property, int index, extern int drm_mode_create_dvi_i_properties(struct drm_device *dev); extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); +extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); +extern int drm_mode_create_dithering_property(struct drm_device *dev); extern char *drm_get_encoder_name(struct drm_encoder *encoder); extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index ac5194c0..be133de3 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -187,7 +187,9 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS) connector->scaling_mode = SCALE_FULLSCREEN; else - connector->scaling_mode = SCALE_PANEL; + connector->scaling_mode = SCALE_NON_GPU; + + connector->use_dithering = false; if (i2c_index < 0xf) connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index); diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index ebd6eac6..02b1561e 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -48,6 +48,7 @@ struct nv50_connector { struct nv50_output *output; int scaling_mode; + bool use_dithering; bool (*detect) (struct nv50_connector *connector); int (*destroy) (struct nv50_connector *connector); diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 6c3d404f..ffb976f4 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -264,7 +264,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) outY = crtc->native_mode->vdisplay; break; case SCALE_NOSCALE: - case SCALE_PANEL: + case SCALE_NON_GPU: default: outX = crtc->mode->hdisplay; outY = crtc->mode->vdisplay; diff --git a/linux-core/nv50_display.h b/linux-core/nv50_display.h index f20e67da..3c2ee1c9 100644 --- a/linux-core/nv50_display.h +++ b/linux-core/nv50_display.h @@ -68,7 +68,7 @@ struct nv50_display { }; enum scaling_modes { - SCALE_PANEL, + SCALE_NON_GPU, SCALE_FULLSCREEN, SCALE_ASPECT, SCALE_NOSCALE, diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index a7966e9a..b0d64340 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -636,10 +636,11 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) continue; crtc->scaling_mode = connector->scaling_mode; + crtc->use_dithering = connector->use_dithering; break; } - if (crtc->scaling_mode == SCALE_PANEL) + if (crtc->scaling_mode == SCALE_NON_GPU) crtc->use_native_mode = false; else crtc->use_native_mode = true; @@ -1078,14 +1079,16 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u } } -static bool nv50_kms_connector_set_property(struct drm_connector *connector, +static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, struct drm_property *property, uint64_t value) { - struct drm_device *dev = connector->dev; + struct drm_device *dev = drm_connector->dev; + struct nv50_connector *connector = to_nv50_connector(drm_connector); - if (property == dev->mode_config.dpms_property && connector->encoder) { - struct nv50_output *output = to_nv50_output(connector->encoder); + /* DPMS */ + if (property == dev->mode_config.dpms_property && drm_connector->encoder) { + struct nv50_output *output = to_nv50_output(drm_connector->encoder); if (!output->set_power_mode(output, (int) value)) return true; @@ -1093,6 +1096,78 @@ static bool nv50_kms_connector_set_property(struct drm_connector *connector, return false; } + /* Scaling mode */ + if (property == dev->mode_config.scaling_mode_property) { + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = nv50_get_display(dev); + int internal_value = 0; + int rval = 0; + + switch (value) { + case DRM_MODE_SCALE_NON_GPU: + internal_value = SCALE_NON_GPU; + break; + case DRM_MODE_SCALE_FULLSCREEN: + internal_value = SCALE_FULLSCREEN; + break; + case DRM_MODE_SCALE_NO_SCALE: + internal_value = SCALE_NOSCALE; + break; + case DRM_MODE_SCALE_ASPECT: + internal_value = SCALE_ASPECT; + break; + default: + break; + } + + connector->scaling_mode = internal_value; + + if (drm_connector->encoder && drm_connector->encoder->crtc) + crtc = to_nv50_crtc(drm_connector->encoder->crtc); + + if (!crtc) + return true; + + crtc->scaling_mode = connector->scaling_mode; + rval = crtc->set_scale(crtc); + if (rval) + return false; + + /* process command buffer */ + display->update(display); + + return true; + } + + /* Dithering */ + if (property == dev->mode_config.dithering_mode_property) { + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = nv50_get_display(dev); + int rval = 0; + + if (value == DRM_MODE_DITHERING_ON) + connector->use_dithering = true; + else + connector->use_dithering = false; + + if (drm_connector->encoder && drm_connector->encoder->crtc) + crtc = to_nv50_crtc(drm_connector->encoder->crtc); + + if (!crtc) + return true; + + /* update hw state */ + crtc->use_dithering = connector->use_dithering; + rval = crtc->set_dither(crtc); + if (rval) + return false; + + /* process command buffer */ + display->update(display); + + return true; + } + return false; } @@ -1105,12 +1180,48 @@ static const struct drm_connector_funcs nv50_kms_connector_funcs = { .set_property = nv50_kms_connector_set_property }; +static int nv50_kms_get_scaling_mode(struct drm_connector *drm_connector) +{ + struct nv50_connector *connector = NULL; + int drm_mode = 0; + + if (!drm_connector) { + DRM_ERROR("drm_connector is NULL\n"); + return 0; + } + + connector = to_nv50_connector(drm_connector); + + switch (connector->scaling_mode) { + case SCALE_NON_GPU: + drm_mode = DRM_MODE_SCALE_NON_GPU; + break; + case SCALE_FULLSCREEN: + drm_mode = DRM_MODE_SCALE_FULLSCREEN; + break; + case SCALE_NOSCALE: + drm_mode = DRM_MODE_SCALE_NO_SCALE; + break; + case SCALE_ASPECT: + drm_mode = DRM_MODE_SCALE_ASPECT; + break; + default: + break; + } + + return drm_mode; +} + static int nv50_kms_connectors_init(struct drm_device *dev) { struct nv50_display *display = nv50_get_display(dev); struct nv50_connector *connector = NULL; int i; + /* Initialise some optional connector properties. */ + drm_mode_create_scaling_mode_property(dev); + drm_mode_create_dithering_property(dev); + list_for_each_entry(connector, &display->connectors, item) { struct drm_connector *drm_connector = to_nv50_kms_connector(connector); uint32_t type = DRM_MODE_CONNECTOR_Unknown; @@ -1154,6 +1265,13 @@ static int nv50_kms_connectors_init(struct drm_device *dev) drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, 0); } + /* If supported in the future, it will have to use the scalers internally and not expose them. */ + if (type != DRM_MODE_CONNECTOR_SVIDEO) { + drm_connector_attach_property(drm_connector, dev->mode_config.scaling_mode_property, nv50_kms_get_scaling_mode(drm_connector)); + } + + drm_connector_attach_property(drm_connector, dev->mode_config.dithering_mode_property, connector->use_dithering ? DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); + /* attach encoders, possibilities are analog + digital */ for (i = 0; i < 2; i++) { struct drm_encoder *drm_encoder = NULL; diff --git a/shared-core/drm.h b/shared-core/drm.h index 2e4d2a94..41190640 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1034,6 +1034,16 @@ struct drm_mm_info_arg { #define DRM_MODE_DPMS_SUSPEND 2 #define DRM_MODE_DPMS_OFF 3 +/* Scaling mode options */ +#define DRM_MODE_SCALE_NON_GPU 0 +#define DRM_MODE_SCALE_FULLSCREEN 1 +#define DRM_MODE_SCALE_NO_SCALE 2 +#define DRM_MODE_SCALE_ASPECT 3 + +/* Dithering mode options */ +#define DRM_MODE_DITHERING_OFF 0 +#define DRM_MODE_DITHERING_ON 1 + struct drm_mode_modeinfo { unsigned int clock; unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; -- cgit v1.2.3 From 3ef1d05001a9e28ed52536de7e020323d8d34d83 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 20 Jul 2008 14:51:22 +0200 Subject: modesetting-101: set_property should return an int, not a bool --- linux-core/drm_crtc.h | 2 +- linux-core/intel_crt.c | 4 ++-- linux-core/intel_tv.c | 2 +- linux-core/nv50_kms_wrapper.c | 26 ++++++++++++-------------- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d88c6149..117b7213 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -375,7 +375,7 @@ struct drm_connector_funcs { void (*restore)(struct drm_connector *connector); enum drm_connector_status (*detect)(struct drm_connector *connector); void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); - bool (*set_property)(struct drm_connector *connector, struct drm_property *property, + int (*set_property)(struct drm_connector *connector, struct drm_property *property, uint64_t val); void (*destroy)(struct drm_connector *connector); }; diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 1b2b5b7e..8e1b833a 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -210,7 +210,7 @@ static int intel_crt_get_modes(struct drm_connector *connector) return intel_ddc_get_modes(intel_output); } -static bool intel_crt_set_property(struct drm_connector *connector, +static int intel_crt_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t value) { @@ -219,7 +219,7 @@ static bool intel_crt_set_property(struct drm_connector *connector, if (property == dev->mode_config.dpms_property && connector->encoder) intel_crt_dpms(connector->encoder, (uint32_t)(value & 0xf)); - return true; + return 0; } /* diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 389487bb..29cfc031 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1560,7 +1560,7 @@ intel_tv_destroy (struct drm_connector *connector) } -static bool +static int intel_tv_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index b0d64340..009972c8 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -1079,21 +1079,21 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u } } -static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, +static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, struct drm_property *property, uint64_t value) { struct drm_device *dev = drm_connector->dev; struct nv50_connector *connector = to_nv50_connector(drm_connector); + int rval = 0; /* DPMS */ if (property == dev->mode_config.dpms_property && drm_connector->encoder) { struct nv50_output *output = to_nv50_output(drm_connector->encoder); - if (!output->set_power_mode(output, (int) value)) - return true; - else - return false; + rval = output->set_power_mode(output, (int) value); + + return rval; } /* Scaling mode */ @@ -1101,7 +1101,6 @@ static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, struct nv50_crtc *crtc = NULL; struct nv50_display *display = nv50_get_display(dev); int internal_value = 0; - int rval = 0; switch (value) { case DRM_MODE_SCALE_NON_GPU: @@ -1126,24 +1125,23 @@ static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, crtc = to_nv50_crtc(drm_connector->encoder->crtc); if (!crtc) - return true; + return 0; crtc->scaling_mode = connector->scaling_mode; rval = crtc->set_scale(crtc); if (rval) - return false; + return rval; /* process command buffer */ display->update(display); - return true; + return 0; } /* Dithering */ if (property == dev->mode_config.dithering_mode_property) { struct nv50_crtc *crtc = NULL; struct nv50_display *display = nv50_get_display(dev); - int rval = 0; if (value == DRM_MODE_DITHERING_ON) connector->use_dithering = true; @@ -1154,21 +1152,21 @@ static bool nv50_kms_connector_set_property(struct drm_connector *drm_connector, crtc = to_nv50_crtc(drm_connector->encoder->crtc); if (!crtc) - return true; + return 0; /* update hw state */ crtc->use_dithering = connector->use_dithering; rval = crtc->set_dither(crtc); if (rval) - return false; + return rval; /* process command buffer */ display->update(display); - return true; + return 0; } - return false; + return -EINVAL; } static const struct drm_connector_funcs nv50_kms_connector_funcs = { -- cgit v1.2.3 From f1e4785d4cf04b679948602ffbbef2043ce81ec0 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 20 Jul 2008 14:55:59 +0200 Subject: NV50: LVDS always needs some kind of gpu scaling --- linux-core/nv50_kms_wrapper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 009972c8..6e0805fc 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -1119,6 +1119,10 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, break; } + /* LVDS always needs gpu scaling */ + if (connector->type == CONNECTOR_LVDS && internal_value == SCALE_NON_GPU) + return -EINVAL; + connector->scaling_mode = internal_value; if (drm_connector->encoder && drm_connector->encoder->crtc) -- cgit v1.2.3 From e51cd78cac24df15e32e23d8db73614524e6ff0d Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 20 Jul 2008 14:58:46 +0200 Subject: modesetting-101: Only store property value when set_property was successful. --- linux-core/drm_crtc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c984209a..91bff1f6 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2184,12 +2184,12 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, } } - /* store the property value */ - drm_connector_property_set_value(connector, property, out_resp->value); - if (connector->funcs->set_property) ret = connector->funcs->set_property(connector, property, out_resp->value); + /* store the property value if succesful */ + if (!ret) + drm_connector_property_set_value(connector, property, out_resp->value); out: mutex_unlock(&dev->mode_config.mutex); return ret; -- cgit v1.2.3 From 685bca02fe6b7406bb157a1a4e0f147b47ba28f8 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 20 Jul 2008 15:40:40 +0200 Subject: NV50: delay changing gpu<->non-gpu scaling modes until next modeset --- linux-core/nv50_connector.c | 4 ++-- linux-core/nv50_connector.h | 3 ++- linux-core/nv50_crtc.c | 8 +++++++- linux-core/nv50_crtc.h | 4 ++++ linux-core/nv50_kms_wrapper.c | 21 ++++++++++++++++----- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index be133de3..309f450c 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -185,9 +185,9 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty /* some reasonable defaults */ if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS) - connector->scaling_mode = SCALE_FULLSCREEN; + connector->requested_scaling_mode = SCALE_FULLSCREEN; else - connector->scaling_mode = SCALE_NON_GPU; + connector->requested_scaling_mode = SCALE_NON_GPU; connector->use_dithering = false; diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index 02b1561e..aac94457 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -47,7 +47,8 @@ struct nv50_connector { struct nv50_i2c_channel *i2c_chan; struct nv50_output *output; - int scaling_mode; + int requested_scaling_mode; + bool use_dithering; bool (*detect) (struct nv50_connector *connector); diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index ffb976f4..c4ca7e76 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -255,7 +255,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) NV50_DEBUG("\n"); - switch (crtc->scaling_mode) { + switch (crtc->requested_scaling_mode) { case SCALE_ASPECT: nv50_crtc_calc_scale(crtc, &outX, &outY); break; @@ -283,6 +283,9 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX); OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX); + /* processed */ + crtc->scaling_mode = crtc->requested_scaling_mode; + return 0; } @@ -492,6 +495,9 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + crtc->requested_scaling_mode = SCALE_INVALID; + crtc->scaling_mode = SCALE_INVALID; + if (!crtc->mode || !crtc->native_mode) { rval = -ENOMEM; goto out; diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index 8235c9d6..b4b83584 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -46,6 +46,10 @@ struct nv50_crtc { bool use_native_mode; bool use_dithering; + + /* Changing scaling modes requires a modeset sometimes. */ + /* We need to know the currently active hw mode, as well as the requested one by the user. */ + int requested_scaling_mode; int scaling_mode; struct nv50_cursor *cursor; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 6e0805fc..67836f3f 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -635,12 +635,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (connector->output != output) continue; - crtc->scaling_mode = connector->scaling_mode; + crtc->requested_scaling_mode = connector->requested_scaling_mode; crtc->use_dithering = connector->use_dithering; break; } - if (crtc->scaling_mode == SCALE_NON_GPU) + if (crtc->requested_scaling_mode == SCALE_NON_GPU) crtc->use_native_mode = false; else crtc->use_native_mode = true; @@ -1086,6 +1086,7 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, struct drm_device *dev = drm_connector->dev; struct nv50_connector *connector = to_nv50_connector(drm_connector); int rval = 0; + bool delay_change = false; /* DPMS */ if (property == dev->mode_config.dpms_property && drm_connector->encoder) { @@ -1123,7 +1124,7 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, if (connector->type == CONNECTOR_LVDS && internal_value == SCALE_NON_GPU) return -EINVAL; - connector->scaling_mode = internal_value; + connector->requested_scaling_mode = internal_value; if (drm_connector->encoder && drm_connector->encoder->crtc) crtc = to_nv50_crtc(drm_connector->encoder->crtc); @@ -1131,7 +1132,17 @@ static int nv50_kms_connector_set_property(struct drm_connector *drm_connector, if (!crtc) return 0; - crtc->scaling_mode = connector->scaling_mode; + crtc->requested_scaling_mode = connector->requested_scaling_mode; + + /* going from and to a gpu scaled regime requires a modesetting, so wait until next modeset */ + if (crtc->scaling_mode == SCALE_NON_GPU || internal_value == SCALE_NON_GPU) { + DRM_INFO("Moving from or to a non-gpu scaled mode, this will be processed upon next modeset."); + delay_change = true; + } + + if (delay_change) + return 0; + rval = crtc->set_scale(crtc); if (rval) return rval; @@ -1194,7 +1205,7 @@ static int nv50_kms_get_scaling_mode(struct drm_connector *drm_connector) connector = to_nv50_connector(drm_connector); - switch (connector->scaling_mode) { + switch (connector->requested_scaling_mode) { case SCALE_NON_GPU: drm_mode = DRM_MODE_SCALE_NON_GPU; break; -- cgit v1.2.3 From d00644c27ddc7023ea0e442c7be6b67d9d0da047 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 21 Jul 2008 14:29:13 +0200 Subject: NV50: Do detect with hpd and load detect if possible. - Appropriate error messages when an unknown situation is encountered are included. - Fallback to i2c will occur when needed. --- linux-core/nv50_connector.c | 49 ++++++++++++++++++++--- linux-core/nv50_connector.h | 3 +- linux-core/nv50_dac.c | 35 +++++++++++++++- linux-core/nv50_kms_wrapper.c | 92 +++++++++++++++++++++++++++++-------------- linux-core/nv50_kms_wrapper.h | 2 +- linux-core/nv50_output.h | 2 +- 6 files changed, 144 insertions(+), 39 deletions(-) diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index 309f450c..6e5fb912 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -76,7 +76,45 @@ static struct nv50_output *nv50_connector_to_output(struct nv50_connector *conne return NULL; } -static bool nv50_connector_detect(struct nv50_connector *connector) +static int nv50_connector_hpd_detect(struct nv50_connector *connector) +{ + struct drm_nouveau_private *dev_priv = connector->dev->dev_private; + struct nv50_output *output = NULL; + bool present = 0; + uint32_t reg = 0; + + /* Assume connected for the moment. */ + if (connector->type == CONNECTOR_LVDS) { + NV50_DEBUG("LVDS is defaulting to connected for the moment.\n"); + return 1; + } + + /* No i2c port, no idea what to do for hotplug. */ + if (connector->i2c_chan->index == 15) { + DRM_ERROR("You have a non-LVDS SOR with no i2c port, please report\n"); + return -EINVAL; + } + + if (connector->i2c_chan->index > 3) { + DRM_ERROR("You have an unusual configuration, index is %d\n", connector->i2c_chan->index); + DRM_ERROR("Please report.\n"); + return -EINVAL; + } + + /* Check hotplug pins. */ + reg = NV_READ(NV50_PCONNECTOR_HOTPLUG_STATE); + if (reg & (NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C0 << (4 * connector->i2c_chan->index))) + present = 1; + + if (present) + NV50_DEBUG("Hotplug detect returned positive for bus %d\n", connector->bus); + else + NV50_DEBUG("Hotplug detect returned negative for bus %d\n", connector->bus); + + return present; +} + +static int nv50_connector_i2c_detect(struct nv50_connector *connector) { /* kindly borrrowed from the intel driver, hope it works. */ uint8_t out_buf[] = { 0x0, 0x0}; @@ -97,13 +135,11 @@ static bool nv50_connector_detect(struct nv50_connector *connector) } }; - NV50_DEBUG("\n"); - if (!connector->i2c_chan) - return false; + return -EINVAL; ret = i2c_transfer(&connector->i2c_chan->adapter, msgs, 2); - DRM_INFO("I2C detect returned %d\n", ret); + NV50_DEBUG("I2C detect returned %d\n", ret); if (ret == 2) return true; @@ -195,7 +231,8 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index); /* set function pointers */ - connector->detect = nv50_connector_detect; + connector->hpd_detect = nv50_connector_hpd_detect; + connector->i2c_detect = nv50_connector_i2c_detect; connector->destroy = nv50_connector_destroy; connector->to_output = nv50_connector_to_output; diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index aac94457..fa7316e2 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -51,7 +51,8 @@ struct nv50_connector { bool use_dithering; - bool (*detect) (struct nv50_connector *connector); + int (*hpd_detect) (struct nv50_connector *connector); + int (*i2c_detect) (struct nv50_connector *connector); int (*destroy) (struct nv50_connector *connector); struct nv50_output *(*to_output) (struct nv50_connector *connector, bool digital); }; diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index ca4bb5e1..3f007166 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -133,6 +133,39 @@ static int nv50_dac_set_power_mode(struct nv50_output *output, int mode) return 0; } +static int nv50_dac_detect(struct nv50_output *output) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + int or = nv50_output_or_offset(output); + bool present = 0; + uint32_t dpms_state, load_pattern, load_state; + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(or), 0x00000001); + dpms_state = NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)); + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), 0x00150000 | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + while (NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + + load_pattern = 340; /* TODO: use a bios table for this */ + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or), NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE | load_pattern); + udelay(10000); /* give it some time to process */ + load_state = NV_READ(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or)); + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or), 0); + NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), dpms_state); + + if ((load_state & NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT) == NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT) + present = 1; + + if (present) + NV50_DEBUG("Load was detected on output with or %d\n", or); + else + NV50_DEBUG("Load was not detected on output with or %d\n", or); + + return present; +} + static int nv50_dac_destroy(struct nv50_output *output) { struct drm_device *dev = output->dev; @@ -210,7 +243,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) output->execute_mode = nv50_dac_execute_mode; output->set_clock_mode = nv50_dac_set_clock_mode; output->set_power_mode = nv50_dac_set_power_mode; - output->detect = NULL; /* TODO */ + output->detect = nv50_dac_detect; output->destroy = nv50_dac_destroy; return 0; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 67836f3f..8b27f80b 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -386,7 +386,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* This is to ensure it knows the connector subtype. */ drm_connector->funcs->fill_modes(drm_connector, 0, 0); - output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); goto out; @@ -458,7 +458,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); goto out; @@ -835,7 +835,9 @@ static int nv50_kms_encoders_init(struct drm_device *dev) * Connector functions */ -bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) + +/* These 2 functions wrap the connector properties that deal with multiple encoders per connector. */ +bool nv50_kms_connector_get_digital(struct drm_connector *drm_connector) { struct drm_device *dev = drm_connector->dev; @@ -892,6 +894,33 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) return false; } +static void nv50_kms_connector_set_digital(struct drm_connector *drm_connector, int digital, bool force) +{ + struct drm_device *dev = drm_connector->dev; + + if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) { + uint64_t cur_value, new_value; + + int rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &cur_value); + if (rval) { + DRM_ERROR("Unable to find subconnector property\n"); + return; + } + + /* Only set when unknown or when forced to do so. */ + if (cur_value != DRM_MODE_SUBCONNECTOR_Unknown && !force) + return; + + if (digital == 1) + new_value = DRM_MODE_SUBCONNECTOR_DVID; + else if (digital == 0) + new_value = DRM_MODE_SUBCONNECTOR_DVIA; + else + new_value = DRM_MODE_SUBCONNECTOR_Unknown; + drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, new_value); + } +} + void nv50_kms_connector_detect_all(struct drm_device *dev) { struct drm_connector *drm_connector = NULL; @@ -903,16 +932,32 @@ void nv50_kms_connector_detect_all(struct drm_device *dev) static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector) { - struct nv50_connector *connector = to_nv50_connector(drm_connector); struct drm_device *dev = drm_connector->dev; - bool connected; - int old_status; + struct nv50_connector *connector = to_nv50_connector(drm_connector); + struct nv50_output *output = NULL; + int hpd_detect = 0, load_detect = 0, i2c_detect = 0; + int old_status = drm_connector->status; - connected = connector->detect(connector); + /* hotplug detect */ + hpd_detect = connector->hpd_detect(connector); - old_status = drm_connector->status; + /* load detect */ + output = connector->to_output(connector, FALSE); /* analog */ + if (output && output->detect) + load_detect = output->detect(output); - if (connected) + if (hpd_detect < 0 || load_detect < 0) /* did an error occur? */ + i2c_detect = connector->i2c_detect(connector); + + if (load_detect == 1) { + nv50_kms_connector_set_digital(drm_connector, 0, TRUE); /* analog, forced */ + } else if (hpd_detect == 1 && load_detect == 0) { + nv50_kms_connector_set_digital(drm_connector, 1, TRUE); /* digital, forced */ + } else { + nv50_kms_connector_set_digital(drm_connector, -1, TRUE); /* unknown, forced */ + } + + if (hpd_detect == 1 || load_detect == 1 || i2c_detect == 1) drm_connector->status = connector_status_connected; else drm_connector->status = connector_status_disconnected; @@ -956,7 +1001,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u struct nv50_connector *connector = to_nv50_connector(drm_connector); struct drm_device *dev = drm_connector->dev; int rval = 0; - bool connected; + bool connected = false; struct drm_display_mode *mode, *t; struct edid *edid = NULL; @@ -965,16 +1010,13 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u list_for_each_entry_safe(mode, t, &drm_connector->modes, head) mode->status = MODE_UNVERIFIED; - connected = connector->detect(connector); + if (nv50_kms_connector_detect(drm_connector) == connector_status_connected) + connected = true; if (connected) - drm_connector->status = connector_status_connected; + NV50_DEBUG("%s is connected\n", drm_get_connector_name(drm_connector)); else - drm_connector->status = connector_status_disconnected; - - if (!connected) { NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); - } /* Not all connnectors have an i2c channel. */ if (connected && connector->i2c_chan) @@ -986,16 +1028,8 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u if (edid) { rval = drm_add_edid_modes(drm_connector, edid); - /* 2 encoders per connector */ - /* eventually do this based on load detect and hot plug detect */ - if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) { - uint64_t subtype = 0; - if (edid->digital) - subtype = DRM_MODE_SUBCONNECTOR_DVID; - else - subtype = DRM_MODE_SUBCONNECTOR_DVIA; - drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, subtype); - } + /* Only update when relevant and when detect couldn't determine type. */ + nv50_kms_connector_set_digital(drm_connector, edid->digital ? 1 : 0, FALSE); kfree(edid); } @@ -1009,7 +1043,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { if (mode->status == MODE_OK) { struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); - struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); mode->status = output->validate_mode(output, hw_mode); /* find native mode, TODO: also check if we actually found one */ @@ -1025,7 +1059,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { if (mode->status == MODE_OK) { struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); - struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); mode->status = output->validate_mode(output, hw_mode); kfree(hw_mode); @@ -1057,7 +1091,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u /* also add it as native mode */ hw_mode = nv50_kms_to_hw_mode(mode); - output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); + output = connector->to_output(connector, nv50_kms_connector_get_digital(drm_connector)); if (hw_mode) *output->native_mode = *hw_mode; diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h index 5ac66522..60384804 100644 --- a/linux-core/nv50_kms_wrapper.h +++ b/linux-core/nv50_kms_wrapper.h @@ -87,7 +87,7 @@ struct nv50_kms_priv { struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev); void nv50_kms_connector_detect_all(struct drm_device *dev); -bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector); +bool nv50_kms_connector_get_digital(struct drm_connector *drm_connector); int nv50_kms_init(struct drm_device *dev); int nv50_kms_destroy(struct drm_device *dev); diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h index a5faf050..ac6d714f 100644 --- a/linux-core/nv50_output.h +++ b/linux-core/nv50_output.h @@ -51,7 +51,7 @@ struct nv50_output { int (*set_clock_mode) (struct nv50_output *output); /* this is not a normal modeset call, it is a direct register write, so it's executed immediately */ int (*set_power_mode) (struct nv50_output *output, int mode); - bool (*detect) (struct nv50_output *output); + int (*detect) (struct nv50_output *output); int (*destroy) (struct nv50_output *output); }; -- cgit v1.2.3 From 03f8208ab0a3ea77a8b30dd1c3fe2b62892f9d8c Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 21 Jul 2008 14:50:07 +0200 Subject: NV50: Use bios table for load pattern when possible. --- linux-core/nouveau_bios.c | 40 ++++++++++++++++++++++++++++++++++++++-- linux-core/nv50_connector.c | 1 - linux-core/nv50_dac.c | 9 ++++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/linux-core/nouveau_bios.c b/linux-core/nouveau_bios.c index 3e7fe23f..370d6522 100644 --- a/linux-core/nouveau_bios.c +++ b/linux-core/nouveau_bios.c @@ -128,6 +128,39 @@ struct bit_entry { uint16_t offset; }; +static int parse_bit_A_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry) +{ + /* Parses the load detect value table. + * + * Starting at bitentry->offset: + * + * offset + 0 (16 bits): table pointer + */ + + uint16_t load_table_pointer; + + if (bitentry->length != 3) { + DRM_ERROR("Do not understand BIT loadval table\n"); + return 0; + } + + load_table_pointer = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset]))); + + if (load_table_pointer == 0x0) { + DRM_ERROR("Pointer to loadval table invalid\n"); + return 0; + } + + /* Some kind of signature */ + if (bios->data[load_table_pointer] != 16 || bios->data[load_table_pointer + 1] != 4 || + bios->data[load_table_pointer + 2] != 4 || bios->data[load_table_pointer + 3] != 2) + return 0; + + bios->dactestval = le32_to_cpu(*((uint32_t *)&bios->data[load_table_pointer + 4])) & 0x3FF; + + return 1; +} + static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry) { /* offset + 8 (16 bits): PLL limits table pointer @@ -136,7 +169,7 @@ static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, stru */ if (bitentry->length < 10) { - DRM_ERROR( "Do not understand BIT C table\n"); + DRM_ERROR("Do not understand BIT C table\n"); return 0; } @@ -149,7 +182,7 @@ static void parse_bit_structure(struct drm_device *dev, struct bios *bios, const { int entries = bios->data[bitoffset + 4]; /* parse i first, I next (which needs C & M before it), and L before D */ - char parseorder[] = "iCMILDT"; + char parseorder[] = "iCMILDTA"; struct bit_entry bitentry; int i, j, offset; @@ -164,6 +197,9 @@ static void parse_bit_structure(struct drm_device *dev, struct bios *bios, const continue; switch (bitentry.id[0]) { + case 'A': + parse_bit_A_tbl_entry(dev, bios, &bitentry); + break; case 'C': parse_bit_C_tbl_entry(dev, bios, &bitentry); break; diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index 6e5fb912..34706bae 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -79,7 +79,6 @@ static struct nv50_output *nv50_connector_to_output(struct nv50_connector *conne static int nv50_connector_hpd_detect(struct nv50_connector *connector) { struct drm_nouveau_private *dev_priv = connector->dev->dev_private; - struct nv50_output *output = NULL; bool present = 0; uint32_t reg = 0; diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index 3f007166..5dddb469 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -146,7 +146,14 @@ static int nv50_dac_detect(struct nv50_output *output) NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), 0x00150000 | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); while (NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); - load_pattern = 340; /* TODO: use a bios table for this */ + /* Use bios provided value if possible. */ + if (dev_priv->bios.dactestval) { + load_pattern = dev_priv->bios.dactestval; + NV50_DEBUG("Using bios provided load_pattern of %d\n", load_pattern); + } else { + load_pattern = 340; + NV50_DEBUG("Using default load_pattern of %d\n", load_pattern); + } NV_WRITE(NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(or), NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE | load_pattern); udelay(10000); /* give it some time to process */ -- cgit v1.2.3 From 147ef45873868a0df9216dac0370ada1ed835590 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 21 Jul 2008 16:40:55 +0200 Subject: NV50: don't fail on LVDS by default --- linux-core/nouveau_bios.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/linux-core/nouveau_bios.c b/linux-core/nouveau_bios.c index 370d6522..faa2b2b0 100644 --- a/linux-core/nouveau_bios.c +++ b/linux-core/nouveau_bios.c @@ -341,11 +341,12 @@ parse_dcb_entry(struct drm_device *dev, int index, uint8_t dcb_version, uint16_t entry->lvdsconf.use_power_scripts = true; } if (conf & mask) { - DRM_ERROR( - "Unknown LVDS configuration bits, please report\n"); - /* cause output setting to fail, so message is seen */ - dev_priv->dcb_table.entries = 0; - return false; + if (dcb_version < 0x40) { /* we know g80 cards have unknown bits */ + DRM_ERROR("Unknown LVDS configuration bits, please report\n"); + /* cause output setting to fail, so message is seen */ + dev_priv->dcb_table.entries = 0; + return false; + } } break; } -- cgit v1.2.3 From 4d5b9f484885ac01457f0a8c39b24ca4aac34b5a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 21 Jul 2008 16:57:25 +0200 Subject: NV50: Don't create a "native" mode for LVDS when there is none. --- linux-core/nv50_kms_wrapper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 8b27f80b..355d25d6 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -1079,6 +1079,10 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u NV50_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector)); + /* Making up native modes for LVDS is a bad idea. */ + if (drm_connector->connector_type == DRM_MODE_CONNECTOR_LVDS) + return; + /* Should we do this here ??? * When no valid EDID modes are available we end up * here and bailed in the past, now we add a standard -- cgit v1.2.3 From 53428453758621da70d9608c9baec58b4b9383ec Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 24 Jul 2008 15:22:44 +1000 Subject: drm: use correct mode destructor --- linux-core/drm_modes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 4ee00305..d4cda0be 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -398,7 +398,7 @@ void drm_mode_prune_invalid(struct drm_device *dev, drm_mode_debug_printmodeline(mode); DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status); } - kfree(mode); + drm_mode_destroy(dev, mode); } } } @@ -556,7 +556,7 @@ void drm_mode_connector_list_update(struct drm_connector *connector) /* if equal delete the probed mode */ mode->status = pmode->status; list_del(&pmode->head); - kfree(pmode); + drm_mode_destroy(connector->dev, pmode); break; } } -- cgit v1.2.3 From 11d30750873260fe19498d90831f07079dfad5d8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 26 Jul 2008 08:41:01 +1000 Subject: modesetting: pass file_priv into cursor set functions --- linux-core/drm_crtc.c | 2 +- linux-core/drm_crtc.h | 4 ++-- linux-core/intel_display.c | 1 + linux-core/nv50_kms_wrapper.c | 6 ++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 91bff1f6..7ee33219 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1445,7 +1445,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (req->flags & DRM_MODE_CURSOR_BO) { /* Turn of the cursor if handle is 0 */ if (crtc->funcs->cursor_set) { - ret = crtc->funcs->cursor_set(crtc, req->handle, req->width, req->height); + ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, req->width, req->height); } else { DRM_ERROR("crtc does not support cursor\n"); ret = -EFAULT; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 117b7213..bfccdeb5 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -299,8 +299,8 @@ struct drm_crtc_funcs { void (*restore)(struct drm_crtc *crtc); /* resume? */ /* cursor controls */ - int (*cursor_set)(struct drm_crtc *crtc, uint32_t buffer_handle, - uint32_t width, uint32_t height); + int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, + uint32_t handle, uint32_t width, uint32_t height); int (*cursor_move)(struct drm_crtc *crtc, int x, int y); /* Set gamma on the CRTC */ diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index a761b61b..0236bbc9 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -975,6 +975,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } static int intel_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height) { diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 355d25d6..694b7260 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -236,8 +236,10 @@ static const struct drm_mode_config_funcs nv50_kms_mode_funcs = { * CRTC functions. */ -static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_handle, - uint32_t width, uint32_t height) +static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, + struct drm_file *file_priv, + uint32_t buffer_handle, + uint32_t width, uint32_t height) { struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); struct nv50_display *display = nv50_get_display(crtc->dev); -- cgit v1.2.3 From 2be292f6ea8df96afc1454f30918b1b391fba2ba Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 26 Jul 2008 08:43:01 +1000 Subject: nv50: remove TRUE/FALSE --- linux-core/nv50_crtc.c | 2 +- linux-core/nv50_display.c | 2 +- linux-core/nv50_kms_wrapper.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index c4ca7e76..f56aa339 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -127,7 +127,7 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0)); /* Maybe move this as well? */ - crtc->blank(crtc, FALSE); + crtc->blank(crtc, false); return 0; } diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index b68c4e28..eeaa0e68 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -171,7 +171,7 @@ static int nv50_display_disable(struct nv50_display *display) /* disable clock change interrupts. */ NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) & ~0x70); - display->init_done = FALSE; + display->init_done = false; return 0; } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 355d25d6..1c4b52d7 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -950,11 +950,11 @@ static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector i2c_detect = connector->i2c_detect(connector); if (load_detect == 1) { - nv50_kms_connector_set_digital(drm_connector, 0, TRUE); /* analog, forced */ + nv50_kms_connector_set_digital(drm_connector, 0, true); /* analog, forced */ } else if (hpd_detect == 1 && load_detect == 0) { - nv50_kms_connector_set_digital(drm_connector, 1, TRUE); /* digital, forced */ + nv50_kms_connector_set_digital(drm_connector, 1, true); /* digital, forced */ } else { - nv50_kms_connector_set_digital(drm_connector, -1, TRUE); /* unknown, forced */ + nv50_kms_connector_set_digital(drm_connector, -1, true); /* unknown, forced */ } if (hpd_detect == 1 || load_detect == 1 || i2c_detect == 1) -- cgit v1.2.3 From 66723c09f5e4d60f1c746d112b065bacc1cfa89f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 26 Jul 2008 08:43:59 +1000 Subject: modesetting: pass file priv to cursor --- linux-core/drm_crtc.c | 2 +- linux-core/drm_crtc.h | 4 ++-- linux-core/intel_display.c | 1 + linux-core/nv50_kms_wrapper.c | 6 ++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 91bff1f6..7ee33219 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1445,7 +1445,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (req->flags & DRM_MODE_CURSOR_BO) { /* Turn of the cursor if handle is 0 */ if (crtc->funcs->cursor_set) { - ret = crtc->funcs->cursor_set(crtc, req->handle, req->width, req->height); + ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, req->width, req->height); } else { DRM_ERROR("crtc does not support cursor\n"); ret = -EFAULT; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 117b7213..bfccdeb5 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -299,8 +299,8 @@ struct drm_crtc_funcs { void (*restore)(struct drm_crtc *crtc); /* resume? */ /* cursor controls */ - int (*cursor_set)(struct drm_crtc *crtc, uint32_t buffer_handle, - uint32_t width, uint32_t height); + int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, + uint32_t handle, uint32_t width, uint32_t height); int (*cursor_move)(struct drm_crtc *crtc, int x, int y); /* Set gamma on the CRTC */ diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 29aae169..b8077bd2 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -972,6 +972,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } static int intel_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height) { diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 1c4b52d7..77271c1b 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -236,8 +236,10 @@ static const struct drm_mode_config_funcs nv50_kms_mode_funcs = { * CRTC functions. */ -static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_handle, - uint32_t width, uint32_t height) +static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, + struct drm_file *file_priv, + uint32_t buffer_handle, + uint32_t width, uint32_t height) { struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); struct nv50_display *display = nv50_get_display(crtc->dev); -- cgit v1.2.3 From 7fd7ba87f35aa4881e99b95bab4151b3f9db9b8e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 25 Jul 2008 13:30:08 +1000 Subject: drm: don't set the signal blocker on the master process. this lets us debug the X server through xkb startup. Not sure what the correct answer is, probably X needs to drop the lock when execing stuff, with input hotplug it can get xkb stuff at any time I believe. --- linux-core/drm_lock.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 6bbf1444..6e90e97f 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -107,14 +107,19 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ret ? "interrupted" : "has lock"); if (ret) return ret; - sigemptyset(&dev->sigmask); - sigaddset(&dev->sigmask, SIGSTOP); - sigaddset(&dev->sigmask, SIGTSTP); - sigaddset(&dev->sigmask, SIGTTIN); - sigaddset(&dev->sigmask, SIGTTOU); - dev->sigdata.context = lock->context; - dev->sigdata.lock = master->lock.hw_lock; - block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + /* don't set the block all signals on the master process for now + * really probably not the correct answer but lets us debug xkb + * xserver for now */ + if (!file_priv->is_master) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock->context; + dev->sigdata.lock = master->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + } if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY)) dev->driver->dma_ready(dev); -- cgit v1.2.3 From df9871064e8b564d9ae2e56d561b64434fd004af Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 26 Jul 2008 08:56:23 +1000 Subject: radeon: add initial atombios modesetting and GEM -> TTM translation layer. This is an initial import of the atom bios parser with modesetting support for r500 hw using atombios. It also includes a simple memory manager layer that translates a radeon GEM style interface onto TTM internally. So far this memory manager has only been used for pinned object allocation for the DDX to test modesetting. --- linux-core/Makefile.kernel | 18 +- linux-core/ObjectID.h | 484 ++++ linux-core/ati_pcigart.c | 234 +- linux-core/atom-bits.h | 48 + linux-core/atom-names.h | 100 + linux-core/atom-types.h | 42 + linux-core/atom.c | 1145 +++++++++ linux-core/atom.h | 148 ++ linux-core/atombios.h | 4498 ++++++++++++++++++++++++++++++++++ linux-core/atombios_crtc.c | 382 +++ linux-core/drmP.h | 8 +- linux-core/drm_bo.c | 10 +- linux-core/drm_compat.c | 6 +- linux-core/drm_crtc.c | 48 +- linux-core/drm_crtc.h | 1 + linux-core/drm_crtc_helper.c | 2 +- linux-core/drm_crtc_helper.h | 2 + linux-core/drm_gem.c | 1 - linux-core/drm_modes.c | 1 + linux-core/drm_objects.h | 4 + linux-core/intel_fb.c | 14 +- linux-core/radeon_atombios.c | 361 +++ linux-core/radeon_buffer.c | 266 ++ linux-core/radeon_combios.c | 381 +++ linux-core/radeon_connectors.c | 344 +++ linux-core/radeon_display.c | 725 ++++++ linux-core/radeon_drv.c | 38 +- linux-core/radeon_encoders.c | 962 ++++++++ linux-core/radeon_fb.c | 1163 +++++++++ linux-core/radeon_fence.c | 96 + linux-core/radeon_gem.c | 687 ++++++ linux-core/radeon_i2c.c | 131 + linux-core/radeon_mode.h | 255 ++ linux-core/radeon_reg.h | 5276 ++++++++++++++++++++++++++++++++++++++++ shared-core/drm.h | 2 +- shared-core/r300_cmdbuf.c | 11 +- shared-core/radeon_cp.c | 992 +++++++- shared-core/radeon_drm.h | 117 +- shared-core/radeon_drv.h | 298 ++- shared-core/radeon_irq.c | 14 +- shared-core/radeon_state.c | 203 +- 41 files changed, 19166 insertions(+), 352 deletions(-) create mode 100644 linux-core/ObjectID.h create mode 100644 linux-core/atom-bits.h create mode 100644 linux-core/atom-names.h create mode 100644 linux-core/atom-types.h create mode 100644 linux-core/atom.c create mode 100644 linux-core/atom.h create mode 100644 linux-core/atombios.h create mode 100644 linux-core/atombios_crtc.c create mode 100644 linux-core/radeon_atombios.c create mode 100644 linux-core/radeon_buffer.c create mode 100644 linux-core/radeon_combios.c create mode 100644 linux-core/radeon_connectors.c create mode 100644 linux-core/radeon_display.c create mode 100644 linux-core/radeon_encoders.c create mode 100644 linux-core/radeon_fb.c create mode 100644 linux-core/radeon_fence.c create mode 100644 linux-core/radeon_gem.c create mode 100644 linux-core/radeon_i2c.c create mode 100644 linux-core/radeon_mode.h create mode 100644 linux-core/radeon_reg.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 768cd22a..d3668dfb 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,9 +13,9 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_hashtab.o drm_memrange.o drm_object.o drm_compat.o \ - drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ - drm_edid.o drm_modes.o drm_bo_lock.o drm_regman.o \ - drm_vm_nopage_compat.o drm_crtc_helper.o drm_gem.o + drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_bo_lock.o \ + drm_crtc.o drm_edid.o drm_modes.o drm_crtc_helper.o \ + drm_regman.o drm_vm_nopage_compat.o drm_gem.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o @@ -40,15 +40,9 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv50_crtc.o nv50_cursor.o nv50_lut.o nv50_fb.o nv50_output.o nv50_sor.o nv50_dac.o nv50_connector.o nv50_i2c.o nv50_display.o \ nv50_kms_wrapper.o \ nv50_fbcon.o -radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o -radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ - radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \ - radeon_ms_bus.o radeon_ms_fence.o \ - radeon_ms_cp.o radeon_ms_cp_mc.o radeon_ms_i2c.o \ - radeon_ms_output.o radeon_ms_crtc.o radeon_ms_fb.o \ - radeon_ms_exec.o radeon_ms_gpu.o radeon_ms_dac.o \ - radeon_ms_properties.o radeon_ms_rom.o radeon_ms_combios.o \ - amd_legacy_cbuffer.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_gem.o \ + radeon_buffer.o radeon_fence.o atom.o radeon_display.o radeon_atombios.o radeon_i2c.o radeon_connectors.o \ + atombios_crtc.o radeon_encoders.o radeon_fb.o radeon_combios.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/ObjectID.h b/linux-core/ObjectID.h new file mode 100644 index 00000000..4b106cf6 --- /dev/null +++ b/linux-core/ObjectID.h @@ -0,0 +1,484 @@ +/* +* Copyright 2006-2007 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. +*/ +/* based on stg/asic_reg/drivers/inc/asic_reg/ObjectID.h ver 23 */ + +#ifndef _OBJECTID_H +#define _OBJECTID_H + +#if defined(_X86_) +#pragma pack(1) +#endif + +/****************************************************/ +/* Graphics Object Type Definition */ +/****************************************************/ +#define GRAPH_OBJECT_TYPE_NONE 0x0 +#define GRAPH_OBJECT_TYPE_GPU 0x1 +#define GRAPH_OBJECT_TYPE_ENCODER 0x2 +#define GRAPH_OBJECT_TYPE_CONNECTOR 0x3 +#define GRAPH_OBJECT_TYPE_ROUTER 0x4 +/* deleted */ + +/****************************************************/ +/* Encoder Object ID Definition */ +/****************************************************/ +#define ENCODER_OBJECT_ID_NONE 0x00 + +/* Radeon Class Display Hardware */ +#define ENCODER_OBJECT_ID_INTERNAL_LVDS 0x01 +#define ENCODER_OBJECT_ID_INTERNAL_TMDS1 0x02 +#define ENCODER_OBJECT_ID_INTERNAL_TMDS2 0x03 +#define ENCODER_OBJECT_ID_INTERNAL_DAC1 0x04 +#define ENCODER_OBJECT_ID_INTERNAL_DAC2 0x05 /* TV/CV DAC */ +#define ENCODER_OBJECT_ID_INTERNAL_SDVOA 0x06 +#define ENCODER_OBJECT_ID_INTERNAL_SDVOB 0x07 + +/* External Third Party Encoders */ +#define ENCODER_OBJECT_ID_SI170B 0x08 +#define ENCODER_OBJECT_ID_CH7303 0x09 +#define ENCODER_OBJECT_ID_CH7301 0x0A +#define ENCODER_OBJECT_ID_INTERNAL_DVO1 0x0B /* This belongs to Radeon Class Display Hardware */ +#define ENCODER_OBJECT_ID_EXTERNAL_SDVOA 0x0C +#define ENCODER_OBJECT_ID_EXTERNAL_SDVOB 0x0D +#define ENCODER_OBJECT_ID_TITFP513 0x0E +#define ENCODER_OBJECT_ID_INTERNAL_LVTM1 0x0F /* not used for Radeon */ +#define ENCODER_OBJECT_ID_VT1623 0x10 +#define ENCODER_OBJECT_ID_HDMI_SI1930 0x11 +#define ENCODER_OBJECT_ID_HDMI_INTERNAL 0x12 +/* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */ +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 0x13 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 0x14 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 0x15 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 0x16 /* Shared with CV/TV and CRT */ +#define ENCODER_OBJECT_ID_SI178 0X17 /* External TMDS (dual link, no HDCP.) */ +#define ENCODER_OBJECT_ID_MVPU_FPGA 0x18 /* MVPU FPGA chip */ +#define ENCODER_OBJECT_ID_INTERNAL_DDI 0x19 +#define ENCODER_OBJECT_ID_VT1625 0x1A +#define ENCODER_OBJECT_ID_HDMI_SI1932 0x1B +#define ENCODER_OBJECT_ID_DP_AN9801 0x1C +#define ENCODER_OBJECT_ID_DP_DP501 0x1D +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY 0x1E +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA 0x1F + +/****************************************************/ +/* Connector Object ID Definition */ +/****************************************************/ +#define CONNECTOR_OBJECT_ID_NONE 0x00 +#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I 0x01 +#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I 0x02 +#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D 0x03 +#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D 0x04 +#define CONNECTOR_OBJECT_ID_VGA 0x05 +#define CONNECTOR_OBJECT_ID_COMPOSITE 0x06 +#define CONNECTOR_OBJECT_ID_SVIDEO 0x07 +#define CONNECTOR_OBJECT_ID_YPbPr 0x08 +#define CONNECTOR_OBJECT_ID_D_CONNECTOR 0x09 +#define CONNECTOR_OBJECT_ID_9PIN_DIN 0x0A /* Supports both CV & TV */ +#define CONNECTOR_OBJECT_ID_SCART 0x0B +#define CONNECTOR_OBJECT_ID_HDMI_TYPE_A 0x0C +#define CONNECTOR_OBJECT_ID_HDMI_TYPE_B 0x0D +#define CONNECTOR_OBJECT_ID_LVDS 0x0E +#define CONNECTOR_OBJECT_ID_7PIN_DIN 0x0F +#define CONNECTOR_OBJECT_ID_PCIE_CONNECTOR 0x10 +#define CONNECTOR_OBJECT_ID_CROSSFIRE 0x11 +#define CONNECTOR_OBJECT_ID_HARDCODE_DVI 0x12 +#define CONNECTOR_OBJECT_ID_DISPLAYPORT 0x13 + +/* deleted */ + +/****************************************************/ +/* Router Object ID Definition */ +/****************************************************/ +#define ROUTER_OBJECT_ID_NONE 0x00 +#define ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL 0x01 + +/****************************************************/ +// Graphics Object ENUM ID Definition */ +/****************************************************/ +#define GRAPH_OBJECT_ENUM_ID1 0x01 +#define GRAPH_OBJECT_ENUM_ID2 0x02 +#define GRAPH_OBJECT_ENUM_ID3 0x03 +#define GRAPH_OBJECT_ENUM_ID4 0x04 + +/****************************************************/ +/* Graphics Object ID Bit definition */ +/****************************************************/ +#define OBJECT_ID_MASK 0x00FF +#define ENUM_ID_MASK 0x0700 +#define RESERVED1_ID_MASK 0x0800 +#define OBJECT_TYPE_MASK 0x7000 +#define RESERVED2_ID_MASK 0x8000 + +#define OBJECT_ID_SHIFT 0x00 +#define ENUM_ID_SHIFT 0x08 +#define OBJECT_TYPE_SHIFT 0x0C + + +/****************************************************/ +/* Graphics Object family definition */ +/****************************************************/ +#define CONSTRUCTOBJECTFAMILYID(GRAPHICS_OBJECT_TYPE, GRAPHICS_OBJECT_ID) (GRAPHICS_OBJECT_TYPE << OBJECT_TYPE_SHIFT | \ + GRAPHICS_OBJECT_ID << OBJECT_ID_SHIFT) +/****************************************************/ +/* GPU Object ID definition - Shared with BIOS */ +/****************************************************/ +#define GPU_ENUM_ID1 ( GRAPH_OBJECT_TYPE_GPU << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT) + +/****************************************************/ +/* Encoder Object ID definition - Shared with BIOS */ +/****************************************************/ +/* +#define ENCODER_INTERNAL_LVDS_ENUM_ID1 0x2101 +#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 0x2102 +#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 0x2103 +#define ENCODER_INTERNAL_DAC1_ENUM_ID1 0x2104 +#define ENCODER_INTERNAL_DAC2_ENUM_ID1 0x2105 +#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 0x2106 +#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 0x2107 +#define ENCODER_SIL170B_ENUM_ID1 0x2108 +#define ENCODER_CH7303_ENUM_ID1 0x2109 +#define ENCODER_CH7301_ENUM_ID1 0x210A +#define ENCODER_INTERNAL_DVO1_ENUM_ID1 0x210B +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 0x210C +#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 0x210D +#define ENCODER_TITFP513_ENUM_ID1 0x210E +#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 0x210F +#define ENCODER_VT1623_ENUM_ID1 0x2110 +#define ENCODER_HDMI_SI1930_ENUM_ID1 0x2111 +#define ENCODER_HDMI_INTERNAL_ENUM_ID1 0x2112 +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 0x2113 +#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 0x2114 +#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 0x2115 +#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 0x2116 +#define ENCODER_SI178_ENUM_ID1 0x2117 +#define ENCODER_MVPU_FPGA_ENUM_ID1 0x2118 +#define ENCODER_INTERNAL_DDI_ENUM_ID1 0x2119 +#define ENCODER_VT1625_ENUM_ID1 0x211A +#define ENCODER_HDMI_SI1932_ENUM_ID1 0x211B +#define ENCODER_ENCODER_DP_AN9801_ENUM_ID1 0x211C +#define ENCODER_DP_DP501_ENUM_ID1 0x211D +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 0x211E +*/ +#define ENCODER_INTERNAL_LVDS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_LVDS << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_TMDS1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_TMDS2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DAC1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DAC1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DAC2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DAC2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOB << OBJECT_ID_SHIFT) + +#define ENCODER_SIL170B_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_SI170B << OBJECT_ID_SHIFT) + +#define ENCODER_CH7303_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_CH7303 << OBJECT_ID_SHIFT) + +#define ENCODER_CH7301_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_CH7301 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DVO1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DVO1 << OBJECT_ID_SHIFT) + +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT) + + +#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOB << OBJECT_ID_SHIFT) + + +#define ENCODER_TITFP513_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_TITFP513 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_LVTM1 << OBJECT_ID_SHIFT) + +#define ENCODER_VT1623_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_VT1623 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_SI1930_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_SI1930 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_INTERNAL_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_INTERNAL << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT) + + +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT) + + +#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 << OBJECT_ID_SHIFT) // Shared with CV/TV and CRT + +#define ENCODER_SI178_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_SI178 << OBJECT_ID_SHIFT) + +#define ENCODER_MVPU_FPGA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_MVPU_FPGA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DDI_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DDI << OBJECT_ID_SHIFT) + +#define ENCODER_VT1625_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_VT1625 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_SI1932_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_SI1932 << OBJECT_ID_SHIFT) + +#define ENCODER_DP_DP501_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_DP_DP501 << OBJECT_ID_SHIFT) + +#define ENCODER_DP_AN9801_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_DP_AN9801 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_LVTMA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA << OBJECT_ID_SHIFT) + +/****************************************************/ +/* Connector Object ID definition - Shared with BIOS */ +/****************************************************/ +/* +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 0x3101 +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 0x3102 +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 0x3103 +#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 0x3104 +#define CONNECTOR_VGA_ENUM_ID1 0x3105 +#define CONNECTOR_COMPOSITE_ENUM_ID1 0x3106 +#define CONNECTOR_SVIDEO_ENUM_ID1 0x3107 +#define CONNECTOR_YPbPr_ENUM_ID1 0x3108 +#define CONNECTOR_D_CONNECTORE_ENUM_ID1 0x3109 +#define CONNECTOR_9PIN_DIN_ENUM_ID1 0x310A +#define CONNECTOR_SCART_ENUM_ID1 0x310B +#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 0x310C +#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 0x310D +#define CONNECTOR_LVDS_ENUM_ID1 0x310E +#define CONNECTOR_7PIN_DIN_ENUM_ID1 0x310F +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 0x3110 +*/ +#define CONNECTOR_LVDS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_LVDS << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_VGA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT) + +#define CONNECTOR_VGA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT) + +#define CONNECTOR_COMPOSITE_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_COMPOSITE << OBJECT_ID_SHIFT) + +#define CONNECTOR_SVIDEO_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SVIDEO << OBJECT_ID_SHIFT) + +#define CONNECTOR_YPbPr_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_YPbPr << OBJECT_ID_SHIFT) + +#define CONNECTOR_D_CONNECTOR_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_D_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_9PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_9PIN_DIN << OBJECT_ID_SHIFT) + +#define CONNECTOR_SCART_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SCART << OBJECT_ID_SHIFT) + +#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT) + +#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT) + +#define CONNECTOR_7PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT) + +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_CROSSFIRE_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT) + +#define CONNECTOR_CROSSFIRE_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT) + + +#define CONNECTOR_HARDCODE_DVI_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT) + +#define CONNECTOR_HARDCODE_DVI_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +/****************************************************/ +/* Router Object ID definition - Shared with BIOS */ +/****************************************************/ +#define ROUTER_I2C_EXTENDER_CNTL_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ROUTER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL << OBJECT_ID_SHIFT) + +/* deleted */ + +/****************************************************/ +/* Object Cap definition - Shared with BIOS */ +/****************************************************/ +#define GRAPHICS_OBJECT_CAP_I2C 0x00000001L +#define GRAPHICS_OBJECT_CAP_TABLE_ID 0x00000002L + + +#define GRAPHICS_OBJECT_I2CCOMMAND_TABLE_ID 0x01 +#define GRAPHICS_OBJECT_HOTPLUGDETECTIONINTERUPT_TABLE_ID 0x02 +#define GRAPHICS_OBJECT_ENCODER_OUTPUT_PROTECTION_TABLE_ID 0x03 + +#if defined(_X86_) +#pragma pack() +#endif + +#endif /*GRAPHICTYPE */ + + + + diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 09251ac3..3aa445e8 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -39,8 +39,50 @@ #define ATI_PCIE_WRITE 0x4 #define ATI_PCIE_READ 0x8 -static int drm_ati_alloc_pcigart_table(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) +static __inline__ void gart_insert_page_into_table(struct drm_ati_pcigart_info *gart_info, dma_addr_t addr, u32 *pci_gart) +{ + u32 page_base; + + page_base = (u32)addr & ATI_PCIGART_PAGE_MASK; + switch(gart_info->gart_reg_if) { + case DRM_ATI_GART_IGP: + page_base |= (upper_32_bits(addr) & 0xff) << 4; + page_base |= 0xc; + break; + case DRM_ATI_GART_PCIE: + page_base >>= 8; + page_base |= (upper_32_bits(addr) & 0xff) << 24; + page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; + break; + default: + case DRM_ATI_GART_PCI: + break; + } + *pci_gart = cpu_to_le32(page_base); +} + +static __inline__ dma_addr_t gart_get_page_from_table(struct drm_ati_pcigart_info *gart_info, u32 *pci_gart) +{ + dma_addr_t retval; + switch(gart_info->gart_reg_if) { + case DRM_ATI_GART_IGP: + retval = (*pci_gart & ATI_PCIGART_PAGE_MASK); + retval += (((*pci_gart & 0xf0) >> 4) << 16) << 16; + break; + case DRM_ATI_GART_PCIE: + retval = (*pci_gart & ~0xc); + retval <<= 8; + break; + case DRM_ATI_GART_PCI: + retval = *pci_gart; + break; + } + + return retval; +} + +int drm_ati_alloc_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) { gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, PAGE_SIZE, @@ -48,8 +90,10 @@ static int drm_ati_alloc_pcigart_table(struct drm_device *dev, if (gart_info->table_handle == NULL) return -ENOMEM; + memset(gart_info->table_handle, 0, gart_info->table_size); return 0; } +EXPORT_SYMBOL(drm_ati_alloc_pcigart_table); static void drm_ati_free_pcigart_table(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) @@ -80,7 +124,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info for (i = 0; i < pages; i++) { if (!entry->busaddr[i]) break; - pci_unmap_single(dev->pdev, entry->busaddr[i], + pci_unmap_page(dev->pdev, entry->busaddr[i], PAGE_SIZE, PCI_DMA_TODEVICE); } @@ -104,18 +148,14 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga struct drm_sg_mem *entry = dev->sg; void *address = NULL; unsigned long pages; - u32 *pci_gart, page_base; + u32 *pci_gart; dma_addr_t bus_address = 0; int i, j, ret = 0; int max_pages; dma_addr_t entry_addr; - if (!entry) { - DRM_ERROR("no scatter/gather memory!\n"); - goto done; - } - if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN && gart_info->table_handle == NULL) { DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); ret = drm_ati_alloc_pcigart_table(dev, gart_info); @@ -123,14 +163,19 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga DRM_ERROR("cannot allocate PCI GART page!\n"); goto done; } + } + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { address = gart_info->table_handle->vaddr; bus_address = gart_info->table_handle->busaddr; } else { address = gart_info->addr; bus_address = gart_info->bus_addr; - DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n", - bus_address, (unsigned long)address); + } + + if (!entry) { + DRM_ERROR("no scatter/gather memory!\n"); + goto done; } pci_gart = (u32 *) address; @@ -139,14 +184,10 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga pages = (entry->pages <= max_pages) ? entry->pages : max_pages; - memset(pci_gart, 0, max_pages * sizeof(u32)); - for (i = 0; i < pages; i++) { /* we need to support large memory configurations */ - entry->busaddr[i] = pci_map_single(dev->pdev, - page_address(entry-> - pagelist[i]), - PAGE_SIZE, PCI_DMA_TODEVICE); + entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i], + 0, PAGE_SIZE, PCI_DMA_TODEVICE); if (entry->busaddr[i] == 0) { DRM_ERROR("unable to map PCIGART pages!\n"); drm_ati_pcigart_cleanup(dev, gart_info); @@ -157,22 +198,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga entry_addr = entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { - page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK; - switch(gart_info->gart_reg_if) { - case DRM_ATI_GART_IGP: - page_base |= (upper_32_bits(entry_addr) & 0xff) << 4; - page_base |= 0xc; - break; - case DRM_ATI_GART_PCIE: - page_base >>= 8; - page_base |= (upper_32_bits(entry_addr) & 0xff) << 24; - page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; - break; - default: - case DRM_ATI_GART_PCI: - break; - } - *pci_gart = cpu_to_le32(page_base); + gart_insert_page_into_table(gart_info, entry_addr, pci_gart); pci_gart++; entry_addr += ATI_PCIGART_PAGE_SIZE; } @@ -192,3 +218,145 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga return ret; } EXPORT_SYMBOL(drm_ati_pcigart_init); + +static int ati_pcigart_needs_unbind_cache_adjust(struct drm_ttm_backend *backend) +{ + return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); +} + +static int ati_pcigart_populate(struct drm_ttm_backend *backend, + unsigned long num_pages, + struct page **pages, + struct page *dummy_read_page) +{ + struct ati_pcigart_ttm_backend *atipci_be = + container_of(backend, struct ati_pcigart_ttm_backend, backend); + + atipci_be->pages = pages; + atipci_be->num_pages = num_pages; + atipci_be->populated = 1; + return 0; +} + +static int ati_pcigart_bind_ttm(struct drm_ttm_backend *backend, + struct drm_bo_mem_reg *bo_mem) +{ + struct ati_pcigart_ttm_backend *atipci_be = + container_of(backend, struct ati_pcigart_ttm_backend, backend); + off_t j; + int i; + struct drm_ati_pcigart_info *info = atipci_be->gart_info; + u32 *pci_gart; + dma_addr_t offset = bo_mem->mm_node->start; + dma_addr_t page_base; + + pci_gart = info->addr; + + j = offset; + while (j < (offset + atipci_be->num_pages)) { + if (gart_get_page_from_table(info, pci_gart+j)) + return -EBUSY; + j++; + } + + for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { + struct page *cur_page = atipci_be->pages[i]; + /* write value */ + page_base = page_to_phys(cur_page); + gart_insert_page_into_table(info, page_base, pci_gart + j); + } + +#if defined(__i386__) || defined(__x86_64__) + wbinvd(); +#else + mb(); +#endif + + atipci_be->gart_flush_fn(atipci_be->dev); + + atipci_be->bound = 1; + atipci_be->offset = offset; + /* need to traverse table and add entries */ + DRM_DEBUG("\n"); + return 0; +} + +static int ati_pcigart_unbind_ttm(struct drm_ttm_backend *backend) +{ + struct ati_pcigart_ttm_backend *atipci_be = + container_of(backend, struct ati_pcigart_ttm_backend, backend); + struct drm_ati_pcigart_info *info = atipci_be->gart_info; + unsigned long offset = atipci_be->offset; + int i; + off_t j; + u32 *pci_gart = info->addr; + + if (atipci_be->bound != 1) + return -EINVAL; + + for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { + *(pci_gart + j) = 0; + } + atipci_be->gart_flush_fn(atipci_be->dev); + atipci_be->bound = 0; + atipci_be->offset = 0; + return 0; +} + +static void ati_pcigart_clear_ttm(struct drm_ttm_backend *backend) +{ + struct ati_pcigart_ttm_backend *atipci_be = + container_of(backend, struct ati_pcigart_ttm_backend, backend); + + DRM_DEBUG("\n"); + if (atipci_be->pages) { + backend->func->unbind(backend); + atipci_be->pages = NULL; + + } + atipci_be->num_pages = 0; +} + +static void ati_pcigart_destroy_ttm(struct drm_ttm_backend *backend) +{ + struct ati_pcigart_ttm_backend *atipci_be; + if (backend) { + DRM_DEBUG("\n"); + atipci_be = container_of(backend, struct ati_pcigart_ttm_backend, backend); + if (atipci_be) { + if (atipci_be->pages) { + backend->func->clear(backend); + } + drm_ctl_free(atipci_be, sizeof(*atipci_be), DRM_MEM_TTM); + } + } +} + +static struct drm_ttm_backend_func ati_pcigart_ttm_backend = +{ + .needs_ub_cache_adjust = ati_pcigart_needs_unbind_cache_adjust, + .populate = ati_pcigart_populate, + .clear = ati_pcigart_clear_ttm, + .bind = ati_pcigart_bind_ttm, + .unbind = ati_pcigart_unbind_ttm, + .destroy = ati_pcigart_destroy_ttm, +}; + +struct drm_ttm_backend *ati_pcigart_init_ttm(struct drm_device *dev, struct drm_ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev)) +{ + struct ati_pcigart_ttm_backend *atipci_be; + + atipci_be = drm_ctl_calloc(1, sizeof (*atipci_be), DRM_MEM_TTM); + if (!atipci_be) + return NULL; + + atipci_be->populated = 0; + atipci_be->backend.func = &ati_pcigart_ttm_backend; +// atipci_be->backend.mem_type = DRM_BO_MEM_TT; + atipci_be->gart_info = info; + atipci_be->gart_flush_fn = gart_flush_fn; + atipci_be->dev = dev; + + return &atipci_be->backend; +} +EXPORT_SYMBOL(ati_pcigart_init_ttm); diff --git a/linux-core/atom-bits.h b/linux-core/atom-bits.h new file mode 100644 index 00000000..f94d2e27 --- /dev/null +++ b/linux-core/atom-bits.h @@ -0,0 +1,48 @@ +/* + * Copyright 2008 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. + * + * Author: Stanislaw Skowronek + */ + +#ifndef ATOM_BITS_H +#define ATOM_BITS_H + +static inline uint8_t get_u8(void *bios, int ptr) +{ + return ((unsigned char *)bios)[ptr]; +} +#define U8(ptr) get_u8(ctx->ctx->bios,(ptr)) +#define CU8(ptr) get_u8(ctx->bios,(ptr)) +static inline uint16_t get_u16(void *bios, int ptr) +{ + return get_u8(bios,ptr)|(((uint16_t)get_u8(bios,ptr+1))<<8); +} +#define U16(ptr) get_u16(ctx->ctx->bios,(ptr)) +#define CU16(ptr) get_u16(ctx->bios,(ptr)) +static inline uint32_t get_u32(void *bios, int ptr) +{ + return get_u16(bios,ptr)|(((uint32_t)get_u16(bios,ptr+2))<<16); +} +#define U32(ptr) get_u32(ctx->ctx->bios,(ptr)) +#define CU32(ptr) get_u32(ctx->bios,(ptr)) +#define CSTR(ptr) (((char *)(ctx->bios))+(ptr)) + +#endif diff --git a/linux-core/atom-names.h b/linux-core/atom-names.h new file mode 100644 index 00000000..2cdc170b --- /dev/null +++ b/linux-core/atom-names.h @@ -0,0 +1,100 @@ +/* + * Copyright 2008 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. + * + * Author: Stanislaw Skowronek + */ + +#ifndef ATOM_NAMES_H +#define ATOM_NAMES_H + +#include "atom.h" + +#ifdef ATOM_DEBUG + +#define ATOM_OP_NAMES_CNT 123 +static char *atom_op_names[ATOM_OP_NAMES_CNT]={ +"RESERVED", "MOVE_REG", "MOVE_PS", "MOVE_WS", "MOVE_FB", "MOVE_PLL", +"MOVE_MC", "AND_REG", "AND_PS", "AND_WS", "AND_FB", "AND_PLL", "AND_MC", +"OR_REG", "OR_PS", "OR_WS", "OR_FB", "OR_PLL", "OR_MC", "SHIFT_LEFT_REG", +"SHIFT_LEFT_PS", "SHIFT_LEFT_WS", "SHIFT_LEFT_FB", "SHIFT_LEFT_PLL", +"SHIFT_LEFT_MC", "SHIFT_RIGHT_REG", "SHIFT_RIGHT_PS", "SHIFT_RIGHT_WS", +"SHIFT_RIGHT_FB", "SHIFT_RIGHT_PLL", "SHIFT_RIGHT_MC", "MUL_REG", +"MUL_PS", "MUL_WS", "MUL_FB", "MUL_PLL", "MUL_MC", "DIV_REG", "DIV_PS", +"DIV_WS", "DIV_FB", "DIV_PLL", "DIV_MC", "ADD_REG", "ADD_PS", "ADD_WS", +"ADD_FB", "ADD_PLL", "ADD_MC", "SUB_REG", "SUB_PS", "SUB_WS", "SUB_FB", +"SUB_PLL", "SUB_MC", "SET_ATI_PORT", "SET_PCI_PORT", "SET_SYS_IO_PORT", +"SET_REG_BLOCK", "SET_FB_BASE", "COMPARE_REG", "COMPARE_PS", +"COMPARE_WS", "COMPARE_FB", "COMPARE_PLL", "COMPARE_MC", "SWITCH", +"JUMP", "JUMP_EQUAL", "JUMP_BELOW", "JUMP_ABOVE", "JUMP_BELOW_OR_EQUAL", +"JUMP_ABOVE_OR_EQUAL", "JUMP_NOT_EQUAL", "TEST_REG", "TEST_PS", "TEST_WS", +"TEST_FB", "TEST_PLL", "TEST_MC", "DELAY_MILLISEC", "DELAY_MICROSEC", +"CALL_TABLE", "REPEAT", "CLEAR_REG", "CLEAR_PS", "CLEAR_WS", "CLEAR_FB", +"CLEAR_PLL", "CLEAR_MC", "NOP", "EOT", "MASK_REG", "MASK_PS", "MASK_WS", +"MASK_FB", "MASK_PLL", "MASK_MC", "POST_CARD", "BEEP", "SAVE_REG", +"RESTORE_REG", "SET_DATA_BLOCK", "XOR_REG", "XOR_PS", "XOR_WS", "XOR_FB", +"XOR_PLL", "XOR_MC", "SHL_REG", "SHL_PS", "SHL_WS", "SHL_FB", "SHL_PLL", +"SHL_MC", "SHR_REG", "SHR_PS", "SHR_WS", "SHR_FB", "SHR_PLL", "SHR_MC", +"DEBUG", "CTB_DS", +}; + +#define ATOM_TABLE_NAMES_CNT 74 +static char *atom_table_names[ATOM_TABLE_NAMES_CNT]={ +"ASIC_Init", "GetDisplaySurfaceSize", "ASIC_RegistersInit", +"VRAM_BlockVenderDetection", "SetClocksRatio", "MemoryControllerInit", +"GPIO_PinInit", "MemoryParamAdjust", "DVOEncoderControl", +"GPIOPinControl", "SetEngineClock", "SetMemoryClock", "SetPixelClock", +"DynamicClockGating", "ResetMemoryDLL", "ResetMemoryDevice", +"MemoryPLLInit", "EnableMemorySelfRefresh", "AdjustMemoryController", +"EnableASIC_StaticPwrMgt", "ASIC_StaticPwrMgtStatusChange", +"DAC_LoadDetection", "TMDS2EncoderControl", "LCD1OutputControl", +"DAC1EncoderControl", "DAC2EncoderControl", "DVOOutputControl", +"CV1OutputControl", "SetCRTC_DPM_State", "TVEncoderControl", +"TMDS1EncoderControl", "LVDSEncoderControl", "TV1OutputControl", +"EnableScaler", "BlankCRTC", "EnableCRTC", "GetPixelClock", +"EnableVGA_Render", "EnableVGA_Access", "SetCRTC_Timing", +"SetCRTC_OverScan", "SetCRTC_Replication", "SelectCRTC_Source", +"EnableGraphSurfaces", "UpdateCRTC_DoubleBufferRegisters", +"LUT_AutoFill", "EnableHW_IconCursor", "GetMemoryClock", +"GetEngineClock", "SetCRTC_UsingDTDTiming", "TVBootUpStdPinDetection", +"DFP2OutputControl", "VRAM_BlockDetectionByStrap", "MemoryCleanUp", +"ReadEDIDFromHWAssistedI2C", "WriteOneByteToHWAssistedI2C", +"ReadHWAssistedI2CStatus", "SpeedFanControl", "PowerConnectorDetection", +"MC_Synchronization", "ComputeMemoryEnginePLL", "MemoryRefreshConversion", +"VRAM_GetCurrentInfoBlock", "DynamicMemorySettings", "MemoryTraining", +"EnableLVDS_SS", "DFP1OutputControl", "SetVoltage", "CRT1OutputControl", +"CRT2OutputControl", "SetupHWAssistedI2CStatus", "ClockSource", +"MemoryDeviceInit", "EnableYUV", +}; + +#define ATOM_IO_NAMES_CNT 5 +static char *atom_io_names[ATOM_IO_NAMES_CNT]={ +"MM", "PLL", "MC", "PCIE", "PCIE PORT", +}; + +#else + +#define ATOM_OP_NAMES_CNT 0 +#define ATOM_TABLE_NAMES_CNT 0 +#define ATOM_IO_NAMES_CNT 0 + +#endif + +#endif diff --git a/linux-core/atom-types.h b/linux-core/atom-types.h new file mode 100644 index 00000000..1125b866 --- /dev/null +++ b/linux-core/atom-types.h @@ -0,0 +1,42 @@ +/* + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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. + * + * Author: Dave Airlie + */ + +#ifndef ATOM_TYPES_H +#define ATOM_TYPES_H + +/* sync atom types to kernel types */ + +typedef uint16_t USHORT; +typedef uint32_t ULONG; +typedef uint8_t UCHAR; + + +#ifndef ATOM_BIG_ENDIAN +#if defined(__BIG_ENDIAN) +#define ATOM_BIG_ENDIAN 1 +#else +#define ATOM_BIG_ENDIAN 0 +#endif +#endif +#endif diff --git a/linux-core/atom.c b/linux-core/atom.c new file mode 100644 index 00000000..33fb02f0 --- /dev/null +++ b/linux-core/atom.c @@ -0,0 +1,1145 @@ +/* + * Copyright 2008 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. + * + * Author: Stanislaw Skowronek + */ + +#include +#include + +#define ATOM_DEBUG + +#include "atom.h" +#include "atom-names.h" +#include "atom-bits.h" + +#define ATOM_COND_ABOVE 0 +#define ATOM_COND_ABOVEOREQUAL 1 +#define ATOM_COND_ALWAYS 2 +#define ATOM_COND_BELOW 3 +#define ATOM_COND_BELOWOREQUAL 4 +#define ATOM_COND_EQUAL 5 +#define ATOM_COND_NOTEQUAL 6 + +#define ATOM_PORT_ATI 0 +#define ATOM_PORT_PCI 1 +#define ATOM_PORT_SYSIO 2 + +#define ATOM_UNIT_MICROSEC 0 +#define ATOM_UNIT_MILLISEC 1 + +#define PLL_INDEX 2 +#define PLL_DATA 3 + +typedef struct { + struct atom_context *ctx; + + uint32_t *ps, *ws; + int ps_shift; + uint16_t start; +} atom_exec_context; + +int atom_debug = 0; +void atom_execute_table(struct atom_context *ctx, int index, uint32_t *params); + +static uint32_t atom_arg_mask[8] = {0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000, 0xFF000000}; +static int atom_arg_shift[8] = {0, 0, 8, 16, 0, 8, 16, 24}; +static int atom_dst_to_src[8][4] = { // translate destination alignment field to the source alignment encoding + { 0, 0, 0, 0 }, + { 1, 2, 3, 0 }, + { 1, 2, 3, 0 }, + { 1, 2, 3, 0 }, + { 4, 5, 6, 7 }, + { 4, 5, 6, 7 }, + { 4, 5, 6, 7 }, + { 4, 5, 6, 7 }, +}; +static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 }; + +static int debug_depth = 0; +#ifdef ATOM_DEBUG +static void debug_print_spaces(int n) +{ + while(n--) + printk(" "); +} +#define DEBUG(...) do if(atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while(0) +#define SDEBUG(...) do if(atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while(0) +#else +#define DEBUG(...) do { } while(0) +#define SDEBUG(...) do { } while(0) +#endif + +static uint32_t atom_iio_execute(struct atom_context *ctx, int base, uint32_t index, uint32_t data) +{ + uint32_t temp = 0xCDCDCDCD; + while(1) + switch(CU8(base)) { + case ATOM_IIO_NOP: + base++; + break; + case ATOM_IIO_READ: + temp = ctx->card->reg_read(ctx->card, CU16(base+1)); + base+=3; + break; + case ATOM_IIO_WRITE: + ctx->card->reg_write(ctx->card, CU16(base+1), temp); + base+=3; + break; + case ATOM_IIO_CLEAR: + temp &= ~((0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2)); + base+=3; + break; + case ATOM_IIO_SET: + temp |= (0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2); + base+=3; + break; + case ATOM_IIO_MOVE_INDEX: + temp &= ~((0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2)); + temp |= ((index >> CU8(base+2)) & (0xFFFFFFFF >> (32-CU8(base+1)))) << CU8(base+3); + base+=4; + break; + case ATOM_IIO_MOVE_DATA: + temp &= ~((0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2)); + temp |= ((data >> CU8(base+2)) & (0xFFFFFFFF >> (32-CU8(base+1)))) << CU8(base+3); + base+=4; + break; + case ATOM_IIO_MOVE_ATTR: + temp &= ~((0xFFFFFFFF >> (32-CU8(base+1))) << CU8(base+2)); + temp |= ((ctx->io_attr >> CU8(base+2)) & (0xFFFFFFFF >> (32-CU8(base+1)))) << CU8(base+3); + base+=4; + break; + case ATOM_IIO_END: + return temp; + default: + printk(KERN_INFO "Unknown IIO opcode.\n"); + return 0; + } +} + +static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr, uint32_t *saved, int print) +{ + uint32_t idx, val = 0xCDCDCDCD, align, arg; + struct atom_context *gctx = ctx->ctx; + arg = attr & 7; + align = (attr >> 3) & 7; + switch(arg) { + case ATOM_ARG_REG: + idx = U16(*ptr); + (*ptr)+=2; + if(print) + DEBUG("REG[0x%04X]", idx); + idx += gctx->reg_block; + switch(gctx->io_mode) { + case ATOM_IO_MM: + val = gctx->card->reg_read(gctx->card, idx); + break; + case ATOM_IO_PCI: + printk(KERN_INFO "PCI registers are not implemented.\n"); + return 0; + case ATOM_IO_SYSIO: + printk(KERN_INFO "SYSIO registers are not implemented.\n"); + return 0; + default: + if(!(gctx->io_mode&0x80)) { + printk(KERN_INFO "Bad IO mode.\n"); + return 0; + } + if(!gctx->iio[gctx->io_mode&0x7F]) { + printk(KERN_INFO "Undefined indirect IO read method %d.\n", gctx->io_mode&0x7F); + return 0; + } + val = atom_iio_execute(gctx, gctx->iio[gctx->io_mode&0x7F], idx, 0); + } + break; + case ATOM_ARG_PS: + idx = U8(*ptr); + (*ptr)++; + val = ctx->ps[idx]; + if(print) + DEBUG("PS[0x%02X,0x%04X]", idx, val); + break; + case ATOM_ARG_WS: + idx = U8(*ptr); + (*ptr)++; + if(print) + DEBUG("WS[0x%02X]", idx); + switch(idx) { + case ATOM_WS_QUOTIENT: + val = gctx->divmul[0]; + break; + case ATOM_WS_REMAINDER: + val = gctx->divmul[1]; + break; + case ATOM_WS_DATAPTR: + val = gctx->data_block; + break; + case ATOM_WS_SHIFT: + val = gctx->shift; + break; + case ATOM_WS_OR_MASK: + val = 1<shift; + break; + case ATOM_WS_AND_MASK: + val = ~(1<shift); + break; + case ATOM_WS_FB_WINDOW: + val = gctx->fb_base; + break; + case ATOM_WS_ATTRIBUTES: + val = gctx->io_attr; + break; + default: + val = ctx->ws[idx]; + } + break; + case ATOM_ARG_ID: + idx = U16(*ptr); + (*ptr)+=2; + if(print) { + if(gctx->data_block) + DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block); + else + DEBUG("ID[0x%04X]", idx); + } + val = U32(idx + gctx->data_block); + break; + case ATOM_ARG_FB: + idx = U8(*ptr); + (*ptr)++; + if(print) + DEBUG("FB[0x%02X]", idx); + printk(KERN_INFO "FB access is not implemented.\n"); + return 0; + case ATOM_ARG_IMM: + switch(align) { + case ATOM_SRC_DWORD: + val = U32(*ptr); + (*ptr)+=4; + if(print) + DEBUG("IMM 0x%08X\n", val); + return val; + case ATOM_SRC_WORD0: + case ATOM_SRC_WORD8: + case ATOM_SRC_WORD16: + val = U16(*ptr); + (*ptr)+=2; + if(print) + DEBUG("IMM 0x%04X\n", val); + return val; + case ATOM_SRC_BYTE0: + case ATOM_SRC_BYTE8: + case ATOM_SRC_BYTE16: + case ATOM_SRC_BYTE24: + val = U8(*ptr); + (*ptr)++; + if(print) + DEBUG("IMM 0x%02X\n", val); + return val; + } + return 0; + case ATOM_ARG_PLL: + idx = U8(*ptr); + (*ptr)++; + if(print) + DEBUG("PLL[0x%02X]", idx); + gctx->card->reg_write(gctx->card, PLL_INDEX, idx); + val = gctx->card->reg_read(gctx->card, PLL_DATA); + break; + case ATOM_ARG_MC: + idx = U8(*ptr); + (*ptr)++; + if(print) + DEBUG("MC[0x%02X]", idx); + val = gctx->card->mc_read(gctx->card, idx); + printk(KERN_INFO "MC registers are not implemented.\n"); + return 0; + } + if(saved) + *saved = val; + val &= atom_arg_mask[align]; + val >>= atom_arg_shift[align]; + if(print) + switch(align) { + case ATOM_SRC_DWORD: + DEBUG(".[31:0] -> 0x%08X\n", val); + break; + case ATOM_SRC_WORD0: + DEBUG(".[15:0] -> 0x%04X\n", val); + break; + case ATOM_SRC_WORD8: + DEBUG(".[23:8] -> 0x%04X\n", val); + break; + case ATOM_SRC_WORD16: + DEBUG(".[31:16] -> 0x%04X\n", val); + break; + case ATOM_SRC_BYTE0: + DEBUG(".[7:0] -> 0x%02X\n", val); + break; + case ATOM_SRC_BYTE8: + DEBUG(".[15:8] -> 0x%02X\n", val); + break; + case ATOM_SRC_BYTE16: + DEBUG(".[23:16] -> 0x%02X\n", val); + break; + case ATOM_SRC_BYTE24: + DEBUG(".[31:24] -> 0x%02X\n", val); + break; + } + return val; +} + +static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr) +{ + uint32_t align = (attr >> 3) & 7, arg = attr & 7; + switch(arg) { + case ATOM_ARG_REG: + case ATOM_ARG_ID: + (*ptr)+=2; + break; + case ATOM_ARG_PLL: + case ATOM_ARG_MC: + case ATOM_ARG_PS: + case ATOM_ARG_WS: + case ATOM_ARG_FB: + (*ptr)++; + break; + case ATOM_ARG_IMM: + switch(align) { + case ATOM_SRC_DWORD: + (*ptr)+=4; + return; + case ATOM_SRC_WORD0: + case ATOM_SRC_WORD8: + case ATOM_SRC_WORD16: + (*ptr)+=2; + return; + case ATOM_SRC_BYTE0: + case ATOM_SRC_BYTE8: + case ATOM_SRC_BYTE16: + case ATOM_SRC_BYTE24: + (*ptr)++; + return; + } + return; + } +} + +static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr) +{ + return atom_get_src_int(ctx, attr, ptr, NULL, 1); +} + +static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t *saved, int print) +{ + return atom_get_src_int(ctx, arg|atom_dst_to_src[(attr>>3)&7][(attr>>6)&3]<<3, ptr, saved, print); +} + +static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr) +{ + atom_skip_src_int(ctx, arg|atom_dst_to_src[(attr>>3)&7][(attr>>6)&3]<<3, ptr); +} + +static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr, uint32_t val, uint32_t saved) +{ + uint32_t align = atom_dst_to_src[(attr>>3)&7][(attr>>6)&3], old_val = val, idx; + struct atom_context *gctx = ctx->ctx; + old_val &= atom_arg_mask[align] >> atom_arg_shift[align]; + val <<= atom_arg_shift[align]; + val &= atom_arg_mask[align]; + saved &= ~atom_arg_mask[align]; + val |= saved; + switch(arg) { + case ATOM_ARG_REG: + idx = U16(*ptr); + (*ptr)+=2; + DEBUG("REG[0x%04X]", idx); + idx += gctx->reg_block; + switch(gctx->io_mode) { + case ATOM_IO_MM: + if(idx == 0) + gctx->card->reg_write(gctx->card, idx, val<<2); + else + gctx->card->reg_write(gctx->card, idx, val); + break; + case ATOM_IO_PCI: + printk(KERN_INFO "PCI registers are not implemented.\n"); + return; + case ATOM_IO_SYSIO: + printk(KERN_INFO "SYSIO registers are not implemented.\n"); + return; + default: + if(!(gctx->io_mode&0x80)) { + printk(KERN_INFO "Bad IO mode.\n"); + return; + } + if(!gctx->iio[gctx->io_mode&0xFF]) { + printk(KERN_INFO "Undefined indirect IO write method %d.\n", gctx->io_mode&0x7F); + return; + } + atom_iio_execute(gctx, gctx->iio[gctx->io_mode&0xFF], idx, val); + } + break; + case ATOM_ARG_PS: + idx = U8(*ptr); + (*ptr)++; + DEBUG("PS[0x%02X]", idx); + ctx->ps[idx] = val; + break; + case ATOM_ARG_WS: + idx = U8(*ptr); + (*ptr)++; + DEBUG("WS[0x%02X]", idx); + switch(idx) { + case ATOM_WS_QUOTIENT: + gctx->divmul[0] = val; + break; + case ATOM_WS_REMAINDER: + gctx->divmul[1] = val; + break; + case ATOM_WS_DATAPTR: + gctx->data_block = val; + break; + case ATOM_WS_SHIFT: + gctx->shift = val; + break; + case ATOM_WS_OR_MASK: + case ATOM_WS_AND_MASK: + break; + case ATOM_WS_FB_WINDOW: + gctx->fb_base = val; + break; + case ATOM_WS_ATTRIBUTES: + gctx->io_attr = val; + break; + default: + ctx->ws[idx] = val; + } + break; + case ATOM_ARG_FB: + idx = U8(*ptr); + (*ptr)++; + DEBUG("FB[0x%02X]", idx); + printk(KERN_INFO "FB access is not implemented.\n"); + return; + case ATOM_ARG_PLL: + idx = U8(*ptr); + (*ptr)++; + DEBUG("PLL[0x%02X]", idx); + gctx->card->reg_write(gctx->card, PLL_INDEX, idx); + gctx->card->reg_write(gctx->card, PLL_DATA, val); + break; + case ATOM_ARG_MC: + idx = U8(*ptr); + (*ptr)++; + DEBUG("MC[0x%02X]", idx); + gctx->card->mc_write(gctx->card, idx, val); + printk(KERN_INFO "MC registers are not implemented.\n"); + return; + } + switch(align) { + case ATOM_SRC_DWORD: + DEBUG(".[31:0] <- 0x%08X\n", old_val); + break; + case ATOM_SRC_WORD0: + DEBUG(".[15:0] <- 0x%04X\n", old_val); + break; + case ATOM_SRC_WORD8: + DEBUG(".[23:8] <- 0x%04X\n", old_val); + break; + case ATOM_SRC_WORD16: + DEBUG(".[31:16] <- 0x%04X\n", old_val); + break; + case ATOM_SRC_BYTE0: + DEBUG(".[7:0] <- 0x%02X\n", old_val); + break; + case ATOM_SRC_BYTE8: + DEBUG(".[15:8] <- 0x%02X\n", old_val); + break; + case ATOM_SRC_BYTE16: + DEBUG(".[23:16] <- 0x%02X\n", old_val); + break; + case ATOM_SRC_BYTE24: + DEBUG(".[31:24] <- 0x%02X\n", old_val); + break; + } +} + +static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst += src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst &= src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg) +{ + printk("ATOM BIOS beeped!\n"); +} + +static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) +{ + int idx = U8((*ptr)++); + if(idx < ATOM_TABLE_NAMES_CNT) + SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); + else + SDEBUG(" table: %d\n", idx); + if(U16(ctx->ctx->cmd_table + 4 + 2*idx)) + atom_execute_table(ctx->ctx, idx, ctx->ps+ctx->ps_shift); +} + +static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t saved; + int dptr = *ptr; + attr &= 0x38; + attr |= atom_def_dst[attr>>3]<<6; + atom_get_dst(ctx, arg, attr, ptr, &saved, 0); + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, 0, saved); +} + +static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + ctx->ctx->cs_equal = (dst == src); + ctx->ctx->cs_above = (dst > src); + SDEBUG(" result: %s %s\n", ctx->ctx->cs_equal?"EQ":"NE", ctx->ctx->cs_above?"GT":"LE"); +} + +static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t count = U8((*ptr)++); + SDEBUG(" count: %d\n", count); + if(arg == ATOM_UNIT_MICROSEC) + schedule_timeout_uninterruptible(usecs_to_jiffies(count)); + else + schedule_timeout_uninterruptible(msecs_to_jiffies(count)); +} + +static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + if(src != 0) { + ctx->ctx->divmul[0] = dst/src; + ctx->ctx->divmul[1] = dst%src; + } else { + ctx->ctx->divmul[0] = 0; + ctx->ctx->divmul[1] = 0; + } +} + +static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg) +{ + /* functionally, a nop */ +} + +static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) +{ + int execute = 0, target = U16(*ptr); + (*ptr)+=2; + switch(arg) { + case ATOM_COND_ABOVE: + execute = ctx->ctx->cs_above; + break; + case ATOM_COND_ABOVEOREQUAL: + execute = ctx->ctx->cs_above || ctx->ctx->cs_equal; + break; + case ATOM_COND_ALWAYS: + execute = 1; + break; + case ATOM_COND_BELOW: + execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal); + break; + case ATOM_COND_BELOWOREQUAL: + execute = !ctx->ctx->cs_above; + break; + case ATOM_COND_EQUAL: + execute = ctx->ctx->cs_equal; + break; + case ATOM_COND_NOTEQUAL: + execute = !ctx->ctx->cs_equal; + break; + } + if(arg != ATOM_COND_ALWAYS) + SDEBUG(" taken: %s\n", execute?"yes":"no"); + SDEBUG(" target: 0x%04X\n", target); + if(execute) + *ptr = ctx->start+target; +} + +static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src1, src2, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src1: "); + src1 = atom_get_src(ctx, attr, ptr); + SDEBUG(" src2: "); + src2 = atom_get_src(ctx, attr, ptr); + dst &= src1; + dst |= src2; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t src, saved; + int dptr = *ptr; + if(((attr>>3)&7) != ATOM_SRC_DWORD) + atom_get_dst(ctx, arg, attr, ptr, &saved, 0); + else { + atom_skip_dst(ctx, arg, attr, ptr); + saved = 0xCDCDCDCD; + } + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, src, saved); +} + +static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + ctx->ctx->divmul[0] = dst*src; +} + +static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg) +{ + /* nothing */ +} + +static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst |= src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t val = U8((*ptr)++); + SDEBUG("POST card output: 0x%02X\n", val); +} + +static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg) +{ + printk(KERN_INFO "unimplemented!\n"); +} + +static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg) +{ + printk(KERN_INFO "unimplemented!\n"); +} + +static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg) +{ + printk(KERN_INFO "unimplemented!\n"); +} + +static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg) +{ + int idx = U8(*ptr); + (*ptr)++; + SDEBUG(" block: %d\n", idx); + if(!idx) + ctx->ctx->data_block = 0; + else if(idx==255) + ctx->ctx->data_block = ctx->start; + else + ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2*idx); + SDEBUG(" base: 0x%04X\n", ctx->ctx->data_block); +} + +static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + SDEBUG(" fb_base: "); + ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr); +} + +static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg) +{ + int port; + switch(arg) { + case ATOM_PORT_ATI: + port = U16(*ptr); + if(port < ATOM_IO_NAMES_CNT) + SDEBUG(" port: %d (%s)\n", port, atom_io_names[port]); + else + SDEBUG(" port: %d\n", port); + if(!port) + ctx->ctx->io_mode = ATOM_IO_MM; + else + ctx->ctx->io_mode = ATOM_IO_IIO|port; + (*ptr)+=2; + break; + case ATOM_PORT_PCI: + ctx->ctx->io_mode = ATOM_IO_PCI; + (*ptr)++; + break; + case ATOM_PORT_SYSIO: + ctx->ctx->io_mode = ATOM_IO_SYSIO; + (*ptr)++; + break; + } +} + +static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg) +{ + ctx->ctx->reg_block = U16(*ptr); + (*ptr)+=2; + SDEBUG(" base: 0x%04X\n", ctx->ctx->reg_block); +} + +static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++), shift; + uint32_t saved, dst; + int dptr = *ptr; + attr &= 0x38; + attr |= atom_def_dst[attr>>3]<<6; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + shift = U8((*ptr)++); + SDEBUG(" shift: %d\n", shift); + dst <<= shift; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++), shift; + uint32_t saved, dst; + int dptr = *ptr; + attr &= 0x38; + attr |= atom_def_dst[attr>>3]<<6; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + shift = U8((*ptr)++); + SDEBUG(" shift: %d\n", shift); + dst >>= shift; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst -= src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t src, val, target; + SDEBUG(" switch: "); + src = atom_get_src(ctx, attr, ptr); + while(U16(*ptr) != ATOM_CASE_END) + if(U8(*ptr) == ATOM_CASE_MAGIC) { + (*ptr)++; + SDEBUG(" case: "); + val = atom_get_src(ctx, (attr&0x38)|ATOM_ARG_IMM, ptr); + target = U16(*ptr); + if(val == src) { + SDEBUG(" target: %04X\n", target); + *ptr = ctx->start+target; + return; + } + (*ptr) += 2; + } else { + printk(KERN_INFO "Bad case.\n"); + return; + } + (*ptr) += 2; +} + +static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src; + SDEBUG(" src1: "); + dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1); + SDEBUG(" src2: "); + src = atom_get_src(ctx, attr, ptr); + ctx->ctx->cs_equal = ((dst & src) == 0); + SDEBUG(" result: %s\n", ctx->ctx->cs_equal?"EQ":"NE"); +} + +static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg) +{ + uint8_t attr = U8((*ptr)++); + uint32_t dst, src, saved; + int dptr = *ptr; + SDEBUG(" dst: "); + dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); + SDEBUG(" src: "); + src = atom_get_src(ctx, attr, ptr); + dst ^= src; + SDEBUG(" dst: "); + atom_put_dst(ctx, arg, attr, &dptr, dst, saved); +} + +static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg) +{ + printk(KERN_INFO "unimplemented!\n"); +} + +static struct { + void (*func)(atom_exec_context *, int *, int); + int arg; +} opcode_table[ATOM_OP_CNT] = { + { NULL, 0 }, + { atom_op_move, ATOM_ARG_REG }, + { atom_op_move, ATOM_ARG_PS }, + { atom_op_move, ATOM_ARG_WS }, + { atom_op_move, ATOM_ARG_FB }, + { atom_op_move, ATOM_ARG_PLL }, + { atom_op_move, ATOM_ARG_MC }, + { atom_op_and, ATOM_ARG_REG }, + { atom_op_and, ATOM_ARG_PS }, + { atom_op_and, ATOM_ARG_WS }, + { atom_op_and, ATOM_ARG_FB }, + { atom_op_and, ATOM_ARG_PLL }, + { atom_op_and, ATOM_ARG_MC }, + { atom_op_or, ATOM_ARG_REG }, + { atom_op_or, ATOM_ARG_PS }, + { atom_op_or, ATOM_ARG_WS }, + { atom_op_or, ATOM_ARG_FB }, + { atom_op_or, ATOM_ARG_PLL }, + { atom_op_or, ATOM_ARG_MC }, + { atom_op_shl, ATOM_ARG_REG }, + { atom_op_shl, ATOM_ARG_PS }, + { atom_op_shl, ATOM_ARG_WS }, + { atom_op_shl, ATOM_ARG_FB }, + { atom_op_shl, ATOM_ARG_PLL }, + { atom_op_shl, ATOM_ARG_MC }, + { atom_op_shr, ATOM_ARG_REG }, + { atom_op_shr, ATOM_ARG_PS }, + { atom_op_shr, ATOM_ARG_WS }, + { atom_op_shr, ATOM_ARG_FB }, + { atom_op_shr, ATOM_ARG_PLL }, + { atom_op_shr, ATOM_ARG_MC }, + { atom_op_mul, ATOM_ARG_REG }, + { atom_op_mul, ATOM_ARG_PS }, + { atom_op_mul, ATOM_ARG_WS }, + { atom_op_mul, ATOM_ARG_FB }, + { atom_op_mul, ATOM_ARG_PLL }, + { atom_op_mul, ATOM_ARG_MC }, + { atom_op_div, ATOM_ARG_REG }, + { atom_op_div, ATOM_ARG_PS }, + { atom_op_div, ATOM_ARG_WS }, + { atom_op_div, ATOM_ARG_FB }, + { atom_op_div, ATOM_ARG_PLL }, + { atom_op_div, ATOM_ARG_MC }, + { atom_op_add, ATOM_ARG_REG }, + { atom_op_add, ATOM_ARG_PS }, + { atom_op_add, ATOM_ARG_WS }, + { atom_op_add, ATOM_ARG_FB }, + { atom_op_add, ATOM_ARG_PLL }, + { atom_op_add, ATOM_ARG_MC }, + { atom_op_sub, ATOM_ARG_REG }, + { atom_op_sub, ATOM_ARG_PS }, + { atom_op_sub, ATOM_ARG_WS }, + { atom_op_sub, ATOM_ARG_FB }, + { atom_op_sub, ATOM_ARG_PLL }, + { atom_op_sub, ATOM_ARG_MC }, + { atom_op_setport, ATOM_PORT_ATI }, + { atom_op_setport, ATOM_PORT_PCI }, + { atom_op_setport, ATOM_PORT_SYSIO }, + { atom_op_setregblock, 0 }, + { atom_op_setfbbase, 0 }, + { atom_op_compare, ATOM_ARG_REG }, + { atom_op_compare, ATOM_ARG_PS }, + { atom_op_compare, ATOM_ARG_WS }, + { atom_op_compare, ATOM_ARG_FB }, + { atom_op_compare, ATOM_ARG_PLL }, + { atom_op_compare, ATOM_ARG_MC }, + { atom_op_switch, 0 }, + { atom_op_jump, ATOM_COND_ALWAYS }, + { atom_op_jump, ATOM_COND_EQUAL }, + { atom_op_jump, ATOM_COND_BELOW }, + { atom_op_jump, ATOM_COND_ABOVE }, + { atom_op_jump, ATOM_COND_BELOWOREQUAL }, + { atom_op_jump, ATOM_COND_ABOVEOREQUAL }, + { atom_op_jump, ATOM_COND_NOTEQUAL }, + { atom_op_test, ATOM_ARG_REG }, + { atom_op_test, ATOM_ARG_PS }, + { atom_op_test, ATOM_ARG_WS }, + { atom_op_test, ATOM_ARG_FB }, + { atom_op_test, ATOM_ARG_PLL }, + { atom_op_test, ATOM_ARG_MC }, + { atom_op_delay, ATOM_UNIT_MILLISEC }, + { atom_op_delay, ATOM_UNIT_MICROSEC }, + { atom_op_calltable, 0 }, + { atom_op_repeat, 0 }, + { atom_op_clear, ATOM_ARG_REG }, + { atom_op_clear, ATOM_ARG_PS }, + { atom_op_clear, ATOM_ARG_WS }, + { atom_op_clear, ATOM_ARG_FB }, + { atom_op_clear, ATOM_ARG_PLL }, + { atom_op_clear, ATOM_ARG_MC }, + { atom_op_nop, 0 }, + { atom_op_eot, 0 }, + { atom_op_mask, ATOM_ARG_REG }, + { atom_op_mask, ATOM_ARG_PS }, + { atom_op_mask, ATOM_ARG_WS }, + { atom_op_mask, ATOM_ARG_FB }, + { atom_op_mask, ATOM_ARG_PLL }, + { atom_op_mask, ATOM_ARG_MC }, + { atom_op_postcard, 0 }, + { atom_op_beep, 0 }, + { atom_op_savereg, 0 }, + { atom_op_restorereg, 0 }, + { atom_op_setdatablock, 0 }, + { atom_op_xor, ATOM_ARG_REG }, + { atom_op_xor, ATOM_ARG_PS }, + { atom_op_xor, ATOM_ARG_WS }, + { atom_op_xor, ATOM_ARG_FB }, + { atom_op_xor, ATOM_ARG_PLL }, + { atom_op_xor, ATOM_ARG_MC }, + { atom_op_shl, ATOM_ARG_REG }, + { atom_op_shl, ATOM_ARG_PS }, + { atom_op_shl, ATOM_ARG_WS }, + { atom_op_shl, ATOM_ARG_FB }, + { atom_op_shl, ATOM_ARG_PLL }, + { atom_op_shl, ATOM_ARG_MC }, + { atom_op_shr, ATOM_ARG_REG }, + { atom_op_shr, ATOM_ARG_PS }, + { atom_op_shr, ATOM_ARG_WS }, + { atom_op_shr, ATOM_ARG_FB }, + { atom_op_shr, ATOM_ARG_PLL }, + { atom_op_shr, ATOM_ARG_MC }, + { atom_op_debug, 0 }, +}; + +void atom_execute_table(struct atom_context *ctx, int index, uint32_t *params) +{ + int base = CU16(ctx->cmd_table+4+2*index); + int len, ws, ps, ptr; + unsigned char op; + atom_exec_context ectx; + + if(!base) + return; + + len = CU16(base+ATOM_CT_SIZE_PTR); + ws = CU8(base+ATOM_CT_WS_PTR); + ps = CU8(base+ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK; + ptr = base+ATOM_CT_CODE_PTR; + + SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps); + + /* reset reg block */ + ctx->reg_block = 0; + ectx.ctx = ctx; + ectx.ps_shift = ps/4; + ectx.start = base; + ectx.ps = params; + if(ws) + ectx.ws = kzalloc(4*ws, GFP_KERNEL); + else + ectx.ws = NULL; + + debug_depth++; + while(1) { + op = CU8(ptr++); + if(op0) + opcode_table[op].func(&ectx, &ptr, opcode_table[op].arg); + else + break; + + if(op == ATOM_OP_EOT) + break; + } + debug_depth--; + SDEBUG("<<\n"); + + if(ws) + kfree(ectx.ws); +} + +static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; +static void atom_index_iio(struct atom_context *ctx, int base) +{ + ctx->iio = kzalloc(2*256, GFP_KERNEL); + while(CU8(base) == ATOM_IIO_START) { + ctx->iio[CU8(base+1)] = base+2; + base += 2; + while(CU8(base) != ATOM_IIO_END) + base += atom_iio_len[CU8(base)]; + base += 3; + } +} + +struct atom_context *atom_parse(struct card_info *card, void *bios) +{ + int base; + struct atom_context *ctx = kzalloc(sizeof(struct atom_context), GFP_KERNEL); + char *str; + + ctx->card = card; + ctx->bios = bios; + + if(CU16(0) != ATOM_BIOS_MAGIC) { + printk(KERN_INFO "Invalid BIOS magic.\n"); + kfree(ctx); + return NULL; + } + if(strncmp(CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC, strlen(ATOM_ATI_MAGIC))) { + printk(KERN_INFO "Invalid ATI magic.\n"); + kfree(ctx); + return NULL; + } + + base = CU16(ATOM_ROM_TABLE_PTR); + if(strncmp(CSTR(base+ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC, strlen(ATOM_ROM_MAGIC))) { + printk(KERN_INFO "Invalid ATOM magic.\n"); + kfree(ctx); + return NULL; + } + + ctx->cmd_table = CU16(base+ATOM_ROM_CMD_PTR); + ctx->data_table = CU16(base+ATOM_ROM_DATA_PTR); + atom_index_iio(ctx, CU16(ctx->data_table+ATOM_DATA_IIO_PTR)+4); + + str = CSTR(CU16(base+ATOM_ROM_MSG_PTR)); + while(*str && ((*str == '\n') || (*str == '\r'))) + str++; + printk(KERN_INFO "ATOM BIOS: %s", str); + + return ctx; +} + +int atom_asic_init(struct atom_context *ctx) +{ + int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR); + uint32_t ps[16]; + memset(ps, 0, 64); + + ps[0] = CU32(hwi + ATOM_FWI_DEFSCLK_PTR); + ps[1] = CU32(hwi + ATOM_FWI_DEFMCLK_PTR); + if(!ps[0] || !ps[1]) + return 1; + + if(!CU16(ctx->cmd_table+4+2*ATOM_CMD_INIT)) + return 1; + atom_execute_table(ctx, ATOM_CMD_INIT, ps); + + return 0; +} + +void atom_destroy(struct atom_context *ctx) +{ + if(ctx->iio) + kfree(ctx->iio); + kfree(ctx); +} + + +void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start) +{ + int offset = index * 2 + 4; + int idx = CU16(ctx->data_table + offset); + + if (size) + *size = CU16(idx); + if (frev) + *frev = CU8(idx + 2); + if (crev) + *crev = CU8(idx + 3); + *data_start = idx; + return; +} + +void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev) +{ + int offset = index * 2 + 4; + int idx = CU16(ctx->cmd_table + offset); + + if (frev) + *frev = CU8(idx + 2); + if (crev) + *crev = CU8(idx + 3); + return; +} diff --git a/linux-core/atom.h b/linux-core/atom.h new file mode 100644 index 00000000..a5d93322 --- /dev/null +++ b/linux-core/atom.h @@ -0,0 +1,148 @@ +/* + * Copyright 2008 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. + * + * Author: Stanislaw Skowronek + */ + +#ifndef ATOM_H +#define ATOM_H + +#include +#include "drmP.h" + +#define ATOM_BIOS_MAGIC 0xAA55 +#define ATOM_ATI_MAGIC_PTR 0x30 +#define ATOM_ATI_MAGIC " 761295520" +#define ATOM_ROM_TABLE_PTR 0x48 + +#define ATOM_ROM_MAGIC "ATOM" +#define ATOM_ROM_MAGIC_PTR 4 + +#define ATOM_ROM_MSG_PTR 0x10 +#define ATOM_ROM_CMD_PTR 0x1E +#define ATOM_ROM_DATA_PTR 0x20 + +#define ATOM_CMD_INIT 0 +#define ATOM_CMD_SETSCLK 0x0A +#define ATOM_CMD_SETMCLK 0x0B +#define ATOM_CMD_SETPCLK 0x0C + +#define ATOM_DATA_FWI_PTR 0xC +#define ATOM_DATA_IIO_PTR 0x32 + +#define ATOM_FWI_DEFSCLK_PTR 8 +#define ATOM_FWI_DEFMCLK_PTR 0xC +#define ATOM_FWI_MAXSCLK_PTR 0x24 +#define ATOM_FWI_MAXMCLK_PTR 0x28 + +#define ATOM_CT_SIZE_PTR 0 +#define ATOM_CT_WS_PTR 4 +#define ATOM_CT_PS_PTR 5 +#define ATOM_CT_PS_MASK 0x7F +#define ATOM_CT_CODE_PTR 6 + +#define ATOM_OP_CNT 123 +#define ATOM_OP_EOT 91 + +#define ATOM_CASE_MAGIC 0x63 +#define ATOM_CASE_END 0x5A5A + +#define ATOM_ARG_REG 0 +#define ATOM_ARG_PS 1 +#define ATOM_ARG_WS 2 +#define ATOM_ARG_ID 4 +#define ATOM_ARG_FB 3 +#define ATOM_ARG_IMM 5 +#define ATOM_ARG_PLL 6 +#define ATOM_ARG_MC 7 + +#define ATOM_SRC_DWORD 0 +#define ATOM_SRC_WORD0 1 +#define ATOM_SRC_WORD8 2 +#define ATOM_SRC_WORD16 3 +#define ATOM_SRC_BYTE0 4 +#define ATOM_SRC_BYTE8 5 +#define ATOM_SRC_BYTE16 6 +#define ATOM_SRC_BYTE24 7 + +#define ATOM_WS_QUOTIENT 0x40 +#define ATOM_WS_REMAINDER 0x41 +#define ATOM_WS_DATAPTR 0x42 +#define ATOM_WS_SHIFT 0x43 +#define ATOM_WS_OR_MASK 0x44 +#define ATOM_WS_AND_MASK 0x45 +#define ATOM_WS_FB_WINDOW 0x46 +#define ATOM_WS_ATTRIBUTES 0x47 + +#define ATOM_IIO_NOP 0 +#define ATOM_IIO_START 1 +#define ATOM_IIO_READ 2 +#define ATOM_IIO_WRITE 3 +#define ATOM_IIO_CLEAR 4 +#define ATOM_IIO_SET 5 +#define ATOM_IIO_MOVE_INDEX 6 +#define ATOM_IIO_MOVE_ATTR 7 +#define ATOM_IIO_MOVE_DATA 8 +#define ATOM_IIO_END 9 + +#define ATOM_IO_MM 0 +#define ATOM_IO_PCI 1 +#define ATOM_IO_SYSIO 2 +#define ATOM_IO_IIO 0x80 + +struct card_info { + struct drm_device *dev; + void (* reg_write)(struct card_info *, uint32_t, uint32_t); // filled by driver + uint32_t (* reg_read)(struct card_info *, uint32_t); // filled by driver + void (* mc_write)(struct card_info *, uint32_t, uint32_t); // filled by driver + uint32_t (* mc_read)(struct card_info *, uint32_t); // filled by driver +// int (* read_rom)(struct card_info *, uint8_t *); // filled by driver +}; + +struct atom_context { + struct card_info *card; + void *bios; + uint32_t cmd_table, data_table; + uint16_t *iio; + + uint16_t data_block; + uint32_t fb_base; + uint32_t divmul[2]; + uint16_t io_attr; + uint16_t reg_block; + uint8_t shift; + int cs_equal, cs_above; + int io_mode; +}; + +extern int atom_debug; + +struct atom_context *atom_parse(struct card_info *, void *); +void atom_execute_table(struct atom_context *, int, uint32_t *); +int atom_asic_init(struct atom_context *); +void atom_destroy(struct atom_context *); +void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start); +void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev); +#include "atom-types.h" +#include "atombios.h" +#include "ObjectID.h" + +#endif diff --git a/linux-core/atombios.h b/linux-core/atombios.h new file mode 100644 index 00000000..2e7dc6c2 --- /dev/null +++ b/linux-core/atombios.h @@ -0,0 +1,4498 @@ +/* + * Copyright 2006-2007 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. + */ + + +/****************************************************************************/ +/*Portion I: Definitions shared between VBIOS and Driver */ +/****************************************************************************/ + + +#ifndef _ATOMBIOS_H +#define _ATOMBIOS_H + +#define ATOM_VERSION_MAJOR 0x00020000 +#define ATOM_VERSION_MINOR 0x00000002 + +#define ATOM_HEADER_VERSION (ATOM_VERSION_MAJOR | ATOM_VERSION_MINOR) + +/* Endianness should be specified before inclusion, + * default to little endian + */ +#ifndef ATOM_BIG_ENDIAN +#error Endian not specified +#endif + +#ifdef _H2INC + #ifndef ULONG + typedef unsigned long ULONG; + #endif + + #ifndef UCHAR + typedef unsigned char UCHAR; + #endif + + #ifndef USHORT + typedef unsigned short USHORT; + #endif +#endif + +#define ATOM_DAC_A 0 +#define ATOM_DAC_B 1 +#define ATOM_EXT_DAC 2 + +#define ATOM_CRTC1 0 +#define ATOM_CRTC2 1 + +#define ATOM_DIGA 0 +#define ATOM_DIGB 1 + +#define ATOM_PPLL1 0 +#define ATOM_PPLL2 1 + +#define ATOM_SCALER1 0 +#define ATOM_SCALER2 1 + +#define ATOM_SCALER_DISABLE 0 +#define ATOM_SCALER_CENTER 1 +#define ATOM_SCALER_EXPANSION 2 +#define ATOM_SCALER_MULTI_EX 3 + +#define ATOM_DISABLE 0 +#define ATOM_ENABLE 1 +#define ATOM_LCD_BLOFF (ATOM_DISABLE+2) +#define ATOM_LCD_BLON (ATOM_ENABLE+2) +#define ATOM_LCD_BL_BRIGHTNESS_CONTROL (ATOM_ENABLE+3) +#define ATOM_LCD_SELFTEST_START (ATOM_DISABLE+5) +#define ATOM_LCD_SELFTEST_STOP (ATOM_ENABLE+5) +#define ATOM_ENCODER_INIT (ATOM_DISABLE+7) + +#define ATOM_BLANKING 1 +#define ATOM_BLANKING_OFF 0 + +#define ATOM_CURSOR1 0 +#define ATOM_CURSOR2 1 + +#define ATOM_ICON1 0 +#define ATOM_ICON2 1 + +#define ATOM_CRT1 0 +#define ATOM_CRT2 1 + +#define ATOM_TV_NTSC 1 +#define ATOM_TV_NTSCJ 2 +#define ATOM_TV_PAL 3 +#define ATOM_TV_PALM 4 +#define ATOM_TV_PALCN 5 +#define ATOM_TV_PALN 6 +#define ATOM_TV_PAL60 7 +#define ATOM_TV_SECAM 8 +#define ATOM_TV_CV 16 + +#define ATOM_DAC1_PS2 1 +#define ATOM_DAC1_CV 2 +#define ATOM_DAC1_NTSC 3 +#define ATOM_DAC1_PAL 4 + +#define ATOM_DAC2_PS2 ATOM_DAC1_PS2 +#define ATOM_DAC2_CV ATOM_DAC1_CV +#define ATOM_DAC2_NTSC ATOM_DAC1_NTSC +#define ATOM_DAC2_PAL ATOM_DAC1_PAL + +#define ATOM_PM_ON 0 +#define ATOM_PM_STANDBY 1 +#define ATOM_PM_SUSPEND 2 +#define ATOM_PM_OFF 3 + +/* Bit0:{=0:single, =1:dual}, + Bit1 {=0:666RGB, =1:888RGB}, + Bit2:3:{Grey level} + Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}*/ + +#define ATOM_PANEL_MISC_DUAL 0x00000001 +#define ATOM_PANEL_MISC_888RGB 0x00000002 +#define ATOM_PANEL_MISC_GREY_LEVEL 0x0000000C +#define ATOM_PANEL_MISC_FPDI 0x00000010 +#define ATOM_PANEL_MISC_GREY_LEVEL_SHIFT 2 +#define ATOM_PANEL_MISC_SPATIAL 0x00000020 +#define ATOM_PANEL_MISC_TEMPORAL 0x00000040 +#define ATOM_PANEL_MISC_API_ENABLED 0x00000080 + + +#define MEMTYPE_DDR1 "DDR1" +#define MEMTYPE_DDR2 "DDR2" +#define MEMTYPE_DDR3 "DDR3" +#define MEMTYPE_DDR4 "DDR4" + +#define ASIC_BUS_TYPE_PCI "PCI" +#define ASIC_BUS_TYPE_AGP "AGP" +#define ASIC_BUS_TYPE_PCIE "PCI_EXPRESS" + +/* Maximum size of that FireGL flag string */ + +#define ATOM_FIREGL_FLAG_STRING "FGL" //Flag used to enable FireGL Support +#define ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING 3 //sizeof( ATOM_FIREGL_FLAG_STRING ) + +#define ATOM_FAKE_DESKTOP_STRING "DSK" //Flag used to enable mobile ASIC on Desktop +#define ATOM_MAX_SIZE_OF_FAKE_DESKTOP_STRING ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING + +#define ATOM_M54T_FLAG_STRING "M54T" //Flag used to enable M54T Support +#define ATOM_MAX_SIZE_OF_M54T_FLAG_STRING 4 //sizeof( ATOM_M54T_FLAG_STRING ) + +#define HW_ASSISTED_I2C_STATUS_FAILURE 2 +#define HW_ASSISTED_I2C_STATUS_SUCCESS 1 + +#pragma pack(1) /* BIOS data must use byte aligment */ + +/* Define offset to location of ROM header. */ + +#define OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER 0x00000048L +#define OFFSET_TO_ATOM_ROM_IMAGE_SIZE 0x00000002L + +#define OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE 0x94 +#define MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE 20 /* including the terminator 0x0! */ +#define OFFSET_TO_GET_ATOMBIOS_STRINGS_NUMBER 0x002f +#define OFFSET_TO_GET_ATOMBIOS_STRINGS_START 0x006e + +/* Common header for all ROM Data tables. + Every table pointed _ATOM_MASTER_DATA_TABLE has this common header. + And the pointer actually points to this header. */ + +typedef struct _ATOM_COMMON_TABLE_HEADER +{ + USHORT usStructureSize; + UCHAR ucTableFormatRevision; /*Change it when the Parser is not backward compatible */ + UCHAR ucTableContentRevision; /*Change it only when the table needs to change but the firmware */ + /*Image can't be updated, while Driver needs to carry the new table! */ +}ATOM_COMMON_TABLE_HEADER; + +typedef struct _ATOM_ROM_HEADER +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR uaFirmWareSignature[4]; /*Signature to distinguish between Atombios and non-atombios, + atombios should init it as "ATOM", don't change the position */ + USHORT usBiosRuntimeSegmentAddress; + USHORT usProtectedModeInfoOffset; + USHORT usConfigFilenameOffset; + USHORT usCRC_BlockOffset; + USHORT usBIOS_BootupMessageOffset; + USHORT usInt10Offset; + USHORT usPciBusDevInitCode; + USHORT usIoBaseAddress; + USHORT usSubsystemVendorID; + USHORT usSubsystemID; + USHORT usPCI_InfoOffset; + USHORT usMasterCommandTableOffset; /*Offset for SW to get all command table offsets, Don't change the position */ + USHORT usMasterDataTableOffset; /*Offset for SW to get all data table offsets, Don't change the position */ + UCHAR ucExtendedFunctionCode; + UCHAR ucReserved; +}ATOM_ROM_HEADER; + +/*==============================Command Table Portion==================================== */ + +#ifdef UEFI_BUILD + #define UTEMP USHORT + #define USHORT void* +#endif + +typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ + USHORT ASIC_Init; //Function Table, used by various SW components,latest version 1.1 + USHORT GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON + USHORT ASIC_RegistersInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT VRAM_BlockVenderDetection; //Atomic Table, used only by Bios + USHORT DIGxEncoderControl; //Only used by Bios + USHORT MemoryControllerInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT EnableCRTCMemReq; //Function Table,directly used by various SW components,latest version 2.1 + USHORT MemoryParamAdjust; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed + USHORT DVOEncoderControl; //Function Table,directly used by various SW components,latest version 1.2 + USHORT GPIOPinControl; //Atomic Table, only used by Bios + USHORT SetEngineClock; //Function Table,directly used by various SW components,latest version 1.1 + USHORT SetMemoryClock; //Function Table,directly used by various SW components,latest version 1.1 + USHORT SetPixelClock; //Function Table,directly used by various SW components,latest version 1.2 + USHORT DynamicClockGating; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT ResetMemoryDLL; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT ResetMemoryDevice; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT MemoryPLLInit; + USHORT AdjustDisplayPll; //only used by Bios + USHORT AdjustMemoryController; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT EnableASIC_StaticPwrMgt; //Atomic Table, only used by Bios + USHORT ASIC_StaticPwrMgtStatusChange; //Obsolete , only used by Bios + USHORT DAC_LoadDetection; //Atomic Table, directly used by various SW components,latest version 1.2 + USHORT LVTMAEncoderControl; //Atomic Table,directly used by various SW components,latest version 1.3 + USHORT LCD1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC1EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC2EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DVOOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT CV1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT GetConditionalGoldenSetting; //only used by Bios + USHORT TVEncoderControl; //Function Table,directly used by various SW components,latest version 1.1 + USHORT TMDSAEncoderControl; //Atomic Table, directly used by various SW components,latest version 1.3 + USHORT LVDSEncoderControl; //Atomic Table, directly used by various SW components,latest version 1.3 + USHORT TV1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableScaler; //Atomic Table, used only by Bios + USHORT BlankCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT GetPixelClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableVGA_Render; //Function Table,directly used by various SW components,latest version 1.1 + USHORT EnableVGA_Access; //Obsolete , only used by Bios + USHORT SetCRTC_Timing; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetCRTC_OverScan; //Atomic Table, used by various SW components,latest version 1.1 + USHORT SetCRTC_Replication; //Atomic Table, used only by Bios + USHORT SelectCRTC_Source; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableGraphSurfaces; //Atomic Table, used only by Bios + USHORT UpdateCRTC_DoubleBufferRegisters; + USHORT LUT_AutoFill; //Atomic Table, only used by Bios + USHORT EnableHW_IconCursor; //Atomic Table, only used by Bios + USHORT GetMemoryClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT GetEngineClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetCRTC_UsingDTDTiming; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT ExternalEncoderControl; //Atomic Table, directly used by various SW components,latest version 2.1 + USHORT LVTMAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT VRAM_BlockDetectionByStrap; + USHORT MemoryCleanUp; //Atomic Table, only used by Bios + USHORT ProcessI2cChannelTransaction; //Function Table,only used by Bios + USHORT WriteOneByteToHWAssistedI2C; //Function Table,indirectly used by various SW components + USHORT ReadHWAssistedI2CStatus; //Atomic Table, indirectly used by various SW components + USHORT SpeedFanControl; //Function Table,indirectly used by various SW components,called from ASIC_Init + USHORT PowerConnectorDetection; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT MC_Synchronization; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT ComputeMemoryEnginePLL; //Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock + USHORT MemoryRefreshConversion; //Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock + USHORT VRAM_GetCurrentInfoBlock; + USHORT DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT MemoryTraining; + USHORT EnableSpreadSpectrumOnPPLL; //Atomic Table, directly used by various SW components,latest version 1.2 + USHORT TMDSAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetVoltage; //Function Table,directly and/or indirectly used by various SW components,latest version 1.1 + USHORT DAC1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC2OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetupHWAssistedI2CStatus; //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C" + USHORT ClockSource; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT MemoryDeviceInit; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT EnableYUV; //Atomic Table, indirectly used by various SW components,called from EnableVGARender + USHORT DIG1EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG2EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG1TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG2TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT ProcessAuxChannelTransaction; //Function Table,only used by Bios + USHORT DPEncoderService; //Function Table,only used by Bios +}ATOM_MASTER_LIST_OF_COMMAND_TABLES; + +#define ReadEDIDFromHWAssistedI2C ProcessI2cChannelTransaction + +#define UNIPHYTransmitterControl DIG1TransmitterControl +#define LVTMATransmitterControl DIG2TransmitterControl +#define SetCRTC_DPM_State GetConditionalGoldenSetting + +typedef struct _ATOM_MASTER_COMMAND_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables; +}ATOM_MASTER_COMMAND_TABLE; + +typedef struct _ATOM_TABLE_ATTRIBUTE +{ +#if ATOM_BIG_ENDIAN + USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag + USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword), + USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword), +#else + USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword), + USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword), + USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag +#endif +}ATOM_TABLE_ATTRIBUTE; + +typedef union _ATOM_TABLE_ATTRIBUTE_ACCESS +{ + ATOM_TABLE_ATTRIBUTE sbfAccess; + USHORT susAccess; +}ATOM_TABLE_ATTRIBUTE_ACCESS; + +// Common header for all command tables. +//Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header. +//And the pointer actually points to this header. + +typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER +{ + ATOM_COMMON_TABLE_HEADER CommonHeader; + ATOM_TABLE_ATTRIBUTE TableAttribute; +}ATOM_COMMON_ROM_COMMAND_TABLE_HEADER; + + +typedef struct _ASIC_INIT_PARAMETERS +{ + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit +}ASIC_INIT_PARAMETERS; + +#define COMPUTE_MEMORY_PLL_PARAM 1 +#define COMPUTE_ENGINE_PLL_PARAM 2 + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS +{ + ULONG ulClock; //When returen, it's the re-calculated clock based on given Fb_div Post_Div and ref_div + UCHAR ucAction; //0:reserved //1:Memory //2:Engine + UCHAR ucReserved; //may expand to return larger Fbdiv later + UCHAR ucFbDiv; //return value + UCHAR ucPostDiv; //return value +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS; + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 +{ + ULONG ulClock; //When return, [23:0] return real clock + UCHAR ucAction; //0:reserved;COMPUTE_MEMORY_PLL_PARAM:Memory;COMPUTE_ENGINE_PLL_PARAM:Engine. it return ref_div to be written to register + USHORT usFbDiv; //return Feedback value to be written to register + UCHAR ucPostDiv; //return post div to be written to register +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2; +#define COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS + + +#define SET_CLOCK_FREQ_MASK 0x00FFFFFF //Clock change tables only take bit [23:0] as the requested clock value +#define USE_NON_BUS_CLOCK_MASK 0x01000000 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) +#define USE_MEMORY_SELF_REFRESH_MASK 0x02000000 //Only applicable to memory clock change, when set, using memory self refresh during clock transition +#define SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04000000 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change +#define FIRST_TIME_CHANGE_CLOCK 0x08000000 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup +#define SKIP_SW_PROGRAM_PLL 0x10000000 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL +#define USE_SS_ENABLED_PIXEL_CLOCK USE_NON_BUS_CLOCK_MASK + +#define b3USE_NON_BUS_CLOCK_MASK 0x01 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) +#define b3USE_MEMORY_SELF_REFRESH 0x02 //Only applicable to memory clock change, when set, using memory self refresh during clock transition +#define b3SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change +#define b3FIRST_TIME_CHANGE_CLOCK 0x08 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup +#define b3SKIP_SW_PROGRAM_PLL 0x10 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL + +typedef struct _SET_ENGINE_CLOCK_PARAMETERS +{ + ULONG ulTargetEngineClock; //In 10Khz unit +}SET_ENGINE_CLOCK_PARAMETERS; + +typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION +{ + ULONG ulTargetEngineClock; //In 10Khz unit + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; +}SET_ENGINE_CLOCK_PS_ALLOCATION; + + +typedef struct _SET_MEMORY_CLOCK_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit +}SET_MEMORY_CLOCK_PARAMETERS; + +typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION +{ + ULONG ulTargetMemoryClock; //In 10Khz unit + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; +}SET_MEMORY_CLOCK_PS_ALLOCATION; + +typedef struct _ASIC_INIT_PS_ALLOCATION +{ + ASIC_INIT_PARAMETERS sASICInitClocks; + SET_ENGINE_CLOCK_PS_ALLOCATION sReserved; //Caller doesn't need to init this structure +}ASIC_INIT_PS_ALLOCATION; + + +typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}DYNAMIC_CLOCK_GATING_PARAMETERS; +#define DYNAMIC_CLOCK_GATING_PS_ALLOCATION DYNAMIC_CLOCK_GATING_PARAMETERS + + +typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS; +#define ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS + + +typedef struct _DAC_LOAD_DETECTION_PARAMETERS +{ + USHORT usDeviceID; //{ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT} + UCHAR ucDacType; //{ATOM_DAC_A,ATOM_DAC_B, ATOM_EXT_DAC} + UCHAR ucMisc; //Valid only when table revision =1.3 and above +}DAC_LOAD_DETECTION_PARAMETERS; + +// DAC_LOAD_DETECTION_PARAMETERS.ucMisc +#define DAC_LOAD_MISC_YPrPb 0x01 + + +typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION +{ + DAC_LOAD_DETECTION_PARAMETERS sDacload; + ULONG Reserved[2];// Don't set this one, allocation for EXT DAC +}DAC_LOAD_DETECTION_PS_ALLOCATION; + + +typedef struct _DAC_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucDacStandard; // See definition of ATOM_DACx_xxx, For DEC3.0, bit 7 used as internal flag to indicate DAC2 (==1) or DAC1 (==0) + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder + // 7: ATOM_ENCODER_INIT Initialize DAC +}DAC_ENCODER_CONTROL_PARAMETERS; + +#define DAC_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PARAMETERS + +typedef struct _TV_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucTvStandard; // See definition "ATOM_TV_NTSC ..." + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder +}TV_ENCODER_CONTROL_PARAMETERS; + +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucConfig; + // [2] Link Select: + // =0: PHY linkA if bfLane<3 + // =1: PHY linkB if bfLanes<3 + // =0: PHY linkA+B if bfLanes=3 + // [3] Transmitter Sel + // =0: UNIPHY or PCIEPHY + // =1: LVTMA + UCHAR ucAction; // =0: turn off encoder + // =1: turn on encoder + UCHAR ucEncoderMode; + // =0: DP encoder + // =1: LVDS encoder + // =2: DVI encoder + // =3: HDMI encoder + // =4: SDVO encoder + UCHAR ucLaneNum; // how many lanes to enable + UCHAR ucReserved[2]; +}DIG_ENCODER_CONTROL_PARAMETERS; +#define DIG_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PARAMETERS +#define EXTERNAL_ENCODER_CONTROL_PARAMETER DIG_ENCODER_CONTROL_PARAMETERS +#define EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PS_ALLOCATION + +//ucConfig +#define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_ENCODER_CONFIG_LINKA 0x00 +#define ATOM_ENCODER_CONFIG_LINKB 0x04 +#define ATOM_ENCODER_CONFIG_LINKA_B ATOM_TRANSMITTER_CONFIG_LINKA +#define ATOM_ENCODER_CONFIG_LINKB_A ATOM_ENCODER_CONFIG_LINKB +#define ATOM_ENCODER_CONFIG_TRANSMITTER_SEL_MASK 0x08 +#define ATOM_ENCODER_CONFIG_UNIPHY 0x00 +#define ATOM_ENCODER_CONFIG_LVTMA 0x08 +#define ATOM_ENCODER_CONFIG_TRANSMITTER1 0x00 +#define ATOM_ENCODER_CONFIG_TRANSMITTER2 0x08 +#define ATOM_ENCODER_CONFIG_DIGB 0x80 // VBIOS Internal use, outside SW should set this bit=0 +// ucAction +// ATOM_ENABLE: Enable Encoder +// ATOM_DISABLE: Disable Encoder + +//ucEncoderMode +#define ATOM_ENCODER_MODE_DP 0 +#define ATOM_ENCODER_MODE_LVDS 1 +#define ATOM_ENCODER_MODE_DVI 2 +#define ATOM_ENCODER_MODE_HDMI 3 +#define ATOM_ENCODER_MODE_SDVO 4 +#define ATOM_ENCODER_MODE_TV 13 +#define ATOM_ENCODER_MODE_CV 14 +#define ATOM_ENCODER_MODE_CRT 15 + +typedef struct _ATOM_DP_VS_MODE +{ + UCHAR ucLaneSel; + UCHAR ucLaneSet; +}ATOM_DP_VS_MODE; + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS +{ + union + { + USHORT usPixelClock; // in 10KHz; for bios convenient + USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h + ATOM_DP_VS_MODE asMode; // DP Voltage swing mode + }; + UCHAR ucConfig; + // [0]=0: 4 lane Link, + // =1: 8 lane Link ( Dual Links TMDS ) + // [1]=0: InCoherent mode + // =1: Coherent Mode + // [2] Link Select: + // =0: PHY linkA if bfLane<3 + // =1: PHY linkB if bfLanes<3 + // =0: PHY linkA+B if bfLanes=3 + // [5:4]PCIE lane Sel + // =0: lane 0~3 or 0~7 + // =1: lane 4~7 + // =2: lane 8~11 or 8~15 + // =3: lane 12~15 + UCHAR ucAction; // =0: turn off encoder + // =1: turn on encoder + UCHAR ucReserved[4]; +}DIG_TRANSMITTER_CONTROL_PARAMETERS; + +#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PARAMETERS + +//ucInitInfo +#define ATOM_TRAMITTER_INITINFO_CONNECTOR_MASK 0x00ff + +//ucConfig +#define ATOM_TRANSMITTER_CONFIG_8LANE_LINK 0x01 +#define ATOM_TRANSMITTER_CONFIG_COHERENT 0x02 +#define ATOM_TRANSMITTER_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_LINKB 0x04 +#define ATOM_TRANSMITTER_CONFIG_LINKA_B 0x00 +#define ATOM_TRANSMITTER_CONFIG_LINKB_A 0x04 + +#define ATOM_TRANSMITTER_CONFIG_ENCODER_SEL_MASK 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE +#define ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER 0x00 // only used when ATOM_TRANSMITTER_ACTION_ENABLE +#define ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE + +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_MASK 0x30 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL 0x00 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PCIE 0x20 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_XTALIN 0x30 +#define ATOM_TRANSMITTER_CONFIG_LANE_SEL_MASK 0xc0 +#define ATOM_TRANSMITTER_CONFIG_LANE_0_3 0x00 +#define ATOM_TRANSMITTER_CONFIG_LANE_0_7 0x00 +#define ATOM_TRANSMITTER_CONFIG_LANE_4_7 0x40 +#define ATOM_TRANSMITTER_CONFIG_LANE_8_11 0x80 +#define ATOM_TRANSMITTER_CONFIG_LANE_8_15 0x80 +#define ATOM_TRANSMITTER_CONFIG_LANE_12_15 0xc0 + +//ucAction +#define ATOM_TRANSMITTER_ACTION_DISABLE 0 +#define ATOM_TRANSMITTER_ACTION_ENABLE 1 +#define ATOM_TRANSMITTER_ACTION_LCD_BLOFF 2 +#define ATOM_TRANSMITTER_ACTION_LCD_BLON 3 +#define ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL 4 +#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_START 5 +#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_STOP 6 +#define ATOM_TRANSMITTER_ACTION_INIT 7 +#define ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT 8 +#define ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT 9 +#define ATOM_TRANSMITTER_ACTION_SETUP 10 +#define ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH 11 + +/****************************Device Output Control Command Table Definitions**********************/ +typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +{ + UCHAR ucAction; // Possible input:ATOM_ENABLE||ATOMDISABLE + // When the display is LCD, in addition to above: + // ATOM_LCD_BLOFF|| ATOM_LCD_BLON ||ATOM_LCD_BL_BRIGHTNESS_CONTROL||ATOM_LCD_SELFTEST_START|| + // ATOM_LCD_SELFTEST_STOP + + UCHAR aucPadding[3]; // padding to DWORD aligned +}DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS; + +#define DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS + + +#define CRT1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CRT1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define CRT2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CRT2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define CV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define TV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define TV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DFP1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DFP1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DFP2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DFP2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define LCD1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define LCD1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DVO_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DVO_OUTPUT_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PS_ALLOCATION +#define DVO_OUTPUT_CONTROL_PARAMETERS_V3 DIG_TRANSMITTER_CONTROL_PARAMETERS + +/**************************************************************************/ +typedef struct _BLANK_CRTC_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucBlanking; // ATOM_BLANKING or ATOM_BLANKINGOFF + USHORT usBlackColorRCr; + USHORT usBlackColorGY; + USHORT usBlackColorBCb; +}BLANK_CRTC_PARAMETERS; +#define BLANK_CRTC_PS_ALLOCATION BLANK_CRTC_PARAMETERS + + +typedef struct _ENABLE_CRTC_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[2]; +}ENABLE_CRTC_PARAMETERS; +#define ENABLE_CRTC_PS_ALLOCATION ENABLE_CRTC_PARAMETERS + + +typedef struct _SET_CRTC_OVERSCAN_PARAMETERS +{ + USHORT usOverscanRight; // right + USHORT usOverscanLeft; // left + USHORT usOverscanBottom; // bottom + USHORT usOverscanTop; // top + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding[3]; +}SET_CRTC_OVERSCAN_PARAMETERS; +#define SET_CRTC_OVERSCAN_PS_ALLOCATION SET_CRTC_OVERSCAN_PARAMETERS + + +typedef struct _SET_CRTC_REPLICATION_PARAMETERS +{ + UCHAR ucH_Replication; // horizontal replication + UCHAR ucV_Replication; // vertical replication + UCHAR usCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding; +}SET_CRTC_REPLICATION_PARAMETERS; +#define SET_CRTC_REPLICATION_PS_ALLOCATION SET_CRTC_REPLICATION_PARAMETERS + + +typedef struct _SELECT_CRTC_SOURCE_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucDevice; // ATOM_DEVICE_CRT1|ATOM_DEVICE_CRT2|.... + UCHAR ucPadding[2]; +}SELECT_CRTC_SOURCE_PARAMETERS; +#define SELECT_CRTC_SOURCE_PS_ALLOCATION SELECT_CRTC_SOURCE_PARAMETERS + +typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2 +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucEncoderID; // DAC1/DAC2/TVOUT/DIG1/DIG2/DVO + UCHAR ucEncodeMode; // Encoding mode, only valid when using DIG1/DIG2/DVO + UCHAR ucPadding; +}SELECT_CRTC_SOURCE_PARAMETERS_V2; + +//ucEncoderID +//#define ASIC_INT_DAC1_ENCODER_ID 0x00 +//#define ASIC_INT_TV_ENCODER_ID 0x02 +//#define ASIC_INT_DIG1_ENCODER_ID 0x03 +//#define ASIC_INT_DAC2_ENCODER_ID 0x04 +//#define ASIC_EXT_TV_ENCODER_ID 0x06 +//#define ASIC_INT_DVO_ENCODER_ID 0x07 +//#define ASIC_INT_DIG2_ENCODER_ID 0x09 +//#define ASIC_EXT_DIG_ENCODER_ID 0x05 + +//ucEncodeMode +//#define ATOM_ENCODER_MODE_DP 0 +//#define ATOM_ENCODER_MODE_LVDS 1 +//#define ATOM_ENCODER_MODE_DVI 2 +//#define ATOM_ENCODER_MODE_HDMI 3 +//#define ATOM_ENCODER_MODE_SDVO 4 +//#define ATOM_ENCODER_MODE_TV 13 +//#define ATOM_ENCODER_MODE_CV 14 +//#define ATOM_ENCODER_MODE_CRT 15 + +//Major revision=1., Minor revision=1 +typedef struct _PIXEL_CLOCK_PARAMETERS +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER + UCHAR ucCRTC; // Which CRTC uses this Ppll + UCHAR ucPadding; +}PIXEL_CLOCK_PARAMETERS; + + +//Major revision=1., Minor revision=2, add ucMiscIfno +//ucMiscInfo: +#define MISC_FORCE_REPROG_PIXEL_CLOCK 0x1 +#define MISC_DEVICE_INDEX_MASK 0xF0 +#define MISC_DEVICE_INDEX_SHIFT 4 + +typedef struct _PIXEL_CLOCK_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER + UCHAR ucCRTC; // Which CRTC uses this Ppll + UCHAR ucMiscInfo; // Different bits for different purpose, bit [7:4] as device index, bit[0]=Force prog +}PIXEL_CLOCK_PARAMETERS_V2; + +//Major revision=1., Minor revision=3, structure/definition change +//ucEncoderMode: +//ATOM_ENCODER_MODE_DP +//ATOM_ENOCDER_MODE_LVDS +//ATOM_ENOCDER_MODE_DVI +//ATOM_ENOCDER_MODE_HDMI +//ATOM_ENOCDER_MODE_SDVO +//ATOM_ENCODER_MODE_TV 13 +//ATOM_ENCODER_MODE_CV 14 +//ATOM_ENCODER_MODE_CRT 15 + +//ucDVOConfig +//#define DVO_ENCODER_CONFIG_RATE_SEL 0x01 +//#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 +//#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 +//#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c +//#define DVO_ENCODER_CONFIG_LOW12BIT 0x00 +//#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 +//#define DVO_ENCODER_CONFIG_24BIT 0x08 + +//ucMiscInfo: also changed, see below +#define PIXEL_CLOCK_MISC_FORCE_PROG_PPLL 0x01 +#define PIXEL_CLOCK_MISC_VGA_MODE 0x02 +#define PIXEL_CLOCK_MISC_CRTC_SEL_MASK 0x04 +#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1 0x00 +#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2 0x04 +#define PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK 0x08 + +typedef struct _PIXEL_CLOCK_PARAMETERS_V3 +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL. For VGA PPLL,make sure this value is not 0. + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucTransmitterId; // graphic encoder id defined in objectId.h + union + { + UCHAR ucEncoderMode; // encoder type defined as ATOM_ENCODER_MODE_DP/DVI/HDMI/ + UCHAR ucDVOConfig; // when use DVO, need to know SDR/DDR, 12bit or 24bit + }; + UCHAR ucMiscInfo; // bit[0]=Force program, bit[1]= set pclk for VGA, b[2]= CRTC sel + // bit[3]=0:use PPLL for dispclk source, =1: use engine clock for dispclock source +}PIXEL_CLOCK_PARAMETERS_V3; + +#define PIXEL_CLOCK_PARAMETERS_LAST PIXEL_CLOCK_PARAMETERS_V2 +#define GET_PIXEL_CLOCK_PS_ALLOCATION PIXEL_CLOCK_PARAMETERS_LAST + +typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS +{ + USHORT usPixelClock; + UCHAR ucTransmitterID; + UCHAR ucEncodeMode; + union + { + UCHAR ucDVOConfig; //if DVO, need passing link rate and output 12bitlow or 24bit + UCHAR ucConfig; //if none DVO, not defined yet + }; + UCHAR ucReserved[3]; +}ADJUST_DISPLAY_PLL_PARAMETERS; + +#define ADJUST_DISPLAY_CONFIG_SS_ENABLE 0x10 + +#define ADJUST_DISPLAY_PLL_PS_ALLOCATION ADJUST_DISPLAY_PLL_PARAMETERS + +typedef struct _ENABLE_YUV_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB) + UCHAR ucCRTC; // Which CRTC needs this YUV or RGB format + UCHAR ucPadding[2]; +}ENABLE_YUV_PARAMETERS; +#define ENABLE_YUV_PS_ALLOCATION ENABLE_YUV_PARAMETERS + +typedef struct _GET_MEMORY_CLOCK_PARAMETERS +{ + ULONG ulReturnMemoryClock; // current memory speed in 10KHz unit +} GET_MEMORY_CLOCK_PARAMETERS; +#define GET_MEMORY_CLOCK_PS_ALLOCATION GET_MEMORY_CLOCK_PARAMETERS + + +typedef struct _GET_ENGINE_CLOCK_PARAMETERS +{ + ULONG ulReturnEngineClock; // current engine speed in 10KHz unit +} GET_ENGINE_CLOCK_PARAMETERS; +#define GET_ENGINE_CLOCK_PS_ALLOCATION GET_ENGINE_CLOCK_PARAMETERS + + +//Maxium 8 bytes,the data read in will be placed in the parameter space. +//Read operaion successeful when the paramter space is non-zero, otherwise read operation failed +typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + USHORT usVRAMAddress; //Adress in Frame Buffer where to pace raw EDID + USHORT usStatus; //When use output: lower byte EDID checksum, high byte hardware status + //WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte + UCHAR ucSlaveAddr; //Read from which slave + UCHAR ucLineNumber; //Read from which HW assisted line +}READ_EDID_FROM_HW_I2C_DATA_PARAMETERS; +#define READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION READ_EDID_FROM_HW_I2C_DATA_PARAMETERS + + +#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSDATABYTE 0 +#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSTWODATABYTES 1 +#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_PSOFFSET_IDDATABLOCK 2 +#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_IDOFFSET_PLUS_IDDATABLOCK 3 +#define ATOM_WRITE_I2C_FORMAT_IDCOUNTER_IDOFFSET_IDDATABLOCK 4 + +typedef struct _WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + USHORT usByteOffset; //Write to which byte + //Upper portion of usByteOffset is Format of data + //1bytePS+offsetPS + //2bytesPS+offsetPS + //blockID+offsetPS + //blockID+offsetID + //blockID+counterID+offsetID + UCHAR ucData; //PS data1 + UCHAR ucStatus; //Status byte 1=success, 2=failure, Also is used as PS data2 + UCHAR ucSlaveAddr; //Write to which slave + UCHAR ucLineNumber; //Write from which HW assisted line +}WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS; + +#define WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + UCHAR ucSlaveAddr; //Write to which slave + UCHAR ucLineNumber; //Write from which HW assisted line +}SET_UP_HW_I2C_DATA_PARAMETERS; + + +/**************************************************************************/ +#define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS +{ + UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected + UCHAR ucPwrBehaviorId; + USHORT usPwrBudget; //how much power currently boot to in unit of watt +}POWER_CONNECTOR_DETECTION_PARAMETERS; + +typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION +{ + UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected + UCHAR ucReserved; + USHORT usPwrBudget; //how much power currently boot to in unit of watt + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}POWER_CONNECTOR_DETECTION_PS_ALLOCATION; + +/****************************LVDS SS Command Table Definitions**********************/ +typedef struct _ENABLE_LVDS_SS_PARAMETERS +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStepSize_Delay; //bits3:2 SS_STEP_SIZE; bit 6:4 SS_DELAY + UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}ENABLE_LVDS_SS_PARAMETERS; + +//ucTableFormatRevision=1,ucTableContentRevision=2 +typedef struct _ENABLE_LVDS_SS_PARAMETERS_V2 +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStep; // + UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE + UCHAR ucSpreadSpectrumDelay; + UCHAR ucSpreadSpectrumRange; + UCHAR ucPadding; +}ENABLE_LVDS_SS_PARAMETERS_V2; + +//This new structure is based on ENABLE_LVDS_SS_PARAMETERS but expands to SS on PPLL, so other devices can use SS. +typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; // Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStep; // + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucSpreadSpectrumDelay; + UCHAR ucSpreadSpectrumRange; + UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2 +}ENABLE_SPREAD_SPECTRUM_ON_PPLL; + +#define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL + +/**************************************************************************/ + +typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION +{ + PIXEL_CLOCK_PARAMETERS sPCLKInput; + ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;//Caller doesn't need to init this portion +}SET_PIXEL_CLOCK_PS_ALLOCATION; + +#define ENABLE_VGA_RENDER_PS_ALLOCATION SET_PIXEL_CLOCK_PS_ALLOCATION + +typedef struct _MEMORY_TRAINING_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit +}MEMORY_TRAINING_PARAMETERS; +#define MEMORY_TRAINING_PS_ALLOCATION MEMORY_TRAINING_PARAMETERS + + + +/****************************LVDS and other encoder command table definitions **********************/ +typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucMisc; // bit0=0: Enable single link + // =1: Enable dual link + // Bit1=0: 666RGB + // =1: 888RGB + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder +}LVDS_ENCODER_CONTROL_PARAMETERS; + +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION LVDS_ENCODER_CONTROL_PARAMETERS + +#define TMDS1_ENCODER_CONTROL_PARAMETERS LVDS_ENCODER_CONTROL_PARAMETERS +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION TMDS1_ENCODER_CONTROL_PARAMETERS + +#define TMDS2_ENCODER_CONTROL_PARAMETERS TMDS1_ENCODER_CONTROL_PARAMETERS +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION TMDS2_ENCODER_CONTROL_PARAMETERS + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS +{ + UCHAR ucEnable; // Enable or Disable External TMDS encoder + UCHAR ucMisc; // Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB} + UCHAR ucPadding[2]; +}ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS; + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION +{ + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION; + + +//ucTableFormatRevision=1,ucTableContentRevision=2 +typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucMisc; // see PANEL_ENCODER_MISC_xx defintions below + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder + UCHAR ucTruncate; // bit0=0: Disable truncate + // =1: Enable truncate + // bit4=0: 666RGB + // =1: 888RGB + UCHAR ucSpatial; // bit0=0: Disable spatial dithering + // =1: Enable spatial dithering + // bit4=0: 666RGB + // =1: 888RGB + UCHAR ucTemporal; // bit0=0: Disable temporal dithering + // =1: Enable temporal dithering + // bit4=0: 666RGB + // =1: 888RGB + // bit5=0: Gray level 2 + // =1: Gray level 4 + UCHAR ucFRC; // bit4=0: 25FRC_SEL pattern E + // =1: 25FRC_SEL pattern F + // bit6:5=0: 50FRC_SEL pattern A + // =1: 50FRC_SEL pattern B + // =2: 50FRC_SEL pattern C + // =3: 50FRC_SEL pattern D + // bit7=0: 75FRC_SEL pattern E + // =1: 75FRC_SEL pattern F +}LVDS_ENCODER_CONTROL_PARAMETERS_V2; + +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS2_ENCODER_CONTROL_PARAMETERS_V2 +#define ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2 +{ + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2; + + +//ucTableFormatRevision=1,ucTableContentRevision=3 + +//ucDVOConfig: +#define DVO_ENCODER_CONFIG_RATE_SEL 0x01 +#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 +#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 +#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c +#define DVO_ENCODER_CONFIG_LOW12BIT 0x00 +#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 +#define DVO_ENCODER_CONFIG_24BIT 0x08 + +typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 +{ + USHORT usPixelClock; + UCHAR ucDVOConfig; + UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT + UCHAR ucReseved[4]; +}DVO_ENCODER_CONTROL_PARAMETERS_V3; +#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 DVO_ENCODER_CONTROL_PARAMETERS_V3 + +//ucTableFormatRevision=1 +//ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for +// bit1=0: non-coherent mode +// =1: coherent mode + +#define LVDS_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS1_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3 + +//========================================================================================== +//Only change is here next time when changing encoder parameter definitions again! +#define LVDS_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_LAST LVDS_ENCODER_CONTROL_PARAMETERS_LAST + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS1_ENCODER_CONTROL_PARAMETERS_LAST + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS2_ENCODER_CONTROL_PARAMETERS_LAST + +#define DVO_ENCODER_CONTROL_PARAMETERS_LAST DVO_ENCODER_CONTROL_PARAMETERS +#define DVO_ENCODER_CONTROL_PS_ALLOCATION_LAST DVO_ENCODER_CONTROL_PS_ALLOCATION + +//========================================================================================== +#define PANEL_ENCODER_MISC_DUAL 0x01 +#define PANEL_ENCODER_MISC_COHERENT 0x02 +#define PANEL_ENCODER_MISC_TMDS_LINKB 0x04 +#define PANEL_ENCODER_MISC_HDMI_TYPE 0x08 + +#define PANEL_ENCODER_ACTION_DISABLE ATOM_DISABLE +#define PANEL_ENCODER_ACTION_ENABLE ATOM_ENABLE +#define PANEL_ENCODER_ACTION_COHERENTSEQ (ATOM_ENABLE+1) + +#define PANEL_ENCODER_TRUNCATE_EN 0x01 +#define PANEL_ENCODER_TRUNCATE_DEPTH 0x10 +#define PANEL_ENCODER_SPATIAL_DITHER_EN 0x01 +#define PANEL_ENCODER_SPATIAL_DITHER_DEPTH 0x10 +#define PANEL_ENCODER_TEMPORAL_DITHER_EN 0x01 +#define PANEL_ENCODER_TEMPORAL_DITHER_DEPTH 0x10 +#define PANEL_ENCODER_TEMPORAL_LEVEL_4 0x20 +#define PANEL_ENCODER_25FRC_MASK 0x10 +#define PANEL_ENCODER_25FRC_E 0x00 +#define PANEL_ENCODER_25FRC_F 0x10 +#define PANEL_ENCODER_50FRC_MASK 0x60 +#define PANEL_ENCODER_50FRC_A 0x00 +#define PANEL_ENCODER_50FRC_B 0x20 +#define PANEL_ENCODER_50FRC_C 0x40 +#define PANEL_ENCODER_50FRC_D 0x60 +#define PANEL_ENCODER_75FRC_MASK 0x80 +#define PANEL_ENCODER_75FRC_E 0x00 +#define PANEL_ENCODER_75FRC_F 0x80 + +/**************************************************************************/ + +#define SET_VOLTAGE_TYPE_ASIC_VDDC 1 +#define SET_VOLTAGE_TYPE_ASIC_MVDDC 2 +#define SET_VOLTAGE_TYPE_ASIC_MVDDQ 3 +#define SET_VOLTAGE_TYPE_ASIC_VDDCI 4 + +#define SET_ASIC_VOLTAGE_MODE_ALL_SOURCE 0x1 +#define SET_ASIC_VOLTAGE_MODE_SOURCE_A 0x2 +#define SET_ASIC_VOLTAGE_MODE_SOURCE_B 0x4 + +#define SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE 0x0 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2 + +typedef struct _SET_VOLTAGE_PARAMETERS +{ + UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ + UCHAR ucVoltageMode; // To set all, to set source A or source B or ... + UCHAR ucVoltageIndex; // An index to tell which voltage level + UCHAR ucReserved; +}SET_VOLTAGE_PARAMETERS; + + +typedef struct _SET_VOLTAGE_PARAMETERS_V2 +{ + UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ + UCHAR ucVoltageMode; // Not used, maybe use for state machine for differen power mode + USHORT usVoltageLevel; // real voltage level +}SET_VOLTAGE_PARAMETERS_V2; + + +typedef struct _SET_VOLTAGE_PS_ALLOCATION +{ + SET_VOLTAGE_PARAMETERS sASICSetVoltage; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}SET_VOLTAGE_PS_ALLOCATION; + +typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION +{ + TV_ENCODER_CONTROL_PARAMETERS sTVEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; // Don't set this one +}TV_ENCODER_CONTROL_PS_ALLOCATION; + +//==============================Data Table Portion==================================== + +#ifdef UEFI_BUILD + #define UTEMP USHORT + #define USHORT void* +#endif + +typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES +{ + USHORT UtilityPipeLine; // Offest for the utility to get parser info,Don't change this position! + USHORT MultimediaCapabilityInfo; // Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios + USHORT MultimediaConfigInfo; // Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios + USHORT StandardVESA_Timing; // Only used by Bios + USHORT FirmwareInfo; // Shared by various SW components,latest version 1.4 + USHORT DAC_Info; // Will be obsolete from R600 + USHORT LVDS_Info; // Shared by various SW components,latest version 1.1 + USHORT TMDS_Info; // Will be obsolete from R600 + USHORT AnalogTV_Info; // Shared by various SW components,latest version 1.1 + USHORT SupportedDevicesInfo; // Will be obsolete from R600 + USHORT GPIO_I2C_Info; // Shared by various SW components,latest version 1.2 will be used from R600 + USHORT VRAM_UsageByFirmware; // Shared by various SW components,latest version 1.3 will be used from R600 + USHORT GPIO_Pin_LUT; // Shared by various SW components,latest version 1.1 + USHORT VESA_ToInternalModeLUT; // Only used by Bios + USHORT ComponentVideoInfo; // Shared by various SW components,latest version 2.1 will be used from R600 + USHORT PowerPlayInfo; // Shared by various SW components,latest version 2.1,new design from R600 + USHORT CompassionateData; // Will be obsolete from R600 + USHORT SaveRestoreInfo; // Only used by Bios + USHORT PPLL_SS_Info; // Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info + USHORT OemInfo; // Defined and used by external SW, should be obsolete soon + USHORT XTMDS_Info; // Will be obsolete from R600 + USHORT MclkSS_Info; // Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used + USHORT Object_Header; // Shared by various SW components,latest version 1.1 + USHORT IndirectIOAccess; // Only used by Bios,this table position can't change at all!! + USHORT MC_InitParameter; // Only used by command table + USHORT ASIC_VDDC_Info; // Will be obsolete from R600 + USHORT ASIC_InternalSS_Info; // New tabel name from R600, used to be called "ASIC_MVDDC_Info" + USHORT TV_VideoMode; // Only used by command table + USHORT VRAM_Info; // Only used by command table, latest version 1.3 + USHORT MemoryTrainingInfo; // Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1 + USHORT IntegratedSystemInfo; // Shared by various SW components + USHORT ASIC_ProfilingInfo; // New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600 + USHORT VoltageObjectInfo; // Shared by various SW components, latest version 1.1 + USHORT PowerSourceInfo; // Shared by various SW components, latest versoin 1.1 +}ATOM_MASTER_LIST_OF_DATA_TABLES; + +#ifdef UEFI_BUILD + #define USHORT UTEMP +#endif + + +typedef struct _ATOM_MASTER_DATA_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables; +}ATOM_MASTER_DATA_TABLE; + + +typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulSignature; // HW info table signature string "$ATI" + UCHAR ucI2C_Type; // I2C type (normal GP_IO, ImpactTV GP_IO, Dedicated I2C pin, etc) + UCHAR ucTV_OutInfo; // Type of TV out supported (3:0) and video out crystal frequency (6:4) and TV data port (7) + UCHAR ucVideoPortInfo; // Provides the video port capabilities + UCHAR ucHostPortInfo; // Provides host port configuration information +}ATOM_MULTIMEDIA_CAPABILITY_INFO; + + +typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulSignature; // MM info table signature sting "$MMT" + UCHAR ucTunerInfo; // Type of tuner installed on the adapter (4:0) and video input for tuner (7:5) + UCHAR ucAudioChipInfo; // List the audio chip type (3:0) product type (4) and OEM revision (7:5) + UCHAR ucProductID; // Defines as OEM ID or ATI board ID dependent on product type setting + UCHAR ucMiscInfo1; // Tuner voltage (1:0) HW teletext support (3:2) FM audio decoder (5:4) reserved (6) audio scrambling (7) + UCHAR ucMiscInfo2; // I2S input config (0) I2S output config (1) I2S Audio Chip (4:2) SPDIF Output Config (5) reserved (7:6) + UCHAR ucMiscInfo3; // Video Decoder Type (3:0) Video In Standard/Crystal (7:4) + UCHAR ucMiscInfo4; // Video Decoder Host Config (2:0) reserved (7:3) + UCHAR ucVideoInput0Info;// Video Input 0 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput1Info;// Video Input 1 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput2Info;// Video Input 2 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput3Info;// Video Input 3 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) +}ATOM_MULTIMEDIA_CONFIG_INFO; + +/****************************Firmware Info Table Definitions**********************/ + +// usBIOSCapability Defintion: +// Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; +// Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported; +// Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported; +// Others: Reserved +#define ATOM_BIOS_INFO_ATOM_FIRMWARE_POSTED 0x0001 +#define ATOM_BIOS_INFO_DUAL_CRTC_SUPPORT 0x0002 +#define ATOM_BIOS_INFO_EXTENDED_DESKTOP_SUPPORT 0x0004 +#define ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT 0x0008 +#define ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT 0x0010 +#define ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU 0x0020 +#define ATOM_BIOS_INFO_WMI_SUPPORT 0x0040 +#define ATOM_BIOS_INFO_PPMODE_ASSIGNGED_BY_SYSTEM 0x0080 +#define ATOM_BIOS_INFO_HYPERMEMORY_SUPPORT 0x0100 +#define ATOM_BIOS_INFO_HYPERMEMORY_SIZE_MASK 0x1E00 +#define ATOM_BIOS_INFO_VPOST_WITHOUT_FIRST_MODE_SET 0x2000 +#define ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE 0x4000 + + +#ifndef _H2INC + +//Please don't add or expand this bitfield structure below, this one will retire soon.! +typedef struct _ATOM_FIRMWARE_CAPABILITY +{ +#if ATOM_BIG_ENDIAN + USHORT Reserved:3; + USHORT HyperMemory_Size:4; + USHORT HyperMemory_Support:1; + USHORT PPMode_Assigned:1; + USHORT WMI_SUPPORT:1; + USHORT GPUControlsBL:1; + USHORT EngineClockSS_Support:1; + USHORT MemoryClockSS_Support:1; + USHORT ExtendedDesktopSupport:1; + USHORT DualCRTC_Support:1; + USHORT FirmwarePosted:1; +#else + USHORT FirmwarePosted:1; + USHORT DualCRTC_Support:1; + USHORT ExtendedDesktopSupport:1; + USHORT MemoryClockSS_Support:1; + USHORT EngineClockSS_Support:1; + USHORT GPUControlsBL:1; + USHORT WMI_SUPPORT:1; + USHORT PPMode_Assigned:1; + USHORT HyperMemory_Support:1; + USHORT HyperMemory_Size:4; + USHORT Reserved:3; +#endif +}ATOM_FIRMWARE_CAPABILITY; + +typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS +{ + ATOM_FIRMWARE_CAPABILITY sbfAccess; + USHORT susAccess; +}ATOM_FIRMWARE_CAPABILITY_ACCESS; + +#else + +typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS +{ + USHORT susAccess; +}ATOM_FIRMWARE_CAPABILITY_ACCESS; + +#endif + +typedef struct _ATOM_FIRMWARE_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucPadding[3]; //Don't use them + ULONG aulReservedForBIOS[3]; //Don't use them + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit, the definitions above can't change!!! + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO; + +typedef struct _ATOM_FIRMWARE_INFO_V1_2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + UCHAR ucPadding[2]; //Don't use them + ULONG aulReservedForBIOS[2]; //Don't use them + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_2; + +typedef struct _ATOM_FIRMWARE_INFO_V1_3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + UCHAR ucPadding[2]; //Don't use them + ULONG aulReservedForBIOS; //Don't use them + ULONG ul3DAccelerationEngineClock;//In 10Khz unit + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_3; + +typedef struct _ATOM_FIRMWARE_INFO_V1_4 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + USHORT usBootUpVDDCVoltage; //In MV unit + USHORT usLcdMinPixelClockPLL_Output; // In MHz unit + USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit + ULONG ul3DAccelerationEngineClock;//In 10Khz unit + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_4; + +#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V1_4 + +#define IGP_CAP_FLAG_DYNAMIC_CLOCK_EN 0x2 +#define IGP_CAP_FLAG_AC_CARD 0x4 +#define IGP_CAP_FLAG_SDVO_CARD 0x8 +#define IGP_CAP_FLAG_POSTDIV_BY_2_MODE 0x10 + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; //in 10kHz unit + ULONG ulBootUpMemoryClock; //in 10kHz unit + ULONG ulMaxSystemMemoryClock; //in 10kHz unit + ULONG ulMinSystemMemoryClock; //in 10kHz unit + UCHAR ucNumberOfCyclesInPeriodHi; + UCHAR ucLCDTimingSel; //=0:not valid.!=0 sel this timing descriptor from LCD EDID. + USHORT usReserved1; + USHORT usInterNBVoltageLow; //An intermidiate PMW value to set the voltage + USHORT usInterNBVoltageHigh; //Another intermidiate PMW value to set the voltage + ULONG ulReserved[2]; + + USHORT usFSBClock; //In MHz unit + USHORT usCapabilityFlag; //Bit0=1 indicates the fake HDMI support,Bit1=0/1 for Dynamic clocking dis/enable + //Bit[3:2]== 0:No PCIE card, 1:AC card, 2:SDVO card + //Bit[4]==1: P/2 mode, ==0: P/1 mode + USHORT usPCIENBCfgReg7; //bit[7:0]=MUX_Sel, bit[9:8]=MUX_SEL_LEVEL2, bit[10]=Lane_Reversal + USHORT usK8MemoryClock; //in MHz unit + USHORT usK8SyncStartDelay; //in 0.01 us unit + USHORT usK8DataReturnTime; //in 0.01 us unit + UCHAR ucMaxNBVoltage; + UCHAR ucMinNBVoltage; + UCHAR ucMemoryType; //[7:4]=1:DDR1;=2:DDR2;=3:DDR3.[3:0] is reserved + UCHAR ucNumberOfCyclesInPeriod; //CG.FVTHROT_PWM_CTRL_REG0.NumberOfCyclesInPeriod + UCHAR ucStartingPWM_HighTime; //CG.FVTHROT_PWM_CTRL_REG0.StartingPWM_HighTime + UCHAR ucHTLinkWidth; //16 bit vs. 8 bit + UCHAR ucMaxNBVoltageHigh; + UCHAR ucMinNBVoltageHigh; +}ATOM_INTEGRATED_SYSTEM_INFO; + +/* Explanation on entries in ATOM_INTEGRATED_SYSTEM_INFO +ulBootUpMemoryClock: For Intel IGP,it's the UMA system memory clock + For AMD IGP,it's 0 if no SidePort memory installed or it's the boot-up SidePort memory clock +ulMaxSystemMemoryClock: For Intel IGP,it's the Max freq from memory SPD if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0 + For AMD IGP,for now this can be 0 +ulMinSystemMemoryClock: For Intel IGP,it's 133MHz if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0 + For AMD IGP,for now this can be 0 + +usFSBClock: For Intel IGP,it's FSB Freq + For AMD IGP,it's HT Link Speed + +usK8MemoryClock: For AMD IGP only. For RevF CPU, set it to 200 +usK8SyncStartDelay: For AMD IGP only. Memory access latency in K8, required for watermark calculation +usK8DataReturnTime: For AMD IGP only. Memory access latency in K8, required for watermark calculation + +VC:Voltage Control +ucMaxNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +ucMinNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all. + +ucNumberOfCyclesInPeriod: Indicate how many cycles when PWM duty is 100%. low 8 bits of the value. +ucNumberOfCyclesInPeriodHi: Indicate how many cycles when PWM duty is 100%. high 8 bits of the value.If the PWM has an inverter,set bit [7]==1,otherwise set it 0 + +ucMaxNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +ucMinNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all. + + +usInterNBVoltageLow: Voltage regulator dependent PWM value. The value makes the the voltage >=Min NB voltage but <=InterNBVoltageHigh. Set this to 0x0000 if VC without PWM or no VC at all. +usInterNBVoltageHigh: Voltage regulator dependent PWM value. The value makes the the voltage >=InterNBVoltageLow but <=Max NB voltage.Set this to 0x0000 if VC without PWM or no VC at all. +*/ + + +/* +The following IGP table is introduced from RS780, which is supposed to be put by SBIOS in FB before IGP VBIOS starts VPOST; +Then VBIOS will copy the whole structure to its image so all GPU SW components can access this data structure to get whatever they need. +The enough reservation should allow us to never change table revisions. Whenever needed, a GPU SW component can use reserved portion for new data entries. + +SW components can access the IGP system infor structure in the same way as before +*/ + + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; //in 10kHz unit + ULONG ulReserved1[2]; //must be 0x0 for the reserved + ULONG ulBootUpUMAClock; //in 10kHz unit + ULONG ulBootUpSidePortClock; //in 10kHz unit + ULONG ulMinSidePortClock; //in 10kHz unit + ULONG ulReserved2[6]; //must be 0x0 for the reserved + ULONG ulSystemConfig; //see explanation below + ULONG ulBootUpReqDisplayVector; + ULONG ulOtherDisplayMisc; + ULONG ulDDISlot1Config; + ULONG ulDDISlot2Config; + UCHAR ucMemoryType; //[3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved + UCHAR ucUMAChannelNumber; + UCHAR ucDockingPinBit; + UCHAR ucDockingPinPolarity; + ULONG ulDockingPinCFGInfo; + ULONG ulCPUCapInfo; + USHORT usNumberOfCyclesInPeriod; + USHORT usMaxNBVoltage; + USHORT usMinNBVoltage; + USHORT usBootUpNBVoltage; + ULONG ulHTLinkFreq; //in 10Khz + USHORT usMinHTLinkWidth; + USHORT usMaxHTLinkWidth; + USHORT usUMASyncStartDelay; + USHORT usUMADataReturnTime; + USHORT usLinkStatusZeroTime; + USHORT usReserved; + ULONG ulReserved3[101]; //must be 0x0 +}ATOM_INTEGRATED_SYSTEM_INFO_V2; + +/* +ulBootUpEngineClock: Boot-up Engine Clock in 10Khz; +ulBootUpUMAClock: Boot-up UMA Clock in 10Khz; it must be 0x0 when UMA is not present +ulBootUpSidePortClock: Boot-up SidePort Clock in 10Khz; it must be 0x0 when SidePort Memory is not present,this could be equal to or less than maximum supported Sideport memory clock + +ulSystemConfig: +Bit[0]: =1 PowerExpress mode =0 Non-PowerExpress mode; +Bit[1]=1: system is running at overdrived engine clock =0:system is not running at overdrived engine clock + +ulBootUpReqDisplayVector: This dword is a bit vector indicates what display devices are requested during boot-up. Refer to ATOM_DEVICE_xxx_SUPPORT for the bit vector definitions. + +ulOtherDisplayMisc: [15:8]- Bootup LCD Expansion selection; 0-center, 1-full panel size expansion; + [7:0] - BootupTV standard selection; This is a bit vector to indicate what TV standards are supported by the system. Refer to ucTVSuppportedStd definition; + +ulDDISlot1Config: Describes the PCIE lane configuration on this DDI PCIE slot (ADD2 card) or connector (Mobile design). + [3:0] - Bit vector to indicate PCIE lane config of the DDI slot/connector on chassis (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12) + [7:4] - Bit vector to indicate PCIE lane config of the same DDI slot/connector on docking station (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12) + [15:8] - Lane configuration attribute; + [23:16]- Connector type, possible value: + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D + CONNECTOR_OBJECT_ID_HDMI_TYPE_A + CONNECTOR_OBJECT_ID_DISPLAYPORT + [31:24]- Reserved + +ulDDISlot2Config: Same as Slot1. +ucMemoryType: SidePort memory type, set it to 0x0 when Sideport memory is not installed. Driver needs this info to change sideport memory clock. Not for display in CCC. +For IGP, Hypermemory is the only memory type showed in CCC. + +ucUMAChannelNumber: how many channels for the UMA; + +ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pin; [31:16]-reg offset in CFG to read this pin +ucDockingPinBit: which bit in this register to read the pin status; +ucDockingPinPolarity:Polarity of the pin when docked; + +ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0 + +usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%. +usMaxNBVoltage:Voltage regulator dependent PWM value.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +usMinNBVoltage:Voltage regulator dependent PWM value.Set this one to 0x00 if VC without PWM or no VC at all. +usBootUpNBVoltage:Boot-up voltage regulator dependent PWM value. + + +ulHTLinkFreq: Current HT link Frequency in 10Khz. +usMinHTLinkWidth: +usMaxHTLinkWidth: +usUMASyncStartDelay: Memory access latency, required for watermark calculation +usUMADataReturnTime: Memory access latency, required for watermark calculation +usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us +for Griffin or Greyhound. SBIOS needs to convert to actual time by: + if T0Ttime [5:4]=00b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.1us (0.0 to 1.5us) + if T0Ttime [5:4]=01b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.5us (0.0 to 7.5us) + if T0Ttime [5:4]=10b, then usLinkStatusZeroTime=T0Ttime [3:0]*2.0us (0.0 to 30us) + if T0Ttime [5:4]=11b, and T0Ttime [3:0]=0x0 to 0xa, then usLinkStatusZeroTime=T0Ttime [3:0]*20us (0.0 to 200us) +*/ + +#define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001 +#define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002 + +#define IGP_DDI_SLOT_LANE_CONFIG_MASK 0x000000FF + +#define b0IGP_DDI_SLOT_LANE_MAP_MASK 0x0F +#define b0IGP_DDI_SLOT_DOCKING_LANE_MAP_MASK 0xF0 +#define b0IGP_DDI_SLOT_CONFIG_LANE_0_3 0x01 +#define b0IGP_DDI_SLOT_CONFIG_LANE_4_7 0x02 +#define b0IGP_DDI_SLOT_CONFIG_LANE_8_11 0x04 +#define b0IGP_DDI_SLOT_CONFIG_LANE_12_15 0x08 + +#define IGP_DDI_SLOT_ATTRIBUTE_MASK 0x0000FF00 +#define IGP_DDI_SLOT_CONFIG_REVERSED 0x00000100 +#define b1IGP_DDI_SLOT_CONFIG_REVERSED 0x01 + +#define IGP_DDI_SLOT_CONNECTOR_TYPE_MASK 0x00FF0000 + +#define ATOM_CRT_INT_ENCODER1_INDEX 0x00000000 +#define ATOM_LCD_INT_ENCODER1_INDEX 0x00000001 +#define ATOM_TV_INT_ENCODER1_INDEX 0x00000002 +#define ATOM_DFP_INT_ENCODER1_INDEX 0x00000003 +#define ATOM_CRT_INT_ENCODER2_INDEX 0x00000004 +#define ATOM_LCD_EXT_ENCODER1_INDEX 0x00000005 +#define ATOM_TV_EXT_ENCODER1_INDEX 0x00000006 +#define ATOM_DFP_EXT_ENCODER1_INDEX 0x00000007 +#define ATOM_CV_INT_ENCODER1_INDEX 0x00000008 +#define ATOM_DFP_INT_ENCODER2_INDEX 0x00000009 +#define ATOM_CRT_EXT_ENCODER1_INDEX 0x0000000A +#define ATOM_CV_EXT_ENCODER1_INDEX 0x0000000B +#define ATOM_DFP_INT_ENCODER3_INDEX 0x0000000C +#define ATOM_DFP_INT_ENCODER4_INDEX 0x0000000D + +// define ASIC internal encoder id ( bit vector ) +#define ASIC_INT_DAC1_ENCODER_ID 0x00 +#define ASIC_INT_TV_ENCODER_ID 0x02 +#define ASIC_INT_DIG1_ENCODER_ID 0x03 +#define ASIC_INT_DAC2_ENCODER_ID 0x04 +#define ASIC_EXT_TV_ENCODER_ID 0x06 +#define ASIC_INT_DVO_ENCODER_ID 0x07 +#define ASIC_INT_DIG2_ENCODER_ID 0x09 +#define ASIC_EXT_DIG_ENCODER_ID 0x05 + +//define Encoder attribute +#define ATOM_ANALOG_ENCODER 0 +#define ATOM_DIGITAL_ENCODER 1 + +#define ATOM_DEVICE_CRT1_INDEX 0x00000000 +#define ATOM_DEVICE_LCD1_INDEX 0x00000001 +#define ATOM_DEVICE_TV1_INDEX 0x00000002 +#define ATOM_DEVICE_DFP1_INDEX 0x00000003 +#define ATOM_DEVICE_CRT2_INDEX 0x00000004 +#define ATOM_DEVICE_LCD2_INDEX 0x00000005 +#define ATOM_DEVICE_TV2_INDEX 0x00000006 +#define ATOM_DEVICE_DFP2_INDEX 0x00000007 +#define ATOM_DEVICE_CV_INDEX 0x00000008 +#define ATOM_DEVICE_DFP3_INDEX 0x00000009 +#define ATOM_DEVICE_RESERVEDA_INDEX 0x0000000A +#define ATOM_DEVICE_RESERVEDB_INDEX 0x0000000B +#define ATOM_DEVICE_RESERVEDC_INDEX 0x0000000C +#define ATOM_DEVICE_RESERVEDD_INDEX 0x0000000D +#define ATOM_DEVICE_RESERVEDE_INDEX 0x0000000E +#define ATOM_DEVICE_RESERVEDF_INDEX 0x0000000F +#define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_CV_INDEX+2) +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_2 ATOM_MAX_SUPPORTED_DEVICE_INFO +#define ATOM_MAX_SUPPORTED_DEVICE (ATOM_DEVICE_RESERVEDF_INDEX+1) + +#define ATOM_DEVICE_CRT1_SUPPORT (0x1L << ATOM_DEVICE_CRT1_INDEX ) +#define ATOM_DEVICE_LCD1_SUPPORT (0x1L << ATOM_DEVICE_LCD1_INDEX ) +#define ATOM_DEVICE_TV1_SUPPORT (0x1L << ATOM_DEVICE_TV1_INDEX ) +#define ATOM_DEVICE_DFP1_SUPPORT (0x1L << ATOM_DEVICE_DFP1_INDEX) +#define ATOM_DEVICE_CRT2_SUPPORT (0x1L << ATOM_DEVICE_CRT2_INDEX ) +#define ATOM_DEVICE_LCD2_SUPPORT (0x1L << ATOM_DEVICE_LCD2_INDEX ) +#define ATOM_DEVICE_TV2_SUPPORT (0x1L << ATOM_DEVICE_TV2_INDEX ) +#define ATOM_DEVICE_DFP2_SUPPORT (0x1L << ATOM_DEVICE_DFP2_INDEX) +#define ATOM_DEVICE_CV_SUPPORT (0x1L << ATOM_DEVICE_CV_INDEX ) +#define ATOM_DEVICE_DFP3_SUPPORT (0x1L << ATOM_DEVICE_DFP3_INDEX ) + +#define ATOM_DEVICE_CRT_SUPPORT ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT +#define ATOM_DEVICE_DFP_SUPPORT ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT +#define ATOM_DEVICE_TV_SUPPORT ATOM_DEVICE_TV1_SUPPORT | ATOM_DEVICE_TV2_SUPPORT +#define ATOM_DEVICE_LCD_SUPPORT ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT + +#define ATOM_DEVICE_CONNECTOR_TYPE_MASK 0x000000F0 +#define ATOM_DEVICE_CONNECTOR_TYPE_SHIFT 0x00000004 +#define ATOM_DEVICE_CONNECTOR_VGA 0x00000001 +#define ATOM_DEVICE_CONNECTOR_DVI_I 0x00000002 +#define ATOM_DEVICE_CONNECTOR_DVI_D 0x00000003 +#define ATOM_DEVICE_CONNECTOR_DVI_A 0x00000004 +#define ATOM_DEVICE_CONNECTOR_SVIDEO 0x00000005 +#define ATOM_DEVICE_CONNECTOR_COMPOSITE 0x00000006 +#define ATOM_DEVICE_CONNECTOR_LVDS 0x00000007 +#define ATOM_DEVICE_CONNECTOR_DIGI_LINK 0x00000008 +#define ATOM_DEVICE_CONNECTOR_SCART 0x00000009 +#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_A 0x0000000A +#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_B 0x0000000B +#define ATOM_DEVICE_CONNECTOR_CASE_1 0x0000000E +#define ATOM_DEVICE_CONNECTOR_DISPLAYPORT 0x0000000F + + +#define ATOM_DEVICE_DAC_INFO_MASK 0x0000000F +#define ATOM_DEVICE_DAC_INFO_SHIFT 0x00000000 +#define ATOM_DEVICE_DAC_INFO_NODAC 0x00000000 +#define ATOM_DEVICE_DAC_INFO_DACA 0x00000001 +#define ATOM_DEVICE_DAC_INFO_DACB 0x00000002 +#define ATOM_DEVICE_DAC_INFO_EXDAC 0x00000003 + +#define ATOM_DEVICE_I2C_ID_NOI2C 0x00000000 + +#define ATOM_DEVICE_I2C_LINEMUX_MASK 0x0000000F +#define ATOM_DEVICE_I2C_LINEMUX_SHIFT 0x00000000 + +#define ATOM_DEVICE_I2C_ID_MASK 0x00000070 +#define ATOM_DEVICE_I2C_ID_SHIFT 0x00000004 +#define ATOM_DEVICE_I2C_ID_IS_FOR_NON_MM_USE 0x00000001 +#define ATOM_DEVICE_I2C_ID_IS_FOR_MM_USE 0x00000002 +#define ATOM_DEVICE_I2C_ID_IS_FOR_SDVO_USE 0x00000003 //For IGP RS600 +#define ATOM_DEVICE_I2C_ID_IS_FOR_DAC_SCL 0x00000004 //For IGP RS690 + +#define ATOM_DEVICE_I2C_HARDWARE_CAP_MASK 0x00000080 +#define ATOM_DEVICE_I2C_HARDWARE_CAP_SHIFT 0x00000007 +#define ATOM_DEVICE_USES_SOFTWARE_ASSISTED_I2C 0x00000000 +#define ATOM_DEVICE_USES_HARDWARE_ASSISTED_I2C 0x00000001 + +// usDeviceSupport: +// Bits0 = 0 - no CRT1 support= 1- CRT1 is supported +// Bit 1 = 0 - no LCD1 support= 1- LCD1 is supported +// Bit 2 = 0 - no TV1 support= 1- TV1 is supported +// Bit 3 = 0 - no DFP1 support= 1- DFP1 is supported +// Bit 4 = 0 - no CRT2 support= 1- CRT2 is supported +// Bit 5 = 0 - no LCD2 support= 1- LCD2 is supported +// Bit 6 = 0 - no TV2 support= 1- TV2 is supported +// Bit 7 = 0 - no DFP2 support= 1- DFP2 is supported +// Bit 8 = 0 - no CV support= 1- CV is supported +// Bit 9 = 0 - no DFP3 support= 1- DFP3 is supported +// Byte1 (Supported Device Info) +// Bit 0 = = 0 - no CV support= 1- CV is supported +// +// + +// ucI2C_ConfigID +// [7:0] - I2C LINE Associate ID +// = 0 - no I2C +// [7] - HW_Cap = 1, [6:0]=HW assisted I2C ID(HW line selection) +// = 0, [6:0]=SW assisted I2C ID +// [6-4] - HW_ENGINE_ID = 1, HW engine for NON multimedia use +// = 2, HW engine for Multimedia use +// = 3-7 Reserved for future I2C engines +// [3-0] - I2C_LINE_MUX = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C + + +typedef struct _ATOM_I2C_ID_CONFIG +{ +#if ATOM_BIG_ENDIAN + UCHAR bfHW_Capable:1; + UCHAR bfHW_EngineID:3; + UCHAR bfI2C_LineMux:4; +#else + UCHAR bfI2C_LineMux:4; + UCHAR bfHW_EngineID:3; + UCHAR bfHW_Capable:1; +#endif +}ATOM_I2C_ID_CONFIG; + +typedef union _ATOM_I2C_ID_CONFIG_ACCESS +{ + ATOM_I2C_ID_CONFIG sbfAccess; + UCHAR ucAccess; +}ATOM_I2C_ID_CONFIG_ACCESS; + + +typedef struct _ATOM_GPIO_I2C_ASSIGMENT +{ + USHORT usClkMaskRegisterIndex; + USHORT usClkEnRegisterIndex; + USHORT usClkY_RegisterIndex; + USHORT usClkA_RegisterIndex; + USHORT usDataMaskRegisterIndex; + USHORT usDataEnRegisterIndex; + USHORT usDataY_RegisterIndex; + USHORT usDataA_RegisterIndex; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; + UCHAR ucClkMaskShift; + UCHAR ucClkEnShift; + UCHAR ucClkY_Shift; + UCHAR ucClkA_Shift; + UCHAR ucDataMaskShift; + UCHAR ucDataEnShift; + UCHAR ucDataY_Shift; + UCHAR ucDataA_Shift; + UCHAR ucReserved1; + UCHAR ucReserved2; +}ATOM_GPIO_I2C_ASSIGMENT; + +typedef struct _ATOM_GPIO_I2C_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE]; +}ATOM_GPIO_I2C_INFO; + + +#ifndef _H2INC + +//Please don't add or expand this bitfield structure below, this one will retire soon.! +typedef struct _ATOM_MODE_MISC_INFO +{ +#if ATOM_BIG_ENDIAN + USHORT Reserved:6; + USHORT RGB888:1; + USHORT DoubleClock:1; + USHORT Interlace:1; + USHORT CompositeSync:1; + USHORT V_ReplicationBy2:1; + USHORT H_ReplicationBy2:1; + USHORT VerticalCutOff:1; + USHORT VSyncPolarity:1; //0=Active High, 1=Active Low + USHORT HSyncPolarity:1; //0=Active High, 1=Active Low + USHORT HorizontalCutOff:1; +#else + USHORT HorizontalCutOff:1; + USHORT HSyncPolarity:1; //0=Active High, 1=Active Low + USHORT VSyncPolarity:1; //0=Active High, 1=Active Low + USHORT VerticalCutOff:1; + USHORT H_ReplicationBy2:1; + USHORT V_ReplicationBy2:1; + USHORT CompositeSync:1; + USHORT Interlace:1; + USHORT DoubleClock:1; + USHORT RGB888:1; + USHORT Reserved:6; +#endif +}ATOM_MODE_MISC_INFO; + +typedef union _ATOM_MODE_MISC_INFO_ACCESS +{ + ATOM_MODE_MISC_INFO sbfAccess; + USHORT usAccess; +}ATOM_MODE_MISC_INFO_ACCESS; + +#else + +typedef union _ATOM_MODE_MISC_INFO_ACCESS +{ + USHORT usAccess; +}ATOM_MODE_MISC_INFO_ACCESS; + +#endif + +// usModeMiscInfo- +#define ATOM_H_CUTOFF 0x01 +#define ATOM_HSYNC_POLARITY 0x02 //0=Active High, 1=Active Low +#define ATOM_VSYNC_POLARITY 0x04 //0=Active High, 1=Active Low +#define ATOM_V_CUTOFF 0x08 +#define ATOM_H_REPLICATIONBY2 0x10 +#define ATOM_V_REPLICATIONBY2 0x20 +#define ATOM_COMPOSITESYNC 0x40 +#define ATOM_INTERLACE 0x80 +#define ATOM_DOUBLE_CLOCK_MODE 0x100 +#define ATOM_RGB888_MODE 0x200 + +//usRefreshRate- +#define ATOM_REFRESH_43 43 +#define ATOM_REFRESH_47 47 +#define ATOM_REFRESH_56 56 +#define ATOM_REFRESH_60 60 +#define ATOM_REFRESH_65 65 +#define ATOM_REFRESH_70 70 +#define ATOM_REFRESH_72 72 +#define ATOM_REFRESH_75 75 +#define ATOM_REFRESH_85 85 + +// ATOM_MODE_TIMING data are exactly the same as VESA timing data. +// Translation from EDID to ATOM_MODE_TIMING, use the following formula. +// +// VESA_HTOTAL = VESA_ACTIVE + 2* VESA_BORDER + VESA_BLANK +// = EDID_HA + EDID_HBL +// VESA_HDISP = VESA_ACTIVE = EDID_HA +// VESA_HSYNC_START = VESA_ACTIVE + VESA_BORDER + VESA_FRONT_PORCH +// = EDID_HA + EDID_HSO +// VESA_HSYNC_WIDTH = VESA_HSYNC_TIME = EDID_HSPW +// VESA_BORDER = EDID_BORDER + + +typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS +{ + USHORT usH_Size; + USHORT usH_Blanking_Time; + USHORT usV_Size; + USHORT usV_Blanking_Time; + USHORT usH_SyncOffset; + USHORT usH_SyncWidth; + USHORT usV_SyncOffset; + USHORT usV_SyncWidth; + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucH_Border; // From DFP EDID + UCHAR ucV_Border; + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding[3]; +}SET_CRTC_USING_DTD_TIMING_PARAMETERS; + +typedef struct _SET_CRTC_TIMING_PARAMETERS +{ + USHORT usH_Total; // horizontal total + USHORT usH_Disp; // horizontal display + USHORT usH_SyncStart; // horozontal Sync start + USHORT usH_SyncWidth; // horizontal Sync width + USHORT usV_Total; // vertical total + USHORT usV_Disp; // vertical display + USHORT usV_SyncStart; // vertical Sync start + USHORT usV_SyncWidth; // vertical Sync width + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucOverscanRight; // right + UCHAR ucOverscanLeft; // left + UCHAR ucOverscanBottom; // bottom + UCHAR ucOverscanTop; // top + UCHAR ucReserved; +}SET_CRTC_TIMING_PARAMETERS; +#define SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION SET_CRTC_TIMING_PARAMETERS + + +typedef struct _ATOM_MODE_TIMING +{ + USHORT usCRTC_H_Total; + USHORT usCRTC_H_Disp; + USHORT usCRTC_H_SyncStart; + USHORT usCRTC_H_SyncWidth; + USHORT usCRTC_V_Total; + USHORT usCRTC_V_Disp; + USHORT usCRTC_V_SyncStart; + USHORT usCRTC_V_SyncWidth; + USHORT usPixelClock; //in 10Khz unit + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + USHORT usCRTC_OverscanRight; + USHORT usCRTC_OverscanLeft; + USHORT usCRTC_OverscanBottom; + USHORT usCRTC_OverscanTop; + USHORT usReserve; + UCHAR ucInternalModeNumber; + UCHAR ucRefreshRate; +}ATOM_MODE_TIMING; + + +typedef struct _ATOM_DTD_FORMAT +{ + USHORT usPixClk; + USHORT usHActive; + USHORT usHBlanking_Time; + USHORT usVActive; + USHORT usVBlanking_Time; + USHORT usHSyncOffset; + USHORT usHSyncWidth; + USHORT usVSyncOffset; + USHORT usVSyncWidth; + USHORT usImageHSize; + USHORT usImageVSize; + UCHAR ucHBorder; + UCHAR ucVBorder; + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucInternalModeNumber; + UCHAR ucRefreshRate; +}ATOM_DTD_FORMAT; + +#define SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004 +#define SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008 +#define SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010 +#define SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020 + +/****************************LVDS Info Table Definitions **********************/ +//ucTableFormatRevision=1 +//ucTableContentRevision=1 +typedef struct _ATOM_LVDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usModePatchTableOffset; + USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec. + USHORT usOffDelayInMs; + UCHAR ucPowerSequenceDigOntoDEin10Ms; + UCHAR ucPowerSequenceDEtoBLOnin10Ms; + UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} + // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} + // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} + // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; +}ATOM_LVDS_INFO; + +//ucTableFormatRevision=1 +//ucTableContentRevision=2 +typedef struct _ATOM_LVDS_INFO_V12 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usExtInfoTableOffset; + USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec. + USHORT usOffDelayInMs; + UCHAR ucPowerSequenceDigOntoDEin10Ms; + UCHAR ucPowerSequenceDEtoBLOnin10Ms; + UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} + // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} + // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} + // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; + USHORT usLCDVenderID; + USHORT usLCDProductID; + UCHAR ucLCDPanel_SpecialHandlingCap; + UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable + UCHAR ucReserved[2]; +}ATOM_LVDS_INFO_V12; + +#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 + +typedef struct _ATOM_PATCH_RECORD_MODE +{ + UCHAR ucRecordType; + USHORT usHDisp; + USHORT usVDisp; +}ATOM_PATCH_RECORD_MODE; + +typedef struct _ATOM_LCD_RTS_RECORD +{ + UCHAR ucRecordType; + UCHAR ucRTSValue; +}ATOM_LCD_RTS_RECORD; + +//!! If the record below exits, it shoud always be the first record for easy use in command table!!! +typedef struct _ATOM_LCD_MODE_CONTROL_CAP +{ + UCHAR ucRecordType; + USHORT usLCDCap; +}ATOM_LCD_MODE_CONTROL_CAP; + +#define LCD_MODE_CAP_BL_OFF 1 +#define LCD_MODE_CAP_CRTC_OFF 2 +#define LCD_MODE_CAP_PANEL_OFF 4 + +typedef struct _ATOM_FAKE_EDID_PATCH_RECORD +{ + UCHAR ucRecordType; + UCHAR ucFakeEDIDLength; + UCHAR ucFakeEDIDString[1]; // This actually has ucFakeEdidLength elements. +} ATOM_FAKE_EDID_PATCH_RECORD; + +typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD +{ + UCHAR ucRecordType; + USHORT usHSize; + USHORT usVSize; +}ATOM_PANEL_RESOLUTION_PATCH_RECORD; + +#define LCD_MODE_PATCH_RECORD_MODE_TYPE 1 +#define LCD_RTS_RECORD_TYPE 2 +#define LCD_CAP_RECORD_TYPE 3 +#define LCD_FAKE_EDID_PATCH_RECORD_TYPE 4 +#define LCD_PANEL_RESOLUTION_RECORD_TYPE 5 +#define ATOM_RECORD_END_TYPE 0xFF + +/****************************Spread Spectrum Info Table Definitions **********************/ + +//ucTableFormatRevision=1 +//ucTableContentRevision=2 +typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSS_Step; + UCHAR ucSS_Delay; + UCHAR ucSS_Id; + UCHAR ucRecommandedRef_Div; + UCHAR ucSS_Range; //it was reserved for V11 +}ATOM_SPREAD_SPECTRUM_ASSIGNMENT; + +#define ATOM_MAX_SS_ENTRY 16 +#define ATOM_DP_SS_ID1 0x0f1 // SS modulation freq=30k +#define ATOM_DP_SS_ID2 0x0f2 // SS modulation freq=33k + + +#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000 +#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000 +#define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001 +#define ATOM_SS_CENTRE_SPREAD_MODE 0x00000001 +#define ATOM_INTERNAL_SS_MASK 0x00000000 +#define ATOM_EXTERNAL_SS_MASK 0x00000002 +#define EXEC_SS_STEP_SIZE_SHIFT 2 +#define EXEC_SS_DELAY_SHIFT 4 +#define ACTIVEDATA_TO_BLON_DELAY_SHIFT 4 + +typedef struct _ATOM_SPREAD_SPECTRUM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY]; +}ATOM_SPREAD_SPECTRUM_INFO; + + + + +//ucTVBootUpDefaultStd definiton: + +//ATOM_TV_NTSC 1 +//ATOM_TV_NTSCJ 2 +//ATOM_TV_PAL 3 +//ATOM_TV_PALM 4 +//ATOM_TV_PALCN 5 +//ATOM_TV_PALN 6 +//ATOM_TV_PAL60 7 +//ATOM_TV_SECAM 8 + + +//ucTVSuppportedStd definition: +#define NTSC_SUPPORT 0x1 +#define NTSCJ_SUPPORT 0x2 + +#define PAL_SUPPORT 0x4 +#define PALM_SUPPORT 0x8 +#define PALCN_SUPPORT 0x10 +#define PALN_SUPPORT 0x20 +#define PAL60_SUPPORT 0x40 +#define SECAM_SUPPORT 0x80 + +#define MAX_SUPPORTED_TV_TIMING 2 + +typedef struct _ATOM_ANALOG_TV_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTV_SupportedStandard; + UCHAR ucTV_BootUpDefaultStandard; + UCHAR ucExt_TV_ASIC_ID; + UCHAR ucExt_TV_ASIC_SlaveAddr; + /*ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING];*/ + ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING]; +}ATOM_ANALOG_TV_INFO; + + +/**************************************************************************/ +// VRAM usage and their defintions + +// One chunk of VRAM used by Bios are for HWICON surfaces,EDID data. +// Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below. +// All the addresses below are the offsets from the frame buffer start.They all MUST be Dword aligned! +// To driver: The physical address of this memory portion=mmFB_START(4K aligned)+ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR +// To Bios: ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR->MM_INDEX + +#ifndef VESA_MEMORY_IN_64K_BLOCK +#define VESA_MEMORY_IN_64K_BLOCK 0x100 //256*64K=16Mb (Max. VESA memory is 16Mb!) +#endif + +#define ATOM_EDID_RAW_DATASIZE 256 //In Bytes +#define ATOM_HWICON_SURFACE_SIZE 4096 //In Bytes +#define ATOM_HWICON_INFOTABLE_SIZE 32 +#define MAX_DTD_MODE_IN_VRAM 6 +#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) //28= (SIZEOF ATOM_DTD_FORMAT) +#define ATOM_STD_MODE_SUPPORT_TBL_SIZE 32*8 //32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT) +#define DFP_ENCODER_TYPE_OFFSET 0x80 +#define DP_ENCODER_LANE_NUM_OFFSET 0x84 +#define DP_ENCODER_LINK_RATE_OFFSET 0x88 + +#define ATOM_HWICON1_SURFACE_ADDR 0 +#define ATOM_HWICON2_SURFACE_ADDR (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) +#define ATOM_HWICON_INFOTABLE_ADDR (ATOM_HWICON2_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) +#define ATOM_CRT1_EDID_ADDR (ATOM_HWICON_INFOTABLE_ADDR + ATOM_HWICON_INFOTABLE_SIZE) +#define ATOM_CRT1_DTD_MODE_TBL_ADDR (ATOM_CRT1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CRT1_STD_MODE_TBL_ADDR (ATOM_CRT1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_LCD1_EDID_ADDR (ATOM_CRT1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_LCD1_DTD_MODE_TBL_ADDR (ATOM_LCD1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_LCD1_STD_MODE_TBL_ADDR (ATOM_LCD1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_TV1_DTD_MODE_TBL_ADDR (ATOM_LCD1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP1_EDID_ADDR (ATOM_TV1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP1_DTD_MODE_TBL_ADDR (ATOM_DFP1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP1_STD_MODE_TBL_ADDR (ATOM_DFP1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_CRT2_EDID_ADDR (ATOM_DFP1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_CRT2_DTD_MODE_TBL_ADDR (ATOM_CRT2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CRT2_STD_MODE_TBL_ADDR (ATOM_CRT2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_LCD2_EDID_ADDR (ATOM_CRT2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_LCD2_DTD_MODE_TBL_ADDR (ATOM_LCD2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_LCD2_STD_MODE_TBL_ADDR (ATOM_LCD2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_TV2_EDID_ADDR (ATOM_LCD2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_TV2_DTD_MODE_TBL_ADDR (ATOM_TV2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_TV2_STD_MODE_TBL_ADDR (ATOM_TV2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP2_EDID_ADDR (ATOM_TV2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP2_DTD_MODE_TBL_ADDR (ATOM_DFP2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP2_STD_MODE_TBL_ADDR (ATOM_DFP2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_CV_EDID_ADDR (ATOM_DFP2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_CV_DTD_MODE_TBL_ADDR (ATOM_CV_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CV_STD_MODE_TBL_ADDR (ATOM_CV_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP3_EDID_ADDR (ATOM_CV_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP3_DTD_MODE_TBL_ADDR (ATOM_DFP3_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP3_STD_MODE_TBL_ADDR (ATOM_DFP3_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP3_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR+256) +#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START+512 + +//The size below is in Kb! +#define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC) + +#define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L +#define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30 +#define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 +#define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0 + +#define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO 1 + +typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO +{ + ULONG ulStartAddrUsedByFirmware; + USHORT usFirmwareUseInKb; + USHORT usReserved; +}ATOM_FIRMWARE_VRAM_RESERVE_INFO; + +typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_FIRMWARE_VRAM_RESERVE_INFO asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO]; +}ATOM_VRAM_USAGE_BY_FIRMWARE; + +/**************************************************************************/ +//GPIO Pin lut table definition +typedef struct _ATOM_GPIO_PIN_ASSIGNMENT +{ + USHORT usGpioPin_AIndex; + UCHAR ucGpioPinBitShift; + UCHAR ucGPIO_ID; +}ATOM_GPIO_PIN_ASSIGNMENT; + +typedef struct _ATOM_GPIO_PIN_LUT +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1]; +}ATOM_GPIO_PIN_LUT; + +/**************************************************************************/ + + +#define GPIO_PIN_ACTIVE_HIGH 0x1 + +#define MAX_SUPPORTED_CV_STANDARDS 5 + +// definitions for ATOM_D_INFO.ucSettings +#define ATOM_GPIO_SETTINGS_BITSHIFT_MASK 0x1F // [4:0] +#define ATOM_GPIO_SETTINGS_RESERVED_MASK 0x60 // [6:5] = must be zeroed out +#define ATOM_GPIO_SETTINGS_ACTIVE_MASK 0x80 // [7] + +typedef struct _ATOM_GPIO_INFO +{ + USHORT usAOffset; + UCHAR ucSettings; + UCHAR ucReserved; +}ATOM_GPIO_INFO; + +// definitions for ATOM_COMPONENT_VIDEO_INFO.ucMiscInfo (bit vector) +#define ATOM_CV_RESTRICT_FORMAT_SELECTION 0x2 + +// definitions for ATOM_COMPONENT_VIDEO_INFO.uc480i/uc480p/uc720p/uc1080i +#define ATOM_GPIO_DEFAULT_MODE_EN 0x80 //[7]; +#define ATOM_GPIO_SETTING_PERMODE_MASK 0x7F //[6:0] + +// definitions for ATOM_COMPONENT_VIDEO_INFO.ucLetterBoxMode +//Line 3 out put 5V. +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_A 0x01 //represent gpio 3 state for 16:9 +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_B 0x02 //represent gpio 4 state for 16:9 +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_SHIFT 0x0 + +//Line 3 out put 2.2V +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_A 0x04 //represent gpio 3 state for 4:3 Letter box +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_B 0x08 //represent gpio 4 state for 4:3 Letter box +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_SHIFT 0x2 + +//Line 3 out put 0V +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_A 0x10 //represent gpio 3 state for 4:3 +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_B 0x20 //represent gpio 4 state for 4:3 +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_SHIFT 0x4 + +#define ATOM_CV_LINE3_ASPECTRATIO_MASK 0x3F // bit [5:0] + +#define ATOM_CV_LINE3_ASPECTRATIO_EXIST 0x80 //bit 7 + +//GPIO bit index in gpio setting per mode value, also represend the block no. in gpio blocks. +#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_A 3 //bit 3 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. +#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_B 4 //bit 4 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. + + +typedef struct _ATOM_COMPONENT_VIDEO_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMask_PinRegisterIndex; + USHORT usEN_PinRegisterIndex; + USHORT usY_PinRegisterIndex; + USHORT usA_PinRegisterIndex; + UCHAR ucBitShift; + UCHAR ucPinActiveState; //ucPinActiveState: Bit0=1 active high, =0 active low + ATOM_DTD_FORMAT sReserved; // must be zeroed out + UCHAR ucMiscInfo; + UCHAR uc480i; + UCHAR uc480p; + UCHAR uc720p; + UCHAR uc1080i; + UCHAR ucLetterBoxMode; + UCHAR ucReserved[3]; + UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector + ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS]; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS]; +}ATOM_COMPONENT_VIDEO_INFO; + +//ucTableFormatRevision=2 +//ucTableContentRevision=1 +typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucMiscInfo; + UCHAR uc480i; + UCHAR uc480p; + UCHAR uc720p; + UCHAR uc1080i; + UCHAR ucReserved; + UCHAR ucLetterBoxMode; + UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector + ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS]; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS]; +}ATOM_COMPONENT_VIDEO_INFO_V21; + +#define ATOM_COMPONENT_VIDEO_INFO_LAST ATOM_COMPONENT_VIDEO_INFO_V21 + +/**************************************************************************/ +//Object table starts here +typedef struct _ATOM_OBJECT_HEADER +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + USHORT usConnectorObjectTableOffset; + USHORT usRouterObjectTableOffset; + USHORT usEncoderObjectTableOffset; + USHORT usProtectionObjectTableOffset; //only available when Protection block is independent. + USHORT usDisplayPathTableOffset; +}ATOM_OBJECT_HEADER; + + +typedef struct _ATOM_DISPLAY_OBJECT_PATH +{ + USHORT usDeviceTag; //supported device + USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH + USHORT usConnObjectId; //Connector Object ID + USHORT usGPUObjectId; //GPU ID + USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector. +}ATOM_DISPLAY_OBJECT_PATH; + +typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE +{ + UCHAR ucNumOfDispPath; + UCHAR ucVersion; + UCHAR ucPadding[2]; + ATOM_DISPLAY_OBJECT_PATH asDispPath[1]; +}ATOM_DISPLAY_OBJECT_PATH_TABLE; + + +typedef struct _ATOM_OBJECT //each object has this structure +{ + USHORT usObjectID; + USHORT usSrcDstTableOffset; + USHORT usRecordOffset; //this pointing to a bunch of records defined below + USHORT usReserved; +}ATOM_OBJECT; + +typedef struct _ATOM_OBJECT_TABLE //Above 4 object table offset pointing to a bunch of objects all have this structure +{ + UCHAR ucNumberOfObjects; + UCHAR ucPadding[3]; + ATOM_OBJECT asObjects[1]; +}ATOM_OBJECT_TABLE; + +typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset pointing to this structure +{ + UCHAR ucNumberOfSrc; + USHORT usSrcObjectID[1]; + UCHAR ucNumberOfDst; + USHORT usDstObjectID[1]; +}ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT; + + +//Related definitions, all records are differnt but they have a commond header +typedef struct _ATOM_COMMON_RECORD_HEADER +{ + UCHAR ucRecordType; //An emun to indicate the record type + UCHAR ucRecordSize; //The size of the whole record in byte +}ATOM_COMMON_RECORD_HEADER; + + +#define ATOM_I2C_RECORD_TYPE 1 +#define ATOM_HPD_INT_RECORD_TYPE 2 +#define ATOM_OUTPUT_PROTECTION_RECORD_TYPE 3 +#define ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE 4 +#define ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD_TYPE 5 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_ENCODER_FPGA_CONTROL_RECORD_TYPE 6 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD_TYPE 7 +#define ATOM_JTAG_RECORD_TYPE 8 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_OBJECT_GPIO_CNTL_RECORD_TYPE 9 +#define ATOM_ENCODER_DVO_CF_RECORD_TYPE 10 +#define ATOM_CONNECTOR_CF_RECORD_TYPE 11 +#define ATOM_CONNECTOR_HARDCODE_DTD_RECORD_TYPE 12 +#define ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE 13 +#define ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE 14 +#define ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE 15 + +//Must be updated when new record type is added,equal to that record definition! +#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_CF_RECORD_TYPE + +typedef struct _ATOM_I2C_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_I2C_ID_CONFIG sucI2cId; + UCHAR ucI2CAddr; //The slave address, it's 0 when the record is attached to connector for DDC +}ATOM_I2C_RECORD; + +typedef struct _ATOM_HPD_INT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucHPDIntGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info + UCHAR ucPluggged_PinState; +}ATOM_HPD_INT_RECORD; + + +typedef struct _ATOM_OUTPUT_PROTECTION_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucProtectionFlag; + UCHAR ucReserved; +}ATOM_OUTPUT_PROTECTION_RECORD; + +typedef struct _ATOM_CONNECTOR_DEVICE_TAG +{ + ULONG ulACPIDeviceEnum; //Reserved for now + USHORT usDeviceID; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT" + USHORT usPadding; +}ATOM_CONNECTOR_DEVICE_TAG; + +typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucNumberOfDevice; + UCHAR ucReserved; + ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1]; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation +}ATOM_CONNECTOR_DEVICE_TAG_RECORD; + + +typedef struct _ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucConfigGPIOID; + UCHAR ucConfigGPIOState; //Set to 1 when it's active high to enable external flow in + UCHAR ucFlowinGPIPID; + UCHAR ucExtInGPIPID; +}ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD; + +typedef struct _ATOM_ENCODER_FPGA_CONTROL_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucCTL1GPIO_ID; + UCHAR ucCTL1GPIOState; //Set to 1 when it's active high + UCHAR ucCTL2GPIO_ID; + UCHAR ucCTL2GPIOState; //Set to 1 when it's active high + UCHAR ucCTL3GPIO_ID; + UCHAR ucCTL3GPIOState; //Set to 1 when it's active high + UCHAR ucCTLFPGA_IN_ID; + UCHAR ucPadding[3]; +}ATOM_ENCODER_FPGA_CONTROL_RECORD; + +typedef struct _ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info + UCHAR ucTVActiveState; //Indicating when the pin==0 or 1 when TV is connected +}ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD; + +typedef struct _ATOM_JTAG_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucTMSGPIO_ID; + UCHAR ucTMSGPIOState; //Set to 1 when it's active high + UCHAR ucTCKGPIO_ID; + UCHAR ucTCKGPIOState; //Set to 1 when it's active high + UCHAR ucTDOGPIO_ID; + UCHAR ucTDOGPIOState; //Set to 1 when it's active high + UCHAR ucTDIGPIO_ID; + UCHAR ucTDIGPIOState; //Set to 1 when it's active high + UCHAR ucPadding[2]; +}ATOM_JTAG_RECORD; + + +//The following generic object gpio pin control record type will replace JTAG_RECORD/FPGA_CONTROL_RECORD/DVI_EXT_INPUT_RECORD above gradually +typedef struct _ATOM_GPIO_PIN_CONTROL_PAIR +{ + UCHAR ucGPIOID; // GPIO_ID, find the corresponding ID in GPIO_LUT table + UCHAR ucGPIO_PinState; // Pin state showing how to set-up the pin +}ATOM_GPIO_PIN_CONTROL_PAIR; + +typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucFlags; // Future expnadibility + UCHAR ucNumberOfPins; // Number of GPIO pins used to control the object + ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1]; // the real gpio pin pair determined by number of pins ucNumberOfPins +}ATOM_OBJECT_GPIO_CNTL_RECORD; + +//Definitions for GPIO pin state +#define GPIO_PIN_TYPE_INPUT 0x00 +#define GPIO_PIN_TYPE_OUTPUT 0x10 +#define GPIO_PIN_TYPE_HW_CONTROL 0x20 + +//For GPIO_PIN_TYPE_OUTPUT the following is defined +#define GPIO_PIN_OUTPUT_STATE_MASK 0x01 +#define GPIO_PIN_OUTPUT_STATE_SHIFT 0 +#define GPIO_PIN_STATE_ACTIVE_LOW 0x0 +#define GPIO_PIN_STATE_ACTIVE_HIGH 0x1 + +typedef struct _ATOM_ENCODER_DVO_CF_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ULONG ulStrengthControl; // DVOA strength control for CF + UCHAR ucPadding[2]; +}ATOM_ENCODER_DVO_CF_RECORD; + +// value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle +#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1 +#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2 + +typedef struct _ATOM_CONNECTOR_CF_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + USHORT usMaxPixClk; + UCHAR ucFlowCntlGpioId; + UCHAR ucSwapCntlGpioId; + UCHAR ucConnectedDvoBundle; + UCHAR ucPadding; +}ATOM_CONNECTOR_CF_RECORD; + +typedef struct _ATOM_CONNECTOR_HARDCODE_DTD_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_DTD_FORMAT asTiming; +}ATOM_CONNECTOR_HARDCODE_DTD_RECORD; + +typedef struct _ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; //ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE + UCHAR ucSubConnectorType; //CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D|X_ID_DUAL_LINK_DVI_D|HDMI_TYPE_A + UCHAR ucReserved; +}ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD; + + +typedef struct _ATOM_ROUTER_DDC_PATH_SELECT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucMuxType; //decide the number of ucMuxState, =0, no pin state, =1: single state with complement, >1: multiple state + UCHAR ucMuxControlPin; + UCHAR ucMuxState[2]; //for alligment purpose +}ATOM_ROUTER_DDC_PATH_SELECT_RECORD; + +typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucMuxType; + UCHAR ucMuxControlPin; + UCHAR ucMuxState[2]; //for alligment purpose +}ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD; + +// define ucMuxType +#define ATOM_ROUTER_MUX_PIN_STATE_MASK 0x0f +#define ATOM_ROUTER_MUX_PIN_SINGLE_STATE_COMPLEMENT 0x01 + +/**************************************************************************/ +//ASIC voltage data table starts here + +typedef struct _ATOM_VOLTAGE_INFO_HEADER +{ + USHORT usVDDCBaseLevel; //In number of 50mv unit + USHORT usReserved; //For possible extension table offset + UCHAR ucNumOfVoltageEntries; + UCHAR ucBytesPerVoltageEntry; + UCHAR ucVoltageStep; //Indicating in how many mv increament is one step, 0.5mv unit + UCHAR ucDefaultVoltageEntry; + UCHAR ucVoltageControlI2cLine; + UCHAR ucVoltageControlAddress; + UCHAR ucVoltageControlOffset; +}ATOM_VOLTAGE_INFO_HEADER; + +typedef struct _ATOM_VOLTAGE_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_INFO_HEADER viHeader; + UCHAR ucVoltageEntries[64]; //64 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries*ucBytesPerVoltageEntry +}ATOM_VOLTAGE_INFO; + + +typedef struct _ATOM_VOLTAGE_FORMULA +{ + USHORT usVoltageBaseLevel; // In number of 1mv unit + USHORT usVoltageStep; // Indicating in how many mv increament is one step, 1mv unit + UCHAR ucNumOfVoltageEntries; // Number of Voltage Entry, which indicate max Voltage + UCHAR ucFlag; // bit0=0 :step is 1mv =1 0.5mv + UCHAR ucBaseVID; // if there is no lookup table, VID= BaseVID + ( Vol - BaseLevle ) /VoltageStep + UCHAR ucReserved; + UCHAR ucVIDAdjustEntries[32]; // 32 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries +}ATOM_VOLTAGE_FORMULA; + +typedef struct _ATOM_VOLTAGE_CONTROL +{ + UCHAR ucVoltageControlId; //Indicate it is controlled by I2C or GPIO or HW state machine + UCHAR ucVoltageControlI2cLine; + UCHAR ucVoltageControlAddress; + UCHAR ucVoltageControlOffset; + USHORT usGpioPin_AIndex; //GPIO_PAD register index + UCHAR ucGpioPinBitShift[9]; //at most 8 pin support 255 VIDs, termintate with 0xff + UCHAR ucReserved; +}ATOM_VOLTAGE_CONTROL; + +// Define ucVoltageControlId +#define VOLTAGE_CONTROLLED_BY_HW 0x00 +#define VOLTAGE_CONTROLLED_BY_I2C_MASK 0x7F +#define VOLTAGE_CONTROLLED_BY_GPIO 0x80 +#define VOLTAGE_CONTROL_ID_LM64 0x01 //I2C control, used for R5xx Core Voltage +#define VOLTAGE_CONTROL_ID_DAC 0x02 //I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI +#define VOLTAGE_CONTROL_ID_VT116xM 0x03 //I2C control, used for R6xx Core Voltage +#define VOLTAGE_CONTROL_ID_DS4402 0x04 + +typedef struct _ATOM_VOLTAGE_OBJECT +{ + UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI + UCHAR ucSize; //Size of Object + ATOM_VOLTAGE_CONTROL asControl; //describ how to control + ATOM_VOLTAGE_FORMULA asFormula; //Indicate How to convert real Voltage to VID +}ATOM_VOLTAGE_OBJECT; + +typedef struct _ATOM_VOLTAGE_OBJECT_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_OBJECT asVoltageObj[3]; //Info for Voltage control +}ATOM_VOLTAGE_OBJECT_INFO; + +typedef struct _ATOM_LEAKID_VOLTAGE +{ + UCHAR ucLeakageId; + UCHAR ucReserved; + USHORT usVoltage; +}ATOM_LEAKID_VOLTAGE; + +typedef struct _ATOM_ASIC_PROFILE_VOLTAGE +{ + UCHAR ucProfileId; + UCHAR ucReserved; + USHORT usSize; + USHORT usEfuseSpareStartAddr; + USHORT usFuseIndex[8]; //from LSB to MSB, Max 8bit,end of 0xffff if less than 8 efuse id, + ATOM_LEAKID_VOLTAGE asLeakVol[2]; //Leakid and relatd voltage +}ATOM_ASIC_PROFILE_VOLTAGE; + +//ucProfileId +#define ATOM_ASIC_PROFILE_ID_EFUSE_VOLTAGE 1 +#define ATOM_ASIC_PROFILE_ID_EFUSE_PERFORMANCE_VOLTAGE 1 +#define ATOM_ASIC_PROFILE_ID_EFUSE_THERMAL_VOLTAGE 2 + +typedef struct _ATOM_ASIC_PROFILING_INFO +{ + ATOM_COMMON_TABLE_HEADER asHeader; + ATOM_ASIC_PROFILE_VOLTAGE asVoltage; +}ATOM_ASIC_PROFILING_INFO; + +typedef struct _ATOM_POWER_SOURCE_OBJECT +{ + UCHAR ucPwrSrcId; // Power source + UCHAR ucPwrSensorType; // GPIO, I2C or none + UCHAR ucPwrSensId; // if GPIO detect, it is GPIO id, if I2C detect, it is I2C id + UCHAR ucPwrSensSlaveAddr; // Slave address if I2C detect + UCHAR ucPwrSensRegIndex; // I2C register Index if I2C detect + UCHAR ucPwrSensRegBitMask; // detect which bit is used if I2C detect + UCHAR ucPwrSensActiveState; // high active or low active + UCHAR ucReserve[3]; // reserve + USHORT usSensPwr; // in unit of watt +}ATOM_POWER_SOURCE_OBJECT; + +typedef struct _ATOM_POWER_SOURCE_INFO +{ + ATOM_COMMON_TABLE_HEADER asHeader; + UCHAR asPwrbehave[16]; + ATOM_POWER_SOURCE_OBJECT asPwrObj[1]; +}ATOM_POWER_SOURCE_INFO; + + +//Define ucPwrSrcId +#define POWERSOURCE_PCIE_ID1 0x00 +#define POWERSOURCE_6PIN_CONNECTOR_ID1 0x01 +#define POWERSOURCE_8PIN_CONNECTOR_ID1 0x02 +#define POWERSOURCE_6PIN_CONNECTOR_ID2 0x04 +#define POWERSOURCE_8PIN_CONNECTOR_ID2 0x08 + +//define ucPwrSensorId +#define POWER_SENSOR_ALWAYS 0x00 +#define POWER_SENSOR_GPIO 0x01 +#define POWER_SENSOR_I2C 0x02 + +/**************************************************************************/ +// This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design +//Memory SS Info Table +//Define Memory Clock SS chip ID +#define ICS91719 1 +#define ICS91720 2 + +//Define one structure to inform SW a "block of data" writing to external SS chip via I2C protocol +typedef struct _ATOM_I2C_DATA_RECORD +{ + UCHAR ucNunberOfBytes; //Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop" + UCHAR ucI2CData[1]; //I2C data in bytes, should be less than 16 bytes usually +}ATOM_I2C_DATA_RECORD; + + +//Define one structure to inform SW how many blocks of data writing to external SS chip via I2C protocol, in addition to other information +typedef struct _ATOM_I2C_DEVICE_SETUP_INFO +{ + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //I2C line and HW/SW assisted cap. + UCHAR ucSSChipID; //SS chip being used + UCHAR ucSSChipSlaveAddr; //Slave Address to set up this SS chip + UCHAR ucNumOfI2CDataRecords; //number of data block + ATOM_I2C_DATA_RECORD asI2CData[1]; +}ATOM_I2C_DEVICE_SETUP_INFO; + +//========================================================================================== +typedef struct _ATOM_ASIC_MVDD_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1]; +}ATOM_ASIC_MVDD_INFO; + +//========================================================================================== +#define ATOM_MCLK_SS_INFO ATOM_ASIC_MVDD_INFO + +//========================================================================================== +/**************************************************************************/ + +typedef struct _ATOM_ASIC_SS_ASSIGNMENT +{ + ULONG ulTargetClockRange; //Clock Out frequence (VCO ), in unit of 10Khz + USHORT usSpreadSpectrumPercentage; //in unit of 0.01% + USHORT usSpreadRateInKhz; //in unit of kHz, modulation freq + UCHAR ucClockIndication; //Indicate which clock source needs SS + UCHAR ucSpreadSpectrumMode; //Bit1=0 Down Spread,=1 Center Spread. + UCHAR ucReserved[2]; +}ATOM_ASIC_SS_ASSIGNMENT; + +//Define ucSpreadSpectrumType +#define ASIC_INTERNAL_MEMORY_SS 1 +#define ASIC_INTERNAL_ENGINE_SS 2 +#define ASIC_INTERNAL_UVD_SS 3 + +typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_ASIC_SS_ASSIGNMENT asSpreadSpectrum[4]; +}ATOM_ASIC_INTERNAL_SS_INFO; + +//==============================Scratch Pad Definition Portion=============================== +#define ATOM_DEVICE_CONNECT_INFO_DEF 0 +#define ATOM_ROM_LOCATION_DEF 1 +#define ATOM_TV_STANDARD_DEF 2 +#define ATOM_ACTIVE_INFO_DEF 3 +#define ATOM_LCD_INFO_DEF 4 +#define ATOM_DOS_REQ_INFO_DEF 5 +#define ATOM_ACC_CHANGE_INFO_DEF 6 +#define ATOM_DOS_MODE_INFO_DEF 7 +#define ATOM_I2C_CHANNEL_STATUS_DEF 8 +#define ATOM_I2C_CHANNEL_STATUS1_DEF 9 + + +// BIOS_0_SCRATCH Definition +#define ATOM_S0_CRT1_MONO 0x00000001L +#define ATOM_S0_CRT1_COLOR 0x00000002L +#define ATOM_S0_CRT1_MASK (ATOM_S0_CRT1_MONO+ATOM_S0_CRT1_COLOR) + +#define ATOM_S0_TV1_COMPOSITE_A 0x00000004L +#define ATOM_S0_TV1_SVIDEO_A 0x00000008L +#define ATOM_S0_TV1_MASK_A (ATOM_S0_TV1_COMPOSITE_A+ATOM_S0_TV1_SVIDEO_A) + +#define ATOM_S0_CV_A 0x00000010L +#define ATOM_S0_CV_DIN_A 0x00000020L +#define ATOM_S0_CV_MASK_A (ATOM_S0_CV_A+ATOM_S0_CV_DIN_A) + + +#define ATOM_S0_CRT2_MONO 0x00000100L +#define ATOM_S0_CRT2_COLOR 0x00000200L +#define ATOM_S0_CRT2_MASK (ATOM_S0_CRT2_MONO+ATOM_S0_CRT2_COLOR) + +#define ATOM_S0_TV1_COMPOSITE 0x00000400L +#define ATOM_S0_TV1_SVIDEO 0x00000800L +#define ATOM_S0_TV1_SCART 0x00004000L +#define ATOM_S0_TV1_MASK (ATOM_S0_TV1_COMPOSITE+ATOM_S0_TV1_SVIDEO+ATOM_S0_TV1_SCART) + +#define ATOM_S0_CV 0x00001000L +#define ATOM_S0_CV_DIN 0x00002000L +#define ATOM_S0_CV_MASK (ATOM_S0_CV+ATOM_S0_CV_DIN) + + +#define ATOM_S0_DFP1 0x00010000L +#define ATOM_S0_DFP2 0x00020000L +#define ATOM_S0_LCD1 0x00040000L +#define ATOM_S0_LCD2 0x00080000L +#define ATOM_S0_TV2 0x00100000L +#define ATOM_S0_DFP3 0x00200000L + +#define ATOM_S0_FAD_REGISTER_BUG 0x02000000L // If set, indicates we are running a PCIE asic with + // the FAD/HDP reg access bug. Bit is read by DAL + +#define ATOM_S0_THERMAL_STATE_MASK 0x1C000000L +#define ATOM_S0_THERMAL_STATE_SHIFT 26 + +#define ATOM_S0_SYSTEM_POWER_STATE_MASK 0xE0000000L +#define ATOM_S0_SYSTEM_POWER_STATE_SHIFT 29 + +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3 + +//Byte aligned defintion for BIOS usage +#define ATOM_S0_CRT1_MONOb0 0x01 +#define ATOM_S0_CRT1_COLORb0 0x02 +#define ATOM_S0_CRT1_MASKb0 (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0) + +#define ATOM_S0_TV1_COMPOSITEb0 0x04 +#define ATOM_S0_TV1_SVIDEOb0 0x08 +#define ATOM_S0_TV1_MASKb0 (ATOM_S0_TV1_COMPOSITEb0+ATOM_S0_TV1_SVIDEOb0) + +#define ATOM_S0_CVb0 0x10 +#define ATOM_S0_CV_DINb0 0x20 +#define ATOM_S0_CV_MASKb0 (ATOM_S0_CVb0+ATOM_S0_CV_DINb0) + +#define ATOM_S0_CRT2_MONOb1 0x01 +#define ATOM_S0_CRT2_COLORb1 0x02 +#define ATOM_S0_CRT2_MASKb1 (ATOM_S0_CRT2_MONOb1+ATOM_S0_CRT2_COLORb1) + +#define ATOM_S0_TV1_COMPOSITEb1 0x04 +#define ATOM_S0_TV1_SVIDEOb1 0x08 +#define ATOM_S0_TV1_SCARTb1 0x40 +#define ATOM_S0_TV1_MASKb1 (ATOM_S0_TV1_COMPOSITEb1+ATOM_S0_TV1_SVIDEOb1+ATOM_S0_TV1_SCARTb1) + +#define ATOM_S0_CVb1 0x10 +#define ATOM_S0_CV_DINb1 0x20 +#define ATOM_S0_CV_MASKb1 (ATOM_S0_CVb1+ATOM_S0_CV_DINb1) + +#define ATOM_S0_DFP1b2 0x01 +#define ATOM_S0_DFP2b2 0x02 +#define ATOM_S0_LCD1b2 0x04 +#define ATOM_S0_LCD2b2 0x08 +#define ATOM_S0_TV2b2 0x10 +#define ATOM_S0_DFP3b2 0x20 + +#define ATOM_S0_THERMAL_STATE_MASKb3 0x1C +#define ATOM_S0_THERMAL_STATE_SHIFTb3 2 + +#define ATOM_S0_SYSTEM_POWER_STATE_MASKb3 0xE0 +#define ATOM_S0_LCD1_SHIFT 18 + +// BIOS_1_SCRATCH Definition +#define ATOM_S1_ROM_LOCATION_MASK 0x0000FFFFL +#define ATOM_S1_PCI_BUS_DEV_MASK 0xFFFF0000L + + +// BIOS_2_SCRATCH Definition +#define ATOM_S2_TV1_STANDARD_MASK 0x0000000FL +#define ATOM_S2_CURRENT_BL_LEVEL_MASK 0x0000FF00L +#define ATOM_S2_CURRENT_BL_LEVEL_SHIFT 8 + +#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L +#define ATOM_S2_LCD1_DPMS_STATE 0x00020000L +#define ATOM_S2_TV1_DPMS_STATE 0x00040000L +#define ATOM_S2_DFP1_DPMS_STATE 0x00080000L +#define ATOM_S2_CRT2_DPMS_STATE 0x00100000L +#define ATOM_S2_LCD2_DPMS_STATE 0x00200000L +#define ATOM_S2_TV2_DPMS_STATE 0x00400000L +#define ATOM_S2_DFP2_DPMS_STATE 0x00800000L +#define ATOM_S2_CV_DPMS_STATE 0x01000000L +#define ATOM_S2_DFP3_DPMS_STATE 0x02000000L + +#define ATOM_S2_DEVICE_DPMS_STATE (ATOM_S2_CRT1_DPMS_STATE+ATOM_S2_LCD1_DPMS_STATE+ATOM_S2_TV1_DPMS_STATE+\ + ATOM_S2_DFP1I_DPMS_STATE+ATOM_S2_CRT2_DPMS_STATE+ATOM_S2_LCD2_DPMS_STATE+\ + ATOM_S2_TV2_DPMS_STATE+ATOM_S2_DFP1X_DPMS_STATE+ATOM_S2_CV_DPMS_STATE+\ + ATOM_S2_DFP3_DPMS_STATE) + + +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK 0x0C000000L +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK_SHIFT 26 +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGE 0x10000000L + +#define ATOM_S2_VRI_BRIGHT_ENABLE 0x20000000L + +#define ATOM_S2_DISPLAY_ROTATION_0_DEGREE 0x0 +#define ATOM_S2_DISPLAY_ROTATION_90_DEGREE 0x1 +#define ATOM_S2_DISPLAY_ROTATION_180_DEGREE 0x2 +#define ATOM_S2_DISPLAY_ROTATION_270_DEGREE 0x3 +#define ATOM_S2_DISPLAY_ROTATION_DEGREE_SHIFT 30 +#define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK 0xC0000000L + + +//Byte aligned defintion for BIOS usage +#define ATOM_S2_TV1_STANDARD_MASKb0 0x0F +#define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF +#define ATOM_S2_CRT1_DPMS_STATEb2 0x01 +#define ATOM_S2_LCD1_DPMS_STATEb2 0x02 +#define ATOM_S2_TV1_DPMS_STATEb2 0x04 +#define ATOM_S2_DFP1_DPMS_STATEb2 0x08 +#define ATOM_S2_CRT2_DPMS_STATEb2 0x10 +#define ATOM_S2_LCD2_DPMS_STATEb2 0x20 +#define ATOM_S2_TV2_DPMS_STATEb2 0x40 +#define ATOM_S2_DFP2_DPMS_STATEb2 0x80 +#define ATOM_S2_CV_DPMS_STATEb3 0x01 +#define ATOM_S2_DFP3_DPMS_STATEb3 0x02 + +#define ATOM_S2_DEVICE_DPMS_MASKw1 0x3FF +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASKb3 0x0C +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGEb3 0x10 +#define ATOM_S2_VRI_BRIGHT_ENABLEb3 0x20 +#define ATOM_S2_ROTATION_STATE_MASKb3 0xC0 + + +// BIOS_3_SCRATCH Definition +#define ATOM_S3_CRT1_ACTIVE 0x00000001L +#define ATOM_S3_LCD1_ACTIVE 0x00000002L +#define ATOM_S3_TV1_ACTIVE 0x00000004L +#define ATOM_S3_DFP1_ACTIVE 0x00000008L +#define ATOM_S3_CRT2_ACTIVE 0x00000010L +#define ATOM_S3_LCD2_ACTIVE 0x00000020L +#define ATOM_S3_TV2_ACTIVE 0x00000040L +#define ATOM_S3_DFP2_ACTIVE 0x00000080L +#define ATOM_S3_CV_ACTIVE 0x00000100L +#define ATOM_S3_DFP3_ACTIVE 0x00000200L + +#define ATOM_S3_DEVICE_ACTIVE_MASK 0x000003FFL + +#define ATOM_S3_LCD_FULLEXPANSION_ACTIVE 0x00001000L +#define ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE 0x00002000L + +#define ATOM_S3_CRT1_CRTC_ACTIVE 0x00010000L +#define ATOM_S3_LCD1_CRTC_ACTIVE 0x00020000L +#define ATOM_S3_TV1_CRTC_ACTIVE 0x00040000L +#define ATOM_S3_DFP1_CRTC_ACTIVE 0x00080000L +#define ATOM_S3_CRT2_CRTC_ACTIVE 0x00100000L +#define ATOM_S3_LCD2_CRTC_ACTIVE 0x00200000L +#define ATOM_S3_TV2_CRTC_ACTIVE 0x00400000L +#define ATOM_S3_DFP2_CRTC_ACTIVE 0x00800000L +#define ATOM_S3_CV_CRTC_ACTIVE 0x01000000L +#define ATOM_S3_DFP3_CRTC_ACTIVE 0x02000000L + +#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x03FF0000L +#define ATOM_S3_ASIC_GUI_ENGINE_HUNG 0x20000000L +#define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L +#define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L + +//Byte aligned defintion for BIOS usage +#define ATOM_S3_CRT1_ACTIVEb0 0x01 +#define ATOM_S3_LCD1_ACTIVEb0 0x02 +#define ATOM_S3_TV1_ACTIVEb0 0x04 +#define ATOM_S3_DFP1_ACTIVEb0 0x08 +#define ATOM_S3_CRT2_ACTIVEb0 0x10 +#define ATOM_S3_LCD2_ACTIVEb0 0x20 +#define ATOM_S3_TV2_ACTIVEb0 0x40 +#define ATOM_S3_DFP2_ACTIVEb0 0x80 +#define ATOM_S3_CV_ACTIVEb1 0x01 +#define ATOM_S3_DFP3_ACTIVEb1 0x02 + +#define ATOM_S3_ACTIVE_CRTC1w0 0x3FF + +#define ATOM_S3_CRT1_CRTC_ACTIVEb2 0x01 +#define ATOM_S3_LCD1_CRTC_ACTIVEb2 0x02 +#define ATOM_S3_TV1_CRTC_ACTIVEb2 0x04 +#define ATOM_S3_DFP1_CRTC_ACTIVEb2 0x08 +#define ATOM_S3_CRT2_CRTC_ACTIVEb2 0x10 +#define ATOM_S3_LCD2_CRTC_ACTIVEb2 0x20 +#define ATOM_S3_TV2_CRTC_ACTIVEb2 0x40 +#define ATOM_S3_DFP2_CRTC_ACTIVEb2 0x80 +#define ATOM_S3_CV_CRTC_ACTIVEb3 0x01 +#define ATOM_S3_DFP3_CRTC_ACTIVEb3 0x02 + +#define ATOM_S3_ACTIVE_CRTC2w1 0x3FF + +#define ATOM_S3_ASIC_GUI_ENGINE_HUNGb3 0x20 +#define ATOM_S3_ALLOW_FAST_PWR_SWITCHb3 0x40 +#define ATOM_S3_RQST_GPU_USE_MIN_PWRb3 0x80 + +// BIOS_4_SCRATCH Definition +#define ATOM_S4_LCD1_PANEL_ID_MASK 0x000000FFL +#define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L +#define ATOM_S4_LCD1_REFRESH_SHIFT 8 + + +//Byte aligned defintion for BIOS usage +#define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF +#define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0 +#define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0 + + +// BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!! +#define ATOM_S5_DOS_REQ_CRT1b0 0x01 +#define ATOM_S5_DOS_REQ_LCD1b0 0x02 +#define ATOM_S5_DOS_REQ_TV1b0 0x04 +#define ATOM_S5_DOS_REQ_DFP1b0 0x08 +#define ATOM_S5_DOS_REQ_CRT2b0 0x10 +#define ATOM_S5_DOS_REQ_LCD2b0 0x20 +#define ATOM_S5_DOS_REQ_TV2b0 0x40 +#define ATOM_S5_DOS_REQ_DFP2b0 0x80 +#define ATOM_S5_DOS_REQ_CVb1 0x01 +#define ATOM_S5_DOS_REQ_DFP3b1 0x02 + +#define ATOM_S5_DOS_REQ_DEVICEw0 0x03FF + +#define ATOM_S5_DOS_REQ_CRT1 0x0001 +#define ATOM_S5_DOS_REQ_LCD1 0x0002 +#define ATOM_S5_DOS_REQ_TV1 0x0004 +#define ATOM_S5_DOS_REQ_DFP1 0x0008 +#define ATOM_S5_DOS_REQ_CRT2 0x0010 +#define ATOM_S5_DOS_REQ_LCD2 0x0020 +#define ATOM_S5_DOS_REQ_TV2 0x0040 +#define ATOM_S5_DOS_REQ_DFP2 0x0080 +#define ATOM_S5_DOS_REQ_CV 0x0100 +#define ATOM_S5_DOS_REQ_DFP3 0x0200 + +#define ATOM_S5_DOS_FORCE_CRT1b2 ATOM_S5_DOS_REQ_CRT1b0 +#define ATOM_S5_DOS_FORCE_TV1b2 ATOM_S5_DOS_REQ_TV1b0 +#define ATOM_S5_DOS_FORCE_CRT2b2 ATOM_S5_DOS_REQ_CRT2b0 +#define ATOM_S5_DOS_FORCE_CVb3 ATOM_S5_DOS_REQ_CVb1 +#define ATOM_S5_DOS_FORCE_DEVICEw1 (ATOM_S5_DOS_FORCE_CRT1b2+ATOM_S5_DOS_FORCE_TV1b2+ATOM_S5_DOS_FORCE_CRT2b2+\ + (ATOM_S5_DOS_FORCE_CVb3<<8)) + +// BIOS_6_SCRATCH Definition +#define ATOM_S6_DEVICE_CHANGE 0x00000001L +#define ATOM_S6_SCALER_CHANGE 0x00000002L +#define ATOM_S6_LID_CHANGE 0x00000004L +#define ATOM_S6_DOCKING_CHANGE 0x00000008L +#define ATOM_S6_ACC_MODE 0x00000010L +#define ATOM_S6_EXT_DESKTOP_MODE 0x00000020L +#define ATOM_S6_LID_STATE 0x00000040L +#define ATOM_S6_DOCK_STATE 0x00000080L +#define ATOM_S6_CRITICAL_STATE 0x00000100L +#define ATOM_S6_HW_I2C_BUSY_STATE 0x00000200L +#define ATOM_S6_THERMAL_STATE_CHANGE 0x00000400L +#define ATOM_S6_INTERRUPT_SET_BY_BIOS 0x00000800L +#define ATOM_S6_REQ_LCD_EXPANSION_FULL 0x00001000L //Normal expansion Request bit for LCD +#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO 0x00002000L //Aspect ratio expansion Request bit for LCD + +#define ATOM_S6_DISPLAY_STATE_CHANGE 0x00004000L //This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion +#define ATOM_S6_I2C_STATE_CHANGE 0x00008000L //This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion + + +#define ATOM_S6_ACC_REQ_CRT1 0x00010000L +#define ATOM_S6_ACC_REQ_LCD1 0x00020000L +#define ATOM_S6_ACC_REQ_TV1 0x00040000L +#define ATOM_S6_ACC_REQ_DFP1 0x00080000L +#define ATOM_S6_ACC_REQ_CRT2 0x00100000L +#define ATOM_S6_ACC_REQ_LCD2 0x00200000L +#define ATOM_S6_ACC_REQ_TV2 0x00400000L +#define ATOM_S6_ACC_REQ_DFP2 0x00800000L +#define ATOM_S6_ACC_REQ_CV 0x01000000L +#define ATOM_S6_ACC_REQ_DFP3 0x02000000L + +#define ATOM_S6_ACC_REQ_MASK 0x03FF0000L +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE 0x10000000L +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH 0x20000000L +#define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L +#define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK 0x80000000L + +//Byte aligned defintion for BIOS usage +#define ATOM_S6_DEVICE_CHANGEb0 0x01 +#define ATOM_S6_SCALER_CHANGEb0 0x02 +#define ATOM_S6_LID_CHANGEb0 0x04 +#define ATOM_S6_DOCKING_CHANGEb0 0x08 +#define ATOM_S6_ACC_MODEb0 0x10 +#define ATOM_S6_EXT_DESKTOP_MODEb0 0x20 +#define ATOM_S6_LID_STATEb0 0x40 +#define ATOM_S6_DOCK_STATEb0 0x80 +#define ATOM_S6_CRITICAL_STATEb1 0x01 +#define ATOM_S6_HW_I2C_BUSY_STATEb1 0x02 +#define ATOM_S6_THERMAL_STATE_CHANGEb1 0x04 +#define ATOM_S6_INTERRUPT_SET_BY_BIOSb1 0x08 +#define ATOM_S6_REQ_LCD_EXPANSION_FULLb1 0x10 +#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIOb1 0x20 + +#define ATOM_S6_ACC_REQ_CRT1b2 0x01 +#define ATOM_S6_ACC_REQ_LCD1b2 0x02 +#define ATOM_S6_ACC_REQ_TV1b2 0x04 +#define ATOM_S6_ACC_REQ_DFP1b2 0x08 +#define ATOM_S6_ACC_REQ_CRT2b2 0x10 +#define ATOM_S6_ACC_REQ_LCD2b2 0x20 +#define ATOM_S6_ACC_REQ_TV2b2 0x40 +#define ATOM_S6_ACC_REQ_DFP2b2 0x80 +#define ATOM_S6_ACC_REQ_CVb3 0x01 +#define ATOM_S6_ACC_REQ_DFP3b3 0x02 + +#define ATOM_S6_ACC_REQ_DEVICEw1 ATOM_S5_DOS_REQ_DEVICEw0 +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGEb3 0x10 +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCHb3 0x20 +#define ATOM_S6_VRI_BRIGHTNESS_CHANGEb3 0x40 +#define ATOM_S6_CONFIG_DISPLAY_CHANGEb3 0x80 + +#define ATOM_S6_DEVICE_CHANGE_SHIFT 0 +#define ATOM_S6_SCALER_CHANGE_SHIFT 1 +#define ATOM_S6_LID_CHANGE_SHIFT 2 +#define ATOM_S6_DOCKING_CHANGE_SHIFT 3 +#define ATOM_S6_ACC_MODE_SHIFT 4 +#define ATOM_S6_EXT_DESKTOP_MODE_SHIFT 5 +#define ATOM_S6_LID_STATE_SHIFT 6 +#define ATOM_S6_DOCK_STATE_SHIFT 7 +#define ATOM_S6_CRITICAL_STATE_SHIFT 8 +#define ATOM_S6_HW_I2C_BUSY_STATE_SHIFT 9 +#define ATOM_S6_THERMAL_STATE_CHANGE_SHIFT 10 +#define ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT 11 +#define ATOM_S6_REQ_SCALER_SHIFT 12 +#define ATOM_S6_REQ_SCALER_ARATIO_SHIFT 13 +#define ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT 14 +#define ATOM_S6_I2C_STATE_CHANGE_SHIFT 15 +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT 28 +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH_SHIFT 29 +#define ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT 30 +#define ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT 31 + +// BIOS_7_SCRATCH Definition, BIOS_7_SCRATCH is used by Firmware only !!!! +#define ATOM_S7_DOS_MODE_TYPEb0 0x03 +#define ATOM_S7_DOS_MODE_VGAb0 0x00 +#define ATOM_S7_DOS_MODE_VESAb0 0x01 +#define ATOM_S7_DOS_MODE_EXTb0 0x02 +#define ATOM_S7_DOS_MODE_PIXEL_DEPTHb0 0x0C +#define ATOM_S7_DOS_MODE_PIXEL_FORMATb0 0xF0 +#define ATOM_S7_DOS_8BIT_DAC_ENb1 0x01 +#define ATOM_S7_DOS_MODE_NUMBERw1 0x0FFFF + +#define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT 8 + +// BIOS_8_SCRATCH Definition +#define ATOM_S8_I2C_CHANNEL_BUSY_MASK 0x00000FFFF +#define ATOM_S8_I2C_HW_ENGINE_BUSY_MASK 0x0FFFF0000 + +#define ATOM_S8_I2C_CHANNEL_BUSY_SHIFT 0 +#define ATOM_S8_I2C_ENGINE_BUSY_SHIFT 16 + +// BIOS_9_SCRATCH Definition +#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_MASK +#define ATOM_S9_I2C_CHANNEL_COMPLETED_MASK 0x0000FFFF +#endif +#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_MASK +#define ATOM_S9_I2C_CHANNEL_ABORTED_MASK 0xFFFF0000 +#endif +#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT +#define ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT 0 +#endif +#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT +#define ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT 16 +#endif + + +#define ATOM_FLAG_SET 0x20 +#define ATOM_FLAG_CLEAR 0 +#define CLEAR_ATOM_S6_ACC_MODE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_ACC_MODE_SHIFT | ATOM_FLAG_CLEAR) +#define SET_ATOM_S6_DEVICE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DEVICE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_VRI_BRIGHTNESS_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_SCALER_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SCALER_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_LID_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_CHANGE_SHIFT | ATOM_FLAG_SET) + +#define SET_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_DOCK_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCKING_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_THERMAL_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_THERMAL_STATE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_SYSTEM_POWER_MODE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_INTERRUPT_SET_BY_BIOS ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT | ATOM_FLAG_SET) + +#define SET_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_CLEAR ) + +#define SET_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_SET ) +#define CLEAR_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_CLEAR ) + +#define SET_ATOM_S6_I2C_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_I2C_STATE_CHANGE_SHIFT | ATOM_FLAG_SET ) + +#define SET_ATOM_S6_DISPLAY_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT | ATOM_FLAG_SET ) + +#define SET_ATOM_S6_DEVICE_RECONFIG ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S0_LCD1 ((ATOM_DEVICE_CONNECT_INFO_DEF << 8 )| ATOM_S0_LCD1_SHIFT | ATOM_FLAG_CLEAR ) +#define SET_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_SET ) +#define CLEAR_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_CLEAR ) + +/****************************************************************************/ +//Portion II: Definitinos only used in Driver +/****************************************************************************/ + +// Macros used by driver + +#define GetIndexIntoMasterTable(MasterOrData, FieldName) (((char*)(&((ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES*)0)->FieldName)-(char*)0)/sizeof(USHORT)) + +#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableFormatRevision)&0x3F) +#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableContentRevision)&0x3F) + +#define GET_DATA_TABLE_MAJOR_REVISION GET_COMMAND_TABLE_COMMANDSET_REVISION +#define GET_DATA_TABLE_MINOR_REVISION GET_COMMAND_TABLE_PARAMETER_REVISION + +/****************************************************************************/ +//Portion III: Definitinos only used in VBIOS +/****************************************************************************/ +#define ATOM_DAC_SRC 0x80 +#define ATOM_SRC_DAC1 0 +#define ATOM_SRC_DAC2 0x80 + + +#ifdef UEFI_BUILD + #define USHORT UTEMP +#endif + +typedef struct _MEMORY_PLLINIT_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit + UCHAR ucAction; //not define yet + UCHAR ucFbDiv_Hi; //Fbdiv Hi byte + UCHAR ucFbDiv; //FB value + UCHAR ucPostDiv; //Post div +}MEMORY_PLLINIT_PARAMETERS; + +#define MEMORY_PLLINIT_PS_ALLOCATION MEMORY_PLLINIT_PARAMETERS + + +#define GPIO_PIN_WRITE 0x01 +#define GPIO_PIN_READ 0x00 + +typedef struct _GPIO_PIN_CONTROL_PARAMETERS +{ + UCHAR ucGPIO_ID; //return value, read from GPIO pins + UCHAR ucGPIOBitShift; //define which bit in uGPIOBitVal need to be update + UCHAR ucGPIOBitVal; //Set/Reset corresponding bit defined in ucGPIOBitMask + UCHAR ucAction; //=GPIO_PIN_WRITE: Read; =GPIO_PIN_READ: Write +}GPIO_PIN_CONTROL_PARAMETERS; + +typedef struct _ENABLE_SCALER_PARAMETERS +{ + UCHAR ucScaler; // ATOM_SCALER1, ATOM_SCALER2 + UCHAR ucEnable; // ATOM_SCALER_DISABLE or ATOM_SCALER_CENTER or ATOM_SCALER_EXPANSION + UCHAR ucTVStandard; // + UCHAR ucPadding[1]; +}ENABLE_SCALER_PARAMETERS; +#define ENABLE_SCALER_PS_ALLOCATION ENABLE_SCALER_PARAMETERS + +//ucEnable: +#define SCALER_BYPASS_AUTO_CENTER_NO_REPLICATION 0 +#define SCALER_BYPASS_AUTO_CENTER_AUTO_REPLICATION 1 +#define SCALER_ENABLE_2TAP_ALPHA_MODE 2 +#define SCALER_ENABLE_MULTITAP_MODE 3 + +typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS +{ + ULONG usHWIconHorzVertPosn; // Hardware Icon Vertical position + UCHAR ucHWIconVertOffset; // Hardware Icon Vertical offset + UCHAR ucHWIconHorzOffset; // Hardware Icon Horizontal offset + UCHAR ucSelection; // ATOM_CURSOR1 or ATOM_ICON1 or ATOM_CURSOR2 or ATOM_ICON2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE +}ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS; + +typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION +{ + ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS sEnableIcon; + ENABLE_CRTC_PARAMETERS sReserved; +}ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS +{ + USHORT usHight; // Image Hight + USHORT usWidth; // Image Width + UCHAR ucSurface; // Surface 1 or 2 + UCHAR ucPadding[3]; +}ENABLE_GRAPH_SURFACE_PARAMETERS; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2 +{ + USHORT usHight; // Image Hight + USHORT usWidth; // Image Width + UCHAR ucSurface; // Surface 1 or 2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[2]; +}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2; + +typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION +{ + ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface; + ENABLE_YUV_PS_ALLOCATION sReserved; // Don't set this one +}ENABLE_GRAPH_SURFACE_PS_ALLOCATION; + +typedef struct _MEMORY_CLEAN_UP_PARAMETERS +{ + USHORT usMemoryStart; //in 8Kb boundry, offset from memory base address + USHORT usMemorySize; //8Kb blocks aligned +}MEMORY_CLEAN_UP_PARAMETERS; +#define MEMORY_CLEAN_UP_PS_ALLOCATION MEMORY_CLEAN_UP_PARAMETERS + +typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS +{ + USHORT usX_Size; //When use as input parameter, usX_Size indicates which CRTC + USHORT usY_Size; +}GET_DISPLAY_SURFACE_SIZE_PARAMETERS; + +typedef struct _INDIRECT_IO_ACCESS +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR IOAccessSequence[256]; +} INDIRECT_IO_ACCESS; + +#define INDIRECT_READ 0x00 +#define INDIRECT_WRITE 0x80 + +#define INDIRECT_IO_MM 0 +#define INDIRECT_IO_PLL 1 +#define INDIRECT_IO_MC 2 +#define INDIRECT_IO_PCIE 3 +#define INDIRECT_IO_PCIEP 4 +#define INDIRECT_IO_NBMISC 5 + +#define INDIRECT_IO_PLL_READ INDIRECT_IO_PLL | INDIRECT_READ +#define INDIRECT_IO_PLL_WRITE INDIRECT_IO_PLL | INDIRECT_WRITE +#define INDIRECT_IO_MC_READ INDIRECT_IO_MC | INDIRECT_READ +#define INDIRECT_IO_MC_WRITE INDIRECT_IO_MC | INDIRECT_WRITE +#define INDIRECT_IO_PCIE_READ INDIRECT_IO_PCIE | INDIRECT_READ +#define INDIRECT_IO_PCIE_WRITE INDIRECT_IO_PCIE | INDIRECT_WRITE +#define INDIRECT_IO_PCIEP_READ INDIRECT_IO_PCIEP | INDIRECT_READ +#define INDIRECT_IO_PCIEP_WRITE INDIRECT_IO_PCIEP | INDIRECT_WRITE +#define INDIRECT_IO_NBMISC_READ INDIRECT_IO_NBMISC | INDIRECT_READ +#define INDIRECT_IO_NBMISC_WRITE INDIRECT_IO_NBMISC | INDIRECT_WRITE + +typedef struct _ATOM_OEM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; +}ATOM_OEM_INFO; + +typedef struct _ATOM_TV_MODE +{ + UCHAR ucVMode_Num; //Video mode number + UCHAR ucTV_Mode_Num; //Internal TV mode number +}ATOM_TV_MODE; + +typedef struct _ATOM_BIOS_INT_TVSTD_MODE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usTV_Mode_LUT_Offset; // Pointer to standard to internal number conversion table + USHORT usTV_FIFO_Offset; // Pointer to FIFO entry table + USHORT usNTSC_Tbl_Offset; // Pointer to SDTV_Mode_NTSC table + USHORT usPAL_Tbl_Offset; // Pointer to SDTV_Mode_PAL table + USHORT usCV_Tbl_Offset; // Pointer to SDTV_Mode_PAL table +}ATOM_BIOS_INT_TVSTD_MODE; + + +typedef struct _ATOM_TV_MODE_SCALER_PTR +{ + USHORT ucFilter0_Offset; //Pointer to filter format 0 coefficients + USHORT usFilter1_Offset; //Pointer to filter format 0 coefficients + UCHAR ucTV_Mode_Num; +}ATOM_TV_MODE_SCALER_PTR; + +typedef struct _ATOM_STANDARD_VESA_TIMING +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MODE_TIMING aModeTimings[16]; // 16 is not the real array number, just for initial allocation +}ATOM_STANDARD_VESA_TIMING; + + +typedef struct _ATOM_STD_FORMAT +{ + USHORT usSTD_HDisp; + USHORT usSTD_VDisp; + USHORT usSTD_RefreshRate; + USHORT usReserved; +}ATOM_STD_FORMAT; + +typedef struct _ATOM_VESA_TO_EXTENDED_MODE +{ + USHORT usVESA_ModeNumber; + USHORT usExtendedModeNumber; +}ATOM_VESA_TO_EXTENDED_MODE; + +typedef struct _ATOM_VESA_TO_INTENAL_MODE_LUT +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VESA_TO_EXTENDED_MODE asVESA_ToExtendedModeInfo[76]; +}ATOM_VESA_TO_INTENAL_MODE_LUT; + +/*************** ATOM Memory Related Data Structure ***********************/ +typedef struct _ATOM_MEMORY_VENDOR_BLOCK{ + UCHAR ucMemoryType; + UCHAR ucMemoryVendor; + UCHAR ucAdjMCId; + UCHAR ucDynClkId; + ULONG ulDllResetClkRange; +}ATOM_MEMORY_VENDOR_BLOCK; + + +typedef struct _ATOM_MEMORY_SETTING_ID_CONFIG{ +#if ATOM_BIG_ENDIAN + ULONG ucMemBlkId:8; + ULONG ulMemClockRange:24; +#else + ULONG ulMemClockRange:24; + ULONG ucMemBlkId:8; +#endif +}ATOM_MEMORY_SETTING_ID_CONFIG; + +typedef union _ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS +{ + ATOM_MEMORY_SETTING_ID_CONFIG slAccess; + ULONG ulAccess; +}ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS; + + +typedef struct _ATOM_MEMORY_SETTING_DATA_BLOCK{ + ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS ulMemoryID; + ULONG aulMemData[1]; +}ATOM_MEMORY_SETTING_DATA_BLOCK; + + +typedef struct _ATOM_INIT_REG_INDEX_FORMAT{ + USHORT usRegIndex; // MC register index + UCHAR ucPreRegDataLength; // offset in ATOM_INIT_REG_DATA_BLOCK.saRegDataBuf +}ATOM_INIT_REG_INDEX_FORMAT; + + +typedef struct _ATOM_INIT_REG_BLOCK{ + USHORT usRegIndexTblSize; //size of asRegIndexBuf + USHORT usRegDataBlkSize; //size of ATOM_MEMORY_SETTING_DATA_BLOCK + ATOM_INIT_REG_INDEX_FORMAT asRegIndexBuf[1]; + ATOM_MEMORY_SETTING_DATA_BLOCK asRegDataBuf[1]; +}ATOM_INIT_REG_BLOCK; + +#define END_OF_REG_INDEX_BLOCK 0x0ffff +#define END_OF_REG_DATA_BLOCK 0x00000000 +#define ATOM_INIT_REG_MASK_FLAG 0x80 +#define CLOCK_RANGE_HIGHEST 0x00ffffff + +#define VALUE_DWORD SIZEOF ULONG +#define VALUE_SAME_AS_ABOVE 0 +#define VALUE_MASK_DWORD 0x84 + +typedef struct _ATOM_MC_INIT_PARAM_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usAdjustARB_SEQDataOffset; + USHORT usMCInitMemTypeTblOffset; + USHORT usMCInitCommonTblOffset; + USHORT usMCInitPowerDownTblOffset; + ULONG ulARB_SEQDataBuf[32]; + ATOM_INIT_REG_BLOCK asMCInitMemType; + ATOM_INIT_REG_BLOCK asMCInitCommon; +}ATOM_MC_INIT_PARAM_TABLE; + + +#define _4Mx16 0x2 +#define _4Mx32 0x3 +#define _8Mx16 0x12 +#define _8Mx32 0x13 +#define _16Mx16 0x22 +#define _16Mx32 0x23 +#define _32Mx16 0x32 +#define _32Mx32 0x33 +#define _64Mx8 0x41 +#define _64Mx16 0x42 + +#define SAMSUNG 0x1 +#define INFINEON 0x2 +#define ELPIDA 0x3 +#define ETRON 0x4 +#define NANYA 0x5 +#define HYNIX 0x6 +#define MOSEL 0x7 +#define WINBOND 0x8 +#define ESMT 0x9 +#define MICRON 0xF + +#define QIMONDA INFINEON +#define PROMOS MOSEL + +#define ATOM_MAX_NUMBER_OF_VRAM_MODULE 16 + +#define ATOM_VRAM_MODULE_MEMORY_VENDOR_ID_MASK 0xF +typedef struct _ATOM_VRAM_MODULE_V1 +{ + ULONG ulReserved; + USHORT usEMRSValue; + USHORT usMRSValue; + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] reserved; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender + UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucChannelNum; // Number of channel; + UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 + UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; + UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; + UCHAR ucReserved[2]; +}ATOM_VRAM_MODULE_V1; + + +typedef struct _ATOM_VRAM_MODULE_V2 +{ + ULONG ulReserved; + ULONG ulFlags; // To enable/disable functionalities based on memory type + ULONG ulEngineClock; // Override of default engine clock for particular memory type + ULONG ulMemoryClock; // Override of default memory clock for particular memory type + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRSValue; + USHORT usMRSValue; + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed + UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucChannelNum; // Number of channel; + UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 + UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; + UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; + UCHAR ucRefreshRateFactor; + UCHAR ucReserved[3]; +}ATOM_VRAM_MODULE_V2; + + +typedef struct _ATOM_MEMORY_TIMING_FORMAT +{ + ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing + USHORT usMRS; // mode register + USHORT usEMRS; // extended mode register + UCHAR ucCL; // CAS latency + UCHAR ucWL; // WRITE Latency + UCHAR uctRAS; // tRAS + UCHAR uctRC; // tRC + UCHAR uctRFC; // tRFC + UCHAR uctRCDR; // tRCDR + UCHAR uctRCDW; // tRCDW + UCHAR uctRP; // tRP + UCHAR uctRRD; // tRRD + UCHAR uctWR; // tWR + UCHAR uctWTR; // tWTR + UCHAR uctPDIX; // tPDIX + UCHAR uctFAW; // tFAW + UCHAR uctAOND; // tAOND + UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon + UCHAR ucReserved; // +}ATOM_MEMORY_TIMING_FORMAT; + +#define MEM_TIMING_FLAG_APP_MODE 0x01 // =0 mid clock range =1 high clock range + +typedef struct _ATOM_MEMORY_FORMAT +{ + ULONG ulDllDisClock; // memory DLL will be disable when target memory clock is below this clock + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucBurstSize; // burst size, 0= burst size=4 1= burst size=8 + UCHAR ucDllDisBit; // position of DLL Enable/Disable bit in EMRS ( Extended Mode Register ) + UCHAR ucRefreshRateFactor; // memory refresh rate in unit of ms + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucPreamble; //[7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemAttrib; // Memory Device Addribute, like RDBI/WDBI etc + ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; //Memory Timing block sort from lower clock to higher clock +}ATOM_MEMORY_FORMAT; + + +typedef struct _ATOM_VRAM_MODULE_V3 +{ + ULONG ulChannelMapCfg; // board dependent paramenter:Channel combination + USHORT usSize; // size of ATOM_VRAM_MODULE_V3 + USHORT usDefaultMVDDQ; // board dependent parameter:Default Memory Core Voltage + USHORT usDefaultMVDDC; // board dependent parameter:Default Memory IO Voltage + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucChannelNum; // board dependent parameter:Number of channel; + UCHAR ucChannelSize; // board dependent parameter:32bit or 64bit + UCHAR ucVREFI; // board dependnt parameter: EXT or INT +160mv to -140mv + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucFlag; // To enable/disable functionalities based on memory type + ATOM_MEMORY_FORMAT asMemory; // describ all of video memory parameters from memory spec +}ATOM_VRAM_MODULE_V3; + + +//ATOM_VRAM_MODULE_V3.ucNPL_RT +#define NPL_RT_MASK 0x0f +#define BATTERY_ODT_MASK 0xc0 + +#define ATOM_VRAM_MODULE ATOM_VRAM_MODULE_V3 + +typedef struct _ATOM_VRAM_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; +}ATOM_VRAM_INFO_V2; + +typedef struct _ATOM_VRAM_INFO_V3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting + USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting + USHORT usRerseved; + UCHAR aVID_PinsShift[9]; // 8 bit strap maximum+terminator + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; + ATOM_INIT_REG_BLOCK asMemPatch; // for allocation + // ATOM_INIT_REG_BLOCK aMemAdjust; +}ATOM_VRAM_INFO_V3; + +#define ATOM_VRAM_INFO_LAST ATOM_VRAM_INFO_V3 + +typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR aVID_PinsShift[9]; //8 bit strap maximum+terminator +}ATOM_VRAM_GPIO_DETECTION_INFO; + + +typedef struct _ATOM_MEMORY_TRAINING_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTrainingLoop; + UCHAR ucReserved[3]; + ATOM_INIT_REG_BLOCK asMemTrainingSetting; +}ATOM_MEMORY_TRAINING_INFO; + + +typedef struct SW_I2C_CNTL_DATA_PARAMETERS +{ + UCHAR ucControl; + UCHAR ucData; + UCHAR ucSatus; + UCHAR ucTemp; +} SW_I2C_CNTL_DATA_PARAMETERS; + +#define SW_I2C_CNTL_DATA_PS_ALLOCATION SW_I2C_CNTL_DATA_PARAMETERS + +typedef struct _SW_I2C_IO_DATA_PARAMETERS +{ + USHORT GPIO_Info; + UCHAR ucAct; + UCHAR ucData; + } SW_I2C_IO_DATA_PARAMETERS; + +#define SW_I2C_IO_DATA_PS_ALLOCATION SW_I2C_IO_DATA_PARAMETERS + +/****************************SW I2C CNTL DEFINITIONS**********************/ +#define SW_I2C_IO_RESET 0 +#define SW_I2C_IO_GET 1 +#define SW_I2C_IO_DRIVE 2 +#define SW_I2C_IO_SET 3 +#define SW_I2C_IO_START 4 + +#define SW_I2C_IO_CLOCK 0 +#define SW_I2C_IO_DATA 0x80 + +#define SW_I2C_IO_ZERO 0 +#define SW_I2C_IO_ONE 0x100 + +#define SW_I2C_CNTL_READ 0 +#define SW_I2C_CNTL_WRITE 1 +#define SW_I2C_CNTL_START 2 +#define SW_I2C_CNTL_STOP 3 +#define SW_I2C_CNTL_OPEN 4 +#define SW_I2C_CNTL_CLOSE 5 +#define SW_I2C_CNTL_WRITE1BIT 6 + +//==============================VESA definition Portion=============================== +#define VESA_OEM_PRODUCT_REV '01.00' +#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT 0xBB //refer to VBE spec p.32, no TTY support +#define VESA_MODE_WIN_ATTRIBUTE 7 +#define VESA_WIN_SIZE 64 + +typedef struct _PTR_32_BIT_STRUCTURE +{ + USHORT Offset16; + USHORT Segment16; +} PTR_32_BIT_STRUCTURE; + +typedef union _PTR_32_BIT_UNION +{ + PTR_32_BIT_STRUCTURE SegmentOffset; + ULONG Ptr32_Bit; +} PTR_32_BIT_UNION; + +typedef struct _VBE_1_2_INFO_BLOCK_UPDATABLE +{ + UCHAR VbeSignature[4]; + USHORT VbeVersion; + PTR_32_BIT_UNION OemStringPtr; + UCHAR Capabilities[4]; + PTR_32_BIT_UNION VideoModePtr; + USHORT TotalMemory; +} VBE_1_2_INFO_BLOCK_UPDATABLE; + + +typedef struct _VBE_2_0_INFO_BLOCK_UPDATABLE +{ + VBE_1_2_INFO_BLOCK_UPDATABLE CommonBlock; + USHORT OemSoftRev; + PTR_32_BIT_UNION OemVendorNamePtr; + PTR_32_BIT_UNION OemProductNamePtr; + PTR_32_BIT_UNION OemProductRevPtr; +} VBE_2_0_INFO_BLOCK_UPDATABLE; + +typedef union _VBE_VERSION_UNION +{ + VBE_2_0_INFO_BLOCK_UPDATABLE VBE_2_0_InfoBlock; + VBE_1_2_INFO_BLOCK_UPDATABLE VBE_1_2_InfoBlock; +} VBE_VERSION_UNION; + +typedef struct _VBE_INFO_BLOCK +{ + VBE_VERSION_UNION UpdatableVBE_Info; + UCHAR Reserved[222]; + UCHAR OemData[256]; +} VBE_INFO_BLOCK; + +typedef struct _VBE_FP_INFO +{ + USHORT HSize; + USHORT VSize; + USHORT FPType; + UCHAR RedBPP; + UCHAR GreenBPP; + UCHAR BlueBPP; + UCHAR ReservedBPP; + ULONG RsvdOffScrnMemSize; + ULONG RsvdOffScrnMEmPtr; + UCHAR Reserved[14]; +} VBE_FP_INFO; + +typedef struct _VESA_MODE_INFO_BLOCK +{ +// Mandatory information for all VBE revisions + USHORT ModeAttributes; // dw ? ; mode attributes + UCHAR WinAAttributes; // db ? ; window A attributes + UCHAR WinBAttributes; // db ? ; window B attributes + USHORT WinGranularity; // dw ? ; window granularity + USHORT WinSize; // dw ? ; window size + USHORT WinASegment; // dw ? ; window A start segment + USHORT WinBSegment; // dw ? ; window B start segment + ULONG WinFuncPtr; // dd ? ; real mode pointer to window function + USHORT BytesPerScanLine;// dw ? ; bytes per scan line + +//; Mandatory information for VBE 1.2 and above + USHORT XResolution; // dw ? ; horizontal resolution in pixels or characters + USHORT YResolution; // dw ? ; vertical resolution in pixels or characters + UCHAR XCharSize; // db ? ; character cell width in pixels + UCHAR YCharSize; // db ? ; character cell height in pixels + UCHAR NumberOfPlanes; // db ? ; number of memory planes + UCHAR BitsPerPixel; // db ? ; bits per pixel + UCHAR NumberOfBanks; // db ? ; number of banks + UCHAR MemoryModel; // db ? ; memory model type + UCHAR BankSize; // db ? ; bank size in KB + UCHAR NumberOfImagePages;// db ? ; number of images + UCHAR ReservedForPageFunction;//db 1 ; reserved for page function + +//; Direct Color fields(required for direct/6 and YUV/7 memory models) + UCHAR RedMaskSize; // db ? ; size of direct color red mask in bits + UCHAR RedFieldPosition; // db ? ; bit position of lsb of red mask + UCHAR GreenMaskSize; // db ? ; size of direct color green mask in bits + UCHAR GreenFieldPosition; // db ? ; bit position of lsb of green mask + UCHAR BlueMaskSize; // db ? ; size of direct color blue mask in bits + UCHAR BlueFieldPosition; // db ? ; bit position of lsb of blue mask + UCHAR RsvdMaskSize; // db ? ; size of direct color reserved mask in bits + UCHAR RsvdFieldPosition; // db ? ; bit position of lsb of reserved mask + UCHAR DirectColorModeInfo;// db ? ; direct color mode attributes + +//; Mandatory information for VBE 2.0 and above + ULONG PhysBasePtr; // dd ? ; physical address for flat memory frame buffer + ULONG Reserved_1; // dd 0 ; reserved - always set to 0 + USHORT Reserved_2; // dw 0 ; reserved - always set to 0 + +//; Mandatory information for VBE 3.0 and above + USHORT LinBytesPerScanLine; // dw ? ; bytes per scan line for linear modes + UCHAR BnkNumberOfImagePages;// db ? ; number of images for banked modes + UCHAR LinNumberOfImagPages; // db ? ; number of images for linear modes + UCHAR LinRedMaskSize; // db ? ; size of direct color red mask(linear modes) + UCHAR LinRedFieldPosition; // db ? ; bit position of lsb of red mask(linear modes) + UCHAR LinGreenMaskSize; // db ? ; size of direct color green mask(linear modes) + UCHAR LinGreenFieldPosition;// db ? ; bit position of lsb of green mask(linear modes) + UCHAR LinBlueMaskSize; // db ? ; size of direct color blue mask(linear modes) + UCHAR LinBlueFieldPosition; // db ? ; bit position of lsb of blue mask(linear modes) + UCHAR LinRsvdMaskSize; // db ? ; size of direct color reserved mask(linear modes) + UCHAR LinRsvdFieldPosition; // db ? ; bit position of lsb of reserved mask(linear modes) + ULONG MaxPixelClock; // dd ? ; maximum pixel clock(in Hz) for graphics mode + UCHAR Reserved; // db 190 dup (0) +} VESA_MODE_INFO_BLOCK; + +// BIOS function CALLS +#define ATOM_BIOS_EXTENDED_FUNCTION_CODE 0xA0 // ATI Extended Function code +#define ATOM_BIOS_FUNCTION_COP_MODE 0x00 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY1 0x04 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY2 0x05 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY3 0x06 +#define ATOM_BIOS_FUNCTION_GET_DDC 0x0B +#define ATOM_BIOS_FUNCTION_ASIC_DSTATE 0x0E +#define ATOM_BIOS_FUNCTION_DEBUG_PLAY 0x0F +#define ATOM_BIOS_FUNCTION_STV_STD 0x16 +#define ATOM_BIOS_FUNCTION_DEVICE_DET 0x17 +#define ATOM_BIOS_FUNCTION_DEVICE_SWITCH 0x18 + +#define ATOM_BIOS_FUNCTION_PANEL_CONTROL 0x82 +#define ATOM_BIOS_FUNCTION_OLD_DEVICE_DET 0x83 +#define ATOM_BIOS_FUNCTION_OLD_DEVICE_SWITCH 0x84 +#define ATOM_BIOS_FUNCTION_HW_ICON 0x8A +#define ATOM_BIOS_FUNCTION_SET_CMOS 0x8B +#define SUB_FUNCTION_UPDATE_DISPLAY_INFO 0x8000 // Sub function 80 +#define SUB_FUNCTION_UPDATE_EXPANSION_INFO 0x8100 // Sub function 80 + +#define ATOM_BIOS_FUNCTION_DISPLAY_INFO 0x8D +#define ATOM_BIOS_FUNCTION_DEVICE_ON_OFF 0x8E +#define ATOM_BIOS_FUNCTION_VIDEO_STATE 0x8F +#define ATOM_SUB_FUNCTION_GET_CRITICAL_STATE 0x0300 // Sub function 03 +#define ATOM_SUB_FUNCTION_GET_LIDSTATE 0x0700 // Sub function 7 +#define ATOM_SUB_FUNCTION_THERMAL_STATE_NOTICE 0x1400 // Notify caller the current thermal state +#define ATOM_SUB_FUNCTION_CRITICAL_STATE_NOTICE 0x8300 // Notify caller the current critical state +#define ATOM_SUB_FUNCTION_SET_LIDSTATE 0x8500 // Sub function 85 +#define ATOM_SUB_FUNCTION_GET_REQ_DISPLAY_FROM_SBIOS_MODE 0x8900// Sub function 89 +#define ATOM_SUB_FUNCTION_INFORM_ADC_SUPPORT 0x9400 // Notify caller that ADC is supported + + +#define ATOM_BIOS_FUNCTION_VESA_DPMS 0x4F10 // Set DPMS +#define ATOM_SUB_FUNCTION_SET_DPMS 0x0001 // BL: Sub function 01 +#define ATOM_SUB_FUNCTION_GET_DPMS 0x0002 // BL: Sub function 02 +#define ATOM_PARAMETER_VESA_DPMS_ON 0x0000 // BH Parameter for DPMS ON. +#define ATOM_PARAMETER_VESA_DPMS_STANDBY 0x0100 // BH Parameter for DPMS STANDBY +#define ATOM_PARAMETER_VESA_DPMS_SUSPEND 0x0200 // BH Parameter for DPMS SUSPEND +#define ATOM_PARAMETER_VESA_DPMS_OFF 0x0400 // BH Parameter for DPMS OFF +#define ATOM_PARAMETER_VESA_DPMS_REDUCE_ON 0x0800 // BH Parameter for DPMS REDUCE ON (NOT SUPPORTED) + +#define ATOM_BIOS_RETURN_CODE_MASK 0x0000FF00L +#define ATOM_BIOS_REG_HIGH_MASK 0x0000FF00L +#define ATOM_BIOS_REG_LOW_MASK 0x000000FFL + +// structure used for VBIOS only + +//DispOutInfoTable +typedef struct _ASIC_TRANSMITTER_INFO +{ + USHORT usTransmitterObjId; + USHORT usSupportDevice; + UCHAR ucTransmitterCmdTblId; + UCHAR ucConfig; + UCHAR ucEncoderID; //available 1st encoder ( default ) + UCHAR ucOptionEncoderID; //available 2nd encoder ( optional ) + UCHAR uc2ndEncoderID; + UCHAR ucReserved; +}ASIC_TRANSMITTER_INFO; + +typedef struct _ASIC_ENCODER_INFO +{ + UCHAR ucEncoderID; + UCHAR ucEncoderConfig; + USHORT usEncoderCmdTblId; +}ASIC_ENCODER_INFO; + +typedef struct _ATOM_DISP_OUT_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT ptrTransmitterInfo; + USHORT ptrEncoderInfo; + ASIC_TRANSMITTER_INFO asTransmitterInfo[1]; + ASIC_ENCODER_INFO asEncoderInfo[1]; +}ATOM_DISP_OUT_INFO; + +// DispDevicePriorityInfo +typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT asDevicePriority[16]; +}ATOM_DISPLAY_DEVICE_PRIORITY_INFO; + +//ProcessAuxChannelTransactionTable +typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS +{ + USHORT lpAuxRequest; + USHORT lpDataOut; + UCHAR ucChannelID; + union + { + UCHAR ucReplyStatus; + UCHAR ucDelay; + }; + UCHAR ucDataOutLen; + UCHAR ucReserved; +}PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS; + +#define PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS + +//GetSinkType + +typedef struct _DP_ENCODER_SERVICE_PARAMETERS +{ + USHORT ucLinkClock; + union + { + UCHAR ucConfig; // for DP training command + UCHAR ucI2cId; // use for GET_SINK_TYPE command + }; + UCHAR ucAction; + UCHAR ucStatus; + UCHAR ucLaneNum; + UCHAR ucReserved[2]; +}DP_ENCODER_SERVICE_PARAMETERS; + +// ucAction +#define ATOM_DP_ACTION_GET_SINK_TYPE 0x01 +#define ATOM_DP_ACTION_TRAINING_START 0x02 +#define ATOM_DP_ACTION_TRAINING_COMPLETE 0x03 +#define ATOM_DP_ACTION_TRAINING_PATTERN_SEL 0x04 +#define ATOM_DP_ACTION_SET_VSWING_PREEMP 0x05 +#define ATOM_DP_ACTION_GET_VSWING_PREEMP 0x06 + +// ucConfig +#define ATOM_DP_CONFIG_ENCODER_SEL_MASK 0x03 +#define ATOM_DP_CONFIG_DIG1_ENCODER 0x00 +#define ATOM_DP_CONFIG_DIG2_ENCODER 0x01 +#define ATOM_DP_CONFIG_EXTERNAL_ENCODER 0x02 +#define ATOM_DP_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_DP_CONFIG_LINK_A 0x00 +#define ATOM_DP_CONFIG_LINK_B 0x04 + +#define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +// DP_TRAINING_TABLE +#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR +#define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 ) +#define DPCD_SET_LANE_VSWING_PREEMP_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 16 ) +#define DPCD_SET_TRAINING_PATTERN0_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 24 ) +#define DPCD_SET_TRAINING_PATTERN2_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 32) +#define DPCD_GET_LINKRATE_LANENUM_SS_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 40) +#define DPCD_GET_LANE_STATUS_ADJUST_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 48) +#define DP_I2C_AUX_DDC_WRITE_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 60) +#define DP_I2C_AUX_DDC_WRITE_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 64) +#define DP_I2C_AUX_DDC_READ_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 72) +#define DP_I2C_AUX_DDC_READ_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 76) +#define DP_I2C_AUX_DDC_READ_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 80) + + +typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS +{ + UCHAR ucI2CSpeed; + union + { + UCHAR ucRegIndex; + UCHAR ucStatus; + }; + USHORT lpI2CDataOut; + UCHAR ucFlag; + UCHAR ucTransBytes; + UCHAR ucSlaveAddr; + UCHAR ucLineNumber; +}PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS; + +#define PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS + +//ucFlag +#define HW_I2C_WRITE 1 +#define HW_I2C_READ 0 + + +/****************************************************************************/ +//Portion VI: Definitinos being oboselete +/****************************************************************************/ + +//========================================================================================== +//Remove the definitions below when driver is ready! +typedef struct _ATOM_DAC_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMaxFrequency; // in 10kHz unit + USHORT usReserved; +}ATOM_DAC_INFO; + + +typedef struct _COMPASSIONATE_DATA +{ + ATOM_COMMON_TABLE_HEADER sHeader; + + //============================== DAC1 portion + UCHAR ucDAC1_BG_Adjustment; + UCHAR ucDAC1_DAC_Adjustment; + USHORT usDAC1_FORCE_Data; + //============================== DAC2 portion + UCHAR ucDAC2_CRT2_BG_Adjustment; + UCHAR ucDAC2_CRT2_DAC_Adjustment; + USHORT usDAC2_CRT2_FORCE_Data; + USHORT usDAC2_CRT2_MUX_RegisterIndex; + UCHAR ucDAC2_CRT2_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_NTSC_BG_Adjustment; + UCHAR ucDAC2_NTSC_DAC_Adjustment; + USHORT usDAC2_TV1_FORCE_Data; + USHORT usDAC2_TV1_MUX_RegisterIndex; + UCHAR ucDAC2_TV1_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_CV_BG_Adjustment; + UCHAR ucDAC2_CV_DAC_Adjustment; + USHORT usDAC2_CV_FORCE_Data; + USHORT usDAC2_CV_MUX_RegisterIndex; + UCHAR ucDAC2_CV_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_PAL_BG_Adjustment; + UCHAR ucDAC2_PAL_DAC_Adjustment; + USHORT usDAC2_TV2_FORCE_Data; +}COMPASSIONATE_DATA; + +/****************************Supported Device Info Table Definitions**********************/ +// ucConnectInfo: +// [7:4] - connector type +// = 1 - VGA connector +// = 2 - DVI-I +// = 3 - DVI-D +// = 4 - DVI-A +// = 5 - SVIDEO +// = 6 - COMPOSITE +// = 7 - LVDS +// = 8 - DIGITAL LINK +// = 9 - SCART +// = 0xA - HDMI_type A +// = 0xB - HDMI_type B +// = 0xE - Special case1 (DVI+DIN) +// Others=TBD +// [3:0] - DAC Associated +// = 0 - no DAC +// = 1 - DACA +// = 2 - DACB +// = 3 - External DAC +// Others=TBD +// + +typedef struct _ATOM_CONNECTOR_INFO +{ +#if ATOM_BIG_ENDIAN + UCHAR bfConnectorType:4; + UCHAR bfAssociatedDAC:4; +#else + UCHAR bfAssociatedDAC:4; + UCHAR bfConnectorType:4; +#endif +}ATOM_CONNECTOR_INFO; + +typedef union _ATOM_CONNECTOR_INFO_ACCESS +{ + ATOM_CONNECTOR_INFO sbfAccess; + UCHAR ucAccess; +}ATOM_CONNECTOR_INFO_ACCESS; + +typedef struct _ATOM_CONNECTOR_INFO_I2C +{ + ATOM_CONNECTOR_INFO_ACCESS sucConnectorInfo; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; +}ATOM_CONNECTOR_INFO_I2C; + + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO]; +}ATOM_SUPPORTED_DEVICES_INFO; + +#define NO_INT_SRC_MAPPED 0xFF + +typedef struct _ATOM_CONNECTOR_INC_SRC_BITMAP +{ + UCHAR ucIntSrcBitmap; +}ATOM_CONNECTOR_INC_SRC_BITMAP; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2]; + ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2]; +}ATOM_SUPPORTED_DEVICES_INFO_2; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE]; + ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE]; +}ATOM_SUPPORTED_DEVICES_INFO_2d1; + +#define ATOM_SUPPORTED_DEVICES_INFO_LAST ATOM_SUPPORTED_DEVICES_INFO_2d1 + + + +typedef struct _ATOM_MISC_CONTROL_INFO +{ + USHORT usFrequency; + UCHAR ucPLL_ChargePump; // PLL charge-pump gain control + UCHAR ucPLL_DutyCycle; // PLL duty cycle control + UCHAR ucPLL_VCO_Gain; // PLL VCO gain control + UCHAR ucPLL_VoltageSwing; // PLL driver voltage swing control +}ATOM_MISC_CONTROL_INFO; + + +#define ATOM_MAX_MISC_INFO 4 + +typedef struct _ATOM_TMDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMaxFrequency; // in 10Khz + ATOM_MISC_CONTROL_INFO asMiscInfo[ATOM_MAX_MISC_INFO]; +}ATOM_TMDS_INFO; + + +typedef struct _ATOM_ENCODER_ANALOG_ATTRIBUTE +{ + UCHAR ucTVStandard; //Same as TV standards defined above, + UCHAR ucPadding[1]; +}ATOM_ENCODER_ANALOG_ATTRIBUTE; + +typedef struct _ATOM_ENCODER_DIGITAL_ATTRIBUTE +{ + UCHAR ucAttribute; //Same as other digital encoder attributes defined above + UCHAR ucPadding[1]; +}ATOM_ENCODER_DIGITAL_ATTRIBUTE; + +typedef union _ATOM_ENCODER_ATTRIBUTE +{ + ATOM_ENCODER_ANALOG_ATTRIBUTE sAlgAttrib; + ATOM_ENCODER_DIGITAL_ATTRIBUTE sDigAttrib; +}ATOM_ENCODER_ATTRIBUTE; + + +typedef struct _DVO_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; + USHORT usEncoderID; + UCHAR ucDeviceType; //Use ATOM_DEVICE_xxx1_Index to indicate device type only. + UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT + ATOM_ENCODER_ATTRIBUTE usDevAttr; +}DVO_ENCODER_CONTROL_PARAMETERS; + +typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION +{ + DVO_ENCODER_CONTROL_PARAMETERS sDVOEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}DVO_ENCODER_CONTROL_PS_ALLOCATION; + + +#define ATOM_XTMDS_ASIC_SI164_ID 1 +#define ATOM_XTMDS_ASIC_SI178_ID 2 +#define ATOM_XTMDS_ASIC_TFP513_ID 3 +#define ATOM_XTMDS_SUPPORTED_SINGLELINK 0x00000001 +#define ATOM_XTMDS_SUPPORTED_DUALLINK 0x00000002 +#define ATOM_XTMDS_MVPU_FPGA 0x00000004 + + +typedef struct _ATOM_XTMDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usSingleLinkMaxFrequency; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //Point the ID on which I2C is used to control external chip + UCHAR ucXtransimitterID; + UCHAR ucSupportedLink; // Bit field, bit0=1, single link supported;bit1=1,dual link supported + UCHAR ucSequnceAlterID; // Even with the same external TMDS asic, it's possible that the program seqence alters + // due to design. This ID is used to alert driver that the sequence is not "standard"! + UCHAR ucMasterAddress; // Address to control Master xTMDS Chip + UCHAR ucSlaveAddress; // Address to control Slave xTMDS Chip +}ATOM_XTMDS_INFO; + +typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE=On or ATOM_DISABLE=Off + UCHAR ucDevice; // ATOM_DEVICE_DFP1_INDEX.... + UCHAR ucPadding[2]; +}DFP_DPMS_STATUS_CHANGE_PARAMETERS; + +/****************************Legacy Power Play Table Definitions **********************/ + +//Definitions for ulPowerPlayMiscInfo +#define ATOM_PM_MISCINFO_SPLIT_CLOCK 0x00000000L +#define ATOM_PM_MISCINFO_USING_MCLK_SRC 0x00000001L +#define ATOM_PM_MISCINFO_USING_SCLK_SRC 0x00000002L + +#define ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT 0x00000004L +#define ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH 0x00000008L + +#define ATOM_PM_MISCINFO_LOAD_PERFORMANCE_EN 0x00000010L + +#define ATOM_PM_MISCINFO_ENGINE_CLOCK_CONTRL_EN 0x00000020L +#define ATOM_PM_MISCINFO_MEMORY_CLOCK_CONTRL_EN 0x00000040L +#define ATOM_PM_MISCINFO_PROGRAM_VOLTAGE 0x00000080L //When this bit set, ucVoltageDropIndex is not an index for GPIO pin, but a voltage ID that SW needs program + +#define ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN 0x00000100L +#define ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN 0x00000200L +#define ATOM_PM_MISCINFO_ASIC_SLEEP_MODE_EN 0x00000400L +#define ATOM_PM_MISCINFO_LOAD_BALANCE_EN 0x00000800L +#define ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE 0x00001000L +#define ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE 0x00002000L +#define ATOM_PM_MISCINFO_LOW_LCD_REFRESH_RATE 0x00004000L + +#define ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE 0x00008000L +#define ATOM_PM_MISCINFO_OVER_CLOCK_MODE 0x00010000L +#define ATOM_PM_MISCINFO_OVER_DRIVE_MODE 0x00020000L +#define ATOM_PM_MISCINFO_POWER_SAVING_MODE 0x00040000L +#define ATOM_PM_MISCINFO_THERMAL_DIODE_MODE 0x00080000L + +#define ATOM_PM_MISCINFO_FRAME_MODULATION_MASK 0x00300000L //0-FM Disable, 1-2 level FM, 2-4 level FM, 3-Reserved +#define ATOM_PM_MISCINFO_FRAME_MODULATION_SHIFT 20 + +#define ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE 0x00400000L +#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2 0x00800000L +#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4 0x01000000L +#define ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN 0x02000000L //When set, Dynamic +#define ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN 0x04000000L //When set, Dynamic +#define ATOM_PM_MISCINFO_3D_ACCELERATION_EN 0x08000000L //When set, This mode is for acceleated 3D mode + +#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_MASK 0x70000000L //1-Optimal Battery Life Group, 2-High Battery, 3-Balanced, 4-High Performance, 5- Optimal Performance (Default state with Default clocks) +#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_SHIFT 28 +#define ATOM_PM_MISCINFO_ENABLE_BACK_BIAS 0x80000000L + +#define ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE 0x00000001L +#define ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT 0x00000002L +#define ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN 0x00000004L +#define ATOM_PM_MISCINFO2_FS3D_OVERDRIVE_INFO 0x00000008L +#define ATOM_PM_MISCINFO2_FORCEDLOWPWR_MODE 0x00000010L +#define ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN 0x00000020L +#define ATOM_PM_MISCINFO2_VIDEO_PLAYBACK_CAPABLE 0x00000040L //If this bit is set in multi-pp mode, then driver will pack up one with the minior power consumption. + //If it's not set in any pp mode, driver will use its default logic to pick a pp mode in video playback +#define ATOM_PM_MISCINFO2_NOT_VALID_ON_DC 0x00000080L +#define ATOM_PM_MISCINFO2_STUTTER_MODE_EN 0x00000100L +#define ATOM_PM_MISCINFO2_UVD_SUPPORT_MODE 0x00000200L + +//ucTableFormatRevision=1 +//ucTableContentRevision=1 +typedef struct _ATOM_POWERMODE_INFO +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulReserved1; // must set to 0 + ULONG ulReserved2; // must set to 0 + USHORT usEngineClock; + USHORT usMemoryClock; + UCHAR ucVoltageDropIndex; // index to GPIO table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes +}ATOM_POWERMODE_INFO; + +//ucTableFormatRevision=2 +//ucTableContentRevision=1 +typedef struct _ATOM_POWERMODE_INFO_V2 +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulMiscInfo2; + ULONG ulEngineClock; + ULONG ulMemoryClock; + UCHAR ucVoltageDropIndex; // index to GPIO table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes +}ATOM_POWERMODE_INFO_V2; + +//ucTableFormatRevision=2 +//ucTableContentRevision=2 +typedef struct _ATOM_POWERMODE_INFO_V3 +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulMiscInfo2; + ULONG ulEngineClock; + ULONG ulMemoryClock; + UCHAR ucVoltageDropIndex; // index to Core (VDDC) votage table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes + UCHAR ucVDDCI_VoltageDropIndex; // index to VDDCI votage table +}ATOM_POWERMODE_INFO_V3; + + +#define ATOM_MAX_NUMBEROF_POWER_BLOCK 8 + +#define ATOM_PP_OVERDRIVE_INTBITMAP_AUXWIN 0x01 +#define ATOM_PP_OVERDRIVE_INTBITMAP_OVERDRIVE 0x02 + +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM63 0x01 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1032 0x02 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1030 0x03 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_MUA6649 0x04 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM64 0x05 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_F75375 0x06 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ASC7512 0x07 // Andigilog + + +typedef struct _ATOM_POWERPLAY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO; + +typedef struct _ATOM_POWERPLAY_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO_V2 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO_V2; + +typedef struct _ATOM_POWERPLAY_INFO_V3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO_V3; + + + +/**************************************************************************/ + + +// Following definitions are for compatiblity issue in different SW components. +#define ATOM_MASTER_DATA_TABLE_REVISION 0x01 +#define Object_Info Object_Header +#define AdjustARB_SEQ MC_InitParameter +#define VRAM_GPIO_DetectionInfo VoltageObjectInfo +#define ASIC_VDDCI_Info ASIC_ProfilingInfo +#define ASIC_MVDDQ_Info MemoryTrainingInfo +#define SS_Info PPLL_SS_Info +#define ASIC_MVDDC_Info ASIC_InternalSS_Info +#define DispDevicePriorityInfo SaveRestoreInfo +#define DispOutInfo TV_VideoMode + + +#define ATOM_ENCODER_OBJECT_TABLE ATOM_OBJECT_TABLE +#define ATOM_CONNECTOR_OBJECT_TABLE ATOM_OBJECT_TABLE + +//New device naming, remove them when both DAL/VBIOS is ready +#define DFP2I_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS +#define DFP2I_OUTPUT_CONTROL_PS_ALLOCATION DFP2I_OUTPUT_CONTROL_PARAMETERS + +#define DFP1X_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS +#define DFP1X_OUTPUT_CONTROL_PS_ALLOCATION DFP1X_OUTPUT_CONTROL_PARAMETERS + +#define DFP1I_OUTPUT_CONTROL_PARAMETERS DFP1_OUTPUT_CONTROL_PARAMETERS +#define DFP1I_OUTPUT_CONTROL_PS_ALLOCATION DFP1_OUTPUT_CONTROL_PS_ALLOCATION + +#define ATOM_DEVICE_DFP1I_SUPPORT ATOM_DEVICE_DFP1_SUPPORT +#define ATOM_DEVICE_DFP1X_SUPPORT ATOM_DEVICE_DFP2_SUPPORT + +#define ATOM_DEVICE_DFP1I_INDEX ATOM_DEVICE_DFP1_INDEX +#define ATOM_DEVICE_DFP1X_INDEX ATOM_DEVICE_DFP2_INDEX + +#define ATOM_DEVICE_DFP2I_INDEX 0x00000009 +#define ATOM_DEVICE_DFP2I_SUPPORT (0x1L << ATOM_DEVICE_DFP2I_INDEX) + +#define ATOM_S0_DFP1I ATOM_S0_DFP1 +#define ATOM_S0_DFP1X ATOM_S0_DFP2 + +#define ATOM_S0_DFP2I 0x00200000L +#define ATOM_S0_DFP2Ib2 0x20 + +#define ATOM_S2_DFP1I_DPMS_STATE ATOM_S2_DFP1_DPMS_STATE +#define ATOM_S2_DFP1X_DPMS_STATE ATOM_S2_DFP2_DPMS_STATE + +#define ATOM_S2_DFP2I_DPMS_STATE 0x02000000L +#define ATOM_S2_DFP2I_DPMS_STATEb3 0x02 + +#define ATOM_S3_DFP2I_ACTIVEb1 0x02 + +#define ATOM_S3_DFP1I_ACTIVE ATOM_S3_DFP1_ACTIVE +#define ATOM_S3_DFP1X_ACTIVE ATOM_S3_DFP2_ACTIVE + +#define ATOM_S3_DFP2I_ACTIVE 0x00000200L + +#define ATOM_S3_DFP1I_CRTC_ACTIVE ATOM_S3_DFP1_CRTC_ACTIVE +#define ATOM_S3_DFP1X_CRTC_ACTIVE ATOM_S3_DFP2_CRTC_ACTIVE +#define ATOM_S3_DFP2I_CRTC_ACTIVE 0x02000000L + +#define ATOM_S3_DFP2I_CRTC_ACTIVEb3 0x02 +#define ATOM_S5_DOS_REQ_DFP2Ib1 0x02 + +#define ATOM_S5_DOS_REQ_DFP2I 0x0200 +#define ATOM_S6_ACC_REQ_DFP1I ATOM_S6_ACC_REQ_DFP1 +#define ATOM_S6_ACC_REQ_DFP1X ATOM_S6_ACC_REQ_DFP2 + +#define ATOM_S6_ACC_REQ_DFP2Ib3 0x02 +#define ATOM_S6_ACC_REQ_DFP2I 0x02000000L + +#define TMDS1XEncoderControl DVOEncoderControl +#define DFP1XOutputControl DVOOutputControl + +#define ExternalDFPOutputControl DFP1XOutputControl +#define EnableExternalTMDS_Encoder TMDS1XEncoderControl + +#define DFP1IOutputControl TMDSAOutputControl +#define DFP2IOutputControl LVTMAOutputControl + +#define DAC1_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS +#define DAC1_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION + +#define DAC2_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS +#define DAC2_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION + +#define ucDac1Standard ucDacStandard +#define ucDac2Standard ucDacStandard + +#define TMDS1EncoderControl TMDSAEncoderControl +#define TMDS2EncoderControl LVTMAEncoderControl + +#define DFP1OutputControl TMDSAOutputControl +#define DFP2OutputControl LVTMAOutputControl +#define CRT1OutputControl DAC1OutputControl +#define CRT2OutputControl DAC2OutputControl + +//These two lines will be removed for sure in a few days, will follow up with Michael V. +#define EnableLVDS_SS EnableSpreadSpectrumOnPPLL +#define ENABLE_LVDS_SS_PARAMETERS_V3 ENABLE_SPREAD_SPECTRUM_ON_PPLL + +/*********************************************************************************/ +#define ATOM_S3_SCALER2_ACTIVE_H 0x00004000L +#define ATOM_S3_SCALER2_ACTIVE_V 0x00008000L +#define ATOM_S6_REQ_SCALER2_H 0x00004000L +#define ATOM_S6_REQ_SCALER2_V 0x00008000L + +#define ATOM_S3_SCALER1_ACTIVE_H ATOM_S3_LCD_FULLEXPANSION_ACTIVE +#define ATOM_S3_SCALER1_ACTIVE_V ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE + +#define ATOM_S6_REQ_SCALER1_H ATOM_S6_REQ_LCD_EXPANSION_FULL +#define ATOM_S6_REQ_SCALER1_V ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO +//========================================================================================== + +#pragma pack() // BIOS data must use byte aligment + +#endif /* _ATOMBIOS_H */ diff --git a/linux-core/atombios_crtc.c b/linux-core/atombios_crtc.c new file mode 100644 index 00000000..1f372045 --- /dev/null +++ b/linux-core/atombios_crtc.c @@ -0,0 +1,382 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#include "drm_crtc_helper.h" +#include "atom.h" +#include "atom-bits.h" + +static void atombios_enable_crtc(struct drm_crtc *crtc, int state) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); + ENABLE_CRTC_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + + args.ucCRTC = radeon_crtc->crtc_id; + args.ucEnable = state; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); + ENABLE_CRTC_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + + args.ucCRTC = radeon_crtc->crtc_id; + args.ucEnable = state; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void atombios_blank_crtc(struct drm_crtc *crtc, int state) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); + BLANK_CRTC_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + + args.ucCRTC = radeon_crtc->crtc_id; + args.ucBlanking = state; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch(mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + if (radeon_is_dce3(dev_priv)) + atombios_enable_crtc_memreq(crtc, 1); + atombios_enable_crtc(crtc, 1); + atombios_blank_crtc(crtc, 0); + + radeon_crtc_load_lut(crtc); + break; + case DRM_MODE_DPMS_OFF: + atombios_blank_crtc(crtc, 1); + atombios_enable_crtc(crtc, 0); + if (radeon_is_dce3(dev_priv)) + atombios_enable_crtc_memreq(crtc, 0); + break; + } +} + + +void atombios_crtc_set_timing(struct drm_crtc *crtc, SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_param) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION conv_param; + int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); + + conv_param.usH_Total = cpu_to_le16(crtc_param->usH_Total); + conv_param.usH_Disp = cpu_to_le16(crtc_param->usH_Disp); + conv_param.usH_SyncStart = cpu_to_le16(crtc_param->usH_SyncStart); + conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth); + conv_param.usV_Total = cpu_to_le16(crtc_param->usV_Total); + conv_param.usV_Disp = cpu_to_le16(crtc_param->usV_Disp); + conv_param.usV_SyncStart = cpu_to_le16(crtc_param->usV_SyncStart); + conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth); + conv_param.susModeMiscInfo.usAccess = cpu_to_le16(crtc_param->susModeMiscInfo.usAccess); + conv_param.ucCRTC = crtc_param->ucCRTC; + conv_param.ucOverscanRight = crtc_param->ucOverscanRight; + conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft; + conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom; + conv_param.ucOverscanTop = crtc_param->ucOverscanTop; + conv_param.ucReserved = crtc_param->ucReserved; + + printk("executing set crtc timing\n"); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&conv_param); +} + +void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, + int pll_flags) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint8_t frev, crev; + int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); + SET_PIXEL_CLOCK_PS_ALLOCATION spc_param; + PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr; + PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr; + uint32_t sclock = mode->clock; + uint32_t ref_div = 0, fb_div = 0, post_div = 0; + + memset(&spc_param, 0, sizeof(SET_PIXEL_CLOCK_PS_ALLOCATION)); + + if (radeon_is_avivo(dev_priv)) { + uint32_t temp; + + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + + radeon_compute_pll(&dev_priv->mode_info.pll, mode->clock, + &temp, &fb_div, &ref_div, &post_div, pll_flags); + sclock = temp; + + if (radeon_crtc->crtc_id == 0) { + temp = RADEON_READ(AVIVO_P1PLL_INT_SS_CNTL); + RADEON_WRITE(AVIVO_P1PLL_INT_SS_CNTL, temp & ~1); + } else { + temp = RADEON_READ(AVIVO_P2PLL_INT_SS_CNTL); + RADEON_WRITE(AVIVO_P2PLL_INT_SS_CNTL, temp & ~1); + } + } else { +#if 0 // TODO r400 + sclock = save->dot_clock_freq; + fb_div = save->feedback_div; + post_div = save->post_div; + ref_div = save->ppll_ref_div; +#endif + } + + /* */ + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + switch(frev) { + case 1: + switch(crev) { + case 1: + case 2: + spc2_ptr = (PIXEL_CLOCK_PARAMETERS_V2*)&spc_param.sPCLKInput; + spc2_ptr->usPixelClock = cpu_to_le16(sclock); + spc2_ptr->usRefDiv = cpu_to_le16(ref_div); + spc2_ptr->usFbDiv = cpu_to_le16(fb_div); + spc2_ptr->ucPostDiv = post_div; + spc2_ptr->ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; + spc2_ptr->ucCRTC = radeon_crtc->crtc_id; + spc2_ptr->ucRefDivSrc = 1; + break; + case 3: + spc3_ptr = (PIXEL_CLOCK_PARAMETERS_V3*)&spc_param.sPCLKInput; + spc3_ptr->usPixelClock = cpu_to_le16(sclock); + spc3_ptr->usRefDiv = cpu_to_le16(ref_div); + spc3_ptr->usFbDiv = cpu_to_le16(fb_div); + spc3_ptr->ucPostDiv = post_div; + spc3_ptr->ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; + spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2); + + /* TODO insert output encoder object stuff herre for r600 */ + 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; + } + + printk("executing set pll\n"); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&spc_param); +} + +void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_framebuffer *radeon_fb; + struct drm_radeon_gem_object *obj_priv; + uint32_t fb_location, fb_format, fb_pitch_pixels; + + if (!crtc->fb) + return; + + radeon_fb = to_radeon_framebuffer(crtc->fb); + + obj_priv = radeon_fb->obj->driver_private; + + fb_location = obj_priv->bo->offset + dev_priv->fb_location; + + switch(crtc->fb->bits_per_pixel) { + case 15: + fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; + break; + case 16: + fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP | AVIVO_D1GRPH_CONTROL_16BPP_RGB565; + break; + case 24: + case 32: + fb_format = AVIVO_D1GRPH_CONTROL_DEPTH_32BPP | AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; + break; + default: + DRM_ERROR("Unsupported screen depth %d\n", crtc->fb->bits_per_pixel); + return; + } + + /* TODO tiling */ + if (radeon_crtc->crtc_id == 0) + RADEON_WRITE(AVIVO_D1VGA_CONTROL, 0); + else + RADEON_WRITE(AVIVO_D2VGA_CONTROL, 0); + + RADEON_WRITE(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, AVIVO_D1GRPH_UPDATE_LOCK); + + RADEON_WRITE(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, fb_location); + RADEON_WRITE(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, fb_location); + RADEON_WRITE(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); + + RADEON_WRITE(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); + RADEON_WRITE(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); + RADEON_WRITE(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, x); + RADEON_WRITE(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, y); + RADEON_WRITE(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, x + crtc->mode.hdisplay); + RADEON_WRITE(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, y + crtc->mode.vdisplay); + + fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); + RADEON_WRITE(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); + RADEON_WRITE(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); + + /* unlock the grph regs */ + RADEON_WRITE(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, 0); + + /* lock the mode regs */ + RADEON_WRITE(AVIVO_D1SCL_UPDATE + radeon_crtc->crtc_offset, AVIVO_D1SCL_UPDATE_LOCK); + + RADEON_WRITE(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, + crtc->mode.vdisplay); + RADEON_WRITE(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, (x << 16) | y); + RADEON_WRITE(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, + (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); + /* unlock the mode regs */ + RADEON_WRITE(AVIVO_D1SCL_UPDATE + radeon_crtc->crtc_offset, 0); +} + +void atombios_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder; + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; + int pll_flags = 0; + /* TODO color tiling */ + + memset(&crtc_timing, 0, sizeof(crtc_timing)); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + + + } + + crtc_timing.ucCRTC = radeon_crtc->crtc_id; + crtc_timing.usH_Total = adjusted_mode->crtc_htotal; + crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay; + crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start; + crtc_timing.usH_SyncWidth = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + + crtc_timing.usV_Total = adjusted_mode->crtc_vtotal; + crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay; + crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start; + crtc_timing.usV_SyncWidth = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; + + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; + + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; + + if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC; + + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE; + + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; + + if (radeon_is_avivo(dev_priv)) { + atombios_crtc_set_base(crtc, x, y); + } + + atombios_crtc_set_pll(crtc, adjusted_mode, pll_flags); + + atombios_crtc_set_timing(crtc, &crtc_timing); +} + +static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + + +static void atombios_crtc_prepare(struct drm_crtc *crtc) +{ + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void atombios_crtc_commit(struct drm_crtc *crtc) +{ + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); +} + +static const struct drm_crtc_helper_funcs atombios_helper_funcs = { + .dpms = atombios_crtc_dpms, + .mode_fixup = atombios_crtc_mode_fixup, + .mode_set = atombios_crtc_mode_set, + .mode_set_base = atombios_crtc_set_base, + .prepare = atombios_crtc_prepare, + .commit = atombios_crtc_commit, +}; + +void radeon_atombios_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc) +{ + if (radeon_crtc->crtc_id == 1) + radeon_crtc->crtc_offset = AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; + drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs); +} diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 708b4fa0..e3a08e79 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1046,8 +1046,7 @@ struct drm_agp_ttm_backend { int populated; }; #endif - -typedef struct ati_pcigart_ttm_backend { +struct ati_pcigart_ttm_backend { struct drm_ttm_backend backend; int populated; void (*gart_flush_fn)(struct drm_device *dev); @@ -1057,7 +1056,8 @@ typedef struct ati_pcigart_ttm_backend { int num_pages; int bound; struct drm_device *dev; -} ati_pcigart_ttm_backend_t; +}; +extern struct drm_ttm_backend *ati_pcigart_init_ttm(struct drm_device *dev, struct drm_ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev)); static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) @@ -1396,6 +1396,8 @@ extern int drm_sg_free(struct drm_device *dev, void *data, /* ATI PCIGART support (ati_pcigart.h) */ extern int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); extern int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); +extern int drm_ati_alloc_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info); extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align, dma_addr_t maxaddr); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 2e0d1243..0021530b 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -51,7 +51,6 @@ static void drm_bo_destroy_locked(struct drm_buffer_object *bo); static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo); -static void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo); static void drm_bo_unmap_virtual(struct drm_buffer_object *bo); static inline uint64_t drm_bo_type_flags(unsigned type) @@ -458,6 +457,7 @@ static void drm_bo_destroy_locked(struct drm_buffer_object *bo) DRM_ASSERT_LOCKED(&dev->struct_mutex); + DRM_DEBUG("freeing %p\n", bo); if (list_empty(&bo->lru) && bo->mem.mm_node == NULL && list_empty(&bo->pinned_lru) && bo->pinned_node == NULL && list_empty(&bo->ddestroy) && atomic_read(&bo->usage) == 0) { @@ -1838,8 +1838,8 @@ out_err_unlocked: EXPORT_SYMBOL(drm_buffer_object_create); -static int drm_bo_add_user_object(struct drm_file *file_priv, - struct drm_buffer_object *bo, int shareable) +int drm_bo_add_user_object(struct drm_file *file_priv, + struct drm_buffer_object *bo, int shareable) { struct drm_device *dev = file_priv->minor->dev; int ret; @@ -1858,6 +1858,7 @@ out: mutex_unlock(&dev->struct_mutex); return ret; } +EXPORT_SYMBOL(drm_bo_add_user_object); int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -2705,7 +2706,7 @@ void drm_bo_unmap_virtual(struct drm_buffer_object *bo) * Remove any associated vm mapping on the drm device node that * would have been created for a drm_bo_type_device buffer */ -static void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo) +void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo) { struct drm_map_list *list; drm_local_map_t *map; @@ -2734,6 +2735,7 @@ static void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo) list->user_token = 0ULL; drm_bo_usage_deref_locked(&bo); } +EXPORT_SYMBOL(drm_bo_takedown_vm_locked); /** * drm_bo_setup_vm_locked: diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index dbb31578..aa825f32 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -781,19 +781,17 @@ EXPORT_SYMBOL(pci_get_bus_and_slot); #endif #if defined(DRM_KMAP_ATOMIC_PROT_PFN) -#define drm_kmap_get_fixmap_pte(vaddr) \ - pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr)) - void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t protection) { enum fixed_addresses idx; unsigned long vaddr; static pte_t *km_pte; + int level; static int initialized = 0; if (unlikely(!initialized)) { - km_pte = drm_kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN)); + km_pte = lookup_address(__fix_to_virt(FIX_KMAP_BEGIN), &level); initialized = 1; } diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 7ee33219..8375bf9a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -122,24 +122,31 @@ char *drm_get_subconnector_name(int val) return "unknown"; } +struct drm_conn_prop_enum_list { + int type; + char *name; + int count; +}; + /* * Connector and encoder types. */ -static struct drm_prop_enum_list drm_connector_enum_list[] = -{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, - { DRM_MODE_CONNECTOR_VGA, "VGA" }, - { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, - { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, - { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, - { DRM_MODE_CONNECTOR_Composite, "Composite" }, - { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, - { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { DRM_MODE_CONNECTOR_Component, "Component" }, - { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, - { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, +static struct drm_conn_prop_enum_list drm_connector_enum_list[] = +{ { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 }, + { DRM_MODE_CONNECTOR_VGA, "VGA", 0 }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 }, + { DRM_MODE_CONNECTOR_Composite, "Composite", 0 }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 }, + { DRM_MODE_CONNECTOR_Component, "Component", 0 }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN", 0 }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 }, }; + static struct drm_prop_enum_list drm_encoder_enum_list[] = { { DRM_MODE_ENCODER_NONE, "None" }, { DRM_MODE_ENCODER_DAC, "DAC" }, @@ -226,7 +233,7 @@ static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object * idr_remove(&dev->mode_config.crtc_idr, object->id); } -static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) +void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj; @@ -236,6 +243,7 @@ static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t return obj; } +EXPORT_SYMBOL(drm_mode_object_find); /** * drm_crtc_from_fb - find the CRTC structure associated with an fb @@ -419,7 +427,7 @@ void drm_connector_init(struct drm_device *dev, connector->funcs = funcs; drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR); connector->connector_type = connector_type; - connector->connector_type_id = 1; /* TODO */ + connector->connector_type_id = ++drm_connector_enum_list[connector_type].count; /* TODO */ INIT_LIST_HEAD(&connector->user_modes); INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); @@ -756,6 +764,9 @@ int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) total_objects += dev->mode_config.num_connector; total_objects += dev->mode_config.num_encoder; + if (total_objects == 0) + return -EINVAL; + group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); if (!group->id_list) return -ENOMEM; @@ -771,9 +782,10 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_gro struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; + int ret; - if (drm_mode_group_init(dev, group)) - return -ENOMEM; + if ((ret = drm_mode_group_init(dev, group))) + return ret; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) group->id_list[group->num_crtcs++] = crtc->base.id; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index bfccdeb5..3a3a09aa 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -664,6 +664,7 @@ extern void drm_mode_connector_detach_encoder(struct drm_connector *connector, struct drm_encoder *encoder); extern bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size); +extern void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type); /* IOCTLs */ extern int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 6f16dad6..e0d93606 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -500,7 +500,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; - DRM_DEBUG("crtc: %p fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->connectors, set->num_connectors, set->x, set->y); + DRM_DEBUG("crtc: %p %d fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->crtc->base.id, set->fb, set->connectors, set->num_connectors, set->x, set->y); dev = set->crtc->dev; diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 45a67f98..dcb46f98 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -54,6 +54,8 @@ struct drm_encoder_helper_funcs { void (*mode_set)(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); + /* detect for DAC style encoders */ + enum drm_connector_status (*detect)(struct drm_encoder *encoder, struct drm_connector *connector); }; struct drm_connector_helper_funcs { diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 434155b3..05320376 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -100,7 +100,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) kfree(obj); return NULL; } - kref_init(&obj->refcount); kref_init(&obj->handlecount); obj->size = size; diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index d4cda0be..67f278eb 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -546,6 +546,7 @@ void drm_mode_connector_list_update(struct drm_connector *connector) struct drm_display_mode *mode; struct drm_display_mode *pmode, *pt; int found_it; + list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) { found_it = 0; diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index d0c34ca3..96cfc113 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -680,6 +680,8 @@ extern int drm_bo_pci_offset(struct drm_device *dev, unsigned long *bus_size); extern int drm_mem_reg_is_pci(struct drm_device *dev, struct drm_bo_mem_reg *mem); +extern int drm_bo_add_user_object(struct drm_file *file_priv, + struct drm_buffer_object *bo, int shareable); extern void drm_bo_usage_deref_locked(struct drm_buffer_object **bo); extern void drm_bo_usage_deref_unlocked(struct drm_buffer_object **bo); extern void drm_putback_buffer_objects(struct drm_device *dev); @@ -718,6 +720,8 @@ extern int drm_bo_do_validate(struct drm_buffer_object *bo, uint32_t fence_class, struct drm_bo_info_rep *rep); extern int drm_bo_evict_cached(struct drm_buffer_object *bo); + +extern void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo); /* * Buffer object memory move- and map helpers. * drm_bo_move.c diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index bc056bc3..ce8ac3d9 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -544,14 +544,14 @@ static void intelfb_on(struct fb_info *info) if (crtc->base.id == par->crtc_ids[i]) break; - crtc_funcs->dpms(crtc, DPMSModeOn); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); /* Found a CRTC on this fb, now find encoders */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { struct drm_encoder_helper_funcs *encoder_funcs; encoder_funcs = encoder->helper_private; - encoder_funcs->dpms(encoder, DPMSModeOn); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } } } @@ -584,7 +584,7 @@ static void intelfb_off(struct fb_info *info, int dpms_mode) encoder_funcs->dpms(encoder, dpms_mode); } } - if (dpms_mode == DPMSModeOff) + if (dpms_mode == DRM_MODE_DPMS_OFF) crtc_funcs->dpms(crtc, dpms_mode); } } @@ -596,16 +596,16 @@ int intelfb_blank(int blank, struct fb_info *info) intelfb_on(info); break; case FB_BLANK_NORMAL: - intelfb_off(info, DPMSModeStandby); + intelfb_off(info, DRM_MODE_DPMS_STANDBY); break; case FB_BLANK_HSYNC_SUSPEND: - intelfb_off(info, DPMSModeStandby); + intelfb_off(info, DRM_MODE_DPMS_STANDBY); break; case FB_BLANK_VSYNC_SUSPEND: - intelfb_off(info, DPMSModeSuspend); + intelfb_off(info, DRM_MODE_DPMS_SUSPEND); break; case FB_BLANK_POWERDOWN: - intelfb_off(info, DPMSModeOff); + intelfb_off(info, DRM_MODE_DPMS_OFF); break; } return 0; diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c new file mode 100644 index 00000000..ee628732 --- /dev/null +++ b/linux-core/radeon_atombios.c @@ -0,0 +1,361 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#include "atom.h" +#include "atom-bits.h" + + +union atom_supported_devices { + struct _ATOM_SUPPORTED_DEVICES_INFO info; + struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2; + struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; +}; + +static inline struct radeon_i2c_bus_rec radeon_lookup_gpio_for_ddc(struct drm_device *dev, uint8_t id) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct atom_context *ctx = dev_priv->mode_info.atom_context; + ATOM_GPIO_I2C_ASSIGMENT gpio; + struct radeon_i2c_bus_rec i2c; + int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info); + struct _ATOM_GPIO_I2C_INFO *i2c_info; + uint16_t data_offset; + + memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec)); + i2c.valid = false; + + atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset); + + i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); + + gpio = i2c_info->asGPIO_Info[id]; + + i2c.mask_clk_reg = le16_to_cpu(gpio.usClkMaskRegisterIndex) * 4; + i2c.mask_data_reg = le16_to_cpu(gpio.usDataMaskRegisterIndex) * 4; + i2c.put_clk_reg = le16_to_cpu(gpio.usClkEnRegisterIndex) * 4; + i2c.put_data_reg = le16_to_cpu(gpio.usDataEnRegisterIndex) * 4; + i2c.get_clk_reg = le16_to_cpu(gpio.usClkY_RegisterIndex) * 4; + i2c.get_data_reg = le16_to_cpu(gpio.usDataY_RegisterIndex) * 4; + i2c.mask_clk_mask = (1 << gpio.ucClkMaskShift); + i2c.mask_data_mask = (1 << gpio.ucDataMaskShift); + i2c.put_clk_mask = (1 << gpio.ucClkEnShift); + i2c.put_data_mask = (1 << gpio.ucDataEnShift); + i2c.get_clk_mask = (1 << gpio.ucClkY_Shift); + i2c.get_data_mask = (1 << gpio.ucDataY_Shift); + i2c.valid = true; + + return i2c; +} + +static void radeon_atom_apply_quirks(struct drm_device *dev, int index) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + + if ((dev->pdev->device == 0x791e) && + (dev->pdev->subsystem_vendor == 0x1043) && + (dev->pdev->subsystem_device == 0x826d)) { + if ((mode_info->bios_connector[index].connector_type == CONNECTOR_HDMI_TYPE_A) && + (mode_info->bios_connector[index].tmds_type == TMDS_LVTMA)) { + mode_info->bios_connector[index].connector_type = CONNECTOR_DVI_D; + } + } + + if ((dev->pdev->device == 0x5653) && + (dev->pdev->subsystem_vendor == 0x1462) && + (dev->pdev->subsystem_device == 0x0291)) { + if (mode_info->bios_connector[index].connector_type == CONNECTOR_LVDS) { + mode_info->bios_connector[index].ddc_i2c.valid = false; + } + } +} + +bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct atom_context *ctx = mode_info->atom_context; + int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo); + uint16_t size, data_offset; + uint8_t frev, crev; + uint16_t device_support; + + union atom_supported_devices *supported_devices; + int i,j; + atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); + + supported_devices = (union atom_supported_devices *)(ctx->bios + data_offset); + + device_support = le16_to_cpu(supported_devices->info.usDeviceSupport); + + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + + ATOM_CONNECTOR_INFO_I2C ci = supported_devices->info.asConnInfo[i]; + + if (!(device_support & (1 << i))) { + mode_info->bios_connector[i].valid = false; + continue; + } + + if (i == ATOM_DEVICE_CV_INDEX) { + DRM_DEBUG("Skipping Component Video\n"); + mode_info->bios_connector[i].valid = false; + continue; + } + + if (i == ATOM_DEVICE_TV1_INDEX) { + DRM_DEBUG("Skipping TV Out\n"); + mode_info->bios_connector[i].valid = false; + continue; + } + + mode_info->bios_connector[i].valid = true; + mode_info->bios_connector[i].output_id = ci.sucI2cId.sbfAccess.bfI2C_LineMux; + mode_info->bios_connector[i].devices = 1 << i; + mode_info->bios_connector[i].connector_type = ci.sucConnectorInfo.sbfAccess.bfConnectorType; + + if (mode_info->bios_connector[i].connector_type == CONNECTOR_NONE) { + mode_info->bios_connector[i].valid = false; + continue; + } + + mode_info->bios_connector[i].dac_type = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC; + + if ((i == ATOM_DEVICE_TV1_INDEX) || + (i == ATOM_DEVICE_TV2_INDEX) || + (i == ATOM_DEVICE_TV1_INDEX)) + mode_info->bios_connector[i].ddc_i2c.valid = false; + else if ((dev_priv->chip_family == CHIP_RS600) || + (dev_priv->chip_family == CHIP_RS690) || + (dev_priv->chip_family == CHIP_RS740)) { + if ((i == ATOM_DEVICE_DFP2_INDEX) || (i == ATOM_DEVICE_DFP3_INDEX)) + mode_info->bios_connector[i].ddc_i2c = + radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1); + else + mode_info->bios_connector[i].ddc_i2c = + radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux); + } else + mode_info->bios_connector[i].ddc_i2c = + radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux); + + if (i == ATOM_DEVICE_DFP1_INDEX) + mode_info->bios_connector[i].tmds_type = TMDS_INT; + else if (i == ATOM_DEVICE_DFP2_INDEX) { + if ((dev_priv->chip_family == CHIP_RS600) || + (dev_priv->chip_family == CHIP_RS690) || + (dev_priv->chip_family == CHIP_RS740)) + mode_info->bios_connector[i].tmds_type = TMDS_DDIA; + else + mode_info->bios_connector[i].tmds_type = TMDS_EXT; + } else if (i == ATOM_DEVICE_DFP3_INDEX) + mode_info->bios_connector[i].tmds_type = TMDS_LVTMA; + else + mode_info->bios_connector[i].tmds_type = TMDS_NONE; + + /* Always set the connector type to VGA for CRT1/CRT2. if they are + * shared with a DVI port, we'll pick up the DVI connector below when we + * merge the outputs + */ + if ((i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) && + (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I || + mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D || + mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_A)) { + mode_info->bios_connector[i].connector_type = CONNECTOR_VGA; + } + + if (crev > 1) { + ATOM_CONNECTOR_INC_SRC_BITMAP isb = supported_devices->info_2.asIntSrcInfo[i]; + + switch(isb.ucIntSrcBitmap) { + case 0x4: + mode_info->bios_connector[i].hpd_mask = 0x1; + break; + case 0xa: + mode_info->bios_connector[i].hpd_mask = 0x100; + break; + default: + mode_info->bios_connector[i].hpd_mask = 0; + break; + } + } else { + mode_info->bios_connector[i].hpd_mask = 0; + } + + radeon_atom_apply_quirks(dev, i); + } + + /* CRTs/DFPs may share a port */ + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + if (!mode_info->bios_connector[i].valid) + continue; + + for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) { + if (mode_info->bios_connector[j].valid && (i != j)) { + if (mode_info->bios_connector[i].output_id == + mode_info->bios_connector[j].output_id) { + if (((i == ATOM_DEVICE_DFP1_INDEX) || + (i == ATOM_DEVICE_DFP2_INDEX) || + (i == ATOM_DEVICE_DFP3_INDEX)) && + ((j == ATOM_DEVICE_CRT1_INDEX) || + (j == ATOM_DEVICE_CRT2_INDEX))) { + mode_info->bios_connector[i].dac_type = mode_info->bios_connector[j].dac_type; + mode_info->bios_connector[i].devices |= mode_info->bios_connector[j].devices; + mode_info->bios_connector[i].hpd_mask = mode_info->bios_connector[j].hpd_mask; + mode_info->bios_connector[j].valid = false; + } else if (((j == ATOM_DEVICE_DFP1_INDEX) || + (j == ATOM_DEVICE_DFP2_INDEX) || + (j == ATOM_DEVICE_DFP3_INDEX)) && + ((i == ATOM_DEVICE_CRT1_INDEX) || + (i == ATOM_DEVICE_CRT2_INDEX))) { + mode_info->bios_connector[j].dac_type = mode_info->bios_connector[i].dac_type; + mode_info->bios_connector[j].devices |= mode_info->bios_connector[i].devices; + mode_info->bios_connector[j].hpd_mask = mode_info->bios_connector[i].hpd_mask; + mode_info->bios_connector[i].valid = false; + } + } + } + } + } + + + DRM_DEBUG("BIOS Connector table\n"); + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + if (!mode_info->bios_connector[i].valid) + continue; + + DRM_DEBUG("Port %d: ddc_type 0x%x, dac_type %d, tmds_type %d, connector type %d, hpd_mask %d\n", + i, mode_info->bios_connector[i].ddc_i2c.mask_clk_reg, + mode_info->bios_connector[i].dac_type, + mode_info->bios_connector[i].tmds_type, + mode_info->bios_connector[i].connector_type, + mode_info->bios_connector[i].hpd_mask); + } + return true; +} + +union firmware_info { + ATOM_FIRMWARE_INFO info; + ATOM_FIRMWARE_INFO_V1_2 info_12; + ATOM_FIRMWARE_INFO_V1_3 info_13; + ATOM_FIRMWARE_INFO_V1_4 info_14; +}; + +bool radeon_atom_get_clock_info(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); + union firmware_info *firmware_info; + uint8_t frev, crev; + struct radeon_pll *pll = &mode_info->pll; + uint16_t data_offset; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + + firmware_info = (union firmware_info *)(mode_info->atom_context->bios + data_offset); + + pll->reference_freq = le16_to_cpu(firmware_info->info.usReferenceClock); + pll->reference_div = 0; + + pll->pll_out_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); + pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); + + if (pll->pll_out_min == 0) { + if (radeon_is_avivo(dev_priv)) + pll->pll_out_min = 64800; + else + pll->pll_out_min = 20000; + } + + pll->pll_in_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input); + pll->pll_in_max = le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input); + + pll->xclk = le16_to_cpu(firmware_info->info.usMaxPixelClock); + + return true; +} + +union lvds_info { + struct _ATOM_LVDS_INFO info; + struct _ATOM_LVDS_INFO_V12 info_12; +}; + +void radeon_get_lvds_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + int index = GetIndexIntoMasterTable(DATA, LVDS_Info); + uint16_t data_offset; + union lvds_info *lvds_info; + uint8_t frev, crev; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + + lvds_info = (union lvds_info *)(mode_info->atom_context->bios + data_offset); + + encoder->dotclock = le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10; + encoder->panel_xres = le16_to_cpu(lvds_info->info.sLCDTiming.usHActive); + encoder->panel_yres = le16_to_cpu(lvds_info->info.sLCDTiming.usVActive); + encoder->hblank = le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time); + encoder->hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset); + encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); + + encoder->vblank = le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); + encoder->hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); + encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); + encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); +} + +void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct atom_context *ctx = mode_info->atom_context; + DYNAMIC_CLOCK_GATING_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating); + + args.ucEnable = enable; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct atom_context *ctx = mode_info->atom_context; + ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt); + + args.ucEnable = enable; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c new file mode 100644 index 00000000..e9ba11d4 --- /dev/null +++ b/linux-core/radeon_buffer.c @@ -0,0 +1,266 @@ +/************************************************************************** + * + * Copyright 2007 Dave Airlie + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Dave Airlie + */ + +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device * dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if(dev_priv->flags & RADEON_IS_AGP) + return drm_agp_init_ttm(dev); + else + return ati_pcigart_init_ttm(dev, &dev_priv->gart_info, radeon_gart_flush); +} + +int radeon_fence_types(struct drm_buffer_object *bo, uint32_t * class, uint32_t * type) +{ + *class = 0; + *type = 1; + return 0; +} + +int radeon_invalidate_caches(struct drm_device * dev, uint64_t flags) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + BEGIN_RING(4); + RADEON_FLUSH_CACHE(); + RADEON_FLUSH_ZCACHE(); + ADVANCE_RING(); + return 0; +} + +int radeon_init_mem_type(struct drm_device * dev, uint32_t type, + struct drm_mem_type_manager * man) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + switch (type) { + case DRM_BO_MEM_LOCAL: + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CACHED; + man->drm_bus_maptype = 0; + break; + case DRM_BO_MEM_VRAM: + man->flags = _DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_NEEDS_IOREMAP; + man->io_addr = NULL; + man->drm_bus_maptype = _DRM_FRAME_BUFFER; + man->io_offset = drm_get_resource_start(dev, 0); + man->io_size = drm_get_resource_len(dev, 0); + break; + case DRM_BO_MEM_TT: + if (dev_priv->flags & RADEON_IS_AGP) { + if (!(drm_core_has_AGP(dev) && dev->agp)) { + DRM_ERROR("AGP is not enabled for memory type %u\n", + (unsigned)type); + return -EINVAL; + } + man->io_offset = dev->agp->agp_info.aper_base; + man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | + _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; + man->drm_bus_maptype = _DRM_AGP; + } else { + man->io_offset = dev_priv->gart_vm_start; + man->io_size = dev_priv->gart_size; + man->io_addr = NULL; + man->flags = _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_MEMTYPE_MAPPABLE | _DRM_FLAG_MEMTYPE_CMA; + man->drm_bus_maptype = _DRM_SCATTER_GATHER; + } + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; + } + return 0; +} + +static void radeon_emit_copy_blit(struct drm_device * dev, + uint32_t src_offset, + uint32_t dst_offset, + uint32_t pages, int direction) +{ + uint32_t cur_pages; + uint32_t stride = PAGE_SIZE; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t format, height; + RING_LOCALS; + + if (!dev_priv) + return; + + /* 32-bit copy format */ + format = RADEON_COLOR_FORMAT_ARGB8888; + + /* radeon limited to 16k stride */ + stride &= 0x3fff; + while(pages > 0) { + cur_pages = pages; + if (cur_pages > 2048) + cur_pages = 2048; + pages -= cur_pages; + + /* needs verification */ + BEGIN_RING(7); + OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); + OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | + RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_NONE | + (format << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_MEMORY | + RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); + if (direction) { + OUT_RING((stride << 22) | (src_offset >> 10)); + OUT_RING((stride << 22) | (dst_offset >> 10)); + } else { + OUT_RING((stride << 22) | (dst_offset >> 10)); + OUT_RING((stride << 22) | (src_offset >> 10)); + } + OUT_RING(0); + OUT_RING(pages); /* x - y */ + OUT_RING((stride << 16) | cur_pages); + ADVANCE_RING(); + } + + BEGIN_RING(2); + RADEON_WAIT_UNTIL_2D_IDLE(); + ADVANCE_RING(); + + return; +} + +static int radeon_move_blit(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem) +{ + struct drm_bo_mem_reg *old_mem = &bo->mem; + int dir = 0; + + if ((old_mem->mem_type == new_mem->mem_type) && + (new_mem->mm_node->start < + old_mem->mm_node->start + old_mem->mm_node->size)) { + dir = 1; + } + + radeon_emit_copy_blit(bo->dev, + old_mem->mm_node->start << PAGE_SHIFT, + new_mem->mm_node->start << PAGE_SHIFT, + new_mem->num_pages, dir); + + + return drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, + DRM_FENCE_TYPE_EXE, 0, + new_mem); +} + +static int radeon_move_flip(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg * new_mem) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg tmp_mem; + int ret; + + tmp_mem = *new_mem; + tmp_mem.mm_node = NULL; + // tmp_mem.mask = DRM_BO_FLAG_MEM_TT | + // DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING; + + ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); + if (ret) + return ret; + + ret = drm_ttm_bind(bo->ttm, &tmp_mem); + if (ret) + goto out_cleanup; + + ret = radeon_move_blit(bo, 1, no_wait, &tmp_mem); + if (ret) + goto out_cleanup; + + ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); +out_cleanup: + if (tmp_mem.mm_node) { + mutex_lock(&dev->struct_mutex); + if (tmp_mem.mm_node != bo->pinned_node) + drm_memrange_put_block(tmp_mem.mm_node); + tmp_mem.mm_node = NULL; + mutex_unlock(&dev->struct_mutex); + } + return ret; +} + +int radeon_move(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg * new_mem) +{ + struct drm_bo_mem_reg *old_mem = &bo->mem; + + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); +#if 0 + DRM_DEBUG("\n"); + if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + if (radeon_move_flip(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } else { + if (radeon_move_blit(bo, evict, no_wait, new_mem)) + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + } + return 0; +#endif +} + + +/* + * i915_evict_flags: + * + * @bo: the buffer object to be evicted + * + * Return the bo flags for a buffer which is not mapped to the hardware. + * These will be placed in proposed_flags so that when the move is + * finished, they'll end up in bo->mem.flags + */ +uint64_t radeon_evict_flags(struct drm_buffer_object *bo) +{ + switch (bo->mem.mem_type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return DRM_BO_FLAG_MEM_LOCAL; + default: + return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; + } +} diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c new file mode 100644 index 00000000..e2b768ca --- /dev/null +++ b/linux-core/radeon_combios.c @@ -0,0 +1,381 @@ +/* + * Copyright 2004 ATI Technologies Inc., Markham, Ontario + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +/* old legacy ATI BIOS routines */ + +enum radeon_combios_ddc +{ + DDC_NONE_DETECTED, + DDC_MONID, + DDC_DVI, + DDC_VGA, + DDC_CRT2, + DDC_LCD, + DDC_GPIO, +}; + +enum radeon_combios_connector +{ + CONNECTOR_NONE_LEGACY, + CONNECTOR_PROPRIETARY_LEGACY, + CONNECTOR_CRT_LEGACY, + CONNECTOR_DVI_I_LEGACY, + CONNECTOR_DVI_D_LEGACY, + CONNECTOR_CTV_LEGACY, + CONNECTOR_STV_LEGACY, + CONNECTOR_UNSUPPORTED_LEGACY +}; + +struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) +{ + struct radeon_i2c_bus_rec i2c; + + i2c.mask_clk_mask = RADEON_GPIO_EN_1 | RADEON_GPIO_Y_1; + i2c.mask_data_mask = RADEON_GPIO_EN_0 | RADEON_GPIO_Y_0; + i2c.put_clk_mask = RADEON_GPIO_EN_1; + i2c.put_data_mask = RADEON_GPIO_EN_0; + i2c.get_clk_mask = RADEON_GPIO_Y_1; + i2c.get_data_mask = RADEON_GPIO_Y_0; + if ((ddc_line == RADEON_LCD_GPIO_MASK) || + (ddc_line == RADEON_MDGPIO_EN_REG)) { + i2c.mask_clk_reg = ddc_line; + i2c.mask_data_reg = ddc_line; + i2c.put_clk_reg = ddc_line; + i2c.put_data_reg = ddc_line; + i2c.get_clk_reg = ddc_line + 4; + i2c.get_data_reg = ddc_line + 4; + } else { + i2c.mask_clk_reg = ddc_line; + i2c.mask_data_reg = ddc_line; + i2c.put_clk_reg = ddc_line; + i2c.put_data_reg = ddc_line; + i2c.get_clk_reg = ddc_line; + i2c.get_data_reg = ddc_line; + } + + if (ddc_line) + i2c.valid = true; + else + i2c.valid = false; + + return i2c; +} + +bool radeon_combios_get_clock_info(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + uint16_t pll_info_block; + struct radeon_pll *pll = &mode_info->pll; + int rev; + + pll_info_block = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x30); + rev = radeon_bios8(dev_priv, pll_info_block); + + pll->reference_freq = radeon_bios16(dev_priv, pll_info_block + 0xe); + pll->reference_div = radeon_bios16(dev_priv, pll_info_block + 0x10); + pll->pll_out_min = radeon_bios32(dev_priv, pll_info_block + 0x12); + pll->pll_out_max = radeon_bios32(dev_priv, pll_info_block + 0x16); + + if (rev > 9) { + pll->pll_in_min = radeon_bios32(dev_priv, pll_info_block + 0x36); + pll->pll_in_max = radeon_bios32(dev_priv, pll_info_block + 0x3a); + } else { + pll->pll_in_min = 40; + pll->pll_in_max = 500; + } + + pll->xclk = radeon_bios16(dev_priv, pll_info_block + 0x08); + + // sclk/mclk use fixed point + + return true; + +} + +bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint16_t tmp; + char stmp[30]; + int tmp0; + int i; + + tmp = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x40); + if (!tmp) { + DRM_INFO("No panel info found in BIOS\n"); + return false; + + } + + for (i = 0; i < 24; i++) + stmp[i] = radeon_bios8(dev_priv, tmp + i + 1); + stmp[24] = 0; + + DRM_INFO("Panel ID String: %s\n", stmp); + + encoder->panel_xres = radeon_bios16(dev_priv, tmp + 25); + encoder->panel_yres = radeon_bios16(dev_priv, tmp + 27); + + DRM_INFO("Panel Size %dx%d\n", encoder->panel_xres, encoder->panel_yres); + + encoder->panel_pwr_delay = radeon_bios16(dev_priv, tmp + 44); + if (encoder->panel_pwr_delay > 2000 || encoder->panel_pwr_delay < 0) + encoder->panel_pwr_delay = 2000; + + for (i = 0; i < 32; i++) { + tmp0 = radeon_bios16(dev_priv, tmp + 64 + i * 2); + if (tmp0 == 0) break; + + if ((radeon_bios16(dev_priv, tmp0) == encoder->panel_xres) && + (radeon_bios16(dev_priv, tmp0 + 2) == encoder->panel_yres)) { + encoder->hblank = (radeon_bios16(dev_priv, tmp0 + 17) - + radeon_bios16(dev_priv, tmp0 + 19)) * 8; + encoder->hoverplus = (radeon_bios16(dev_priv, tmp0 + 21) - + radeon_bios16(dev_priv, tmp0 + 19) - 1) * 8; + encoder->hsync_width = radeon_bios8(dev_priv, tmp0 + 23) * 8; + + encoder->vblank = (radeon_bios16(dev_priv, tmp0 + 24) - + radeon_bios16(dev_priv, tmp0 + 26)); + encoder->voverplus = ((radeon_bios16(dev_priv, tmp0 + 28) & 0x7fff) - + radeon_bios16(dev_priv, tmp0 + 26)); + encoder->vsync_width = ((radeon_bios16(dev_priv, tmp0 + 28) & 0xf800) >> 11); + encoder->dotclock = radeon_bios16(dev_priv, tmp0 + 9) * 10; + encoder->flags = 0; + } + } + return true; +} + +static void radeon_apply_legacy_quirks(struct drm_device *dev, int bios_index) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + + /* on XPRESS chips, CRT2_DDC and MONID_DCC both use the + * MONID gpio, but use different pins. + * CRT2_DDC uses the standard pinout, MONID_DDC uses + * something else. + */ + if ((dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) && + mode_info->bios_connector[bios_index].connector_type == CONNECTOR_VGA && + mode_info->bios_connector[bios_index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) { + mode_info->bios_connector[bios_index].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); + } + + /* XPRESS desktop chips seem to have a proprietary connector listed for + * DVI-D, try and do the right thing here. + */ + if ((dev_priv->flags & RADEON_IS_MOBILITY) && + (mode_info->bios_connector[bios_index].connector_type == CONNECTOR_LVDS)) { + DRM_INFO("proprietary connector found. assuming DVI-D\n"); + mode_info->bios_connector[bios_index].dac_type = DAC_NONE; + mode_info->bios_connector[bios_index].tmds_type = TMDS_EXT; + mode_info->bios_connector[bios_index].connector_type = CONNECTOR_DVI_D; + } + + /* Certain IBM chipset RN50s have a BIOS reporting two VGAs, + one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */ + if (dev->pdev->device == 0x515e && + dev->pdev->subsystem_vendor == 0x1014) { + if (mode_info->bios_connector[bios_index].connector_type == CONNECTOR_VGA && + mode_info->bios_connector[bios_index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) { + mode_info->bios_connector[bios_index].valid = false; + } + } + + /* Some RV100 cards with 2 VGA ports show up with DVI+VGA */ + if (dev->pdev->device == 0x5159 && + dev->pdev->subsystem_vendor == 0x1002 && + dev->pdev->subsystem_device == 0x013a) { + if (mode_info->bios_connector[bios_index].connector_type == CONNECTOR_DVI_I) + mode_info->bios_connector[bios_index].connector_type = CONNECTOR_VGA; + + } + +} + +bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + uint32_t offset, entry; + uint16_t tmp0, tmp1, tmp; + enum radeon_combios_ddc ddctype; + enum radeon_combios_connector connector_type; + int i; + + DRM_DEBUG("\n"); + offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x50); + if (offset) { + for (i = 0; i < 4; i++) { + entry = offset + 2 + i * 2; + + if (!radeon_bios16(dev_priv, entry)) + break; + + mode_info->bios_connector[i].valid = true; + + tmp = radeon_bios16(dev_priv, entry); + + connector_type = (tmp >> 12) & 0xf; + mode_info->bios_connector[i].connector_type = connector_type; + + switch(connector_type) { + case CONNECTOR_PROPRIETARY_LEGACY: + mode_info->bios_connector[i].connector_type = CONNECTOR_LVDS; + break; + case CONNECTOR_CRT_LEGACY: + mode_info->bios_connector[i].connector_type = CONNECTOR_VGA; + break; + case CONNECTOR_DVI_I_LEGACY: + mode_info->bios_connector[i].connector_type = CONNECTOR_DVI_I; + break; + case CONNECTOR_DVI_D_LEGACY: + mode_info->bios_connector[i].connector_type = CONNECTOR_DVI_D; + break; + case CONNECTOR_CTV_LEGACY: + mode_info->bios_connector[i].connector_type = CONNECTOR_CTV; + break; + case CONNECTOR_STV_LEGACY: + mode_info->bios_connector[i].connector_type = CONNECTOR_STV; + break; + default: + DRM_ERROR("Unknown connector type: %d\n", connector_type); + mode_info->bios_connector[i].valid = false; + break; + } + + mode_info->bios_connector[i].ddc_i2c.valid = false; + + ddctype = (tmp >> 8) & 0xf; + switch (ddctype) { + case DDC_MONID: + mode_info->bios_connector[i].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); + break; + case DDC_DVI: + mode_info->bios_connector[i].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + break; + case DDC_VGA: + mode_info->bios_connector[i].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + break; + case DDC_CRT2: + mode_info->bios_connector[i].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + break; + default: + break; + } + + if (tmp & 0x1) + mode_info->bios_connector[i].dac_type = DAC_TVDAC; + else + mode_info->bios_connector[i].dac_type = DAC_PRIMARY; + + if ((dev_priv->chip_family == CHIP_RS300) || + (dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) + mode_info->bios_connector[i].dac_type = DAC_TVDAC; + + if ((tmp >> 4) & 0x1) + mode_info->bios_connector[i].tmds_type = TMDS_EXT; + else + mode_info->bios_connector[i].tmds_type = TMDS_INT; + + radeon_apply_legacy_quirks(dev, i); + } + } else { + DRM_INFO("no connector table found in BIOS\n"); + offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x34); + if (offset) { + DRM_DEBUG("Found DFP table, assuming DVI connector\n"); + + mode_info->bios_connector[0].valid = true; + mode_info->bios_connector[0].connector_type = CONNECTOR_DVI_I; + mode_info->bios_connector[0].dac_type = DAC_PRIMARY; + mode_info->bios_connector[0].tmds_type = TMDS_INT; + mode_info->bios_connector[0].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + } else { + DRM_DEBUG("No table found\n"); + return false; + } + } + + if (dev_priv->flags & RADEON_IS_MOBILITY) { + offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x40); + if (offset) { + mode_info->bios_connector[4].valid = true; + mode_info->bios_connector[4].connector_type = CONNECTOR_LVDS; + mode_info->bios_connector[4].dac_type = DAC_NONE; + mode_info->bios_connector[4].tmds_type = TMDS_NONE; + mode_info->bios_connector[4].ddc_i2c.valid = false; + + tmp = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x42); + if (tmp) { + tmp0 = radeon_bios16(dev_priv, tmp + 0x15); + if (tmp0) { + tmp1 = radeon_bios8(dev_priv, tmp0 + 2) & 0x07; + if (tmp1) { + ddctype = tmp1; + + switch(ddctype) { + case DDC_MONID: + case DDC_DVI: + case DDC_CRT2: + case DDC_LCD: + case DDC_GPIO: + default: + break; + } + DRM_DEBUG("LCD DDC Info Table found!\n"); + } + } + } else + mode_info->bios_connector[4].ddc_i2c.valid = false; + } + } + + DRM_DEBUG("BIOS Connector table\n"); + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + if (!mode_info->bios_connector[i].valid) + continue; + + DRM_DEBUG("Port %d: ddc_type 0x%x, dac_type %d, tmds_type %d, connector type %d, hpd_mask %d\n", + i, mode_info->bios_connector[i].ddc_i2c.mask_clk_reg, + mode_info->bios_connector[i].dac_type, + mode_info->bios_connector[i].tmds_type, + mode_info->bios_connector[i].connector_type, + mode_info->bios_connector[i].hpd_mask); + } + + return true; +} + diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c new file mode 100644 index 00000000..344b4f77 --- /dev/null +++ b/linux-core/radeon_connectors.c @@ -0,0 +1,344 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "drm_edid.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +static int radeon_lvds_get_modes(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *lvds_encoder; + int ret = 0; + struct edid *edid; + + avivo_i2c_do_lock(radeon_connector, 1); + edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + avivo_i2c_do_lock(radeon_connector, 0); + if (edid) { + drm_mode_connector_update_edid_property(&radeon_connector->base, edid); + ret = drm_add_edid_modes(&radeon_connector->base, edid); + kfree(edid); + return 0; + } + +#if 0 + lvds_encoder = radeon_best_single_encoder(connector); + + if (!lvds_encoder) + return ret; + + radeon_encoder_update_panel_size(lvds_encoder, connector); +#endif + return ret; +} + +static int radeon_lvds_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + + return MODE_OK; +} + +static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector) +{ + return connector_status_connected; +} + + + +struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) +{ + int enc_id = connector->encoder_ids[0]; + struct drm_mode_object *obj; + struct drm_encoder *encoder; + + /* pick the encoder ids */ + if (enc_id) { + obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); + if (!obj) + return NULL; + encoder = obj_to_encoder(obj); + return encoder; + } + return NULL; +} + +static void radeon_connector_destroy(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (radeon_connector->ddc_bus) + radeon_i2c_destroy(radeon_connector->ddc_bus); + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); + kfree(connector); +} + +struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = { + .get_modes = radeon_lvds_get_modes, + .mode_valid = radeon_lvds_mode_valid, + .best_encoder = radeon_best_single_encoder, +}; + +struct drm_connector_funcs radeon_lvds_connector_funcs = { + .detect = radeon_lvds_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = radeon_connector_destroy, +}; + +static int radeon_atom_vga_get_modes(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + int ret; + + ret = radeon_ddc_get_modes(radeon_connector); + + return ret; +} + +static int radeon_atom_vga_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + + return MODE_OK; +} + +static enum drm_connector_status radeon_atom_vga_detect(struct drm_connector *connector) +{ + struct edid *edid; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + + avivo_i2c_do_lock(radeon_connector, 1); + edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + avivo_i2c_do_lock(radeon_connector, 0); + if (edid) { + kfree(edid); + return connector_status_connected; + } + + /* if EDID fails to a load detect */ + encoder = radeon_best_single_encoder(connector); + if (!encoder) + return connector_status_disconnected; + + encoder_funcs = encoder->helper_private; + return encoder_funcs->detect(encoder, connector); +} + +struct drm_connector_helper_funcs radeon_atom_vga_connector_helper_funcs = { + .get_modes = radeon_atom_vga_get_modes, + .mode_valid = radeon_atom_vga_mode_valid, + .best_encoder = radeon_best_single_encoder, +}; + +struct drm_connector_funcs radeon_atom_vga_connector_funcs = { + .detect = radeon_atom_vga_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = radeon_connector_destroy, +}; + + +static enum drm_connector_status radeon_atom_dvi_detect(struct drm_connector *connector) +{ + struct edid *edid; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_mode_object *obj; + int i; + enum drm_connector_status ret; + + avivo_i2c_do_lock(radeon_connector, 1); + edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + avivo_i2c_do_lock(radeon_connector, 0); + if (edid) { + /* if the monitor is digital - set the bits */ + if (edid->digital) + radeon_connector->use_digital = 1; + else + radeon_connector->use_digital = 0; + + kfree(edid); + return connector_status_connected; + } + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; + + encoder = obj_to_encoder(obj); + + encoder_funcs = encoder->helper_private; + if (encoder_funcs->detect) { + ret = encoder_funcs->detect(encoder, connector); + if (ret == connector_status_connected) { + radeon_connector->use_digital = 0; + return ret; + } + } + } + return connector_status_disconnected; +} + +/* okay need to be smart in here about which encoder to pick */ +struct drm_encoder *radeon_atom_dvi_encoder(struct drm_connector *connector) +{ + int enc_id = connector->encoder_ids[0]; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_mode_object *obj; + struct drm_encoder *encoder; + int i; + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; + + encoder = obj_to_encoder(obj); + + if (radeon_connector->use_digital) { + if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) + return encoder; + } else { + if (encoder->encoder_type == DRM_MODE_ENCODER_DAC || + encoder->encoder_type == DRM_MODE_ENCODER_TVDAC) + return encoder; + } + } + + /* see if we have a default encoder TODO */ + + /* then check use digitial */ + /* pick the first one */ + if (enc_id) { + obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); + if (!obj) + return NULL; + encoder = obj_to_encoder(obj); + return encoder; + } + return NULL; +} + +struct drm_connector_helper_funcs radeon_atom_dvi_connector_helper_funcs = { + .get_modes = radeon_atom_vga_get_modes, + .mode_valid = radeon_atom_vga_mode_valid, + .best_encoder = radeon_atom_dvi_encoder, +}; + +struct drm_connector_funcs radeon_atom_dvi_connector_funcs = { + .detect = radeon_atom_dvi_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = radeon_connector_destroy, +}; + + +static struct connector_funcs { + int conn_id; + struct drm_connector_funcs *connector_funcs; + struct drm_connector_helper_funcs *helper_funcs; + int conn_type; + char *i2c_id; +} connector_fns[] = { + { CONNECTOR_NONE, NULL, NULL, DRM_MODE_CONNECTOR_Unknown }, + { CONNECTOR_VGA, &radeon_atom_vga_connector_funcs, &radeon_atom_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA , "VGA"}, + { CONNECTOR_LVDS, &radeon_lvds_connector_funcs, &radeon_lvds_connector_helper_funcs, DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { CONNECTOR_DVI_A, &radeon_atom_vga_connector_funcs, &radeon_atom_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_DVIA, "DVI" }, + { CONNECTOR_DVI_I, &radeon_atom_dvi_connector_funcs, &radeon_atom_dvi_connector_helper_funcs, DRM_MODE_CONNECTOR_DVII, "DVI" }, + +#if 0 + { CONNECTOR_DVI_D, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + + { CONNECTOR_STV, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + { CONNECTOR_CTV, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + { CONNECTOR_DIGITAL, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + { CONNECTOR_SCART, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + + { CONNECTOR_HDMI_TYPE_A, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + { CONNECTOR_HDMI_TYPE_B, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + { CONNECTOR_HDMI_TYPE_B, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + { CONNECTOR_HDMI_TYPE_B, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + { CONNECTOR_DIN, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, + { CONNECTOR_DISPLAY_PORT, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, +#endif +}; + +struct drm_connector *radeon_connector_add(struct drm_device *dev, int bios_index) +{ + struct radeon_connector *radeon_connector; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct drm_connector *connector; + int table_idx; + + for (table_idx = 0; table_idx < ARRAY_SIZE(connector_fns); table_idx++) { + if (connector_fns[table_idx].conn_id == mode_info->bios_connector[bios_index].connector_type) + break; + } + + if (table_idx == ARRAY_SIZE(connector_fns)) + return NULL; + + radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); + if (!radeon_connector) { + return NULL; + } + + connector = &radeon_connector->base; + + drm_connector_init(dev, &radeon_connector->base, connector_fns[table_idx].connector_funcs, + connector_fns[table_idx].conn_type); + + drm_connector_helper_add(&radeon_connector->base, connector_fns[table_idx].helper_funcs); + + if (mode_info->bios_connector[bios_index].ddc_i2c.valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, &mode_info->bios_connector[bios_index].ddc_i2c, + connector_fns[table_idx].i2c_id); + if (!radeon_connector->ddc_bus) + goto failed; + } + + drm_sysfs_connector_add(connector); + return connector; + + +failed: + if (radeon_connector->ddc_bus) + radeon_i2c_destroy(radeon_connector->ddc_bus); + drm_connector_cleanup(connector); + kfree(connector); + return NULL; +} diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c new file mode 100644 index 00000000..7a7b5856 --- /dev/null +++ b/linux-core/radeon_display.c @@ -0,0 +1,725 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#include "atom.h" +#include + +#include "drm_crtc_helper.h" + +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 + +int radeon_ddc_dump(struct drm_connector *connector); + + + +static void avivo_crtc_load_lut(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + int i; + + DRM_DEBUG("%d\n", radeon_crtc->crtc_id); + RADEON_WRITE(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0); + + RADEON_WRITE(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); + RADEON_WRITE(AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0); + RADEON_WRITE(AVIVO_DC_LUTA_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0); + + RADEON_WRITE(AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff); + RADEON_WRITE(AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff); + RADEON_WRITE(AVIVO_DC_LUTA_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff); + + RADEON_WRITE(AVIVO_DC_LUT_RW_SELECT, radeon_crtc->crtc_id); + RADEON_WRITE(AVIVO_DC_LUT_RW_MODE, 0); + RADEON_WRITE(AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f); + + for (i = 0; i < 256; i++) { + + RADEON_WRITE8(AVIVO_DC_LUT_RW_INDEX, i); + RADEON_WRITE(AVIVO_DC_LUT_30_COLOR, + (radeon_crtc->lut_r[i] << 22) | + (radeon_crtc->lut_g[i] << 12) | + (radeon_crtc->lut_b[i] << 2)); + } + + RADEON_WRITE(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); +} + + +void radeon_crtc_load_lut(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + u32 temp; + int i; + if (!crtc->enabled) + return; + + + if (radeon_is_avivo(dev_priv)) { + avivo_crtc_load_lut(crtc); + return; + } + + temp = RADEON_READ(RADEON_DAC_CNTL2); + if (radeon_crtc->crtc_id == 0) + temp &= (uint32_t)~RADEON_DAC2_PALETTE_ACC_CTL; + else + temp |= RADEON_DAC2_PALETTE_ACC_CTL; + RADEON_WRITE(RADEON_DAC_CNTL2, temp); + + for (i = 0; i < 256; i++) { +// OUTPAL(i, radeon_crtc->lut_r[i], radeon_crtc->lut_g[i], radeon_crtc->lut_b[i]); + } + +} + +/** Sets the color ramps on behalf of RandR */ +void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (regno==0) + DRM_DEBUG("gamma set %d\n", radeon_crtc->crtc_id); + radeon_crtc->lut_r[regno] = red >> 8; + radeon_crtc->lut_g[regno] = green >> 8; + radeon_crtc->lut_b[regno] = blue >> 8; +} + +void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) +{ +} + + + +static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y) +{ + +} + +void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y) +{ +} + +static void radeon_crtc_prepare(struct drm_crtc *crtc) +{ +} + +static void radeon_crtc_commit(struct drm_crtc *crtc) +{ +} + +static void avivo_lock_cursor(struct drm_crtc *crtc, bool lock) +{ + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + uint32_t tmp; + + tmp = RADEON_READ(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset); + if (lock) + tmp |= AVIVO_D1CURSOR_UPDATE_LOCK; + else + tmp &= ~AVIVO_D1CURSOR_UPDATE_LOCK; + + RADEON_WRITE(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, tmp); +} + +static int radeon_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + + if (!handle) { + RADEON_WRITE(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 0); + return 0; + /* turn off cursor */ + } + + obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); + if (!obj) { + DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); + return -EINVAL; + } + + obj_priv = obj->driver_private; + + RADEON_WRITE(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 0); + if (radeon_is_avivo(dev_priv)) { + RADEON_WRITE(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + dev_priv->fb_location + obj_priv->bo->offset); + RADEON_WRITE(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, + (CURSOR_WIDTH - 1) << 16 | (CURSOR_HEIGHT - 1)); + RADEON_WRITE(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, + AVIVO_D1CURSOR_EN | (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); + } + + mutex_lock(&crtc->dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&crtc->dev->struct_mutex); + + return 0; +} + +static int radeon_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + int xorigin = 0, yorigin = 0; + + if (x < 0) xorigin = -x+1; + if (y < 0) yorigin = -x+1; + if (xorigin >= CURSOR_WIDTH) xorigin = CURSOR_WIDTH - 1; + if (yorigin >= CURSOR_WIDTH) yorigin = CURSOR_WIDTH - 1; + + if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + y /= 2; + else if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) + y *= 2; + + if (radeon_is_avivo(dev_priv)) { + avivo_lock_cursor(crtc, true); + + RADEON_WRITE(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, + ((xorigin ? 0: x) << 16) | + (yorigin ? 0 : y)); + RADEON_WRITE(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); + avivo_lock_cursor(crtc, false); + } + + return 0; +} + +static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, uint32_t size) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + int i; + + if (size != 256) + return; + + for (i = 0; i < 256; i++) { + radeon_crtc->lut_r[i] = red[i] >> 8; + radeon_crtc->lut_g[i] = green[i] >> 8; + radeon_crtc->lut_b[i] = blue[i] >> 8; + } + + radeon_crtc_load_lut(crtc); +} + +static void radeon_crtc_destroy(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + drm_crtc_cleanup(crtc); + kfree(radeon_crtc); +} + +static const struct drm_crtc_helper_funcs radeon_helper_funcs = { + .dpms = radeon_crtc_dpms, + .mode_fixup = radeon_crtc_mode_fixup, + .mode_set = radeon_crtc_mode_set, + .mode_set_base = radeon_crtc_set_base, + .prepare = radeon_crtc_prepare, + .commit = radeon_crtc_commit, +}; + +static const struct drm_crtc_funcs radeon_crtc_funcs = { + .cursor_set = radeon_crtc_cursor_set, + .cursor_move = radeon_crtc_cursor_move, + .gamma_set = radeon_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = radeon_crtc_destroy, +}; + +static void radeon_crtc_init(struct drm_device *dev, int index) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc; + int i; + + radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); + // radeon_crtc = kzalloc(sizeof(struct radeon_crtc), GFP_KERNEL); + if (radeon_crtc == NULL) + return; + + drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs); + + drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); + radeon_crtc->crtc_id = index; + + radeon_crtc->mode_set.crtc = &radeon_crtc->base; + radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); + radeon_crtc->mode_set.num_connectors = 0; + + for (i = 0; i < 256; i++) { + radeon_crtc->lut_r[i] = i; + radeon_crtc->lut_g[i] = i; + radeon_crtc->lut_b[i] = i; + } + + if (dev_priv->is_atom_bios && dev_priv->chip_family > CHIP_RS690) + radeon_atombios_init_crtc(dev, radeon_crtc); + else + drm_crtc_helper_add(&radeon_crtc->base, &radeon_helper_funcs); +} + +bool radeon_legacy_setup_enc_conn(struct drm_device *dev) +{ + + radeon_get_legacy_connector_info_from_bios(dev); + return false; +} + +bool radeon_setup_enc_conn(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + /* do all the mac and stuff */ + struct drm_connector *connector; + struct drm_encoder *encoder; + int i; + + if (dev_priv->is_atom_bios) + radeon_get_atom_connector_info_from_bios_connector_table(dev); + else + radeon_get_legacy_connector_info_from_bios(dev); + + for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) { + if (!mode_info->bios_connector[i].valid) + continue; + + /* add a connector for this */ + if (mode_info->bios_connector[i].connector_type == CONNECTOR_NONE) + continue; + + connector = radeon_connector_add(dev, i); + if (!connector) + continue; + + encoder = NULL; + /* if we find an LVDS connector */ + if (mode_info->bios_connector[i].connector_type == CONNECTOR_LVDS) { + if (radeon_is_avivo(dev_priv)) + encoder = radeon_encoder_lvtma_add(dev, i); + else + encoder = radeon_encoder_legacy_lvds_add(dev, i); + if (encoder) + drm_mode_connector_attach_encoder(connector, encoder); + } + + /* DAC on DVI or VGA */ + if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || + (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_A) || + (mode_info->bios_connector[i].connector_type == CONNECTOR_VGA)) { + if (radeon_is_avivo(dev_priv)) + encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 0); + if (encoder) + drm_mode_connector_attach_encoder(connector, encoder); + } + + /* TMDS on DVI */ + if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || + (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D)) { + if (radeon_is_avivo(dev_priv)) + encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].dac_type); + if (encoder) + drm_mode_connector_attach_encoder(connector, encoder); + } + + /* TVDAC on DIN */ + if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN) { + if (radeon_is_avivo(dev_priv)) + encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 1); + if (encoder) + drm_mode_connector_attach_encoder(connector, encoder); + } + } + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + radeon_ddc_dump(connector); + return true; +} + + + +void avivo_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) +{ + struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; + uint32_t temp; + struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec; + + temp = RADEON_READ(rec->mask_clk_reg); + if (lock_state) + temp |= rec->put_clk_mask; + else + temp &= ~rec->put_clk_mask; + RADEON_WRITE(rec->mask_clk_reg, temp); + temp = RADEON_READ(rec->mask_clk_reg); + + temp = RADEON_READ(rec->mask_data_reg); + if (lock_state) + temp |= rec->put_data_mask; + else + temp &= ~rec->put_data_mask; + RADEON_WRITE(rec->mask_data_reg, temp); + temp = RADEON_READ(rec->mask_data_reg); +} + +int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) +{ + struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; + struct edid *edid; + int ret = 0; + + if (!radeon_connector->ddc_bus) + return -1; + + if (radeon_is_avivo(dev_priv)) + avivo_i2c_do_lock(radeon_connector, 1); + edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + if (radeon_is_avivo(dev_priv)) + avivo_i2c_do_lock(radeon_connector, 0); + if (edid) { + drm_mode_connector_update_edid_property(&radeon_connector->base, edid); + ret = drm_add_edid_modes(&radeon_connector->base, edid); + kfree(edid); + return ret; + } + return -1; +} + +int radeon_ddc_dump(struct drm_connector *connector) +{ + struct edid *edid; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + int ret = 0; + + if (!radeon_connector->ddc_bus) + return -1; + edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); + if (edid) { + kfree(edid); + } + return ret; +} + +static inline uint32_t radeon_div(uint64_t n, uint32_t d) +{ + uint64_t x, y, result; + uint64_t mod; + + n += d / 2; + + mod = do_div(n, d); + return n; +} + +void radeon_compute_pll(struct radeon_pll *pll, + uint64_t freq, + uint32_t *dot_clock_p, + uint32_t *fb_div_p, + uint32_t *ref_div_p, + uint32_t *post_div_p, + int flags) +{ + uint32_t min_ref_div = pll->min_ref_div; + uint32_t max_ref_div = pll->max_ref_div; + uint32_t best_vco = pll->best_vco; + uint32_t best_post_div = 1; + uint32_t best_ref_div = 1; + uint32_t best_feedback_div = 1; + uint32_t best_freq = -1; + uint32_t best_error = 0xffffffff; + uint32_t best_vco_diff = 1; + uint32_t post_div; + + DRM_DEBUG("PLL freq %llu\n", freq); + freq = freq * 1000; + + if (flags & RADEON_PLL_USE_REF_DIV) + min_ref_div = max_ref_div = pll->reference_div; + else { + while (min_ref_div < max_ref_div-1) { + uint32_t mid=(min_ref_div+max_ref_div)/2; + uint32_t pll_in = pll->reference_freq / mid; + if (pll_in < pll->pll_in_min) + max_ref_div = mid; + else if (pll_in > pll->pll_in_max) + min_ref_div = mid; + else + break; + } + } + + for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) { + uint32_t ref_div; + + if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) + continue; + + /* legacy radeons only have a few post_divs */ + if (flags & RADEON_PLL_LEGACY) { + if ((post_div == 5) || + (post_div == 7) || + (post_div == 9) || + (post_div == 10) || + (post_div == 11)) + continue; + } + + for (ref_div = min_ref_div; ref_div <= max_ref_div; ++ref_div) { + uint32_t feedback_div, current_freq, error, vco_diff; + uint32_t pll_in = pll->reference_freq / ref_div; + uint32_t min_feed_div = pll->min_feedback_div; + uint32_t max_feed_div = pll->max_feedback_div+1; + + if (pll_in < pll->pll_in_min || pll_in > pll->pll_in_max) + continue; + + while (min_feed_div < max_feed_div) { + uint32_t vco; + feedback_div = (min_feed_div+max_feed_div)/2; + + vco = radeon_div((uint64_t)pll->reference_freq * feedback_div, + ref_div); + + if (vco < pll->pll_out_min) { + min_feed_div = feedback_div+1; + continue; + } else if(vco > pll->pll_out_max) { + max_feed_div = feedback_div; + continue; + } + + current_freq = radeon_div((uint64_t)pll->reference_freq * 10000 * feedback_div, + ref_div * post_div); + + error = abs(current_freq - freq); + vco_diff = abs(vco - best_vco); + + if ((best_vco == 0 && error < best_error) || + (best_vco != 0 && + (error < best_error - 100 || + (abs(error - best_error) < 100 && vco_diff < best_vco_diff )))) { + best_post_div = post_div; + best_ref_div = ref_div; + best_feedback_div = feedback_div; + best_freq = current_freq; + best_error = error; + best_vco_diff = vco_diff; + } else if (current_freq == freq) { + if (best_freq == -1) { + best_post_div = post_div; + best_ref_div = ref_div; + best_feedback_div = feedback_div; + best_freq = current_freq; + best_error = error; + best_vco_diff = vco_diff; + } else if ((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) { + best_post_div = post_div; + best_ref_div = ref_div; + best_feedback_div = feedback_div; + best_freq = current_freq; + best_error = error; + best_vco_diff = vco_diff; + } + } + + if (current_freq < freq) + min_feed_div = feedback_div+1; + else + max_feed_div = feedback_div; + } + } + } + + *dot_clock_p = best_freq / 10000; + *fb_div_p = best_feedback_div; + *ref_div_p = best_ref_div; + *post_div_p = best_post_div; +} + +void radeon_get_clock_info(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct radeon_pll *pll = &dev_priv->mode_info.pll; + int ret; + + if (dev_priv->is_atom_bios) + ret = radeon_atom_get_clock_info(dev); + else + ret = radeon_combios_get_clock_info(dev); + + if (ret) { + + if (pll->reference_div < 2) pll->reference_div = 12; + } else { + // TODO FALLBACK + } + + if (radeon_is_avivo(dev_priv)) { + pll->min_post_div = 2; + pll->max_post_div = 0x7f; + } else { + pll->min_post_div = 1; + pll->max_post_div = 12; // 16 on crtc 0?? + } + + pll->min_ref_div = 2; + pll->max_ref_div = 0x3ff; + pll->min_feedback_div = 4; + pll->max_feedback_div = 0x7ff; + pll->best_vco = 0; + +} + +static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + struct drm_device *dev = fb->dev; + + if (fb->fbdev) + radeonfb_remove(dev, fb); + + drm_framebuffer_cleanup(fb); + kfree(radeon_fb); +} + +static const struct drm_framebuffer_funcs radeon_fb_funcs = { + .destroy = radeon_user_framebuffer_destroy, +}; + +struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, + struct drm_file *filp, + struct drm_mode_fb_cmd *mode_cmd) +{ + + struct radeon_framebuffer *radeon_fb; + + radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); + if (!radeon_fb) + return NULL; + + drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs); + drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd); + + if (filp) { + radeon_fb->obj = drm_gem_object_lookup(dev, filp, + mode_cmd->handle); + if (!radeon_fb->obj) { + kfree(radeon_fb); + return NULL; + } + drm_gem_object_unreference(radeon_fb->obj); + } + return &radeon_fb->base; +} + +static const struct drm_mode_config_funcs radeon_mode_funcs = { + .fb_create = radeon_user_framebuffer_create, + .fb_changed = radeonfb_probe, +}; + + +int radeon_modeset_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + static struct card_info card; + size_t size; + int num_crtc = 2, i; + int ret; + + drm_mode_config_init(dev); + + dev->mode_config.funcs = (void *)&radeon_mode_funcs; + + if (radeon_is_avivo(dev_priv)) { + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; + } else { + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; + } + + dev->mode_config.fb_base = dev_priv->fb_aper_offset; + + /* allocate crtcs - TODO single crtc */ + for (i = 0; i < num_crtc; i++) { + radeon_crtc_init(dev, i); + } + + /* okay we should have all the bios connectors */ + + ret = radeon_setup_enc_conn(dev); + + if (!ret) + return ret; + + drm_helper_initial_config(dev, false); + + return 0; +} + + +int radeon_load_modeset_init(struct drm_device *dev) +{ + int ret; + ret = radeon_modeset_init(dev); + + return ret; +} + +void radeon_modeset_cleanup(struct drm_device *dev) +{ + drm_mode_config_cleanup(dev); +} + diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index f0f3320e..5f51c813 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -37,10 +37,17 @@ #include "drm_pciids.h" int radeon_no_wb; +int radeon_dynclks = 1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers\n"); module_param_named(no_wb, radeon_no_wb, int, 0444); +unsigned int radeon_modeset = 0; +module_param_named(modeset, radeon_modeset, int, 0400); + +MODULE_PARM_DESC(dynclks, "Disable/Enable dynamic clocks"); +module_param_named(dynclks, radeon_dynclks, int, 0444); + static int dri_library_name(struct drm_device * dev, char * buf) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -56,11 +63,29 @@ static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; +extern struct drm_fence_driver radeon_fence_driver; + +static uint32_t radeon_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; +static uint32_t radeon_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; + +static struct drm_bo_driver radeon_bo_driver = { + .mem_type_prio = radeon_mem_prios, + .mem_busy_prio = radeon_busy_prios, + .num_mem_type_prio = sizeof(radeon_mem_prios)/sizeof(uint32_t), + .num_mem_busy_prio = sizeof(radeon_busy_prios)/sizeof(uint32_t), + .create_ttm_backend_entry = radeon_create_ttm_backend_entry, + .fence_type = radeon_fence_types, + .invalidate_caches = radeon_invalidate_caches, + .init_mem_type = radeon_init_mem_type, + .move = radeon_move, + .evict_flags = radeon_evict_flags, +}; + static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | - DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, + DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_GEM, .dev_priv_size = sizeof(drm_radeon_buf_priv_t), .load = radeon_driver_load, .firstopen = radeon_driver_firstopen, @@ -81,7 +106,11 @@ static struct drm_driver driver = { .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, .ioctls = radeon_ioctls, + .gem_init_object = radeon_gem_init_object, + .gem_free_object = radeon_gem_free_object, .dma_ioctl = radeon_cp_buffers, + .master_create = radeon_master_create, + .master_destroy = radeon_master_destroy, .fops = { .owner = THIS_MODULE, .open = drm_open, @@ -101,6 +130,9 @@ static struct drm_driver driver = { .remove = __devexit_p(drm_cleanup_pci), }, + .fence_driver = &radeon_fence_driver, + .bo_driver = &radeon_bo_driver, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, @@ -117,6 +149,10 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __init radeon_init(void) { driver.num_ioctls = radeon_max_ioctl; + + if (radeon_modeset == 1) + driver.driver_features |= DRIVER_MODESET; + return drm_init(&driver, pciidlist); } diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c new file mode 100644 index 00000000..1b75bd6a --- /dev/null +++ b/linux-core/radeon_encoders.c @@ -0,0 +1,962 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +extern int atom_debug; + +static void radeon_rmx_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + if (mode->hdisplay < radeon_encoder->panel_xres || + mode->vdisplay < radeon_encoder->panel_yres) { + radeon_encoder->flags |= RADEON_USE_RMX; + adjusted_mode->hdisplay = radeon_encoder->panel_xres; + adjusted_mode->vdisplay = radeon_encoder->panel_yres; + adjusted_mode->htotal = radeon_encoder->panel_xres + radeon_encoder->hblank; + adjusted_mode->hsync_start = radeon_encoder->panel_xres + radeon_encoder->hoverplus; + adjusted_mode->hsync_end = adjusted_mode->hsync_start + radeon_encoder->hsync_width; + adjusted_mode->vtotal = radeon_encoder->panel_yres + radeon_encoder->vblank; + adjusted_mode->vsync_start = radeon_encoder->panel_yres + radeon_encoder->voverplus; + adjusted_mode->vsync_end = adjusted_mode->vsync_start + radeon_encoder->vsync_width; + /* update crtc values */ + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + /* adjust crtc values */ + adjusted_mode->crtc_hdisplay = radeon_encoder->panel_xres; + adjusted_mode->crtc_vdisplay = radeon_encoder->panel_yres; + adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + radeon_encoder->hblank; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + radeon_encoder->hoverplus; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + radeon_encoder->hsync_width; + adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + radeon_encoder->vblank; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + radeon_encoder->voverplus; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + radeon_encoder->vsync_width; + } else { + adjusted_mode->htotal = radeon_encoder->panel_xres + radeon_encoder->hblank; + adjusted_mode->hsync_start = radeon_encoder->panel_xres + radeon_encoder->hoverplus; + adjusted_mode->hsync_end = adjusted_mode->hsync_start + radeon_encoder->hsync_width; + adjusted_mode->vtotal = radeon_encoder->panel_yres + radeon_encoder->vblank; + adjusted_mode->vsync_start = radeon_encoder->panel_yres + radeon_encoder->voverplus; + adjusted_mode->vsync_end = adjusted_mode->vsync_start + radeon_encoder->vsync_width; + /* update crtc values */ + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + /* adjust crtc values */ + adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + radeon_encoder->hblank; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + radeon_encoder->hoverplus; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + radeon_encoder->hsync_width; + adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + radeon_encoder->vblank; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + radeon_encoder->voverplus; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + radeon_encoder->vsync_width; + } + adjusted_mode->clock = radeon_encoder->dotclock; + adjusted_mode->flags = radeon_encoder->flags; +} + + +static int atom_dac_find_atom_type(struct radeon_encoder *radeon_encoder, struct drm_connector *connector) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct drm_connector *connector_find; + int atom_type = -1; + + if (!connector) { + list_for_each_entry(connector_find, &dev->mode_config.connector_list, head) { + if (connector_find->encoder == &radeon_encoder->base) + connector = connector_find; + } + } + if (connector) { + /* look for the encoder in the connector list - + check if we the DAC is enabled on a VGA or STV/CTV or CV connector */ + /* work out the ATOM_DEVICE bits */ + switch (connector->connector_type) { + case CONNECTOR_VGA: + case CONNECTOR_DVI_I: + case CONNECTOR_DVI_A: + if (radeon_encoder->atom_device & ATOM_DEVICE_CRT1_SUPPORT) + atom_type = ATOM_DEVICE_CRT1_INDEX; + else if (radeon_encoder->atom_device & ATOM_DEVICE_CRT2_SUPPORT) + atom_type = ATOM_DEVICE_CRT2_INDEX; + break; + case CONNECTOR_STV: + case CONNECTOR_CTV: + if (radeon_encoder->atom_device & ATOM_DEVICE_TV1_SUPPORT) + atom_type = ATOM_DEVICE_TV1_INDEX; + break; + case CONNECTOR_DIN: + if (radeon_encoder->atom_device & ATOM_DEVICE_TV1_SUPPORT) + atom_type = ATOM_DEVICE_TV1_INDEX; + if (radeon_encoder->atom_device & ATOM_DEVICE_CV_SUPPORT) + atom_type = ATOM_DEVICE_CV_INDEX; + break; + } + } + + return atom_type; +} + +/* LVTMA encoder for LVDS usage */ +static void atombios_display_device_control(struct drm_encoder *encoder, int index, uint8_t state) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + args.ucAction = state; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + + +static void atombios_scaler_setup(struct drm_encoder *encoder, struct drm_display_mode *mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + ENABLE_SCALER_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); + + memset(&args, 0, sizeof(args)); + args.ucScaler = radeon_crtc->crtc_id; + + if (radeon_encoder->flags & RADEON_USE_RMX) { + if (radeon_encoder->rmx_type == RMX_FULL) + args.ucEnable = ATOM_SCALER_EXPANSION; + else if (radeon_encoder->rmx_type == RMX_CENTER) + args.ucEnable = ATOM_SCALER_CENTER; + } else + args.ucEnable = ATOM_SCALER_DISABLE; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +void atombios_set_crtc_source(struct drm_encoder *encoder, int source) +{ + int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + uint8_t frev, crev; + SELECT_CRTC_SOURCE_PS_ALLOCATION crtc_src_param; + SELECT_CRTC_SOURCE_PARAMETERS_V2 crtc_src_param2; + uint32_t *param = NULL; + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + switch (frev) { + case 1: { + switch (crev) { + case 0: + case 1: + default: + memset(&crtc_src_param, 0, sizeof(crtc_src_param)); + crtc_src_param.ucCRTC = radeon_crtc->crtc_id; + crtc_src_param.ucDevice = source; + param = (uint32_t *)&crtc_src_param; + break; + case 2: + memset(&crtc_src_param2, 0, sizeof(crtc_src_param2)); + crtc_src_param2.ucCRTC = radeon_crtc->crtc_id; + crtc_src_param2.ucEncoderID = source; + switch (source) { + case ATOM_DEVICE_CRT1_INDEX: + case ATOM_DEVICE_CRT2_INDEX: + crtc_src_param2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; + break; + case ATOM_DEVICE_DFP1_INDEX: + case ATOM_DEVICE_DFP2_INDEX: + case ATOM_DEVICE_DFP3_INDEX: + crtc_src_param2.ucEncodeMode = ATOM_ENCODER_MODE_DVI; + // TODO ENCODER MODE + break; + case ATOM_DEVICE_LCD1_INDEX: + crtc_src_param2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; + break; + case ATOM_DEVICE_TV1_INDEX: + crtc_src_param2.ucEncodeMode = ATOM_ENCODER_MODE_TV; + break; + case ATOM_DEVICE_CV_INDEX: + crtc_src_param2.ucEncodeMode = ATOM_ENCODER_MODE_CV; + break; + } + param = (uint32_t *)&crtc_src_param2; + break; + } + } + break; + default: + return; + } + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)param); + +} + +static void radeon_dfp_disable_dither(struct drm_encoder *encoder, int device) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + + switch (device) { + case ATOM_DEVICE_DFP1_INDEX: + RADEON_WRITE(AVIVO_TMDSA_BIT_DEPTH_CONTROL, 0); /* TMDSA */ + break; + case ATOM_DEVICE_DFP2_INDEX: + if ((dev_priv->chip_family == CHIP_RS600) || + (dev_priv->chip_family == CHIP_RS690) || + (dev_priv->chip_family == CHIP_RS740)) + RADEON_WRITE(AVIVO_DDIA_BIT_DEPTH_CONTROL, 0); /* DDIA */ + else + RADEON_WRITE(AVIVO_DVOA_BIT_DEPTH_CONTROL, 0); /* DVO */ + break; + /*case ATOM_DEVICE_LCD1_INDEX:*/ /* LVDS panels need dither enabled */ + case ATOM_DEVICE_DFP3_INDEX: + RADEON_WRITE(AVIVO_LVTMA_BIT_DEPTH_CONTROL, 0); /* LVTMA */ + break; + default: + break; + } +} + + +static void radeon_lvtma_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + LVDS_ENCODER_CONTROL_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + + memset(&args, 0, sizeof(args)); + atombios_scaler_setup(encoder, mode); + atombios_set_crtc_source(encoder, ATOM_DEVICE_LCD1_INDEX); + + args.ucAction = 1; + if (adjusted_mode->clock > 165000) + args.ucMisc = 1; + else + args.ucMisc = 0; + args.usPixelClock = cpu_to_le16(adjusted_mode->clock / 10); + + printk("executing set LVDS encoder\n"); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + + +static void radeon_lvtma_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + int index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + + switch(mode) { + case DRM_MODE_DPMS_ON: + atombios_display_device_control(encoder, index, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_display_device_control(encoder, index, ATOM_DISABLE); + break; + } +} + +static bool radeon_lvtma_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + radeon_encoder->flags &= ~RADEON_USE_RMX; + + if (radeon_encoder->rmx_type != RMX_OFF) + radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); + + return true; +} + +static void radeon_lvtma_prepare(struct drm_encoder *encoder) +{ + radeon_lvtma_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_lvtma_commit(struct drm_encoder *encoder) +{ + radeon_lvtma_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static const struct drm_encoder_helper_funcs radeon_atom_lvtma_helper_funcs = { + .dpms = radeon_lvtma_dpms, + .mode_fixup = radeon_lvtma_mode_fixup, + .prepare = radeon_lvtma_prepare, + .mode_set = radeon_lvtma_mode_set, + .commit = radeon_lvtma_commit, +}; + +static void radeon_enc_destroy(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + drm_encoder_cleanup(encoder); + kfree(radeon_encoder); +} + +static const struct drm_encoder_funcs radeon_atom_lvtma_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct drm_encoder *radeon_encoder_lvtma_add(struct drm_device *dev, int bios_index) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder; + struct drm_encoder *encoder; + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_atom_lvtma_enc_funcs, + DRM_MODE_ENCODER_LVDS); + + drm_encoder_helper_add(encoder, &radeon_atom_lvtma_helper_funcs); + radeon_encoder->atom_device = mode_info->bios_connector[bios_index].devices; + + /* TODO get the LVDS info from the BIOS for panel size etc. */ + /* get the lvds info from the bios */ + radeon_get_lvds_info(radeon_encoder); + + /* LVDS gets default RMX full scaling */ + radeon_encoder->rmx_type = RMX_FULL; + + return encoder; +} + +static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + int atom_type = -1; + int index; + + atom_type = atom_dac_find_atom_type(radeon_encoder, NULL); + if (atom_type == -1) + return; + + switch(atom_type) { + case ATOM_DEVICE_CRT1_INDEX: + index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + break; + case ATOM_DEVICE_CRT2_INDEX: + index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + break; + case ATOM_DEVICE_TV1_INDEX: + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + break; + case ATOM_DEVICE_CV_INDEX: + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + break; + default: + return; + } + + switch(mode) { + case DRM_MODE_DPMS_ON: + atombios_display_device_control(encoder, index, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_display_device_control(encoder, index, ATOM_DISABLE); + break; + } +} + +static bool radeon_atom_dac_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_atom_dac_prepare(struct drm_encoder *encoder) +{ + radeon_atom_dac_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_atom_dac_commit(struct drm_encoder *encoder) +{ + radeon_atom_dac_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static int atombios_dac_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + int atom_type) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DAC_ENCODER_CONTROL_PS_ALLOCATION args; + int id = (radeon_encoder->type.dac == DAC_TVDAC); + int index; + + memset(&args, 0, sizeof(args)); + if (id == 0) + index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); + + args.ucAction = 1; + args.usPixelClock = cpu_to_le16(mode->clock / 10); + if ((atom_type == ATOM_DEVICE_CRT1_INDEX) || + (atom_type == ATOM_DEVICE_CRT2_INDEX)) + args.ucDacStandard = id ? ATOM_DAC2_PS2 : ATOM_DAC1_PS2; + else if (atom_type == ATOM_DEVICE_CV_INDEX) + args.ucDacStandard = id ? ATOM_DAC2_CV : ATOM_DAC1_CV; + else if (atom_type == ATOM_DEVICE_TV1_INDEX) + args.ucDacStandard = id ? ATOM_DAC2_NTSC : ATOM_DAC1_NTSC; + /* TODO PAL */ + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + + return 0; +} + +static int atombios_tv1_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + int atom_type) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + TV_ENCODER_CONTROL_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); + + memset(&args, 0, sizeof(args)); + args.sTVEncoder.ucAction = 1; + if (atom_type == ATOM_DEVICE_CV_INDEX) + args.sTVEncoder.ucTvStandard = ATOM_TV_CV; + else { + // TODO PAL + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + } + + args.sTVEncoder.usPixelClock = cpu_to_le16(mode->clock / 10); + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + return 0; +} + +static void radeon_atom_dac_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + int atom_type = -1; + + atom_type = atom_dac_find_atom_type(radeon_encoder, NULL); + if (atom_type == -1) + return; + + atombios_scaler_setup(encoder, mode); + atombios_set_crtc_source(encoder, atom_type); + + atombios_dac_setup(encoder, adjusted_mode, atom_type); + if ((atom_type == ATOM_DEVICE_TV1_INDEX) || + (atom_type == ATOM_DEVICE_CV_INDEX)) + atombios_tv1_setup(encoder, adjusted_mode, atom_type); + +} + +static bool atom_dac_load_detect(struct drm_encoder *encoder, int atom_devices) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + DAC_LOAD_DETECTION_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + + memset(&args, 0, sizeof(args)); + args.sDacload.ucMisc = 0; + args.sDacload.ucDacType = (radeon_encoder->type.dac == DAC_PRIMARY) ? ATOM_DAC_A : ATOM_DAC_B; + + if (atom_devices & ATOM_DEVICE_CRT1_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); + else if (atom_devices & ATOM_DEVICE_CRT2_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); + else if (atom_devices & ATOM_DEVICE_CV_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); + if (radeon_is_dce3(dev_priv)) + args.sDacload.ucMisc = 1; + } else if (atom_devices & ATOM_DEVICE_TV1_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); + if (radeon_is_dce3(dev_priv)) + args.sDacload.ucMisc = 1; + } else + return false; + + DRM_DEBUG("writing %x %x\n", args.sDacload.usDeviceID, args.sDacload.ucDacType); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + return true; +} + +static enum drm_connector_status radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + int atom_type = -1; + uint32_t bios_0_scratch; + + atom_type = atom_dac_find_atom_type(radeon_encoder, connector); + if (atom_type == -1) { + DRM_DEBUG("exit after find \n"); + return connector_status_unknown; + } + + if(!atom_dac_load_detect(encoder, (1 << atom_type))) { + DRM_DEBUG("detect returned false \n"); + return connector_status_unknown; + } + + + if (dev_priv->chip_family >= CHIP_R600) + bios_0_scratch = RADEON_READ(R600_BIOS_0_SCRATCH); + else + bios_0_scratch = RADEON_READ(RADEON_BIOS_0_SCRATCH); + + DRM_DEBUG("Bios 0 scratch %x\n", bios_0_scratch); + if (radeon_encoder->atom_device & ATOM_DEVICE_CRT1_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT1_MASK) + return connector_status_connected; + } else if (radeon_encoder->atom_device & ATOM_DEVICE_CRT2_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT2_MASK) + return connector_status_connected; + } else if (radeon_encoder->atom_device & ATOM_DEVICE_CV_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) + return connector_status_connected; + } else if (radeon_encoder->atom_device & ATOM_DEVICE_TV1_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) + return connector_status_connected; // CTV + else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) + return connector_status_connected; // STV + } + return connector_status_disconnected; +} + +static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { + .dpms = radeon_atom_dac_dpms, + .mode_fixup = radeon_atom_dac_mode_fixup, + .prepare = radeon_atom_dac_prepare, + .mode_set = radeon_atom_dac_mode_set, + .commit = radeon_atom_dac_commit, + .detect = radeon_atom_dac_detect, +}; + +static const struct drm_encoder_funcs radeon_atom_dac_enc_funcs = { + . destroy = radeon_enc_destroy, +}; + + +static void atombios_tmds1_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + TMDS1_ENCODER_CONTROL_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); + + memset(&args, 0, sizeof(args)); + args.ucAction = 1; + if (mode->clock > 165000) + args.ucMisc = 1; + else + args.ucMisc = 0; + + args.usPixelClock = cpu_to_le16(mode->clock / 10); + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void atombios_tmds2_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + TMDS2_ENCODER_CONTROL_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); + + memset(&args, 0, sizeof(args)); + args.ucAction = 1; + if (mode->clock > 165000) + args.ucMisc = 1; + else + args.ucMisc = 0; + + args.usPixelClock = cpu_to_le16(mode->clock / 10); + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + + +static void atombios_ext_tmds_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + + memset(&args, 0, sizeof(args)); + args.sXTmdsEncoder.ucEnable = 1; + + if (mode->clock > 165000) + args.sXTmdsEncoder.ucMisc = 1; + else + args.sXTmdsEncoder.ucMisc = 0; + + // TODO 6-bit DAC +// args.usPixelClock = cpu_to_le16(mode->clock / 10); + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void atombios_dig1_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + DIG_ENCODER_CONTROL_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + + args.ucAction = 1; + args.usPixelClock = mode->clock / 10; + args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER1; + + // TODO coherent mode +// if (encoder->coherent_mode) +// args.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + + if (mode->clock > 165000) { + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B; + args.ucLaneNum = 8; + } else { + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + args.ucLaneNum = 4; + } + + // TODO Encoder MODE + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void atombios_ddia_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + DVO_ENCODER_CONTROL_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + + args.sDVOEncoder.ucAction = ATOM_ENABLE; + args.sDVOEncoder.usPixelClock = mode->clock / 10; + + if (mode->clock > 165000) + args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; + else + args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = 0; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +struct drm_encoder *radeon_encoder_atom_dac_add(struct drm_device *dev, int bios_index, int dac_type, int with_tv) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder = NULL; + struct drm_encoder *encoder; + int type = with_tv ? DRM_MODE_ENCODER_TVDAC : DRM_MODE_ENCODER_DAC; + int found = 0; + int digital_enc_mask = ~(ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT | + ATOM_DEVICE_LCD1_SUPPORT); + /* we may already have added this encoder */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC || + encoder->encoder_type != DRM_MODE_ENCODER_TVDAC) + continue; + + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->type.dac == dac_type) { + found = 1; + break; + } + } + + if (found) { + /* upgrade to a TV controlling DAC */ + if (type == DRM_MODE_ENCODER_TVDAC) + encoder->encoder_type = type; + radeon_encoder->atom_device |= mode_info->bios_connector[bios_index].devices; + radeon_encoder->atom_device &= digital_enc_mask; + return encoder; + } + + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_atom_dac_enc_funcs, + type); + + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + radeon_encoder->type.dac = dac_type; + radeon_encoder->atom_device = mode_info->bios_connector[bios_index].devices; + + /* mask off any digital encoders */ + radeon_encoder->atom_device &= digital_enc_mask; + return encoder; +} + +static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + int atom_type = -1; + int index = -1; + + if (radeon_encoder->atom_device & ATOM_DEVICE_DFP1_SUPPORT) + atom_type = ATOM_DEVICE_DFP1_INDEX; + if (radeon_encoder->atom_device & ATOM_DEVICE_DFP2_SUPPORT) + atom_type = ATOM_DEVICE_DFP2_INDEX; + if (radeon_encoder->atom_device & ATOM_DEVICE_DFP3_SUPPORT) + atom_type = ATOM_DEVICE_DFP3_INDEX; + + if (atom_type == -1) + return; + + switch(atom_type) { + case ATOM_DEVICE_DFP1_INDEX: + index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); + break; + case ATOM_DEVICE_DFP2_INDEX: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; + case ATOM_DEVICE_DFP3_INDEX: + index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); + break; + } + + if (index == -1) + return; + + switch(mode) { + case DRM_MODE_DPMS_ON: + atombios_display_device_control(encoder, index, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_display_device_control(encoder, index, ATOM_DISABLE); + break; + } +} + +static bool radeon_atom_tmds_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_atom_tmds_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + int atom_type; + + if (radeon_encoder->atom_device & ATOM_DEVICE_DFP1_SUPPORT) + atom_type = ATOM_DEVICE_DFP1_INDEX; + if (radeon_encoder->atom_device & ATOM_DEVICE_DFP2_SUPPORT) + atom_type = ATOM_DEVICE_DFP2_INDEX; + if (radeon_encoder->atom_device & ATOM_DEVICE_DFP3_SUPPORT) + atom_type = ATOM_DEVICE_DFP3_INDEX; + + atombios_scaler_setup(encoder, mode); + atombios_set_crtc_source(encoder, atom_type); + + if (atom_type == ATOM_DEVICE_DFP1_INDEX) + atombios_tmds1_setup(encoder, adjusted_mode); + if (atom_type == ATOM_DEVICE_DFP2_INDEX) { + if ((dev_priv->chip_family == CHIP_RS600) || + (dev_priv->chip_family == CHIP_RS690) || + (dev_priv->chip_family == CHIP_RS740)) + atombios_ddia_setup(encoder, adjusted_mode); + else + atombios_ext_tmds_setup(encoder, adjusted_mode); + } + if (atom_type == ATOM_DEVICE_DFP3_INDEX) + atombios_tmds2_setup(encoder, adjusted_mode); + radeon_dfp_disable_dither(encoder, atom_type); + + +} + +static void radeon_atom_tmds_prepare(struct drm_encoder *encoder) +{ + radeon_atom_tmds_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_atom_tmds_commit(struct drm_encoder *encoder) +{ + radeon_atom_tmds_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static const struct drm_encoder_helper_funcs radeon_atom_tmds_helper_funcs = { + .dpms = radeon_atom_tmds_dpms, + .mode_fixup = radeon_atom_tmds_mode_fixup, + .prepare = radeon_atom_tmds_prepare, + .mode_set = radeon_atom_tmds_mode_set, + .commit = radeon_atom_tmds_commit, + /* no detect for TMDS */ +}; + +static const struct drm_encoder_funcs radeon_atom_tmds_enc_funcs = { + . destroy = radeon_enc_destroy, +}; + +struct drm_encoder *radeon_encoder_atom_tmds_add(struct drm_device *dev, int bios_index, int tmds_type) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder = NULL; + struct drm_encoder *encoder; + int analog_enc_mask = ~(ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT); + + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_atom_tmds_enc_funcs, + DRM_MODE_ENCODER_TMDS); + + drm_encoder_helper_add(encoder, &radeon_atom_tmds_helper_funcs); + + radeon_encoder->atom_device = mode_info->bios_connector[bios_index].devices; + + /* mask off any analog encoders */ + radeon_encoder->atom_device &= analog_enc_mask; + return encoder; +} + +static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; +} + +static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) +{ + radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) +{ + radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + +} + +static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { + .dpms = radeon_legacy_lvds_dpms, + .mode_fixup = radeon_lvtma_mode_fixup, + .prepare = radeon_legacy_lvds_prepare, + .mode_set = radeon_legacy_lvds_mode_set, + .commit = radeon_legacy_lvds_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder; + struct drm_encoder *encoder; + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, + DRM_MODE_ENCODER_LVDS); + + drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); + + /* TODO get the LVDS info from the BIOS for panel size etc. */ + /* get the lvds info from the bios */ + radeon_combios_get_lvds_info(radeon_encoder); + + /* LVDS gets default RMX full scaling */ + radeon_encoder->rmx_type = RMX_FULL; + + return encoder; +} diff --git a/linux-core/radeon_fb.c b/linux-core/radeon_fb.c new file mode 100644 index 00000000..5cb118c5 --- /dev/null +++ b/linux-core/radeon_fb.c @@ -0,0 +1,1163 @@ +/* + * Copyright © 2007 David Airlie + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * David Airlie + */ + /* + * Modularization + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drmP.h" +#include "drm.h" +#include "drm_crtc.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +struct radeonfb_par { + struct drm_device *dev; + struct drm_display_mode *our_mode; + struct radeon_framebuffer *radeon_fb; + int crtc_count; + /* crtc currently bound to this */ + uint32_t crtc_ids[2]; +}; +/* +static int +var_to_refresh(const struct fb_var_screeninfo *var) +{ + int xtot = var->xres + var->left_margin + var->right_margin + + var->hsync_len; + int ytot = var->yres + var->upper_margin + var->lower_margin + + var->vsync_len; + + return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot; +}*/ + +static int radeonfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct radeonfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + int i; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_mode_set *modeset = &radeon_crtc->mode_set; + struct drm_framebuffer *fb = modeset->fb; + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + + if (regno > 255) + return 1; + + if (fb->depth == 8) { + radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno); + return 0; + } + + if (regno < 16) { + switch (fb->depth) { + case 15: + fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + } + return 0; +} + +static int radeonfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct radeonfb_par *par = info->par; + struct radeon_framebuffer *radeon_fb = par->radeon_fb; + struct drm_framebuffer *fb = &radeon_fb->base; + int depth; + + if (var->pixclock == -1 || !var->pixclock) + return -EINVAL; + + /* Need to resize the fb object !!! */ + if (var->xres > fb->width || var->yres > fb->height) { + DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); + DRM_ERROR("Need resizing code.\n"); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + depth = var->bits_per_pixel; + break; + } + + switch (depth) { + case 8: + var->red.offset = 0; + var->green.offset = 0; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 15: + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.length = 1; + var->transp.offset = 15; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 24; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* this will let fbcon do the mode init */ +/* FIXME: take mode config lock? */ +static int radeonfb_set_par(struct fb_info *info) +{ + struct radeonfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct fb_var_screeninfo *var = &info->var; + int i; + + DRM_DEBUG("%d %d\n", var->xres, var->pixclock); + + if (var->pixclock != -1) { + + DRM_ERROR("PIXEL CLCOK SET\n"); +#if 0 + struct radeon_framebuffer *radeon_fb = par->radeon_fb; + struct drm_framebuffer *fb = &radeon_fb->base; + struct drm_display_mode *drm_mode, *search_mode; + struct drm_connector *connector = NULL; + struct drm_device *dev = par->dev; + + int found = 0; + + switch (var->bits_per_pixel) { + case 16: + fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + fb->depth = var->bits_per_pixel; + break; + } + + fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = fb->pitch; + info->fix.smem_len = info->fix.line_length * fb->height; + info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + + info->screen_size = info->fix.smem_len; /* ??? */ + /* reuse desired mode if possible */ + /* create a drm mode */ + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode->flags = 0; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; + + drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + + found = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder && + connector->encoder->crtc == par->set.crtc){ + found = 1; + break; + } + } + + /* no connector bound, bail */ + if (!found) + return -EINVAL; + + found = 0; + drm_mode_debug_printmodeline(drm_mode); + list_for_each_entry(search_mode, &connector->modes, head) { + drm_mode_debug_printmodeline(search_mode); + if (drm_mode_equal(drm_mode, search_mode)) { + drm_mode_destroy(dev, drm_mode); + drm_mode = search_mode; + found = 1; + break; + } + } + + /* If we didn't find a matching mode that exists on our connector, + * create a new attachment for the incoming user specified mode + */ + if (!found) { + if (par->our_mode) { + /* this also destroys the mode */ + drm_mode_detachmode_crtc(dev, par->our_mode); + } + + par->set.mode = drm_mode; + par->our_mode = drm_mode; + drm_mode_debug_printmodeline(drm_mode); + /* attach mode */ + drm_mode_attachmode_crtc(dev, par->set.crtc, par->set.mode); + } else { + par->set.mode = drm_mode; + if (par->our_mode) + drm_mode_detachmode_crtc(dev, par->our_mode); + par->our_mode = NULL; + } + return par->set.crtc->funcs->set_config(&par->set); +#endif + return -EINVAL; + } else { + struct drm_crtc *crtc; + int ret; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + if (crtc->fb == radeon_crtc->mode_set.fb) { + ret = crtc->funcs->set_config(&radeon_crtc->mode_set); + if (ret) + return ret; + } + } + return 0; + } +} + +#if 0 +static void radeonfb_copyarea(struct fb_info *info, + const struct fb_copyarea *region) +{ + struct radeonfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset; + u32 cmd, rop_depth_pitch, src_pitch; + RING_LOCALS; + + cmd = XY_SRC_COPY_BLT_CMD; + src_x1 = region->sx; + src_y1 = region->sy; + dst_x1 = region->dx; + dst_y1 = region->dy; + dst_x2 = region->dx + region->width; + dst_y2 = region->dy + region->height; + offset = par->fb->offset; + rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch; + src_pitch = par->fb->pitch; + + switch (par->fb->bits_per_pixel) { + case 16: + rop_depth_pitch |= BLT_DEPTH_16_565; + break; + case 32: + rop_depth_pitch |= BLT_DEPTH_32; + cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; + break; + } + + BEGIN_LP_RING(8); + OUT_RING(cmd); + OUT_RING(rop_depth_pitch); + OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); + OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); + OUT_RING(offset); + OUT_RING((src_y1 << 16) | (src_x1 & 0xffff)); + OUT_RING(src_pitch); + OUT_RING(offset); + ADVANCE_LP_RING(); +} + +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) +#define ROUND_DOWN_TO(x, y) ((x) / (y) * (y)) + +void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct radeonfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 cmd, rop_pitch_depth, tmp; + int nbytes, ndwords, pad; + u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg; + int dat, ix, iy, iw; + int i, j; + RING_LOCALS; + + /* size in bytes of a padded scanline */ + nbytes = ROUND_UP_TO(image->width, 16) / 8; + + /* Total bytes of padded scanline data to write out. */ + nbytes *= image->height; + + /* + * Check if the glyph data exceeds the immediate mode limit. + * It would take a large font (1K pixels) to hit this limit. + */ + if (nbytes > 128 || image->depth != 1) + return cfb_imageblit(info, image); + + /* Src data is packaged a dword (32-bit) at a time. */ + ndwords = ROUND_UP_TO(nbytes, 4) / 4; + + /* + * Ring has to be padded to a quad word. But because the command starts + with 7 bytes, pad only if there is an even number of ndwords + */ + pad = !(ndwords % 2); + + DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width, + image->height, image->depth, image->dx, image->dy); + DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad); + + tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords; + cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp; + offset = par->fb->offset; + dst_x1 = image->dx; + dst_y1 = image->dy; + dst_x2 = image->dx + image->width; + dst_y2 = image->dy + image->height; + rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch; + + switch (par->fb->bits_per_pixel) { + case 8: + rop_pitch_depth |= BLT_DEPTH_8; + fg = image->fg_color; + bg = image->bg_color; + break; + case 16: + rop_pitch_depth |= BLT_DEPTH_16_565; + fg = par->fb->pseudo_palette[image->fg_color]; + bg = par->fb->pseudo_palette[image->bg_color]; + break; + case 32: + rop_pitch_depth |= BLT_DEPTH_32; + cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB; + fg = par->fb->pseudo_palette[image->fg_color]; + bg = par->fb->pseudo_palette[image->bg_color]; + break; + default: + DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel); + break; + } + + BEGIN_LP_RING(8 + ndwords); + OUT_RING(cmd); + OUT_RING(rop_pitch_depth); + OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff)); + OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff)); + OUT_RING(offset); + OUT_RING(bg); + OUT_RING(fg); + ix = iy = 0; + iw = ROUND_UP_TO(image->width, 8) / 8; + while (ndwords--) { + dat = 0; + for (j = 0; j < 2; ++j) { + for (i = 0; i < 2; ++i) { + if (ix != iw || i == 0) + dat |= image->data[iy*iw + ix++] << (i+j*2)*8; + } + if (ix == iw && iy != (image->height - 1)) { + ix = 0; + ++iy; + } + } + OUT_RING(dat); + } + if (pad) + OUT_RING(MI_NOOP); + ADVANCE_LP_RING(); +} +#endif +static int radeonfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct radeonfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_mode_set *modeset; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + int ret = 0; + int i; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + if (i == par->crtc_count) + continue; + + radeon_crtc = to_radeon_crtc(crtc); + modeset = &radeon_crtc->mode_set; + + modeset->x = var->xoffset; + modeset->y = var->yoffset; + + if (modeset->num_connectors) { + ret = crtc->funcs->set_config(modeset); + + if (!ret) { + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + } + } + } + + return ret; +} + +static void radeonfb_on(struct fb_info *info) +{ + struct radeonfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int i; + + /* + * For each CRTC in this fb, find all associated encoders + * and turn them off, then turn off the CRTC. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); + + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); + } + } + } +} + +static void radeonfb_off(struct fb_info *info, int dpms_mode) +{ + struct radeonfb_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int i; + + /* + * For each CRTC in this fb, find all associated encoders + * and turn them off, then turn off the CRTC. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + + for (i = 0; i < par->crtc_count; i++) + if (crtc->base.id == par->crtc_ids[i]) + break; + + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, dpms_mode); + } + } + if (dpms_mode == DRM_MODE_DPMS_OFF) + crtc_funcs->dpms(crtc, dpms_mode); + } +} + +int radeonfb_blank(int blank, struct fb_info *info) +{ + switch (blank) { + case FB_BLANK_UNBLANK: + radeonfb_on(info); + break; + case FB_BLANK_NORMAL: + radeonfb_off(info, DRM_MODE_DPMS_STANDBY); + break; + case FB_BLANK_HSYNC_SUSPEND: + radeonfb_off(info, DRM_MODE_DPMS_STANDBY); + break; + case FB_BLANK_VSYNC_SUSPEND: + radeonfb_off(info, DRM_MODE_DPMS_SUSPEND); + break; + case FB_BLANK_POWERDOWN: + radeonfb_off(info, DRM_MODE_DPMS_OFF); + break; + } + return 0; +} + +static struct fb_ops radeonfb_ops = { + .owner = THIS_MODULE, + //.fb_open = radeonfb_open, + //.fb_read = radeonfb_read, + //.fb_write = radeonfb_write, + //.fb_release = radeonfb_release, + //.fb_ioctl = radeonfb_ioctl, + .fb_check_var = radeonfb_check_var, + .fb_set_par = radeonfb_set_par, + .fb_setcolreg = radeonfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, //radeonfb_copyarea, + .fb_imageblit = cfb_imageblit, //radeonfb_imageblit, + .fb_pan_display = radeonfb_pan_display, + .fb_blank = radeonfb_blank, +}; + +/** + * Curretly it is assumed that the old framebuffer is reused. + * + * LOCKING + * caller should hold the mode config lock. + * + */ +int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_display_mode *mode = crtc->desired_mode; + + fb = crtc->fb; + if (!fb) + return 1; + + info = fb->fbdev; + if (!info) + return 1; + + if (!mode) + return 1; + + info->var.xres = mode->hdisplay; + info->var.right_margin = mode->hsync_start - mode->hdisplay; + info->var.hsync_len = mode->hsync_end - mode->hsync_start; + info->var.left_margin = mode->htotal - mode->hsync_end; + info->var.yres = mode->vdisplay; + info->var.lower_margin = mode->vsync_start - mode->vdisplay; + info->var.vsync_len = mode->vsync_end - mode->vsync_start; + info->var.upper_margin = mode->vtotal - mode->vsync_end; + info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + + return 0; +} +EXPORT_SYMBOL(radeonfb_resize); + +static struct drm_mode_set panic_mode; + +int radeonfb_panic(struct notifier_block *n, unsigned long ununsed, + void *panic_str) +{ + DRM_ERROR("panic occurred, switching back to text console\n"); + drm_crtc_helper_set_config(&panic_mode); + + return 0; +} +EXPORT_SYMBOL(radeonfb_panic); + +static struct notifier_block paniced = { + .notifier_call = radeonfb_panic, +}; + +static int radeon_align_pitch(struct drm_device *dev, int width, int bpp) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int aligned = width; + int align_large = (radeon_is_avivo(dev_priv)); + int pitch_mask = 0; + + switch(bpp / 8) { + case 1: pitch_mask = align_large ? 255 : 127; break; + case 2: pitch_mask = align_large ? 127 : 31; break; + case 3: + case 4: pitch_mask = align_large ? 63 : 15; break; + } + + aligned += pitch_mask; + aligned &= ~pitch_mask; + return aligned; +} + +int radeonfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height, + uint32_t surface_width, uint32_t surface_height, + struct radeon_framebuffer **radeon_fb_p) +{ + struct fb_info *info; + struct radeonfb_par *par; + struct drm_framebuffer *fb; + struct radeon_framebuffer *radeon_fb; + struct drm_mode_fb_cmd mode_cmd; + struct drm_gem_object *fbo = NULL; + struct drm_radeon_gem_object *obj_priv; + struct device *device = &dev->pdev->dev; + int size, aligned_size, ret; + + mode_cmd.width = surface_width;/* crtc->desired_mode->hdisplay; */ + mode_cmd.height = surface_height;/* crtc->desired_mode->vdisplay; */ + + mode_cmd.bpp = 32; + /* need to align pitch with crtc limits */ + mode_cmd.pitch = radeon_align_pitch(dev, mode_cmd.width, mode_cmd.bpp) * ((mode_cmd.bpp + 1) / 8); + mode_cmd.depth = 24; + + size = mode_cmd.pitch * mode_cmd.height; + aligned_size = ALIGN(size, PAGE_SIZE); + + fbo = radeon_gem_object_alloc(dev, aligned_size, 1, RADEON_GEM_DOMAIN_VRAM); + if (!fbo) { + printk(KERN_ERR "failed to allocate framebuffer\n"); + ret = -ENOMEM; + goto out; + } + obj_priv = fbo->driver_private; + + ret = radeon_gem_object_pin(fbo, PAGE_SIZE); + if (ret) { + DRM_ERROR("failed to pin fb: %d\n", ret); + mutex_lock(&dev->struct_mutex); + goto out_unref; + } + + mutex_lock(&dev->struct_mutex); + fb = radeon_user_framebuffer_create(dev, NULL, &mode_cmd); + if (!fb) { + DRM_ERROR("failed to allocate fb.\n"); + ret = -ENOMEM; + goto out_unref; + } + + list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); + + radeon_fb = to_radeon_framebuffer(fb); + *radeon_fb_p = radeon_fb; + + radeon_fb->obj = fbo; + + info = framebuffer_alloc(sizeof(struct radeonfb_par), device); + if (!info) { + ret = -ENOMEM; + goto out_unref; + } + + par = info->par; + + strcpy(info->fix.id, "radeondrmfb"); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.type_aux = 0; + info->fix.xpanstep = 1; /* doing it in hw */ + info->fix.ypanstep = 1; /* doing it in hw */ + info->fix.ywrapstep = 0; + info->fix.accel = FB_ACCEL_I830; + info->fix.type_aux = 0; + + info->flags = FBINFO_DEFAULT; + + info->fbops = &radeonfb_ops; + + info->fix.line_length = fb->pitch; + info->fix.smem_start = dev->mode_config.fb_base + obj_priv->bo->offset; + info->fix.smem_len = size; + + info->flags = FBINFO_DEFAULT; + + ret = drm_bo_kmap(obj_priv->bo, 0, PAGE_ALIGN(size) >> PAGE_SHIFT, + &radeon_fb->kmap_obj); + info->screen_base = radeon_fb->kmap_obj.virtual; + if (!info->screen_base) { + ret = -ENOSPC; + goto out_unref; + } + info->screen_size = size; + + memset(info->screen_base, 0, size); + + info->pseudo_palette = fb->pseudo_palette; + info->var.xres_virtual = fb->width; + info->var.yres_virtual = fb->height; + info->var.bits_per_pixel = fb->bits_per_pixel; + info->var.xoffset = 0; + info->var.yoffset = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + + info->var.xres = fb_width; + info->var.yres = fb_height; + + info->fix.mmio_start = pci_resource_start(dev->pdev, 2); + info->fix.mmio_len = pci_resource_len(dev->pdev, 2); + + info->pixmap.size = 64*1024; + info->pixmap.buf_align = 8; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + info->pixmap.scan_align = 1; + + DRM_DEBUG("fb depth is %d\n", fb->depth); + DRM_DEBUG(" pitch is %d\n", fb->pitch); + switch(fb->depth) { + case 8: + info->var.red.offset = 0; + info->var.green.offset = 0; + info->var.blue.offset = 0; + info->var.red.length = 8; /* 8bit DAC */ + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; + case 15: + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 5; + info->var.blue.length = 5; + info->var.transp.offset = 15; + info->var.transp.length = 1; + break; + case 16: + info->var.red.offset = 11; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 6; + info->var.blue.length = 5; + info->var.transp.offset = 0; + break; + case 24: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; + case 32: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 24; + info->var.transp.length = 8; + break; + default: + break; + } + + fb->fbdev = info; + + par->radeon_fb = radeon_fb; + par->dev = dev; + + /* To allow resizeing without swapping buffers */ + printk("allocated %p %dx%d fb: 0x%08x, bo %p\n", dev, radeon_fb->base.width, + radeon_fb->base.height, obj_priv->bo->offset, fbo); + + mutex_unlock(&dev->struct_mutex); + return 0; + +out_unref: + drm_gem_object_unreference(fbo); + mutex_unlock(&dev->struct_mutex); +out: + return ret; +} + +static int radeonfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_framebuffer *radeon_fb; + struct drm_framebuffer *fb; + struct drm_connector *connector; + struct fb_info *info; + struct radeonfb_par *par; + struct drm_mode_set *modeset; + unsigned int width, height; + int new_fb = 0; + int ret, i, conn_count; + + if (!drm_helper_crtc_in_use(crtc)) + return 0; + + if (!crtc->desired_mode) + return 0; + + width = crtc->desired_mode->hdisplay; + height = crtc->desired_mode->vdisplay; + + /* is there an fb bound to this crtc already */ + if (!radeon_crtc->mode_set.fb) { + ret = radeonfb_create(dev, width, height, width, height, &radeon_fb); + if (ret) + return -EINVAL; + new_fb = 1; + } else { + fb = radeon_crtc->mode_set.fb; + radeon_fb = to_radeon_framebuffer(fb); + if ((radeon_fb->base.width < width) || (radeon_fb->base.height < height)) + return -EINVAL; + } + + info = radeon_fb->base.fbdev; + par = info->par; + + modeset = &radeon_crtc->mode_set; + modeset->fb = &radeon_fb->base; + conn_count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if (connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; + conn_count++; + if (conn_count > RADEONFB_CONN_LIMIT) + BUG(); + } + } + + for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; + + par->crtc_ids[0] = crtc->base.id; + + modeset->num_connectors = conn_count; + if (modeset->mode != modeset->crtc->desired_mode) + modeset->mode = modeset->crtc->desired_mode; + + par->crtc_count = 1; + + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } else + radeonfb_set_par(info); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + + /* Switch back to kernel console on panic */ + panic_mode = *modeset; + atomic_notifier_chain_register(&panic_notifier_list, &paniced); + printk(KERN_INFO "registered panic notifier\n"); + + return 0; +} + +static int radeonfb_multi_fb_probe(struct drm_device *dev) +{ + + struct drm_crtc *crtc; + int ret = 0; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + ret = radeonfb_multi_fb_probe_crtc(dev, crtc); + if (ret) + return ret; + } + return ret; +} + +static int radeonfb_single_fb_probe(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_connector *connector; + unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; + unsigned int surface_width = 0, surface_height = 0; + int new_fb = 0; + int crtc_count = 0; + int ret, i, conn_count = 0; + struct radeon_framebuffer *radeon_fb; + struct fb_info *info; + struct radeonfb_par *par; + struct drm_mode_set *modeset = NULL; + + DRM_DEBUG("\n"); + /* first up get a count of crtcs now in use and new min/maxes width/heights */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (drm_helper_crtc_in_use(crtc)) { + if (crtc->desired_mode) { + if (crtc->desired_mode->hdisplay < fb_width) + fb_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay < fb_height) + fb_height = crtc->desired_mode->vdisplay; + + if (crtc->desired_mode->hdisplay > surface_width) + surface_width = crtc->desired_mode->hdisplay; + + if (crtc->desired_mode->vdisplay > surface_height) + surface_height = crtc->desired_mode->vdisplay; + + } + crtc_count++; + } + } + + if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { + /* hmm everyone went away - assume VGA cable just fell out + and will come back later. */ + return 0; + } + + /* do we have an fb already? */ + if (list_empty(&dev->mode_config.fb_kernel_list)) { + /* create an fb if we don't have one */ + ret = radeonfb_create(dev, fb_width, fb_height, surface_width, surface_height, &radeon_fb); + if (ret) + return -EINVAL; + new_fb = 1; + } else { + struct drm_framebuffer *fb; + fb = list_first_entry(&dev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head); + radeon_fb = to_radeon_framebuffer(fb); + + /* if someone hotplugs something bigger than we have already allocated, we are pwned. + As really we can't resize an fbdev that is in the wild currently due to fbdev + not really being designed for the lower layers moving stuff around under it. + - so in the grand style of things - punt. */ + if ((fb->width < surface_width) || (fb->height < surface_height)) { + DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); + return -EINVAL; + } + } + + info = radeon_fb->base.fbdev; + par = info->par; + + crtc_count = 0; + /* okay we need to setup new connector sets in the crtcs */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + modeset = &radeon_crtc->mode_set; + modeset->fb = &radeon_fb->base; + conn_count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder) + if(connector->encoder->crtc == modeset->crtc) { + modeset->connectors[conn_count] = connector; + conn_count++; + if (conn_count > RADEONFB_CONN_LIMIT) + BUG(); + } + } + + for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++) + modeset->connectors[i] = NULL; + + + par->crtc_ids[crtc_count++] = crtc->base.id; + + modeset->num_connectors = conn_count; + if (modeset->mode != modeset->crtc->desired_mode) + modeset->mode = modeset->crtc->desired_mode; + } + par->crtc_count = crtc_count; + + if (new_fb) { + info->var.pixclock = -1; + if (register_framebuffer(info) < 0) + return -EINVAL; + } else + radeonfb_set_par(info); + + printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, + info->fix.id); + + /* Switch back to kernel console on panic */ + panic_mode = *modeset; + atomic_notifier_chain_register(&panic_notifier_list, &paniced); + printk(KERN_INFO "registered panic notifier\n"); + + return 0; +} + +int radeonfb_probe(struct drm_device *dev) +{ + int ret; + + DRM_DEBUG("\n"); + + /* something has changed in the lower levels of hell - deal with it + here */ + + /* two modes : a) 1 fb to rule all crtcs. + b) one fb per crtc. + two actions 1) new connected device + 2) device removed. + case a/1 : if the fb surface isn't big enough - resize the surface fb. + if the fb size isn't big enough - resize fb into surface. + if everything big enough configure the new crtc/etc. + case a/2 : undo the configuration + possibly resize down the fb to fit the new configuration. + case b/1 : see if it is on a new crtc - setup a new fb and add it. + case b/2 : teardown the new fb. + */ + + /* mode a first */ + /* search for an fb */ + // if (radeon_fbpercrtc == 1) { + // ret = radeonfb_multi_fb_probe(dev); + // } else { + ret = radeonfb_single_fb_probe(dev); + // } + + return ret; +} +EXPORT_SYMBOL(radeonfb_probe); + +int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) +{ + struct fb_info *info; + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + + if (!fb) + return -EINVAL; + + info = fb->fbdev; + + if (info) { + unregister_framebuffer(info); + drm_bo_kunmap(&radeon_fb->kmap_obj); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(radeon_fb->obj); + mutex_unlock(&dev->struct_mutex); + framebuffer_release(info); + } + + atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); + memset(&panic_mode, 0, sizeof(struct drm_mode_set)); + return 0; +} +EXPORT_SYMBOL(radeonfb_remove); +MODULE_LICENSE("GPL"); diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c new file mode 100644 index 00000000..1b327369 --- /dev/null +++ b/linux-core/radeon_fence.c @@ -0,0 +1,96 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type) +{ + struct drm_radeon_private *dev_priv = (struct drm_radeon_private *) dev->dev_private; + RING_LOCALS; + + if (!dev_priv) + return -EINVAL; + + radeon_emit_irq(dev); + *sequence = (uint32_t) dev_priv->counter; + *native_type = DRM_FENCE_TYPE_EXE; + + return 0; +} + +static void radeon_fence_poll(struct drm_device *dev, uint32_t fence_class, + uint32_t waiting_types) +{ + struct drm_radeon_private *dev_priv = (struct drm_radeon_private *) dev->dev_private; + uint32_t sequence; + if (waiting_types & DRM_FENCE_TYPE_EXE) { + + sequence = READ_BREADCRUMB(dev_priv); + + drm_fence_handler(dev, 0, sequence, + DRM_FENCE_TYPE_EXE, 0); + } +} + +void radeon_fence_handler(struct drm_device * dev) +{ + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[0]; + + write_lock(&fm->lock); + radeon_fence_poll(dev, 0, fc->waiting_types); + write_unlock(&fm->lock); +} + +int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags) +{ + /* + * We have an irq that tells us when we have a new breadcrumb. + */ + return 1; +} + + +struct drm_fence_driver radeon_fence_driver = { + .num_classes = 1, + .wrap_diff = (1U << (BREADCRUMB_BITS -1)), + .flush_diff = (1U << (BREADCRUMB_BITS - 2)), + .sequence_mask = BREADCRUMB_MASK, + .emit = radeon_fence_emit_sequence, + .has_irq = radeon_fence_has_irq, + .poll = radeon_fence_poll, +}; + diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c new file mode 100644 index 00000000..d536aed2 --- /dev/null +++ b/linux-core/radeon_gem.c @@ -0,0 +1,687 @@ +/* + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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. + * + * Author: Dave Airlie + */ +#include "drmP.h" +#include "drm.h" + +#include "radeon_drm.h" +#include "radeon_drv.h" + +int radeon_gem_init_object(struct drm_gem_object *obj) +{ + struct drm_radeon_gem_object *obj_priv; + + obj_priv = drm_calloc(1, sizeof(*obj_priv), DRM_MEM_DRIVER); + if (!obj_priv) { + return -ENOMEM; + } + + obj->driver_private = obj_priv; + obj_priv->obj = obj; + + return 0; +} + +void radeon_gem_free_object(struct drm_gem_object *obj) +{ + + struct drm_radeon_gem_object *obj_priv = obj->driver_private; + + /* tear down the buffer object - gem holds struct mutex */ + drm_bo_takedown_vm_locked(obj_priv->bo); + drm_bo_usage_deref_locked(&obj_priv->bo); + drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); +} + +int radeon_gem_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_radeon_gem_info *args = data; + + args->vram_start = dev_priv->mm.vram_offset; + args->vram_size = dev_priv->mm.vram_size; + args->vram_visible = dev_priv->mm.vram_visible; + + args->gart_start = dev_priv->mm.gart_start; + args->gart_size = dev_priv->mm.gart_size; + + return 0; +} + +struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, + int initial_domain) +{ + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + int ret; + uint32_t flags; + + DRM_DEBUG("size 0x%x, alignment %d, initial_domain %d\n", size, alignment, initial_domain); + obj = drm_gem_object_alloc(dev, size); + if (!obj) + return NULL;; + + obj_priv = obj->driver_private; + if (initial_domain == RADEON_GEM_DOMAIN_VRAM) + flags = DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MAPPABLE; + else + flags = DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MAPPABLE; + + flags |= DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE; + /* create a TTM BO */ + ret = drm_buffer_object_create(dev, + size, drm_bo_type_device, + flags, 0, alignment, + 0, &obj_priv->bo); + if (ret) + goto fail; + + return obj; +fail: + + return NULL; +} + +int radeon_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_gem_create *args = data; + struct drm_radeon_gem_object *obj_priv; + struct drm_gem_object *obj; + int ret = 0; + uint32_t flags; + int handle; + + /* create a gem object to contain this object in */ + args->size = roundup(args->size, PAGE_SIZE); + + obj = radeon_gem_object_alloc(dev, args->size, args->alignment, args->initial_domain); + if (!obj) + return -EINVAL; + + obj_priv = obj->driver_private; + DRM_DEBUG("obj is %p bo is %p, %d\n", obj, obj_priv->bo, obj_priv->bo->num_pages); + ret = drm_gem_handle_create(file_priv, obj, &handle); + mutex_lock(&dev->struct_mutex); + drm_gem_object_handle_unreference(obj); + mutex_unlock(&dev->struct_mutex); + + if (ret) + goto fail; + + args->handle = handle; + + return 0; +fail: + drm_gem_object_unreference(obj); + + return ret; +} + +int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + /* transition the BO to a domain - just validate the BO into a certain domain */ + struct drm_radeon_gem_set_domain *args = data; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + int ret; + /* for now if someone requests domain CPU - just make sure the buffer is finished with */ + + /* just do a BO wait for now */ + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + obj_priv = obj->driver_private; + + mutex_lock(&obj_priv->bo->mutex); + ret = drm_bo_wait(obj_priv->bo, 0, 1, 0, 0); + mutex_unlock(&obj_priv->bo->mutex); + + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -ENOSYS; +} + +int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -ENOSYS; +} + +int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_gem_mmap *args = data; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + loff_t offset; + unsigned long addr; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + offset = args->offset; + + DRM_DEBUG("got here %p\n", obj); + obj_priv = obj->driver_private; + + DRM_DEBUG("got here %p %p %lld %ld\n", obj, obj_priv->bo, args->size, obj_priv->bo->num_pages); + if (!obj_priv->bo) { + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + + down_write(¤t->mm->mmap_sem); + addr = do_mmap_pgoff(file_priv->filp, 0, args->size, + PROT_READ | PROT_WRITE, MAP_SHARED, + obj_priv->bo->map_list.hash.key); + up_write(¤t->mm->mmap_sem); + + DRM_DEBUG("got here %p\n", obj); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + if (IS_ERR((void *)addr)) + return addr; + + args->addr_ptr = (uint64_t) addr; + + return 0; + +} + +int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_gem_pin *args = data; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + int ret; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + obj_priv = obj->driver_private; + + DRM_DEBUG("got here %p %p %d\n", obj, obj_priv->bo, atomic_read(&obj_priv->bo->usage)); + /* validate into a pin with no fence */ + + ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, + 0, NULL); + + args->offset = obj_priv->bo->offset; + DRM_DEBUG("got here %p %p\n", obj, obj_priv->bo); + + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_gem_unpin *args = data; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + int ret; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + obj_priv = obj->driver_private; + + /* validate into a pin with no fence */ + + ret = drm_bo_do_validate(obj_priv->bo, DRM_BO_FLAG_NO_EVICT, DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, + 0, NULL); + + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int radeon_gem_busy(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} + +int radeon_gem_execbuffer(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return -ENOSYS; + + +} + +int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_gem_indirect *args = data; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + uint32_t start, end; + int ret; + RING_LOCALS; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + obj_priv = obj->driver_private; + + DRM_DEBUG("got here %p %d\n", obj, args->used); + //RING_SPACE_TEST_WITH_RETURN(dev_priv); + //VB_AGE_TEST_WITH_RETURN(dev_priv); + + ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, + 0 , 0, NULL); + if (ret) + return ret; + + /* Wait for the 3D stream to idle before the indirect buffer + * containing 2D acceleration commands is processed. + */ + BEGIN_RING(2); + + RADEON_WAIT_UNTIL_3D_IDLE(); + + ADVANCE_RING(); + + start = 0; + end = args->used; + + if (start != end) { + int offset = (dev_priv->gart_vm_start + + + obj_priv->bo->offset + start); + int dwords = (end - start + 3) / sizeof(u32); + +#if 0 + /* Indirect buffer data must be an even number of + * dwords, so if we've been given an odd number we must + * pad the data with a Type-2 CP packet. + */ + if (dwords & 1) { + u32 *data = (u32 *) + ((char *)dev->agp_buffer_map->handle + + buf->offset + start); + data[dwords++] = RADEON_CP_PACKET2; + } +#endif + /* Fire off the indirect buffer */ + BEGIN_RING(3); + + OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); + OUT_RING(offset); + OUT_RING(dwords); + + ADVANCE_RING(); + } + + COMMIT_RING(); + + /* we need to fence the buffer */ + ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &obj_priv->fence); + if (ret) { + + drm_putback_buffer_objects(dev); + ret = 0; + goto fail; + } + + /* dereference he fence object */ + drm_fence_usage_deref_unlocked(&obj_priv->fence); + + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + ret = 0; + fail: + return ret; +} + +/* + * Depending on card genertation, chipset bugs, etc... the amount of vram + * accessible to the CPU can vary. This function is our best shot at figuring + * it out. Returns a value in KB. + */ +static uint32_t radeon_get_accessible_vram(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t aper_size; + u8 byte; + + if (dev_priv->chip_family >= CHIP_R600) + aper_size = RADEON_READ(R600_CONFIG_APER_SIZE) / 1024; + else + aper_size = RADEON_READ(RADEON_CONFIG_APER_SIZE) / 1024; + + /* Set HDP_APER_CNTL only on cards that are known not to be broken, + * that is has the 2nd generation multifunction PCI interface + */ + if (dev_priv->chip_family == CHIP_RV280 || + dev_priv->chip_family == CHIP_RV350 || + dev_priv->chip_family == CHIP_RV380 || + dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_RV410 || + dev_priv->chip_family >= CHIP_RS600) { + uint32_t temp = RADEON_READ(RADEON_HOST_PATH_CNTL); + temp |= RADEON_HDP_APER_CNTL; + RADEON_WRITE(RADEON_HOST_PATH_CNTL, temp); + return aper_size * 2; + } + + /* Older cards have all sorts of funny issues to deal with. First + * check if it's a multifunction card by reading the PCI config + * header type... Limit those to one aperture size + */ + pci_read_config_byte(dev->pdev, 0xe, &byte); + if (byte & 0x80) + return aper_size; + + /* Single function older card. We read HDP_APER_CNTL to see how the BIOS + * have set it up. We don't write this as it's broken on some ASICs but + * we expect the BIOS to have done the right thing (might be too optimistic...) + */ + if (RADEON_READ(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL) + return aper_size * 2; + + return aper_size; +} + +/* code from the DDX - do memory sizing */ +void radeon_vram_setup(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t vram; + uint32_t accessible, bar_size; + + if ((dev_priv->chip_family <= CHIP_RV515) && (dev_priv->flags & RADEON_IS_IGP)) { + uint32_t tom = RADEON_READ(RADEON_NB_TOM); + + vram = (((tom >> 16) - (tom & 0xffff) + 1) << 6); + RADEON_WRITE(RADEON_CONFIG_MEMSIZE, vram * 1024); + } else { + if (dev_priv->chip_family >= CHIP_R600) + vram = RADEON_READ(R600_CONFIG_MEMSIZE) / 1024; + else { + vram = RADEON_READ(RADEON_CONFIG_MEMSIZE) / 1024; + + /* Some production boards of m6 will return 0 if it's 8 MB */ + if (vram == 0) { + vram = 8192; + RADEON_WRITE(RADEON_CONFIG_MEMSIZE, 0x800000); + } + } + } + + accessible = radeon_get_accessible_vram(dev); + + bar_size = drm_get_resource_len(dev, 0) / 1024; + if (bar_size == 0) + bar_size = 0x20000; + if (accessible > bar_size) + accessible = bar_size; + + DRM_INFO("Detected VRAM RAM=%dK, accessible=%uK, BAR=%uK\n", + vram, accessible, bar_size); + + dev_priv->mm.vram_offset = dev_priv->fb_aper_offset; + dev_priv->mm.vram_size = vram * 1024; + dev_priv->mm.vram_visible = accessible * 1024; + + +} + +static int radeon_gart_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; + u32 base = 0; + + /* setup a 32MB GART */ + dev_priv->gart_size = dev_priv->mm.gart_size; + +#if __OS_HAS_AGP + /* setup VRAM vs GART here */ + if (dev_priv->flags & RADEON_IS_AGP) { + base = dev->agp->base; + if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location && + base < (dev_priv->fb_location + dev_priv->fb_size - 1)) { + DRM_INFO("Can't use agp base @0x%08xlx, won't fit\n", + dev->agp->base); + base = 0; + } + } +#endif + + if (base == 0) { + base = dev_priv->fb_location + dev_priv->fb_size; + if (base < dev_priv->fb_location || + ((base + dev_priv->gart_size) & 0xfffffffful) < base) + base = dev_priv->fb_location + - dev_priv->gart_size; + } + /* start on the card */ + dev_priv->gart_vm_start = base & 0xffc00000u; + if (dev_priv->gart_vm_start != base) + DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n", + base, dev_priv->gart_vm_start); + + /* if on PCIE we need to allocate an fb object for the PCIE GART table */ + if (dev_priv->flags & RADEON_IS_PCIE) { + ret = drm_buffer_object_create(dev, RADEON_PCIGART_TABLE_SIZE, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_NO_EVICT, + 0, 1, 0, &dev_priv->mm.pcie_table); + if (ret) + return -EINVAL; + + DRM_DEBUG("pcie table bo created %p, %x\n", dev_priv->mm.pcie_table, dev_priv->mm.pcie_table->offset); + ret = drm_bo_kmap(dev_priv->mm.pcie_table, 0, RADEON_PCIGART_TABLE_SIZE >> PAGE_SHIFT, + &dev_priv->mm.pcie_table_map); + if (ret) + return -EINVAL; + + dev_priv->pcigart_offset_set = 2; + dev_priv->gart_info.bus_addr = dev_priv->fb_location + dev_priv->mm.pcie_table->offset; + dev_priv->gart_info.addr = dev_priv->mm.pcie_table_map.virtual; + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; + dev_priv->gart_info.gart_table_location = DRM_ATI_GART_FB; + memset(dev_priv->gart_info.addr, 0, RADEON_PCIGART_TABLE_SIZE); + } else if (!(dev_priv->flags & RADEON_IS_AGP)) { + /* allocate PCI GART table */ + dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); + ret = drm_ati_alloc_pcigart_table(dev, &dev_priv->gart_info); + if (ret) { + DRM_ERROR("cannot allocate PCI GART page!\n"); + return -EINVAL; + } + + dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; + if (dev_priv->flags & RADEON_IS_IGPGART) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; + dev_priv->gart_info.addr = NULL; + dev_priv->gart_info.bus_addr = 0; + } + + /* gart values setup - start the GART */ + if (dev_priv->flags & RADEON_IS_AGP) { + radeon_set_pcigart(dev_priv, 0); + } else { + radeon_set_pcigart(dev_priv, 1); + } + + return 0; +} + +int radeon_alloc_gart_objects(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; + + ret = drm_buffer_object_create(dev, RADEON_DEFAULT_RING_SIZE, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_NO_EVICT, + 0, 1, 0, &dev_priv->mm.ring); + if (ret) { + DRM_ERROR("failed to allocate ring\n"); + return -EINVAL; + } + + ret = drm_bo_kmap(dev_priv->mm.ring, 0, RADEON_DEFAULT_RING_SIZE >> PAGE_SHIFT, + &dev_priv->mm.ring_map); + if (ret) { + DRM_ERROR("failed to map ring\n"); + return -EINVAL; + } + + ret = drm_buffer_object_create(dev, PAGE_SIZE, + drm_bo_type_kernel, + DRM_BO_FLAG_WRITE |DRM_BO_FLAG_READ | DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_NO_EVICT, + 0, 1, 0, &dev_priv->mm.ring_read_ptr); + if (ret) { + DRM_ERROR("failed to allocate ring read\n"); + return -EINVAL; + } + + ret = drm_bo_kmap(dev_priv->mm.ring_read_ptr, 0, + PAGE_SIZE >> PAGE_SHIFT, + &dev_priv->mm.ring_read_ptr_map); + if (ret) { + DRM_ERROR("failed to map ring read\n"); + return -EINVAL; + } + + DRM_DEBUG("Ring ptr %p mapped at %d %p, read ptr %p maped at %d %p\n", + dev_priv->mm.ring, dev_priv->mm.ring->offset, dev_priv->mm.ring_map.virtual, + dev_priv->mm.ring_read_ptr, dev_priv->mm.ring_read_ptr->offset, dev_priv->mm.ring_read_ptr_map.virtual); + + return 0; + +} + +/* init memory manager - start with all of VRAM and a 32MB GART aperture for now */ +int radeon_gem_mm_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; + + /* size the mappable VRAM memory for now */ + radeon_vram_setup(dev); + + drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, /*dev_priv->mm.vram_offset >> PAGE_SHIFT,*/ + (dev_priv->mm.vram_visible) >> PAGE_SHIFT, + 0); + + + dev_priv->mm.gart_size = (32 * 1024 * 1024); + dev_priv->mm.gart_start = 0; + ret = radeon_gart_init(dev); + if (ret) + return -EINVAL; + + drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0, + dev_priv->mm.gart_size >> PAGE_SHIFT, + 0); + + /* need to allocate some objects in the GART */ + /* ring + ring read ptr */ + ret = radeon_alloc_gart_objects(dev); + if (ret) + return -EINVAL; + return 0; +} + +void radeon_gem_mm_fini(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + mutex_lock(&dev->struct_mutex); + + if (dev_priv->mm.ring_read_ptr) { + drm_bo_kunmap(&dev_priv->mm.ring_read_ptr_map); + drm_bo_usage_deref_locked(&dev_priv->mm.ring_read_ptr); + } + + if (dev_priv->mm.ring) { + drm_bo_kunmap(&dev_priv->mm.ring_map); + drm_bo_usage_deref_locked(&dev_priv->mm.ring); + } + + if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { + DRM_DEBUG("delaying takedown of TTM memory\n"); + } + + if (dev_priv->flags & RADEON_IS_PCIE) { + if (dev_priv->mm.pcie_table) { + drm_bo_kunmap(&dev_priv->mm.pcie_table_map); + drm_bo_usage_deref_locked(&dev_priv->mm.pcie_table); + } + } + + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { + DRM_DEBUG("delaying takedown of TTM memory\n"); + } + + mutex_unlock(&dev->struct_mutex); +} + +int radeon_gem_object_pin(struct drm_gem_object *obj, + uint32_t alignment) +{ + struct drm_radeon_gem_object *obj_priv; + int ret; + + obj_priv = obj->driver_private; + + ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0, NULL); + + return ret; +} + diff --git a/linux-core/radeon_i2c.c b/linux-core/radeon_i2c.c new file mode 100644 index 00000000..eccec650 --- /dev/null +++ b/linux-core/radeon_i2c.c @@ -0,0 +1,131 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + + +static int get_clock(void *i2c_priv) +{ + struct radeon_i2c_chan *i2c = i2c_priv; + struct drm_radeon_private *dev_priv = i2c->dev->dev_private; + struct radeon_i2c_bus_rec *rec = &i2c->rec; + uint32_t val; + + val = RADEON_READ(rec->get_clk_reg); + val &= rec->get_clk_mask; + + return (val != 0); +} + + +static int get_data(void *i2c_priv) +{ + struct radeon_i2c_chan *i2c = i2c_priv; + struct drm_radeon_private *dev_priv = i2c->dev->dev_private; + struct radeon_i2c_bus_rec *rec = &i2c->rec; + uint32_t val; + + val = RADEON_READ(rec->get_data_reg); + val &= rec->get_data_mask; + return (val != 0); +} + +static void set_clock(void *i2c_priv, int clock) +{ + struct radeon_i2c_chan *i2c = i2c_priv; + struct drm_radeon_private *dev_priv = i2c->dev->dev_private; + struct radeon_i2c_bus_rec *rec = &i2c->rec; + uint32_t val; + + val = RADEON_READ(rec->put_clk_reg) & (uint32_t)~(rec->put_clk_mask); + val |= clock ? 0 : rec->put_clk_mask; + RADEON_WRITE(rec->put_clk_reg, val); +} + +static void set_data(void *i2c_priv, int data) +{ + struct radeon_i2c_chan *i2c = i2c_priv; + struct drm_radeon_private *dev_priv = i2c->dev->dev_private; + struct radeon_i2c_bus_rec *rec = &i2c->rec; + uint32_t val; + + val = RADEON_READ(rec->put_data_reg) & (uint32_t)~(rec->put_data_mask); + val |= data ? 0 : rec->put_data_mask; + RADEON_WRITE(rec->put_data_reg, val); +} + +struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, + struct radeon_i2c_bus_rec *rec, + const char *name) +{ + struct radeon_i2c_chan *i2c; + int ret; + + i2c = drm_calloc(1, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); + if (i2c == NULL) + return NULL; + + i2c->adapter.owner = THIS_MODULE; + i2c->adapter.id = I2C_HW_B_RADEON; + i2c->adapter.algo_data = &i2c->algo; + i2c->dev = dev; + i2c->algo.setsda = set_data; + i2c->algo.setscl = set_clock; + i2c->algo.getsda = get_data; + i2c->algo.getscl = get_clock; + i2c->algo.udelay = 20; + i2c->algo.timeout = usecs_to_jiffies(2200); + i2c->algo.data = i2c; + i2c->rec = *rec; + i2c_set_adapdata(&i2c->adapter, i2c); + + ret = i2c_bit_add_bus(&i2c->adapter); + if (ret) { + DRM_INFO("Failed to register i2c %s\n", name); + goto out_free; + } + + return i2c; +out_free: + drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); + return NULL; + +} + +void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) +{ + if (!i2c) + return; + + i2c_del_adapter(&i2c->adapter); + drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); +} + +struct drm_encoder *radeon_best_encoder(struct drm_connector *connector) +{ + return NULL; +} diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h new file mode 100644 index 00000000..f75e8272 --- /dev/null +++ b/linux-core/radeon_mode.h @@ -0,0 +1,255 @@ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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. + * + * Original Authors: + * Kevin E. Martin, Rickard E. Faith, Alan Hourihane + * + * Kernel port Author: Dave Airlie + */ + +#ifndef RADEON_MODE_H +#define RADEON_MODE_H + +#include +#include +#include + +#define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base) +#define to_radeon_connector(x) container_of(x, struct radeon_connector, base) +#define to_radeon_encoder(x) container_of(x, struct radeon_encoder, base) +#define to_radeon_framebuffer(x) container_of(x, struct radeon_framebuffer, base) + +enum radeon_connector_type { + CONNECTOR_NONE, + CONNECTOR_VGA, + CONNECTOR_DVI_I, + CONNECTOR_DVI_D, + CONNECTOR_DVI_A, + CONNECTOR_STV, + CONNECTOR_CTV, + CONNECTOR_LVDS, + CONNECTOR_DIGITAL, + CONNECTOR_SCART, + CONNECTOR_HDMI_TYPE_A, + CONNECTOR_HDMI_TYPE_B, + CONNECTOR_0XC, + CONNECTOR_0XD, + CONNECTOR_DIN, + CONNECTOR_DISPLAY_PORT, + CONNECTOR_UNSUPPORTED +}; + +enum radeon_dac_type { + DAC_NONE = 0, + DAC_PRIMARY = 1, + DAC_TVDAC = 2, + DAC_EXT = 3 +}; + +enum radeon_tmds_type { + TMDS_NONE = 0, + TMDS_INT = 1, + TMDS_EXT = 2, + TMDS_LVTMA = 3, + TMDS_DDIA = 4, + TMDS_UNIPHY = 5 +}; + +enum radeon_dvi_type { + DVI_AUTO, + DVI_DIGITAL, + DVI_ANALOG +}; + +enum radeon_rmx_type { + RMX_OFF, + RMX_FULL, + RMX_CENTER, +}; + +struct radeon_i2c_bus_rec { + bool valid; + uint32_t mask_clk_reg; + uint32_t mask_data_reg; + uint32_t put_clk_reg; + uint32_t put_data_reg; + uint32_t get_clk_reg; + uint32_t get_data_reg; + uint32_t mask_clk_mask; + uint32_t mask_data_mask; + uint32_t put_clk_mask; + uint32_t put_data_mask; + uint32_t get_clk_mask; + uint32_t get_data_mask; +}; + +struct radeon_bios_connector { + enum radeon_dac_type dac_type; + enum radeon_tmds_type tmds_type; + enum radeon_connector_type connector_type; + bool valid; + int output_id; + int devices; + int hpd_mask; + struct radeon_i2c_bus_rec ddc_i2c; + int igp_lane_info; +}; + +#define RADEON_MAX_BIOS_CONNECTOR 16 + +#define RADEON_PLL_USE_BIOS_DIVS (1 << 0) +#define RADEON_PLL_NO_ODD_POST_DIV (1 << 1) +#define RADEON_PLL_USE_REF_DIV (1 << 2) +#define RADEON_PLL_LEGACY (1 << 3) +#define RADEON_PLL_PREFER_LOW_REF_DIV (1 << 4) + +struct radeon_pll { + uint16_t reference_freq; + uint16_t reference_div; + uint32_t pll_in_min; + uint32_t pll_in_max; + uint32_t pll_out_min; + uint32_t pll_out_max; + uint16_t xclk; + + uint32_t min_ref_div; + uint32_t max_ref_div; + uint32_t min_post_div; + uint32_t max_post_div; + uint32_t min_feedback_div; + uint32_t max_feedback_div; + uint32_t best_vco; +}; + +struct radeon_mode_info { + struct atom_context *atom_context; + struct radeon_bios_connector bios_connector[RADEON_MAX_BIOS_CONNECTOR]; + struct radeon_pll pll; +}; + +struct radeon_crtc { + struct drm_crtc base; + int crtc_id; + u8 lut_r[256], lut_g[256], lut_b[256]; + bool enabled; + bool can_tile; + uint32_t crtc_offset; + struct radeon_framebuffer *fbdev_fb; + struct drm_mode_set mode_set; +}; + +struct radeon_i2c_chan { + struct drm_device *dev; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; + struct radeon_i2c_bus_rec rec; +}; + + +#define RADEON_USE_RMX 1 + +struct radeon_encoder { + struct drm_encoder base; + uint32_t encoder_mode; + uint32_t flags; + enum radeon_rmx_type rmx_type; + union { + enum radeon_dac_type dac; + enum radeon_tmds_type tmds; + } type; + int atom_device; /* atom devices */ + uint32_t panel_xres, panel_yres; + uint32_t hoverplus, hsync_width; + uint32_t hblank; + uint32_t voverplus, vsync_width; + uint32_t vblank; + uint32_t panel_pwr_delay; + uint32_t dotclock; +}; + +struct radeon_connector { + struct drm_connector base; + struct radeon_i2c_chan *ddc_bus; + int use_digital; + +}; + +struct radeon_framebuffer { + struct drm_framebuffer base; + struct drm_gem_object *obj; + struct drm_bo_kmap_obj kmap_obj; +}; + +extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, + struct radeon_i2c_bus_rec *rec, + const char *name); +extern void radeon_i2c_destroy(struct radeon_i2c_chan *i2c); +extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); +extern struct drm_connector *radeon_connector_add(struct drm_device *dev, int bios_index); + +extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); + +extern void radeon_compute_pll(struct radeon_pll *pll, + uint64_t freq, + uint32_t *dot_clock_p, + uint32_t *fb_div_p, + uint32_t *ref_div_p, + uint32_t *post_div_p, + int flags); + +struct drm_encoder *radeon_encoder_lvtma_add(struct drm_device *dev, int bios_index); +struct drm_encoder *radeon_encoder_atom_dac_add(struct drm_device *dev, int bios_index, int dac_id, int with_tv); +struct drm_encoder *radeon_encoder_atom_tmds_add(struct drm_device *dev, int bios_index, int tmds_type); +struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index); + +extern void radeon_crtc_load_lut(struct drm_crtc *crtc); +extern void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y); +extern void atombios_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y); +extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); +extern bool radeon_atom_get_clock_info(struct drm_device *dev); +extern bool radeon_combios_get_clock_info(struct drm_device *dev); +extern void radeon_get_lvds_info(struct radeon_encoder *encoder); +extern bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder); +extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno); +struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, + struct drm_file *filp, + struct drm_mode_fb_cmd *mode_cmd); + +int radeonfb_probe(struct drm_device *dev); + +int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); +bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev); +void radeon_atombios_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc); +void avivo_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state); + +void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable); +void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable); +void radeon_get_clock_info(struct drm_device *dev); +extern bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev); + +#endif diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h new file mode 100644 index 00000000..9b6bf1ec --- /dev/null +++ b/linux-core/radeon_reg.h @@ -0,0 +1,5276 @@ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + * Authors: + * Kevin E. Martin + * Rickard E. Faith + * Alan Hourihane + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * !!!! FIXME !!!! + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + +/* !!!! FIXME !!!! NOTE: THIS FILE HAS BEEN CONVERTED FROM r128_reg.h + * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT + * ON THE RADEON. A FULL AUDIT OF THIS CODE IS NEEDED! */ + +#ifndef _RADEON_REG_H_ +#define _RADEON_REG_H_ + +#define ATI_DATATYPE_VQ 0 +#define ATI_DATATYPE_CI4 1 +#define ATI_DATATYPE_CI8 2 +#define ATI_DATATYPE_ARGB1555 3 +#define ATI_DATATYPE_RGB565 4 +#define ATI_DATATYPE_RGB888 5 +#define ATI_DATATYPE_ARGB8888 6 +#define ATI_DATATYPE_RGB332 7 +#define ATI_DATATYPE_Y8 8 +#define ATI_DATATYPE_RGB8 9 +#define ATI_DATATYPE_CI16 10 +#define ATI_DATATYPE_VYUY_422 11 +#define ATI_DATATYPE_YVYU_422 12 +#define ATI_DATATYPE_AYUV_444 14 +#define ATI_DATATYPE_ARGB4444 15 + + /* Registers for 2D/Video/Overlay */ +#define RADEON_ADAPTER_ID 0x0f2c /* PCI */ +#define RADEON_AGP_BASE 0x0170 +#define RADEON_AGP_CNTL 0x0174 +# define RADEON_AGP_APER_SIZE_256MB (0x00 << 0) +# define RADEON_AGP_APER_SIZE_128MB (0x20 << 0) +# define RADEON_AGP_APER_SIZE_64MB (0x30 << 0) +# define RADEON_AGP_APER_SIZE_32MB (0x38 << 0) +# define RADEON_AGP_APER_SIZE_16MB (0x3c << 0) +# define RADEON_AGP_APER_SIZE_8MB (0x3e << 0) +# define RADEON_AGP_APER_SIZE_4MB (0x3f << 0) +# define RADEON_AGP_APER_SIZE_MASK (0x3f << 0) +#define RADEON_STATUS_PCI_CONFIG 0x06 +# define RADEON_CAP_LIST 0x100000 +#define RADEON_CAPABILITIES_PTR_PCI_CONFIG 0x34 /* offset in PCI config*/ +# define RADEON_CAP_PTR_MASK 0xfc /* mask off reserved bits of CAP_PTR */ +# define RADEON_CAP_ID_NULL 0x00 /* End of capability list */ +# define RADEON_CAP_ID_AGP 0x02 /* AGP capability ID */ +# define RADEON_CAP_ID_EXP 0x10 /* PCI Express */ +#define RADEON_AGP_COMMAND 0x0f60 /* PCI */ +#define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config*/ +# define RADEON_AGP_ENABLE (1<<8) +#define RADEON_AGP_PLL_CNTL 0x000b /* PLL */ +#define RADEON_AGP_STATUS 0x0f5c /* PCI */ +# define RADEON_AGP_1X_MODE 0x01 +# define RADEON_AGP_2X_MODE 0x02 +# define RADEON_AGP_4X_MODE 0x04 +# define RADEON_AGP_FW_MODE 0x10 +# define RADEON_AGP_MODE_MASK 0x17 +# define RADEON_AGPv3_MODE 0x08 +# define RADEON_AGPv3_4X_MODE 0x01 +# define RADEON_AGPv3_8X_MODE 0x02 +#define RADEON_ATTRDR 0x03c1 /* VGA */ +#define RADEON_ATTRDW 0x03c0 /* VGA */ +#define RADEON_ATTRX 0x03c0 /* VGA */ +#define RADEON_AUX_SC_CNTL 0x1660 +# define RADEON_AUX1_SC_EN (1 << 0) +# define RADEON_AUX1_SC_MODE_OR (0 << 1) +# define RADEON_AUX1_SC_MODE_NAND (1 << 1) +# define RADEON_AUX2_SC_EN (1 << 2) +# define RADEON_AUX2_SC_MODE_OR (0 << 3) +# define RADEON_AUX2_SC_MODE_NAND (1 << 3) +# define RADEON_AUX3_SC_EN (1 << 4) +# define RADEON_AUX3_SC_MODE_OR (0 << 5) +# define RADEON_AUX3_SC_MODE_NAND (1 << 5) +#define RADEON_AUX1_SC_BOTTOM 0x1670 +#define RADEON_AUX1_SC_LEFT 0x1664 +#define RADEON_AUX1_SC_RIGHT 0x1668 +#define RADEON_AUX1_SC_TOP 0x166c +#define RADEON_AUX2_SC_BOTTOM 0x1680 +#define RADEON_AUX2_SC_LEFT 0x1674 +#define RADEON_AUX2_SC_RIGHT 0x1678 +#define RADEON_AUX2_SC_TOP 0x167c +#define RADEON_AUX3_SC_BOTTOM 0x1690 +#define RADEON_AUX3_SC_LEFT 0x1684 +#define RADEON_AUX3_SC_RIGHT 0x1688 +#define RADEON_AUX3_SC_TOP 0x168c +#define RADEON_AUX_WINDOW_HORZ_CNTL 0x02d8 +#define RADEON_AUX_WINDOW_VERT_CNTL 0x02dc + +#define RADEON_BASE_CODE 0x0f0b +#define RADEON_BIOS_0_SCRATCH 0x0010 +# define RADEON_FP_PANEL_SCALABLE (1 << 16) +# define RADEON_FP_PANEL_SCALE_EN (1 << 17) +# define RADEON_FP_CHIP_SCALE_EN (1 << 18) +# define RADEON_DRIVER_BRIGHTNESS_EN (1 << 26) +# define RADEON_DISPLAY_ROT_MASK (3 << 28) +# define RADEON_DISPLAY_ROT_00 (0 << 28) +# define RADEON_DISPLAY_ROT_90 (1 << 28) +# define RADEON_DISPLAY_ROT_180 (2 << 28) +# define RADEON_DISPLAY_ROT_270 (3 << 28) +#define RADEON_BIOS_1_SCRATCH 0x0014 +#define RADEON_BIOS_2_SCRATCH 0x0018 +#define RADEON_BIOS_3_SCRATCH 0x001c +#define RADEON_BIOS_4_SCRATCH 0x0020 +# define RADEON_CRT1_ATTACHED_MASK (3 << 0) +# define RADEON_CRT1_ATTACHED_MONO (1 << 0) +# define RADEON_CRT1_ATTACHED_COLOR (2 << 0) +# define RADEON_LCD1_ATTACHED (1 << 2) +# define RADEON_DFP1_ATTACHED (1 << 3) +# define RADEON_TV1_ATTACHED_MASK (3 << 4) +# define RADEON_TV1_ATTACHED_COMP (1 << 4) +# define RADEON_TV1_ATTACHED_SVIDEO (2 << 4) +# define RADEON_CRT2_ATTACHED_MASK (3 << 8) +# define RADEON_CRT2_ATTACHED_MONO (1 << 8) +# define RADEON_CRT2_ATTACHED_COLOR (2 << 8) +# define RADEON_DFP2_ATTACHED (1 << 11) +#define RADEON_BIOS_5_SCRATCH 0x0024 +# define RADEON_LCD1_ON (1 << 0) +# define RADEON_CRT1_ON (1 << 1) +# define RADEON_TV1_ON (1 << 2) +# define RADEON_DFP1_ON (1 << 3) +# define RADEON_CRT2_ON (1 << 5) +# define RADEON_CV1_ON (1 << 6) +# define RADEON_DFP2_ON (1 << 7) +# define RADEON_LCD1_CRTC_MASK (1 << 8) +# define RADEON_LCD1_CRTC_SHIFT 8 +# define RADEON_CRT1_CRTC_MASK (1 << 9) +# define RADEON_CRT1_CRTC_SHIFT 9 +# define RADEON_TV1_CRTC_MASK (1 << 10) +# define RADEON_TV1_CRTC_SHIFT 10 +# define RADEON_DFP1_CRTC_MASK (1 << 11) +# define RADEON_DFP1_CRTC_SHIFT 11 +# define RADEON_CRT2_CRTC_MASK (1 << 12) +# define RADEON_CRT2_CRTC_SHIFT 12 +# define RADEON_CV1_CRTC_MASK (1 << 13) +# define RADEON_CV1_CRTC_SHIFT 13 +# define RADEON_DFP2_CRTC_MASK (1 << 14) +# define RADEON_DFP2_CRTC_SHIFT 14 +#define RADEON_BIOS_6_SCRATCH 0x0028 +# define RADEON_ACC_MODE_CHANGE (1 << 2) +# define RADEON_EXT_DESKTOP_MODE (1 << 3) +# define RADEON_LCD_DPMS_ON (1 << 20) +# define RADEON_CRT_DPMS_ON (1 << 21) +# define RADEON_TV_DPMS_ON (1 << 22) +# define RADEON_DFP_DPMS_ON (1 << 23) +# define RADEON_DPMS_MASK (3 << 24) +# define RADEON_DPMS_ON (0 << 24) +# define RADEON_DPMS_STANDBY (1 << 24) +# define RADEON_DPMS_SUSPEND (2 << 24) +# define RADEON_DPMS_OFF (3 << 24) +# define RADEON_SCREEN_BLANKING (1 << 26) +# define RADEON_DRIVER_CRITICAL (1 << 27) +# define RADEON_DISPLAY_SWITCHING_DIS (1 << 30) +#define RADEON_BIOS_7_SCRATCH 0x002c +# define RADEON_SYS_HOTKEY (1 << 10) +# define RADEON_DRV_LOADED (1 << 12) +#define RADEON_BIOS_ROM 0x0f30 /* PCI */ +#define RADEON_BIST 0x0f0f /* PCI */ +#define RADEON_BRUSH_DATA0 0x1480 +#define RADEON_BRUSH_DATA1 0x1484 +#define RADEON_BRUSH_DATA10 0x14a8 +#define RADEON_BRUSH_DATA11 0x14ac +#define RADEON_BRUSH_DATA12 0x14b0 +#define RADEON_BRUSH_DATA13 0x14b4 +#define RADEON_BRUSH_DATA14 0x14b8 +#define RADEON_BRUSH_DATA15 0x14bc +#define RADEON_BRUSH_DATA16 0x14c0 +#define RADEON_BRUSH_DATA17 0x14c4 +#define RADEON_BRUSH_DATA18 0x14c8 +#define RADEON_BRUSH_DATA19 0x14cc +#define RADEON_BRUSH_DATA2 0x1488 +#define RADEON_BRUSH_DATA20 0x14d0 +#define RADEON_BRUSH_DATA21 0x14d4 +#define RADEON_BRUSH_DATA22 0x14d8 +#define RADEON_BRUSH_DATA23 0x14dc +#define RADEON_BRUSH_DATA24 0x14e0 +#define RADEON_BRUSH_DATA25 0x14e4 +#define RADEON_BRUSH_DATA26 0x14e8 +#define RADEON_BRUSH_DATA27 0x14ec +#define RADEON_BRUSH_DATA28 0x14f0 +#define RADEON_BRUSH_DATA29 0x14f4 +#define RADEON_BRUSH_DATA3 0x148c +#define RADEON_BRUSH_DATA30 0x14f8 +#define RADEON_BRUSH_DATA31 0x14fc +#define RADEON_BRUSH_DATA32 0x1500 +#define RADEON_BRUSH_DATA33 0x1504 +#define RADEON_BRUSH_DATA34 0x1508 +#define RADEON_BRUSH_DATA35 0x150c +#define RADEON_BRUSH_DATA36 0x1510 +#define RADEON_BRUSH_DATA37 0x1514 +#define RADEON_BRUSH_DATA38 0x1518 +#define RADEON_BRUSH_DATA39 0x151c +#define RADEON_BRUSH_DATA4 0x1490 +#define RADEON_BRUSH_DATA40 0x1520 +#define RADEON_BRUSH_DATA41 0x1524 +#define RADEON_BRUSH_DATA42 0x1528 +#define RADEON_BRUSH_DATA43 0x152c +#define RADEON_BRUSH_DATA44 0x1530 +#define RADEON_BRUSH_DATA45 0x1534 +#define RADEON_BRUSH_DATA46 0x1538 +#define RADEON_BRUSH_DATA47 0x153c +#define RADEON_BRUSH_DATA48 0x1540 +#define RADEON_BRUSH_DATA49 0x1544 +#define RADEON_BRUSH_DATA5 0x1494 +#define RADEON_BRUSH_DATA50 0x1548 +#define RADEON_BRUSH_DATA51 0x154c +#define RADEON_BRUSH_DATA52 0x1550 +#define RADEON_BRUSH_DATA53 0x1554 +#define RADEON_BRUSH_DATA54 0x1558 +#define RADEON_BRUSH_DATA55 0x155c +#define RADEON_BRUSH_DATA56 0x1560 +#define RADEON_BRUSH_DATA57 0x1564 +#define RADEON_BRUSH_DATA58 0x1568 +#define RADEON_BRUSH_DATA59 0x156c +#define RADEON_BRUSH_DATA6 0x1498 +#define RADEON_BRUSH_DATA60 0x1570 +#define RADEON_BRUSH_DATA61 0x1574 +#define RADEON_BRUSH_DATA62 0x1578 +#define RADEON_BRUSH_DATA63 0x157c +#define RADEON_BRUSH_DATA7 0x149c +#define RADEON_BRUSH_DATA8 0x14a0 +#define RADEON_BRUSH_DATA9 0x14a4 +#define RADEON_BRUSH_SCALE 0x1470 +#define RADEON_BRUSH_Y_X 0x1474 +#define RADEON_BUS_CNTL 0x0030 +# define RADEON_BUS_MASTER_DIS (1 << 6) +# define RADEON_BUS_BIOS_DIS_ROM (1 << 12) +# define RADEON_BUS_RD_DISCARD_EN (1 << 24) +# define RADEON_BUS_RD_ABORT_EN (1 << 25) +# define RADEON_BUS_MSTR_DISCONNECT_EN (1 << 28) +# define RADEON_BUS_WRT_BURST (1 << 29) +# define RADEON_BUS_READ_BURST (1 << 30) +#define RADEON_BUS_CNTL1 0x0034 +# define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4) + +#define RADEON_CACHE_CNTL 0x1724 +#define RADEON_CACHE_LINE 0x0f0c /* PCI */ +#define RADEON_CAPABILITIES_ID 0x0f50 /* PCI */ +#define RADEON_CAPABILITIES_PTR 0x0f34 /* PCI */ +#define RADEON_CLK_PIN_CNTL 0x0001 /* PLL */ +# define RADEON_SCLK_DYN_START_CNTL (1 << 15) +#define RADEON_CLOCK_CNTL_DATA 0x000c +#define RADEON_CLOCK_CNTL_INDEX 0x0008 +# define RADEON_PLL_WR_EN (1 << 7) +# define RADEON_PLL_DIV_SEL (3 << 8) +# define RADEON_PLL2_DIV_SEL_MASK ~(3 << 8) +#define RADEON_CLK_PWRMGT_CNTL 0x0014 +# define RADEON_ENGIN_DYNCLK_MODE (1 << 12) +# define RADEON_ACTIVE_HILO_LAT_MASK (3 << 13) +# define RADEON_ACTIVE_HILO_LAT_SHIFT 13 +# define RADEON_DISP_DYN_STOP_LAT_MASK (1 << 12) +# define RADEON_MC_BUSY (1 << 16) +# define RADEON_DLL_READY (1 << 19) +# define RADEON_CG_NO1_DEBUG_0 (1 << 24) +# define RADEON_CG_NO1_DEBUG_MASK (0x1f << 24) +# define RADEON_DYN_STOP_MODE_MASK (7 << 21) +# define RADEON_TVPLL_PWRMGT_OFF (1 << 30) +# define RADEON_TVCLK_TURNOFF (1 << 31) +#define RADEON_PLL_PWRMGT_CNTL 0x0015 +# define RADEON_TCL_BYPASS_DISABLE (1 << 20) +#define RADEON_CLR_CMP_CLR_3D 0x1a24 +#define RADEON_CLR_CMP_CLR_DST 0x15c8 +#define RADEON_CLR_CMP_CLR_SRC 0x15c4 +#define RADEON_CLR_CMP_CNTL 0x15c0 +# define RADEON_SRC_CMP_EQ_COLOR (4 << 0) +# define RADEON_SRC_CMP_NEQ_COLOR (5 << 0) +# define RADEON_CLR_CMP_SRC_SOURCE (1 << 24) +#define RADEON_CLR_CMP_MASK 0x15cc +# define RADEON_CLR_CMP_MSK 0xffffffff +#define RADEON_CLR_CMP_MASK_3D 0x1A28 +#define RADEON_COMMAND 0x0f04 /* PCI */ +#define RADEON_COMPOSITE_SHADOW_ID 0x1a0c +#define RADEON_CONFIG_APER_0_BASE 0x0100 +#define RADEON_CONFIG_APER_1_BASE 0x0104 +#define RADEON_CONFIG_APER_SIZE 0x0108 +#define RADEON_CONFIG_BONDS 0x00e8 +#define RADEON_CONFIG_CNTL 0x00e0 +# define RADEON_CFG_ATI_REV_A11 (0 << 16) +# define RADEON_CFG_ATI_REV_A12 (1 << 16) +# define RADEON_CFG_ATI_REV_A13 (2 << 16) +# define RADEON_CFG_ATI_REV_ID_MASK (0xf << 16) +#define RADEON_CONFIG_MEMSIZE 0x00f8 +#define RADEON_CONFIG_MEMSIZE_EMBEDDED 0x0114 +#define RADEON_CONFIG_REG_1_BASE 0x010c +#define RADEON_CONFIG_REG_APER_SIZE 0x0110 +#define RADEON_CONFIG_XSTRAP 0x00e4 +#define RADEON_CONSTANT_COLOR_C 0x1d34 +# define RADEON_CONSTANT_COLOR_MASK 0x00ffffff +# define RADEON_CONSTANT_COLOR_ONE 0x00ffffff +# define RADEON_CONSTANT_COLOR_ZERO 0x00000000 +#define RADEON_CRC_CMDFIFO_ADDR 0x0740 +#define RADEON_CRC_CMDFIFO_DOUT 0x0744 +#define RADEON_GRPH_BUFFER_CNTL 0x02f0 +# define RADEON_GRPH_START_REQ_MASK (0x7f) +# define RADEON_GRPH_START_REQ_SHIFT 0 +# define RADEON_GRPH_STOP_REQ_MASK (0x7f<<8) +# define RADEON_GRPH_STOP_REQ_SHIFT 8 +# define RADEON_GRPH_CRITICAL_POINT_MASK (0x7f<<16) +# define RADEON_GRPH_CRITICAL_POINT_SHIFT 16 +# define RADEON_GRPH_CRITICAL_CNTL (1<<28) +# define RADEON_GRPH_BUFFER_SIZE (1<<29) +# define RADEON_GRPH_CRITICAL_AT_SOF (1<<30) +# define RADEON_GRPH_STOP_CNTL (1<<31) +#define RADEON_GRPH2_BUFFER_CNTL 0x03f0 +# define RADEON_GRPH2_START_REQ_MASK (0x7f) +# define RADEON_GRPH2_START_REQ_SHIFT 0 +# define RADEON_GRPH2_STOP_REQ_MASK (0x7f<<8) +# define RADEON_GRPH2_STOP_REQ_SHIFT 8 +# define RADEON_GRPH2_CRITICAL_POINT_MASK (0x7f<<16) +# define RADEON_GRPH2_CRITICAL_POINT_SHIFT 16 +# define RADEON_GRPH2_CRITICAL_CNTL (1<<28) +# define RADEON_GRPH2_BUFFER_SIZE (1<<29) +# define RADEON_GRPH2_CRITICAL_AT_SOF (1<<30) +# define RADEON_GRPH2_STOP_CNTL (1<<31) +#define RADEON_CRTC_CRNT_FRAME 0x0214 +#define RADEON_CRTC_EXT_CNTL 0x0054 +# define RADEON_CRTC_VGA_XOVERSCAN (1 << 0) +# define RADEON_VGA_ATI_LINEAR (1 << 3) +# define RADEON_XCRT_CNT_EN (1 << 6) +# define RADEON_CRTC_HSYNC_DIS (1 << 8) +# define RADEON_CRTC_VSYNC_DIS (1 << 9) +# define RADEON_CRTC_DISPLAY_DIS (1 << 10) +# define RADEON_CRTC_SYNC_TRISTAT (1 << 11) +# define RADEON_CRTC_CRT_ON (1 << 15) +#define RADEON_CRTC_EXT_CNTL_DPMS_BYTE 0x0055 +# define RADEON_CRTC_HSYNC_DIS_BYTE (1 << 0) +# define RADEON_CRTC_VSYNC_DIS_BYTE (1 << 1) +# define RADEON_CRTC_DISPLAY_DIS_BYTE (1 << 2) +#define RADEON_CRTC_GEN_CNTL 0x0050 +# define RADEON_CRTC_DBL_SCAN_EN (1 << 0) +# define RADEON_CRTC_INTERLACE_EN (1 << 1) +# define RADEON_CRTC_CSYNC_EN (1 << 4) +# define RADEON_CRTC_ICON_EN (1 << 15) +# define RADEON_CRTC_CUR_EN (1 << 16) +# define RADEON_CRTC_CUR_MODE_MASK (7 << 20) +# define RADEON_CRTC_EXT_DISP_EN (1 << 24) +# define RADEON_CRTC_EN (1 << 25) +# define RADEON_CRTC_DISP_REQ_EN_B (1 << 26) +#define RADEON_CRTC2_GEN_CNTL 0x03f8 +# define RADEON_CRTC2_DBL_SCAN_EN (1 << 0) +# define RADEON_CRTC2_INTERLACE_EN (1 << 1) +# define RADEON_CRTC2_SYNC_TRISTAT (1 << 4) +# define RADEON_CRTC2_HSYNC_TRISTAT (1 << 5) +# define RADEON_CRTC2_VSYNC_TRISTAT (1 << 6) +# define RADEON_CRTC2_CRT2_ON (1 << 7) +# define RADEON_CRTC2_PIX_WIDTH_SHIFT 8 +# define RADEON_CRTC2_PIX_WIDTH_MASK (0xf << 8) +# define RADEON_CRTC2_ICON_EN (1 << 15) +# define RADEON_CRTC2_CUR_EN (1 << 16) +# define RADEON_CRTC2_CUR_MODE_MASK (7 << 20) +# define RADEON_CRTC2_DISP_DIS (1 << 23) +# define RADEON_CRTC2_EN (1 << 25) +# define RADEON_CRTC2_DISP_REQ_EN_B (1 << 26) +# define RADEON_CRTC2_CSYNC_EN (1 << 27) +# define RADEON_CRTC2_HSYNC_DIS (1 << 28) +# define RADEON_CRTC2_VSYNC_DIS (1 << 29) +#define RADEON_CRTC_MORE_CNTL 0x27c +# define RADEON_CRTC_AUTO_HORZ_CENTER_EN (1<<2) +# define RADEON_CRTC_AUTO_VERT_CENTER_EN (1<<3) +# define RADEON_CRTC_H_CUTOFF_ACTIVE_EN (1<<4) +# define RADEON_CRTC_V_CUTOFF_ACTIVE_EN (1<<5) +#define RADEON_CRTC_GUI_TRIG_VLINE 0x0218 +#define RADEON_CRTC_H_SYNC_STRT_WID 0x0204 +# define RADEON_CRTC_H_SYNC_STRT_PIX (0x07 << 0) +# define RADEON_CRTC_H_SYNC_STRT_CHAR (0x3ff << 3) +# define RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT 3 +# define RADEON_CRTC_H_SYNC_WID (0x3f << 16) +# define RADEON_CRTC_H_SYNC_WID_SHIFT 16 +# define RADEON_CRTC_H_SYNC_POL (1 << 23) +#define RADEON_CRTC2_H_SYNC_STRT_WID 0x0304 +# define RADEON_CRTC2_H_SYNC_STRT_PIX (0x07 << 0) +# define RADEON_CRTC2_H_SYNC_STRT_CHAR (0x3ff << 3) +# define RADEON_CRTC2_H_SYNC_STRT_CHAR_SHIFT 3 +# define RADEON_CRTC2_H_SYNC_WID (0x3f << 16) +# define RADEON_CRTC2_H_SYNC_WID_SHIFT 16 +# define RADEON_CRTC2_H_SYNC_POL (1 << 23) +#define RADEON_CRTC_H_TOTAL_DISP 0x0200 +# define RADEON_CRTC_H_TOTAL (0x03ff << 0) +# define RADEON_CRTC_H_TOTAL_SHIFT 0 +# define RADEON_CRTC_H_DISP (0x01ff << 16) +# define RADEON_CRTC_H_DISP_SHIFT 16 +#define RADEON_CRTC2_H_TOTAL_DISP 0x0300 +# define RADEON_CRTC2_H_TOTAL (0x03ff << 0) +# define RADEON_CRTC2_H_TOTAL_SHIFT 0 +# define RADEON_CRTC2_H_DISP (0x01ff << 16) +# define RADEON_CRTC2_H_DISP_SHIFT 16 + +#define RADEON_CRTC_OFFSET_RIGHT 0x0220 +#define RADEON_CRTC_OFFSET 0x0224 +# define RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET (1<<30) +# define RADEON_CRTC_OFFSET__OFFSET_LOCK (1<<31) + +#define RADEON_CRTC2_OFFSET 0x0324 +# define RADEON_CRTC2_OFFSET__GUI_TRIG_OFFSET (1<<30) +# define RADEON_CRTC2_OFFSET__OFFSET_LOCK (1<<31) +#define RADEON_CRTC_OFFSET_CNTL 0x0228 +# define RADEON_CRTC_TILE_LINE_SHIFT 0 +# define RADEON_CRTC_TILE_LINE_RIGHT_SHIFT 4 +# define R300_CRTC_X_Y_MODE_EN_RIGHT (1 << 6) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_MASK (3 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_AUTO (0 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_SINGLE (1 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_DOUBLE (2 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_DIS (3 << 7) +# define R300_CRTC_X_Y_MODE_EN (1 << 9) +# define R300_CRTC_MICRO_TILE_BUFFER_MASK (3 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_AUTO (0 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_SINGLE (1 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_DOUBLE (2 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_DIS (3 << 10) +# define R300_CRTC_MICRO_TILE_EN_RIGHT (1 << 12) +# define R300_CRTC_MICRO_TILE_EN (1 << 13) +# define R300_CRTC_MACRO_TILE_EN_RIGHT (1 << 14) +# define R300_CRTC_MACRO_TILE_EN (1 << 15) +# define RADEON_CRTC_TILE_EN_RIGHT (1 << 14) +# define RADEON_CRTC_TILE_EN (1 << 15) +# define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16) +# define RADEON_CRTC_STEREO_OFFSET_EN (1 << 17) + +#define R300_CRTC_TILE_X0_Y0 0x0350 +#define R300_CRTC2_TILE_X0_Y0 0x0358 + +#define RADEON_CRTC2_OFFSET_CNTL 0x0328 +# define RADEON_CRTC2_OFFSET_FLIP_CNTL (1 << 16) +# define RADEON_CRTC2_TILE_EN (1 << 15) +#define RADEON_CRTC_PITCH 0x022c +# define RADEON_CRTC_PITCH__SHIFT 0 +# define RADEON_CRTC_PITCH__RIGHT_SHIFT 16 + +#define RADEON_CRTC2_PITCH 0x032c +#define RADEON_CRTC_STATUS 0x005c +# define RADEON_CRTC_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC2_STATUS 0x03fc +# define RADEON_CRTC2_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC2_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC_V_SYNC_STRT_WID 0x020c +# define RADEON_CRTC_V_SYNC_STRT (0x7ff << 0) +# define RADEON_CRTC_V_SYNC_STRT_SHIFT 0 +# define RADEON_CRTC_V_SYNC_WID (0x1f << 16) +# define RADEON_CRTC_V_SYNC_WID_SHIFT 16 +# define RADEON_CRTC_V_SYNC_POL (1 << 23) +#define RADEON_CRTC2_V_SYNC_STRT_WID 0x030c +# define RADEON_CRTC2_V_SYNC_STRT (0x7ff << 0) +# define RADEON_CRTC2_V_SYNC_STRT_SHIFT 0 +# define RADEON_CRTC2_V_SYNC_WID (0x1f << 16) +# define RADEON_CRTC2_V_SYNC_WID_SHIFT 16 +# define RADEON_CRTC2_V_SYNC_POL (1 << 23) +#define RADEON_CRTC_V_TOTAL_DISP 0x0208 +# define RADEON_CRTC_V_TOTAL (0x07ff << 0) +# define RADEON_CRTC_V_TOTAL_SHIFT 0 +# define RADEON_CRTC_V_DISP (0x07ff << 16) +# define RADEON_CRTC_V_DISP_SHIFT 16 +#define RADEON_CRTC2_V_TOTAL_DISP 0x0308 +# define RADEON_CRTC2_V_TOTAL (0x07ff << 0) +# define RADEON_CRTC2_V_TOTAL_SHIFT 0 +# define RADEON_CRTC2_V_DISP (0x07ff << 16) +# define RADEON_CRTC2_V_DISP_SHIFT 16 +#define RADEON_CRTC_VLINE_CRNT_VLINE 0x0210 +# define RADEON_CRTC_CRNT_VLINE_MASK (0x7ff << 16) +#define RADEON_CRTC2_CRNT_FRAME 0x0314 +#define RADEON_CRTC2_GUI_TRIG_VLINE 0x0318 +#define RADEON_CRTC2_STATUS 0x03fc +#define RADEON_CRTC2_VLINE_CRNT_VLINE 0x0310 +#define RADEON_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */ +#define RADEON_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */ +#define RADEON_CUR_CLR0 0x026c +#define RADEON_CUR_CLR1 0x0270 +#define RADEON_CUR_HORZ_VERT_OFF 0x0268 +#define RADEON_CUR_HORZ_VERT_POSN 0x0264 +#define RADEON_CUR_OFFSET 0x0260 +# define RADEON_CUR_LOCK (1 << 31) +#define RADEON_CUR2_CLR0 0x036c +#define RADEON_CUR2_CLR1 0x0370 +#define RADEON_CUR2_HORZ_VERT_OFF 0x0368 +#define RADEON_CUR2_HORZ_VERT_POSN 0x0364 +#define RADEON_CUR2_OFFSET 0x0360 +# define RADEON_CUR2_LOCK (1 << 31) + +#define RADEON_DAC_CNTL 0x0058 +# define RADEON_DAC_RANGE_CNTL (3 << 0) +# define RADEON_DAC_RANGE_CNTL_PS2 (2 << 0) +# define RADEON_DAC_RANGE_CNTL_MASK 0x03 +# define RADEON_DAC_BLANKING (1 << 2) +# define RADEON_DAC_CMP_EN (1 << 3) +# define RADEON_DAC_CMP_OUTPUT (1 << 7) +# define RADEON_DAC_8BIT_EN (1 << 8) +# define RADEON_DAC_TVO_EN (1 << 10) +# define RADEON_DAC_VGA_ADR_EN (1 << 13) +# define RADEON_DAC_PDWN (1 << 15) +# define RADEON_DAC_MASK_ALL (0xff << 24) +#define RADEON_DAC_CNTL2 0x007c +# define RADEON_DAC2_TV_CLK_SEL (0 << 1) +# define RADEON_DAC2_DAC_CLK_SEL (1 << 0) +# define RADEON_DAC2_DAC2_CLK_SEL (1 << 1) +# define RADEON_DAC2_PALETTE_ACC_CTL (1 << 5) +# define RADEON_DAC2_CMP_EN (1 << 7) +# define RADEON_DAC2_CMP_OUT_R (1 << 8) +# define RADEON_DAC2_CMP_OUT_G (1 << 9) +# define RADEON_DAC2_CMP_OUT_B (1 << 10) +# define RADEON_DAC2_CMP_OUTPUT (1 << 11) +#define RADEON_DAC_EXT_CNTL 0x0280 +# define RADEON_DAC2_FORCE_BLANK_OFF_EN (1 << 0) +# define RADEON_DAC2_FORCE_DATA_EN (1 << 1) +# define RADEON_DAC_FORCE_BLANK_OFF_EN (1 << 4) +# define RADEON_DAC_FORCE_DATA_EN (1 << 5) +# define RADEON_DAC_FORCE_DATA_SEL_MASK (3 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_R (0 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_G (1 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_B (2 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_RGB (3 << 6) +# define RADEON_DAC_FORCE_DATA_MASK 0x0003ff00 +# define RADEON_DAC_FORCE_DATA_SHIFT 8 +#define RADEON_DAC_MACRO_CNTL 0x0d04 +# define RADEON_DAC_PDWN_R (1 << 16) +# define RADEON_DAC_PDWN_G (1 << 17) +# define RADEON_DAC_PDWN_B (1 << 18) +#define RADEON_TV_DAC_CNTL 0x088c +# define RADEON_TV_DAC_NBLANK (1 << 0) +# define RADEON_TV_DAC_NHOLD (1 << 1) +# define RADEON_TV_DAC_PEDESTAL (1 << 2) +# define RADEON_TV_MONITOR_DETECT_EN (1 << 4) +# define RADEON_TV_DAC_CMPOUT (1 << 5) +# define RADEON_TV_DAC_STD_MASK (3 << 8) +# define RADEON_TV_DAC_STD_PAL (0 << 8) +# define RADEON_TV_DAC_STD_NTSC (1 << 8) +# define RADEON_TV_DAC_STD_PS2 (2 << 8) +# define RADEON_TV_DAC_STD_RS343 (3 << 8) +# define RADEON_TV_DAC_BGSLEEP (1 << 6) +# define RADEON_TV_DAC_BGADJ_MASK (0xf << 16) +# define RADEON_TV_DAC_BGADJ_SHIFT 16 +# define RADEON_TV_DAC_DACADJ_MASK (0xf << 20) +# define RADEON_TV_DAC_DACADJ_SHIFT 20 +# define RADEON_TV_DAC_RDACPD (1 << 24) +# define RADEON_TV_DAC_GDACPD (1 << 25) +# define RADEON_TV_DAC_BDACPD (1 << 26) +# define RADEON_TV_DAC_RDACDET (1 << 29) +# define RADEON_TV_DAC_GDACDET (1 << 30) +# define RADEON_TV_DAC_BDACDET (1 << 31) +# define R420_TV_DAC_DACADJ_MASK (0x1f << 20) +# define R420_TV_DAC_RDACPD (1 << 25) +# define R420_TV_DAC_GDACPD (1 << 26) +# define R420_TV_DAC_BDACPD (1 << 27) +# define R420_TV_DAC_TVENABLE (1 << 28) +#define RADEON_DISP_HW_DEBUG 0x0d14 +# define RADEON_CRT2_DISP1_SEL (1 << 5) +#define RADEON_DISP_OUTPUT_CNTL 0x0d64 +# define RADEON_DISP_DAC_SOURCE_MASK 0x03 +# define RADEON_DISP_DAC2_SOURCE_MASK 0x0c +# define RADEON_DISP_DAC_SOURCE_CRTC2 0x01 +# define RADEON_DISP_DAC_SOURCE_RMX 0x02 +# define RADEON_DISP_DAC_SOURCE_LTU 0x03 +# define RADEON_DISP_DAC2_SOURCE_CRTC2 0x04 +# define RADEON_DISP_TVDAC_SOURCE_MASK (0x03 << 2) +# define RADEON_DISP_TVDAC_SOURCE_CRTC 0x0 +# define RADEON_DISP_TVDAC_SOURCE_CRTC2 (0x01 << 2) +# define RADEON_DISP_TVDAC_SOURCE_RMX (0x02 << 2) +# define RADEON_DISP_TVDAC_SOURCE_LTU (0x03 << 2) +# define RADEON_DISP_TRANS_MATRIX_MASK (0x03 << 4) +# define RADEON_DISP_TRANS_MATRIX_ALPHA_MSB (0x00 << 4) +# define RADEON_DISP_TRANS_MATRIX_GRAPHICS (0x01 << 4) +# define RADEON_DISP_TRANS_MATRIX_VIDEO (0x02 << 4) +# define RADEON_DISP_TV_SOURCE_CRTC (1 << 16) /* crtc1 or crtc2 */ +# define RADEON_DISP_TV_SOURCE_LTU (0 << 16) /* linear transform unit */ +#define RADEON_DISP_TV_OUT_CNTL 0x0d6c +# define RADEON_DISP_TV_PATH_SRC_CRTC2 (1 << 16) +# define RADEON_DISP_TV_PATH_SRC_CRTC1 (0 << 16) +#define RADEON_DAC_CRC_SIG 0x02cc +#define RADEON_DAC_DATA 0x03c9 /* VGA */ +#define RADEON_DAC_MASK 0x03c6 /* VGA */ +#define RADEON_DAC_R_INDEX 0x03c7 /* VGA */ +#define RADEON_DAC_W_INDEX 0x03c8 /* VGA */ +#define RADEON_DDA_CONFIG 0x02e0 +#define RADEON_DDA_ON_OFF 0x02e4 +#define RADEON_DEFAULT_OFFSET 0x16e0 +#define RADEON_DEFAULT_PITCH 0x16e4 +#define RADEON_DEFAULT_SC_BOTTOM_RIGHT 0x16e8 +# define RADEON_DEFAULT_SC_RIGHT_MAX (0x1fff << 0) +# define RADEON_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16) +#define RADEON_DESTINATION_3D_CLR_CMP_VAL 0x1820 +#define RADEON_DESTINATION_3D_CLR_CMP_MSK 0x1824 +#define RADEON_DEVICE_ID 0x0f02 /* PCI */ +#define RADEON_DISP_MISC_CNTL 0x0d00 +# define RADEON_SOFT_RESET_GRPH_PP (1 << 0) +#define RADEON_DISP_MERGE_CNTL 0x0d60 +# define RADEON_DISP_ALPHA_MODE_MASK 0x03 +# define RADEON_DISP_ALPHA_MODE_KEY 0 +# define RADEON_DISP_ALPHA_MODE_PER_PIXEL 1 +# define RADEON_DISP_ALPHA_MODE_GLOBAL 2 +# define RADEON_DISP_RGB_OFFSET_EN (1 << 8) +# define RADEON_DISP_GRPH_ALPHA_MASK (0xff << 16) +# define RADEON_DISP_OV0_ALPHA_MASK (0xff << 24) +# define RADEON_DISP_LIN_TRANS_BYPASS (0x01 << 9) +#define RADEON_DISP2_MERGE_CNTL 0x0d68 +# define RADEON_DISP2_RGB_OFFSET_EN (1 << 8) +#define RADEON_DISP_LIN_TRANS_GRPH_A 0x0d80 +#define RADEON_DISP_LIN_TRANS_GRPH_B 0x0d84 +#define RADEON_DISP_LIN_TRANS_GRPH_C 0x0d88 +#define RADEON_DISP_LIN_TRANS_GRPH_D 0x0d8c +#define RADEON_DISP_LIN_TRANS_GRPH_E 0x0d90 +#define RADEON_DISP_LIN_TRANS_GRPH_F 0x0d98 +#define RADEON_DP_BRUSH_BKGD_CLR 0x1478 +#define RADEON_DP_BRUSH_FRGD_CLR 0x147c +#define RADEON_DP_CNTL 0x16c0 +# define RADEON_DST_X_LEFT_TO_RIGHT (1 << 0) +# define RADEON_DST_Y_TOP_TO_BOTTOM (1 << 1) +# define RADEON_DP_DST_TILE_LINEAR (0 << 3) +# define RADEON_DP_DST_TILE_MACRO (1 << 3) +# define RADEON_DP_DST_TILE_MICRO (2 << 3) +# define RADEON_DP_DST_TILE_BOTH (3 << 3) +#define RADEON_DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0 +# define RADEON_DST_Y_MAJOR (1 << 2) +# define RADEON_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15) +# define RADEON_DST_X_DIR_LEFT_TO_RIGHT (1 << 31) +#define RADEON_DP_DATATYPE 0x16c4 +# define RADEON_HOST_BIG_ENDIAN_EN (1 << 29) +#define RADEON_DP_GUI_MASTER_CNTL 0x146c +# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +# define RADEON_GMC_SRC_CLIPPING (1 << 2) +# define RADEON_GMC_DST_CLIPPING (1 << 3) +# define RADEON_GMC_BRUSH_DATATYPE_MASK (0x0f << 4) +# define RADEON_GMC_BRUSH_8X8_MONO_FG_BG (0 << 4) +# define RADEON_GMC_BRUSH_8X8_MONO_FG_LA (1 << 4) +# define RADEON_GMC_BRUSH_1X8_MONO_FG_BG (4 << 4) +# define RADEON_GMC_BRUSH_1X8_MONO_FG_LA (5 << 4) +# define RADEON_GMC_BRUSH_32x1_MONO_FG_BG (6 << 4) +# define RADEON_GMC_BRUSH_32x1_MONO_FG_LA (7 << 4) +# define RADEON_GMC_BRUSH_32x32_MONO_FG_BG (8 << 4) +# define RADEON_GMC_BRUSH_32x32_MONO_FG_LA (9 << 4) +# define RADEON_GMC_BRUSH_8x8_COLOR (10 << 4) +# define RADEON_GMC_BRUSH_1X8_COLOR (12 << 4) +# define RADEON_GMC_BRUSH_SOLID_COLOR (13 << 4) +# define RADEON_GMC_BRUSH_NONE (15 << 4) +# define RADEON_GMC_DST_8BPP_CI (2 << 8) +# define RADEON_GMC_DST_15BPP (3 << 8) +# define RADEON_GMC_DST_16BPP (4 << 8) +# define RADEON_GMC_DST_24BPP (5 << 8) +# define RADEON_GMC_DST_32BPP (6 << 8) +# define RADEON_GMC_DST_8BPP_RGB (7 << 8) +# define RADEON_GMC_DST_Y8 (8 << 8) +# define RADEON_GMC_DST_RGB8 (9 << 8) +# define RADEON_GMC_DST_VYUY (11 << 8) +# define RADEON_GMC_DST_YVYU (12 << 8) +# define RADEON_GMC_DST_AYUV444 (14 << 8) +# define RADEON_GMC_DST_ARGB4444 (15 << 8) +# define RADEON_GMC_DST_DATATYPE_MASK (0x0f << 8) +# define RADEON_GMC_DST_DATATYPE_SHIFT 8 +# define RADEON_GMC_SRC_DATATYPE_MASK (3 << 12) +# define RADEON_GMC_SRC_DATATYPE_MONO_FG_BG (0 << 12) +# define RADEON_GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12) +# define RADEON_GMC_SRC_DATATYPE_COLOR (3 << 12) +# define RADEON_GMC_BYTE_PIX_ORDER (1 << 14) +# define RADEON_GMC_BYTE_MSB_TO_LSB (0 << 14) +# define RADEON_GMC_BYTE_LSB_TO_MSB (1 << 14) +# define RADEON_GMC_CONVERSION_TEMP (1 << 15) +# define RADEON_GMC_CONVERSION_TEMP_6500 (0 << 15) +# define RADEON_GMC_CONVERSION_TEMP_9300 (1 << 15) +# define RADEON_GMC_ROP3_MASK (0xff << 16) +# define RADEON_DP_SRC_SOURCE_MASK (7 << 24) +# define RADEON_DP_SRC_SOURCE_MEMORY (2 << 24) +# define RADEON_DP_SRC_SOURCE_HOST_DATA (3 << 24) +# define RADEON_GMC_3D_FCN_EN (1 << 27) +# define RADEON_GMC_CLR_CMP_CNTL_DIS (1 << 28) +# define RADEON_GMC_AUX_CLIP_DIS (1 << 29) +# define RADEON_GMC_WR_MSK_DIS (1 << 30) +# define RADEON_GMC_LD_BRUSH_Y_X (1 << 31) +# define RADEON_ROP3_ZERO 0x00000000 +# define RADEON_ROP3_DSa 0x00880000 +# define RADEON_ROP3_SDna 0x00440000 +# define RADEON_ROP3_S 0x00cc0000 +# define RADEON_ROP3_DSna 0x00220000 +# define RADEON_ROP3_D 0x00aa0000 +# define RADEON_ROP3_DSx 0x00660000 +# define RADEON_ROP3_DSo 0x00ee0000 +# define RADEON_ROP3_DSon 0x00110000 +# define RADEON_ROP3_DSxn 0x00990000 +# define RADEON_ROP3_Dn 0x00550000 +# define RADEON_ROP3_SDno 0x00dd0000 +# define RADEON_ROP3_Sn 0x00330000 +# define RADEON_ROP3_DSno 0x00bb0000 +# define RADEON_ROP3_DSan 0x00770000 +# define RADEON_ROP3_ONE 0x00ff0000 +# define RADEON_ROP3_DPa 0x00a00000 +# define RADEON_ROP3_PDna 0x00500000 +# define RADEON_ROP3_P 0x00f00000 +# define RADEON_ROP3_DPna 0x000a0000 +# define RADEON_ROP3_D 0x00aa0000 +# define RADEON_ROP3_DPx 0x005a0000 +# define RADEON_ROP3_DPo 0x00fa0000 +# define RADEON_ROP3_DPon 0x00050000 +# define RADEON_ROP3_PDxn 0x00a50000 +# define RADEON_ROP3_PDno 0x00f50000 +# define RADEON_ROP3_Pn 0x000f0000 +# define RADEON_ROP3_DPno 0x00af0000 +# define RADEON_ROP3_DPan 0x005f0000 +#define RADEON_DP_GUI_MASTER_CNTL_C 0x1c84 +#define RADEON_DP_MIX 0x16c8 +#define RADEON_DP_SRC_BKGD_CLR 0x15dc +#define RADEON_DP_SRC_FRGD_CLR 0x15d8 +#define RADEON_DP_WRITE_MASK 0x16cc +#define RADEON_DST_BRES_DEC 0x1630 +#define RADEON_DST_BRES_ERR 0x1628 +#define RADEON_DST_BRES_INC 0x162c +#define RADEON_DST_BRES_LNTH 0x1634 +#define RADEON_DST_BRES_LNTH_SUB 0x1638 +#define RADEON_DST_HEIGHT 0x1410 +#define RADEON_DST_HEIGHT_WIDTH 0x143c +#define RADEON_DST_HEIGHT_WIDTH_8 0x158c +#define RADEON_DST_HEIGHT_WIDTH_BW 0x15b4 +#define RADEON_DST_HEIGHT_Y 0x15a0 +#define RADEON_DST_LINE_START 0x1600 +#define RADEON_DST_LINE_END 0x1604 +#define RADEON_DST_LINE_PATCOUNT 0x1608 +# define RADEON_BRES_CNTL_SHIFT 8 +#define RADEON_DST_OFFSET 0x1404 +#define RADEON_DST_PITCH 0x1408 +#define RADEON_DST_PITCH_OFFSET 0x142c +#define RADEON_DST_PITCH_OFFSET_C 0x1c80 +# define RADEON_PITCH_SHIFT 21 +# define RADEON_DST_TILE_LINEAR (0 << 30) +# define RADEON_DST_TILE_MACRO (1 << 30) +# define RADEON_DST_TILE_MICRO (2 << 30) +# define RADEON_DST_TILE_BOTH (3 << 30) +#define RADEON_DST_WIDTH 0x140c +#define RADEON_DST_WIDTH_HEIGHT 0x1598 +#define RADEON_DST_WIDTH_X 0x1588 +#define RADEON_DST_WIDTH_X_INCY 0x159c +#define RADEON_DST_X 0x141c +#define RADEON_DST_X_SUB 0x15a4 +#define RADEON_DST_X_Y 0x1594 +#define RADEON_DST_Y 0x1420 +#define RADEON_DST_Y_SUB 0x15a8 +#define RADEON_DST_Y_X 0x1438 + +#define RADEON_FCP_CNTL 0x0910 +# define RADEON_FCP0_SRC_PCICLK 0 +# define RADEON_FCP0_SRC_PCLK 1 +# define RADEON_FCP0_SRC_PCLKb 2 +# define RADEON_FCP0_SRC_HREF 3 +# define RADEON_FCP0_SRC_GND 4 +# define RADEON_FCP0_SRC_HREFb 5 +#define RADEON_FLUSH_1 0x1704 +#define RADEON_FLUSH_2 0x1708 +#define RADEON_FLUSH_3 0x170c +#define RADEON_FLUSH_4 0x1710 +#define RADEON_FLUSH_5 0x1714 +#define RADEON_FLUSH_6 0x1718 +#define RADEON_FLUSH_7 0x171c +#define RADEON_FOG_3D_TABLE_START 0x1810 +#define RADEON_FOG_3D_TABLE_END 0x1814 +#define RADEON_FOG_3D_TABLE_DENSITY 0x181c +#define RADEON_FOG_TABLE_INDEX 0x1a14 +#define RADEON_FOG_TABLE_DATA 0x1a18 +#define RADEON_FP_CRTC_H_TOTAL_DISP 0x0250 +#define RADEON_FP_CRTC_V_TOTAL_DISP 0x0254 +# define RADEON_FP_CRTC_H_TOTAL_MASK 0x000003ff +# define RADEON_FP_CRTC_H_DISP_MASK 0x01ff0000 +# define RADEON_FP_CRTC_V_TOTAL_MASK 0x00000fff +# define RADEON_FP_CRTC_V_DISP_MASK 0x0fff0000 +# define RADEON_FP_H_SYNC_STRT_CHAR_MASK 0x00001ff8 +# define RADEON_FP_H_SYNC_WID_MASK 0x003f0000 +# define RADEON_FP_V_SYNC_STRT_MASK 0x00000fff +# define RADEON_FP_V_SYNC_WID_MASK 0x001f0000 +# define RADEON_FP_CRTC_H_TOTAL_SHIFT 0x00000000 +# define RADEON_FP_CRTC_H_DISP_SHIFT 0x00000010 +# define RADEON_FP_CRTC_V_TOTAL_SHIFT 0x00000000 +# define RADEON_FP_CRTC_V_DISP_SHIFT 0x00000010 +# define RADEON_FP_H_SYNC_STRT_CHAR_SHIFT 0x00000003 +# define RADEON_FP_H_SYNC_WID_SHIFT 0x00000010 +# define RADEON_FP_V_SYNC_STRT_SHIFT 0x00000000 +# define RADEON_FP_V_SYNC_WID_SHIFT 0x00000010 +#define RADEON_FP_GEN_CNTL 0x0284 +# define RADEON_FP_FPON (1 << 0) +# define RADEON_FP_BLANK_EN (1 << 1) +# define RADEON_FP_TMDS_EN (1 << 2) +# define RADEON_FP_PANEL_FORMAT (1 << 3) +# define RADEON_FP_EN_TMDS (1 << 7) +# define RADEON_FP_DETECT_SENSE (1 << 8) +# define R200_FP_SOURCE_SEL_MASK (3 << 10) +# define R200_FP_SOURCE_SEL_CRTC1 (0 << 10) +# define R200_FP_SOURCE_SEL_CRTC2 (1 << 10) +# define R200_FP_SOURCE_SEL_RMX (2 << 10) +# define R200_FP_SOURCE_SEL_TRANS (3 << 10) +# define RADEON_FP_SEL_CRTC1 (0 << 13) +# define RADEON_FP_SEL_CRTC2 (1 << 13) +# define RADEON_FP_CRTC_DONT_SHADOW_HPAR (1 << 15) +# define RADEON_FP_CRTC_DONT_SHADOW_VPAR (1 << 16) +# define RADEON_FP_CRTC_DONT_SHADOW_HEND (1 << 17) +# define RADEON_FP_CRTC_USE_SHADOW_VEND (1 << 18) +# define RADEON_FP_RMX_HVSYNC_CONTROL_EN (1 << 20) +# define RADEON_FP_DFP_SYNC_SEL (1 << 21) +# define RADEON_FP_CRTC_LOCK_8DOT (1 << 22) +# define RADEON_FP_CRT_SYNC_SEL (1 << 23) +# define RADEON_FP_USE_SHADOW_EN (1 << 24) +# define RADEON_FP_CRT_SYNC_ALT (1 << 26) +#define RADEON_FP2_GEN_CNTL 0x0288 +# define RADEON_FP2_BLANK_EN (1 << 1) +# define RADEON_FP2_ON (1 << 2) +# define RADEON_FP2_PANEL_FORMAT (1 << 3) +# define RADEON_FP2_DETECT_SENSE (1 << 8) +# define R200_FP2_SOURCE_SEL_MASK (3 << 10) +# define R200_FP2_SOURCE_SEL_CRTC1 (0 << 10) +# define R200_FP2_SOURCE_SEL_CRTC2 (1 << 10) +# define R200_FP2_SOURCE_SEL_RMX (2 << 10) +# define R200_FP2_SOURCE_SEL_TRANS_UNIT (3 << 10) +# define RADEON_FP2_SRC_SEL_MASK (3 << 13) +# define RADEON_FP2_SRC_SEL_CRTC2 (1 << 13) +# define RADEON_FP2_FP_POL (1 << 16) +# define RADEON_FP2_LP_POL (1 << 17) +# define RADEON_FP2_SCK_POL (1 << 18) +# define RADEON_FP2_LCD_CNTL_MASK (7 << 19) +# define RADEON_FP2_PAD_FLOP_EN (1 << 22) +# define RADEON_FP2_CRC_EN (1 << 23) +# define RADEON_FP2_CRC_READ_EN (1 << 24) +# define RADEON_FP2_DVO_EN (1 << 25) +# define RADEON_FP2_DVO_RATE_SEL_SDR (1 << 26) +# define R200_FP2_DVO_RATE_SEL_SDR (1 << 27) +# define R300_FP2_DVO_CLOCK_MODE_SINGLE (1 << 28) +# define R300_FP2_DVO_DUAL_CHANNEL_EN (1 << 29) +#define RADEON_FP_H_SYNC_STRT_WID 0x02c4 +#define RADEON_FP_H2_SYNC_STRT_WID 0x03c4 +#define RADEON_FP_HORZ_STRETCH 0x028c +#define RADEON_FP_HORZ2_STRETCH 0x038c +# define RADEON_HORZ_STRETCH_RATIO_MASK 0xffff +# define RADEON_HORZ_STRETCH_RATIO_MAX 4096 +# define RADEON_HORZ_PANEL_SIZE (0x1ff << 16) +# define RADEON_HORZ_PANEL_SHIFT 16 +# define RADEON_HORZ_STRETCH_PIXREP (0 << 25) +# define RADEON_HORZ_STRETCH_BLEND (1 << 26) +# define RADEON_HORZ_STRETCH_ENABLE (1 << 25) +# define RADEON_HORZ_AUTO_RATIO (1 << 27) +# define RADEON_HORZ_FP_LOOP_STRETCH (0x7 << 28) +# define RADEON_HORZ_AUTO_RATIO_INC (1 << 31) +#define RADEON_FP_HORZ_VERT_ACTIVE 0x0278 +#define RADEON_FP_V_SYNC_STRT_WID 0x02c8 +#define RADEON_FP_VERT_STRETCH 0x0290 +#define RADEON_FP_V2_SYNC_STRT_WID 0x03c8 +#define RADEON_FP_VERT2_STRETCH 0x0390 +# define RADEON_VERT_PANEL_SIZE (0xfff << 12) +# define RADEON_VERT_PANEL_SHIFT 12 +# define RADEON_VERT_STRETCH_RATIO_MASK 0xfff +# define RADEON_VERT_STRETCH_RATIO_SHIFT 0 +# define RADEON_VERT_STRETCH_RATIO_MAX 4096 +# define RADEON_VERT_STRETCH_ENABLE (1 << 25) +# define RADEON_VERT_STRETCH_LINEREP (0 << 26) +# define RADEON_VERT_STRETCH_BLEND (1 << 26) +# define RADEON_VERT_AUTO_RATIO_EN (1 << 27) +# define RADEON_VERT_AUTO_RATIO_INC (1 << 31) +# define RADEON_VERT_STRETCH_RESERVED 0x71000000 +#define RS400_FP_2ND_GEN_CNTL 0x0384 +# define RS400_FP_2ND_ON (1 << 0) +# define RS400_FP_2ND_BLANK_EN (1 << 1) +# define RS400_TMDS_2ND_EN (1 << 2) +# define RS400_PANEL_FORMAT_2ND (1 << 3) +# define RS400_FP_2ND_EN_TMDS (1 << 7) +# define RS400_FP_2ND_DETECT_SENSE (1 << 8) +# define RS400_FP_2ND_SOURCE_SEL_MASK (3 << 10) +# define RS400_FP_2ND_SOURCE_SEL_CRTC1 (0 << 10) +# define RS400_FP_2ND_SOURCE_SEL_CRTC2 (1 << 10) +# define RS400_FP_2ND_SOURCE_SEL_RMX (2 << 10) +# define RS400_FP_2ND_DETECT_EN (1 << 12) +# define RS400_HPD_2ND_SEL (1 << 13) +#define RS400_FP2_2_GEN_CNTL 0x0388 +# define RS400_FP2_2_BLANK_EN (1 << 1) +# define RS400_FP2_2_ON (1 << 2) +# define RS400_FP2_2_PANEL_FORMAT (1 << 3) +# define RS400_FP2_2_DETECT_SENSE (1 << 8) +# define RS400_FP2_2_SOURCE_SEL_MASK (3 << 10) +# define RS400_FP2_2_SOURCE_SEL_CRTC1 (0 << 10) +# define RS400_FP2_2_SOURCE_SEL_CRTC2 (1 << 10) +# define RS400_FP2_2_SOURCE_SEL_RMX (2 << 10) +# define RS400_FP2_2_DVO2_EN (1 << 25) +#define RS400_TMDS2_CNTL 0x0394 +#define RS400_TMDS2_TRANSMITTER_CNTL 0x03a4 +# define RS400_TMDS2_PLLEN (1 << 0) +# define RS400_TMDS2_PLLRST (1 << 1) + +#define RADEON_GEN_INT_CNTL 0x0040 +#define RADEON_GEN_INT_STATUS 0x0044 +# define RADEON_VSYNC_INT_AK (1 << 2) +# define RADEON_VSYNC_INT (1 << 2) +# define RADEON_VSYNC2_INT_AK (1 << 6) +# define RADEON_VSYNC2_INT (1 << 6) +#define RADEON_GENENB 0x03c3 /* VGA */ +#define RADEON_GENFC_RD 0x03ca /* VGA */ +#define RADEON_GENFC_WT 0x03da /* VGA, 0x03ba */ +#define RADEON_GENMO_RD 0x03cc /* VGA */ +#define RADEON_GENMO_WT 0x03c2 /* VGA */ +#define RADEON_GENS0 0x03c2 /* VGA */ +#define RADEON_GENS1 0x03da /* VGA, 0x03ba */ +#define RADEON_GPIO_MONID 0x0068 /* DDC interface via I2C */ +#define RADEON_GPIO_MONIDB 0x006c +#define RADEON_GPIO_CRT2_DDC 0x006c +#define RADEON_GPIO_DVI_DDC 0x0064 +#define RADEON_GPIO_VGA_DDC 0x0060 +# define RADEON_GPIO_A_0 (1 << 0) +# define RADEON_GPIO_A_1 (1 << 1) +# define RADEON_GPIO_Y_0 (1 << 8) +# define RADEON_GPIO_Y_1 (1 << 9) +# define RADEON_GPIO_Y_SHIFT_0 8 +# define RADEON_GPIO_Y_SHIFT_1 9 +# define RADEON_GPIO_EN_0 (1 << 16) +# define RADEON_GPIO_EN_1 (1 << 17) +# define RADEON_GPIO_MASK_0 (1 << 24) /*??*/ +# define RADEON_GPIO_MASK_1 (1 << 25) /*??*/ +#define RADEON_GRPH8_DATA 0x03cf /* VGA */ +#define RADEON_GRPH8_IDX 0x03ce /* VGA */ +#define RADEON_GUI_SCRATCH_REG0 0x15e0 +#define RADEON_GUI_SCRATCH_REG1 0x15e4 +#define RADEON_GUI_SCRATCH_REG2 0x15e8 +#define RADEON_GUI_SCRATCH_REG3 0x15ec +#define RADEON_GUI_SCRATCH_REG4 0x15f0 +#define RADEON_GUI_SCRATCH_REG5 0x15f4 + +#define RADEON_HEADER 0x0f0e /* PCI */ +#define RADEON_HOST_DATA0 0x17c0 +#define RADEON_HOST_DATA1 0x17c4 +#define RADEON_HOST_DATA2 0x17c8 +#define RADEON_HOST_DATA3 0x17cc +#define RADEON_HOST_DATA4 0x17d0 +#define RADEON_HOST_DATA5 0x17d4 +#define RADEON_HOST_DATA6 0x17d8 +#define RADEON_HOST_DATA7 0x17dc +#define RADEON_HOST_DATA_LAST 0x17e0 +#define RADEON_HOST_PATH_CNTL 0x0130 +# define RADEON_HDP_SOFT_RESET (1 << 26) +# define RADEON_HDP_APER_CNTL (1 << 23) +#define RADEON_HTOTAL_CNTL 0x0009 /* PLL */ +# define RADEON_HTOT_CNTL_VGA_EN (1 << 28) +#define RADEON_HTOTAL2_CNTL 0x002e /* PLL */ + + /* Multimedia I2C bus */ +#define RADEON_I2C_CNTL_0 0x0090 +#define RADEON_I2C_DONE (1<<0) +#define RADEON_I2C_NACK (1<<1) +#define RADEON_I2C_HALT (1<<2) +#define RADEON_I2C_SOFT_RST (1<<5) +#define RADEON_I2C_DRIVE_EN (1<<6) +#define RADEON_I2C_DRIVE_SEL (1<<7) +#define RADEON_I2C_START (1<<8) +#define RADEON_I2C_STOP (1<<9) +#define RADEON_I2C_RECEIVE (1<<10) +#define RADEON_I2C_ABORT (1<<11) +#define RADEON_I2C_GO (1<<12) +#define RADEON_I2C_CNTL_1 0x0094 +#define RADEON_I2C_SEL (1<<16) +#define RADEON_I2C_EN (1<<17) +#define RADEON_I2C_DATA 0x0098 + +#define RADEON_DVI_I2C_CNTL_0 0x02e0 +#define RADEON_DVI_I2C_CNTL_1 0x02e4 /* ? */ +#define RADEON_DVI_I2C_DATA 0x02e8 + +#define RADEON_INTERRUPT_LINE 0x0f3c /* PCI */ +#define RADEON_INTERRUPT_PIN 0x0f3d /* PCI */ +#define RADEON_IO_BASE 0x0f14 /* PCI */ + +#define RADEON_LATENCY 0x0f0d /* PCI */ +#define RADEON_LEAD_BRES_DEC 0x1608 +#define RADEON_LEAD_BRES_LNTH 0x161c +#define RADEON_LEAD_BRES_LNTH_SUB 0x1624 +#define RADEON_LVDS_GEN_CNTL 0x02d0 +# define RADEON_LVDS_ON (1 << 0) +# define RADEON_LVDS_DISPLAY_DIS (1 << 1) +# define RADEON_LVDS_PANEL_TYPE (1 << 2) +# define RADEON_LVDS_PANEL_FORMAT (1 << 3) +# define RADEON_LVDS_RST_FM (1 << 6) +# define RADEON_LVDS_EN (1 << 7) +# define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 +# define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) +# define RADEON_LVDS_BL_MOD_EN (1 << 16) +# define RADEON_LVDS_DIGON (1 << 18) +# define RADEON_LVDS_BLON (1 << 19) +# define RADEON_LVDS_SEL_CRTC2 (1 << 23) +#define RADEON_LVDS_PLL_CNTL 0x02d4 +# define RADEON_HSYNC_DELAY_SHIFT 28 +# define RADEON_HSYNC_DELAY_MASK (0xf << 28) +# define RADEON_LVDS_PLL_EN (1 << 16) +# define RADEON_LVDS_PLL_RESET (1 << 17) +# define R300_LVDS_SRC_SEL_MASK (3 << 18) +# define R300_LVDS_SRC_SEL_CRTC1 (0 << 18) +# define R300_LVDS_SRC_SEL_CRTC2 (1 << 18) +# define R300_LVDS_SRC_SEL_RMX (2 << 18) + +#define RADEON_MAX_LATENCY 0x0f3f /* PCI */ +#define RADEON_MC_AGP_LOCATION 0x014c +#define RADEON_MC_FB_LOCATION 0x0148 +#define RADEON_DISPLAY_BASE_ADDR 0x23c +#define RADEON_DISPLAY2_BASE_ADDR 0x33c +#define RADEON_OV0_BASE_ADDR 0x43c +#define RADEON_NB_TOM 0x15c +#define R300_MC_INIT_MISC_LAT_TIMER 0x180 +#define RADEON_MCLK_CNTL 0x0012 /* PLL */ +# define RADEON_FORCEON_MCLKA (1 << 16) +# define RADEON_FORCEON_MCLKB (1 << 17) +# define RADEON_FORCEON_YCLKA (1 << 18) +# define RADEON_FORCEON_YCLKB (1 << 19) +# define RADEON_FORCEON_MC (1 << 20) +# define RADEON_FORCEON_AIC (1 << 21) +# define R300_DISABLE_MC_MCLKA (1 << 21) +# define R300_DISABLE_MC_MCLKB (1 << 21) +#define RADEON_MCLK_MISC 0x001f /* PLL */ +# define RADEON_MC_MCLK_MAX_DYN_STOP_LAT (1 << 12) +# define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1 << 13) +# define RADEON_MC_MCLK_DYN_ENABLE (1 << 14) +# define RADEON_IO_MCLK_DYN_ENABLE (1 << 15) +#define RADEON_LCD_GPIO_MASK 0x01a0 +#define RADEON_GPIOPAD_EN 0x01a0 +#define RADEON_LCD_GPIO_Y_REG 0x01a4 +#define RADEON_MDGPIO_A_REG 0x01ac +#define RADEON_MDGPIO_EN_REG 0x01b0 +#define RADEON_MDGPIO_MASK 0x0198 +#define RADEON_GPIOPAD_MASK 0x0198 +#define RADEON_GPIOPAD_A 0x019c +#define RADEON_MDGPIO_Y_REG 0x01b4 +#define RADEON_MEM_ADDR_CONFIG 0x0148 +#define RADEON_MEM_BASE 0x0f10 /* PCI */ +#define RADEON_MEM_CNTL 0x0140 +# define RADEON_MEM_NUM_CHANNELS_MASK 0x01 +# define RADEON_MEM_USE_B_CH_ONLY (1 << 1) +# define RV100_HALF_MODE (1 << 3) +# define R300_MEM_NUM_CHANNELS_MASK 0x03 +# define R300_MEM_USE_CD_CH_ONLY (1 << 2) +#define RADEON_MEM_TIMING_CNTL 0x0144 /* EXT_MEM_CNTL */ +#define RADEON_MEM_INIT_LAT_TIMER 0x0154 +#define RADEON_MEM_INTF_CNTL 0x014c +#define RADEON_MEM_SDRAM_MODE_REG 0x0158 +# define RADEON_SDRAM_MODE_MASK 0xffff0000 +# define RADEON_B3MEM_RESET_MASK 0x6fffffff +# define RADEON_MEM_CFG_TYPE_DDR (1 << 30) +#define RADEON_MEM_STR_CNTL 0x0150 +# define RADEON_MEM_PWRUP_COMPL_A (1 << 0) +# define RADEON_MEM_PWRUP_COMPL_B (1 << 1) +# define R300_MEM_PWRUP_COMPL_C (1 << 2) +# define R300_MEM_PWRUP_COMPL_D (1 << 3) +# define RADEON_MEM_PWRUP_COMPLETE 0x03 +# define R300_MEM_PWRUP_COMPLETE 0x0f +#define RADEON_MC_STATUS 0x0150 +# define RADEON_MC_IDLE (1 << 2) +# define R300_MC_IDLE (1 << 4) +#define RADEON_MEM_VGA_RP_SEL 0x003c +#define RADEON_MEM_VGA_WP_SEL 0x0038 +#define RADEON_MIN_GRANT 0x0f3e /* PCI */ +#define RADEON_MM_DATA 0x0004 +#define RADEON_MM_INDEX 0x0000 +#define RADEON_MPLL_CNTL 0x000e /* PLL */ +#define RADEON_MPP_TB_CONFIG 0x01c0 /* ? */ +#define RADEON_MPP_GP_CONFIG 0x01c8 /* ? */ +#define RADEON_SEPROM_CNTL1 0x01c0 +# define RADEON_SCK_PRESCALE_SHIFT 24 +# define RADEON_SCK_PRESCALE_MASK (0xff << 24) +#define R300_MC_IND_INDEX 0x01f8 +# define R300_MC_IND_ADDR_MASK 0x3f +# define R300_MC_IND_WR_EN (1 << 8) +#define R300_MC_IND_DATA 0x01fc +#define R300_MC_READ_CNTL_AB 0x017c +# define R300_MEM_RBS_POSITION_A_MASK 0x03 +#define R300_MC_READ_CNTL_CD_mcind 0x24 +# define R300_MEM_RBS_POSITION_C_MASK 0x03 + +#define RADEON_N_VIF_COUNT 0x0248 + +#define RADEON_OV0_AUTO_FLIP_CNTL 0x0470 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_NUM 0x00000007 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_REPEAT_FIELD 0x00000008 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD 0x00000010 +# define RADEON_OV0_AUTO_FLIP_CNTL_IGNORE_REPEAT_FIELD 0x00000020 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_EOF_TOGGLE 0x00000040 +# define RADEON_OV0_AUTO_FLIP_CNTL_VID_PORT_SELECT 0x00000300 +# define RADEON_OV0_AUTO_FLIP_CNTL_P1_FIRST_LINE_EVEN 0x00010000 +# define RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_EVEN_DOWN 0x00040000 +# define RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_ODD_DOWN 0x00080000 +# define RADEON_OV0_AUTO_FLIP_CNTL_FIELD_POL_SOURCE 0x00800000 + +#define RADEON_OV0_COLOUR_CNTL 0x04E0 +#define RADEON_OV0_DEINTERLACE_PATTERN 0x0474 +#define RADEON_OV0_EXCLUSIVE_HORZ 0x0408 +# define RADEON_EXCL_HORZ_START_MASK 0x000000ff +# define RADEON_EXCL_HORZ_END_MASK 0x0000ff00 +# define RADEON_EXCL_HORZ_BACK_PORCH_MASK 0x00ff0000 +# define RADEON_EXCL_HORZ_EXCLUSIVE_EN 0x80000000 +#define RADEON_OV0_EXCLUSIVE_VERT 0x040C +# define RADEON_EXCL_VERT_START_MASK 0x000003ff +# define RADEON_EXCL_VERT_END_MASK 0x03ff0000 +#define RADEON_OV0_FILTER_CNTL 0x04A0 +# define RADEON_FILTER_PROGRAMMABLE_COEF 0x0 +# define RADEON_FILTER_HC_COEF_HORZ_Y 0x1 +# define RADEON_FILTER_HC_COEF_HORZ_UV 0x2 +# define RADEON_FILTER_HC_COEF_VERT_Y 0x4 +# define RADEON_FILTER_HC_COEF_VERT_UV 0x8 +# define RADEON_FILTER_HARDCODED_COEF 0xf +# define RADEON_FILTER_COEF_MASK 0xf + +#define RADEON_OV0_FOUR_TAP_COEF_0 0x04B0 +#define RADEON_OV0_FOUR_TAP_COEF_1 0x04B4 +#define RADEON_OV0_FOUR_TAP_COEF_2 0x04B8 +#define RADEON_OV0_FOUR_TAP_COEF_3 0x04BC +#define RADEON_OV0_FOUR_TAP_COEF_4 0x04C0 +#define RADEON_OV0_FLAG_CNTL 0x04DC +#define RADEON_OV0_GAMMA_000_00F 0x0d40 +#define RADEON_OV0_GAMMA_010_01F 0x0d44 +#define RADEON_OV0_GAMMA_020_03F 0x0d48 +#define RADEON_OV0_GAMMA_040_07F 0x0d4c +#define RADEON_OV0_GAMMA_080_0BF 0x0e00 +#define RADEON_OV0_GAMMA_0C0_0FF 0x0e04 +#define RADEON_OV0_GAMMA_100_13F 0x0e08 +#define RADEON_OV0_GAMMA_140_17F 0x0e0c +#define RADEON_OV0_GAMMA_180_1BF 0x0e10 +#define RADEON_OV0_GAMMA_1C0_1FF 0x0e14 +#define RADEON_OV0_GAMMA_200_23F 0x0e18 +#define RADEON_OV0_GAMMA_240_27F 0x0e1c +#define RADEON_OV0_GAMMA_280_2BF 0x0e20 +#define RADEON_OV0_GAMMA_2C0_2FF 0x0e24 +#define RADEON_OV0_GAMMA_300_33F 0x0e28 +#define RADEON_OV0_GAMMA_340_37F 0x0e2c +#define RADEON_OV0_GAMMA_380_3BF 0x0d50 +#define RADEON_OV0_GAMMA_3C0_3FF 0x0d54 +#define RADEON_OV0_GRAPHICS_KEY_CLR_LOW 0x04EC +#define RADEON_OV0_GRAPHICS_KEY_CLR_HIGH 0x04F0 +#define RADEON_OV0_H_INC 0x0480 +#define RADEON_OV0_KEY_CNTL 0x04F4 +# define RADEON_VIDEO_KEY_FN_MASK 0x00000003L +# define RADEON_VIDEO_KEY_FN_FALSE 0x00000000L +# define RADEON_VIDEO_KEY_FN_TRUE 0x00000001L +# define RADEON_VIDEO_KEY_FN_EQ 0x00000002L +# define RADEON_VIDEO_KEY_FN_NE 0x00000003L +# define RADEON_GRAPHIC_KEY_FN_MASK 0x00000030L +# define RADEON_GRAPHIC_KEY_FN_FALSE 0x00000000L +# define RADEON_GRAPHIC_KEY_FN_TRUE 0x00000010L +# define RADEON_GRAPHIC_KEY_FN_EQ 0x00000020L +# define RADEON_GRAPHIC_KEY_FN_NE 0x00000030L +# define RADEON_CMP_MIX_MASK 0x00000100L +# define RADEON_CMP_MIX_OR 0x00000000L +# define RADEON_CMP_MIX_AND 0x00000100L +#define RADEON_OV0_LIN_TRANS_A 0x0d20 +#define RADEON_OV0_LIN_TRANS_B 0x0d24 +#define RADEON_OV0_LIN_TRANS_C 0x0d28 +#define RADEON_OV0_LIN_TRANS_D 0x0d2c +#define RADEON_OV0_LIN_TRANS_E 0x0d30 +#define RADEON_OV0_LIN_TRANS_F 0x0d34 +#define RADEON_OV0_P1_BLANK_LINES_AT_TOP 0x0430 +# define RADEON_P1_BLNK_LN_AT_TOP_M1_MASK 0x00000fffL +# define RADEON_P1_ACTIVE_LINES_M1 0x0fff0000L +#define RADEON_OV0_P1_H_ACCUM_INIT 0x0488 +#define RADEON_OV0_P1_V_ACCUM_INIT 0x0428 +# define RADEON_OV0_P1_MAX_LN_IN_PER_LN_OUT 0x00000003L +# define RADEON_OV0_P1_V_ACCUM_INIT_MASK 0x01ff8000L +#define RADEON_OV0_P1_X_START_END 0x0494 +#define RADEON_OV0_P2_X_START_END 0x0498 +#define RADEON_OV0_P23_BLANK_LINES_AT_TOP 0x0434 +# define RADEON_P23_BLNK_LN_AT_TOP_M1_MASK 0x000007ffL +# define RADEON_P23_ACTIVE_LINES_M1 0x07ff0000L +#define RADEON_OV0_P23_H_ACCUM_INIT 0x048C +#define RADEON_OV0_P23_V_ACCUM_INIT 0x042C +#define RADEON_OV0_P3_X_START_END 0x049C +#define RADEON_OV0_REG_LOAD_CNTL 0x0410 +# define RADEON_REG_LD_CTL_LOCK 0x00000001L +# define RADEON_REG_LD_CTL_VBLANK_DURING_LOCK 0x00000002L +# define RADEON_REG_LD_CTL_STALL_GUI_UNTIL_FLIP 0x00000004L +# define RADEON_REG_LD_CTL_LOCK_READBACK 0x00000008L +# define RADEON_REG_LD_CTL_FLIP_READBACK 0x00000010L +#define RADEON_OV0_SCALE_CNTL 0x0420 +# define RADEON_SCALER_HORZ_PICK_NEAREST 0x00000004L +# define RADEON_SCALER_VERT_PICK_NEAREST 0x00000008L +# define RADEON_SCALER_SIGNED_UV 0x00000010L +# define RADEON_SCALER_GAMMA_SEL_MASK 0x00000060L +# define RADEON_SCALER_GAMMA_SEL_BRIGHT 0x00000000L +# define RADEON_SCALER_GAMMA_SEL_G22 0x00000020L +# define RADEON_SCALER_GAMMA_SEL_G18 0x00000040L +# define RADEON_SCALER_GAMMA_SEL_G14 0x00000060L +# define RADEON_SCALER_COMCORE_SHIFT_UP_ONE 0x00000080L +# define RADEON_SCALER_SURFAC_FORMAT 0x00000f00L +# define RADEON_SCALER_SOURCE_15BPP 0x00000300L +# define RADEON_SCALER_SOURCE_16BPP 0x00000400L +# define RADEON_SCALER_SOURCE_32BPP 0x00000600L +# define RADEON_SCALER_SOURCE_YUV9 0x00000900L +# define RADEON_SCALER_SOURCE_YUV12 0x00000A00L +# define RADEON_SCALER_SOURCE_VYUY422 0x00000B00L +# define RADEON_SCALER_SOURCE_YVYU422 0x00000C00L +# define RADEON_SCALER_ADAPTIVE_DEINT 0x00001000L +# define RADEON_SCALER_TEMPORAL_DEINT 0x00002000L +# define RADEON_SCALER_CRTC_SEL 0x00004000L +# define RADEON_SCALER_SMART_SWITCH 0x00008000L +# define RADEON_SCALER_BURST_PER_PLANE 0x007F0000L +# define RADEON_SCALER_DOUBLE_BUFFER 0x01000000L +# define RADEON_SCALER_DIS_LIMIT 0x08000000L +# define RADEON_SCALER_LIN_TRANS_BYPASS 0x10000000L +# define RADEON_SCALER_INT_EMU 0x20000000L +# define RADEON_SCALER_ENABLE 0x40000000L +# define RADEON_SCALER_SOFT_RESET 0x80000000L +#define RADEON_OV0_STEP_BY 0x0484 +#define RADEON_OV0_TEST 0x04F8 +#define RADEON_OV0_V_INC 0x0424 +#define RADEON_OV0_VID_BUF_PITCH0_VALUE 0x0460 +#define RADEON_OV0_VID_BUF_PITCH1_VALUE 0x0464 +#define RADEON_OV0_VID_BUF0_BASE_ADRS 0x0440 +# define RADEON_VIF_BUF0_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF0_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF0_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF0_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF1_BASE_ADRS 0x0444 +# define RADEON_VIF_BUF1_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF1_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF1_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF1_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF2_BASE_ADRS 0x0448 +# define RADEON_VIF_BUF2_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF2_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF2_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF2_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF3_BASE_ADRS 0x044C +#define RADEON_OV0_VID_BUF4_BASE_ADRS 0x0450 +#define RADEON_OV0_VID_BUF5_BASE_ADRS 0x0454 +#define RADEON_OV0_VIDEO_KEY_CLR_HIGH 0x04E8 +#define RADEON_OV0_VIDEO_KEY_CLR_LOW 0x04E4 +#define RADEON_OV0_Y_X_START 0x0400 +#define RADEON_OV0_Y_X_END 0x0404 +#define RADEON_OV1_Y_X_START 0x0600 +#define RADEON_OV1_Y_X_END 0x0604 +#define RADEON_OVR_CLR 0x0230 +#define RADEON_OVR_WID_LEFT_RIGHT 0x0234 +#define RADEON_OVR_WID_TOP_BOTTOM 0x0238 + +/* first capture unit */ + +#define RADEON_CAP0_BUF0_OFFSET 0x0920 +#define RADEON_CAP0_BUF1_OFFSET 0x0924 +#define RADEON_CAP0_BUF0_EVEN_OFFSET 0x0928 +#define RADEON_CAP0_BUF1_EVEN_OFFSET 0x092C + +#define RADEON_CAP0_BUF_PITCH 0x0930 +#define RADEON_CAP0_V_WINDOW 0x0934 +#define RADEON_CAP0_H_WINDOW 0x0938 +#define RADEON_CAP0_VBI0_OFFSET 0x093C +#define RADEON_CAP0_VBI1_OFFSET 0x0940 +#define RADEON_CAP0_VBI_V_WINDOW 0x0944 +#define RADEON_CAP0_VBI_H_WINDOW 0x0948 +#define RADEON_CAP0_PORT_MODE_CNTL 0x094C +#define RADEON_CAP0_TRIG_CNTL 0x0950 +#define RADEON_CAP0_DEBUG 0x0954 +#define RADEON_CAP0_CONFIG 0x0958 +# define RADEON_CAP0_CONFIG_CONTINUOS 0x00000001 +# define RADEON_CAP0_CONFIG_START_FIELD_EVEN 0x00000002 +# define RADEON_CAP0_CONFIG_START_BUF_GET 0x00000004 +# define RADEON_CAP0_CONFIG_START_BUF_SET 0x00000008 +# define RADEON_CAP0_CONFIG_BUF_TYPE_ALT 0x00000010 +# define RADEON_CAP0_CONFIG_BUF_TYPE_FRAME 0x00000020 +# define RADEON_CAP0_CONFIG_ONESHOT_MODE_FRAME 0x00000040 +# define RADEON_CAP0_CONFIG_BUF_MODE_DOUBLE 0x00000080 +# define RADEON_CAP0_CONFIG_BUF_MODE_TRIPLE 0x00000100 +# define RADEON_CAP0_CONFIG_MIRROR_EN 0x00000200 +# define RADEON_CAP0_CONFIG_ONESHOT_MIRROR_EN 0x00000400 +# define RADEON_CAP0_CONFIG_VIDEO_SIGNED_UV 0x00000800 +# define RADEON_CAP0_CONFIG_ANC_DECODE_EN 0x00001000 +# define RADEON_CAP0_CONFIG_VBI_EN 0x00002000 +# define RADEON_CAP0_CONFIG_SOFT_PULL_DOWN_EN 0x00004000 +# define RADEON_CAP0_CONFIG_VIP_EXTEND_FLAG_EN 0x00008000 +# define RADEON_CAP0_CONFIG_FAKE_FIELD_EN 0x00010000 +# define RADEON_CAP0_CONFIG_ODD_ONE_MORE_LINE 0x00020000 +# define RADEON_CAP0_CONFIG_EVEN_ONE_MORE_LINE 0x00040000 +# define RADEON_CAP0_CONFIG_HORZ_DIVIDE_2 0x00080000 +# define RADEON_CAP0_CONFIG_HORZ_DIVIDE_4 0x00100000 +# define RADEON_CAP0_CONFIG_VERT_DIVIDE_2 0x00200000 +# define RADEON_CAP0_CONFIG_VERT_DIVIDE_4 0x00400000 +# define RADEON_CAP0_CONFIG_FORMAT_BROOKTREE 0x00000000 +# define RADEON_CAP0_CONFIG_FORMAT_CCIR656 0x00800000 +# define RADEON_CAP0_CONFIG_FORMAT_ZV 0x01000000 +# define RADEON_CAP0_CONFIG_FORMAT_VIP 0x01800000 +# define RADEON_CAP0_CONFIG_FORMAT_TRANSPORT 0x02000000 +# define RADEON_CAP0_CONFIG_HORZ_DECIMATOR 0x04000000 +# define RADEON_CAP0_CONFIG_VIDEO_IN_YVYU422 0x00000000 +# define RADEON_CAP0_CONFIG_VIDEO_IN_VYUY422 0x20000000 +# define RADEON_CAP0_CONFIG_VBI_DIVIDE_2 0x40000000 +# define RADEON_CAP0_CONFIG_VBI_DIVIDE_4 0x80000000 +#define RADEON_CAP0_ANC_ODD_OFFSET 0x095C +#define RADEON_CAP0_ANC_EVEN_OFFSET 0x0960 +#define RADEON_CAP0_ANC_H_WINDOW 0x0964 +#define RADEON_CAP0_VIDEO_SYNC_TEST 0x0968 +#define RADEON_CAP0_ONESHOT_BUF_OFFSET 0x096C +#define RADEON_CAP0_BUF_STATUS 0x0970 +/* #define RADEON_CAP0_DWNSC_XRATIO 0x0978 */ +/* #define RADEON_CAP0_XSHARPNESS 0x097C */ +#define RADEON_CAP0_VBI2_OFFSET 0x0980 +#define RADEON_CAP0_VBI3_OFFSET 0x0984 +#define RADEON_CAP0_ANC2_OFFSET 0x0988 +#define RADEON_CAP0_ANC3_OFFSET 0x098C +#define RADEON_VID_BUFFER_CONTROL 0x0900 + +/* second capture unit */ + +#define RADEON_CAP1_BUF0_OFFSET 0x0990 +#define RADEON_CAP1_BUF1_OFFSET 0x0994 +#define RADEON_CAP1_BUF0_EVEN_OFFSET 0x0998 +#define RADEON_CAP1_BUF1_EVEN_OFFSET 0x099C + +#define RADEON_CAP1_BUF_PITCH 0x09A0 +#define RADEON_CAP1_V_WINDOW 0x09A4 +#define RADEON_CAP1_H_WINDOW 0x09A8 +#define RADEON_CAP1_VBI_ODD_OFFSET 0x09AC +#define RADEON_CAP1_VBI_EVEN_OFFSET 0x09B0 +#define RADEON_CAP1_VBI_V_WINDOW 0x09B4 +#define RADEON_CAP1_VBI_H_WINDOW 0x09B8 +#define RADEON_CAP1_PORT_MODE_CNTL 0x09BC +#define RADEON_CAP1_TRIG_CNTL 0x09C0 +#define RADEON_CAP1_DEBUG 0x09C4 +#define RADEON_CAP1_CONFIG 0x09C8 +#define RADEON_CAP1_ANC_ODD_OFFSET 0x09CC +#define RADEON_CAP1_ANC_EVEN_OFFSET 0x09D0 +#define RADEON_CAP1_ANC_H_WINDOW 0x09D4 +#define RADEON_CAP1_VIDEO_SYNC_TEST 0x09D8 +#define RADEON_CAP1_ONESHOT_BUF_OFFSET 0x09DC +#define RADEON_CAP1_BUF_STATUS 0x09E0 +#define RADEON_CAP1_DWNSC_XRATIO 0x09E8 +#define RADEON_CAP1_XSHARPNESS 0x09EC + +/* misc multimedia registers */ + +#define RADEON_IDCT_RUNS 0x1F80 +#define RADEON_IDCT_LEVELS 0x1F84 +#define RADEON_IDCT_CONTROL 0x1FBC +#define RADEON_IDCT_AUTH_CONTROL 0x1F88 +#define RADEON_IDCT_AUTH 0x1F8C + +#define RADEON_P2PLL_CNTL 0x002a /* P2PLL */ +# define RADEON_P2PLL_RESET (1 << 0) +# define RADEON_P2PLL_SLEEP (1 << 1) +# define RADEON_P2PLL_PVG_MASK (7 << 11) +# define RADEON_P2PLL_PVG_SHIFT 11 +# define RADEON_P2PLL_ATOMIC_UPDATE_EN (1 << 16) +# define RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +# define RADEON_P2PLL_ATOMIC_UPDATE_VSYNC (1 << 18) +#define RADEON_P2PLL_DIV_0 0x002c +# define RADEON_P2PLL_FB0_DIV_MASK 0x07ff +# define RADEON_P2PLL_POST0_DIV_MASK 0x00070000 +#define RADEON_P2PLL_REF_DIV 0x002B /* PLL */ +# define RADEON_P2PLL_REF_DIV_MASK 0x03ff +# define RADEON_P2PLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define RADEON_P2PLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +# define R300_PPLL_REF_DIV_ACC_MASK (0x3ff << 18) +# define R300_PPLL_REF_DIV_ACC_SHIFT 18 +#define RADEON_PALETTE_DATA 0x00b4 +#define RADEON_PALETTE_30_DATA 0x00b8 +#define RADEON_PALETTE_INDEX 0x00b0 +#define RADEON_PCI_GART_PAGE 0x017c +#define RADEON_PIXCLKS_CNTL 0x002d +# define RADEON_PIX2CLK_SRC_SEL_MASK 0x03 +# define RADEON_PIX2CLK_SRC_SEL_CPUCLK 0x00 +# define RADEON_PIX2CLK_SRC_SEL_PSCANCLK 0x01 +# define RADEON_PIX2CLK_SRC_SEL_BYTECLK 0x02 +# define RADEON_PIX2CLK_SRC_SEL_P2PLLCLK 0x03 +# define RADEON_PIX2CLK_ALWAYS_ONb (1<<6) +# define RADEON_PIX2CLK_DAC_ALWAYS_ONb (1<<7) +# define RADEON_PIXCLK_TV_SRC_SEL (1 << 8) +# define RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb (1 << 9) +# define R300_DVOCLK_ALWAYS_ONb (1 << 10) +# define RADEON_PIXCLK_BLEND_ALWAYS_ONb (1 << 11) +# define RADEON_PIXCLK_GV_ALWAYS_ONb (1 << 12) +# define RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb (1 << 13) +# define R300_PIXCLK_DVO_ALWAYS_ONb (1 << 13) +# define RADEON_PIXCLK_LVDS_ALWAYS_ONb (1 << 14) +# define RADEON_PIXCLK_TMDS_ALWAYS_ONb (1 << 15) +# define R300_PIXCLK_TRANS_ALWAYS_ONb (1 << 16) +# define R300_PIXCLK_TVO_ALWAYS_ONb (1 << 17) +# define R300_P2G2CLK_ALWAYS_ONb (1 << 18) +# define R300_P2G2CLK_DAC_ALWAYS_ONb (1 << 19) +# define R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF (1 << 23) +#define RADEON_PLANE_3D_MASK_C 0x1d44 +#define RADEON_PLL_TEST_CNTL 0x0013 /* PLL */ +# define RADEON_PLL_MASK_READ_B (1 << 9) +#define RADEON_PMI_CAP_ID 0x0f5c /* PCI */ +#define RADEON_PMI_DATA 0x0f63 /* PCI */ +#define RADEON_PMI_NXT_CAP_PTR 0x0f5d /* PCI */ +#define RADEON_PMI_PMC_REG 0x0f5e /* PCI */ +#define RADEON_PMI_PMCSR_REG 0x0f60 /* PCI */ +#define RADEON_PMI_REGISTER 0x0f5c /* PCI */ +#define RADEON_PPLL_CNTL 0x0002 /* PLL */ +# define RADEON_PPLL_RESET (1 << 0) +# define RADEON_PPLL_SLEEP (1 << 1) +# define RADEON_PPLL_PVG_MASK (7 << 11) +# define RADEON_PPLL_PVG_SHIFT 11 +# define RADEON_PPLL_ATOMIC_UPDATE_EN (1 << 16) +# define RADEON_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +# define RADEON_PPLL_ATOMIC_UPDATE_VSYNC (1 << 18) +#define RADEON_PPLL_DIV_0 0x0004 /* PLL */ +#define RADEON_PPLL_DIV_1 0x0005 /* PLL */ +#define RADEON_PPLL_DIV_2 0x0006 /* PLL */ +#define RADEON_PPLL_DIV_3 0x0007 /* PLL */ +# define RADEON_PPLL_FB3_DIV_MASK 0x07ff +# define RADEON_PPLL_POST3_DIV_MASK 0x00070000 +#define RADEON_PPLL_REF_DIV 0x0003 /* PLL */ +# define RADEON_PPLL_REF_DIV_MASK 0x03ff +# define RADEON_PPLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define RADEON_PPLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +#define RADEON_PWR_MNGMT_CNTL_STATUS 0x0f60 /* PCI */ + +#define RADEON_RBBM_GUICNTL 0x172c +# define RADEON_HOST_DATA_SWAP_NONE (0 << 0) +# define RADEON_HOST_DATA_SWAP_16BIT (1 << 0) +# define RADEON_HOST_DATA_SWAP_32BIT (2 << 0) +# define RADEON_HOST_DATA_SWAP_HDW (3 << 0) +#define RADEON_RBBM_SOFT_RESET 0x00f0 +# define RADEON_SOFT_RESET_CP (1 << 0) +# define RADEON_SOFT_RESET_HI (1 << 1) +# define RADEON_SOFT_RESET_SE (1 << 2) +# define RADEON_SOFT_RESET_RE (1 << 3) +# define RADEON_SOFT_RESET_PP (1 << 4) +# define RADEON_SOFT_RESET_E2 (1 << 5) +# define RADEON_SOFT_RESET_RB (1 << 6) +# define RADEON_SOFT_RESET_HDP (1 << 7) +#define RADEON_RBBM_STATUS 0x0e40 +# define RADEON_RBBM_FIFOCNT_MASK 0x007f +# define RADEON_RBBM_ACTIVE (1 << 31) +#define RADEON_RB2D_DSTCACHE_CTLSTAT 0x342c +# define RADEON_RB2D_DC_FLUSH (3 << 0) +# define RADEON_RB2D_DC_FREE (3 << 2) +# define RADEON_RB2D_DC_FLUSH_ALL 0xf +# define RADEON_RB2D_DC_BUSY (1 << 31) +#define RADEON_RB2D_DSTCACHE_MODE 0x3428 +#define RADEON_DSTCACHE_CTLSTAT 0x1714 + +#define RADEON_RB3D_ZCACHE_MODE 0x3250 +#define RADEON_RB3D_ZCACHE_CTLSTAT 0x3254 +# define RADEON_RB3D_ZC_FLUSH_ALL 0x5 +#define RADEON_RB3D_DSTCACHE_MODE 0x3258 +# define RADEON_RB3D_DC_CACHE_ENABLE (0) +# define RADEON_RB3D_DC_2D_CACHE_DISABLE (1) +# define RADEON_RB3D_DC_3D_CACHE_DISABLE (2) +# define RADEON_RB3D_DC_CACHE_DISABLE (3) +# define RADEON_RB3D_DC_2D_CACHE_LINESIZE_128 (1 << 2) +# define RADEON_RB3D_DC_3D_CACHE_LINESIZE_128 (2 << 2) +# define RADEON_RB3D_DC_2D_CACHE_AUTOFLUSH (1 << 8) +# define RADEON_RB3D_DC_3D_CACHE_AUTOFLUSH (2 << 8) +# define R200_RB3D_DC_2D_CACHE_AUTOFREE (1 << 10) +# define R200_RB3D_DC_3D_CACHE_AUTOFREE (2 << 10) +# define RADEON_RB3D_DC_FORCE_RMW (1 << 16) +# define RADEON_RB3D_DC_DISABLE_RI_FILL (1 << 24) +# define RADEON_RB3D_DC_DISABLE_RI_READ (1 << 25) + +#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325C +# define RADEON_RB3D_DC_FLUSH (3 << 0) +# define RADEON_RB3D_DC_FREE (3 << 2) +# define RADEON_RB3D_DC_FLUSH_ALL 0xf +# define RADEON_RB3D_DC_BUSY (1 << 31) + +#define RADEON_REG_BASE 0x0f18 /* PCI */ +#define RADEON_REGPROG_INF 0x0f09 /* PCI */ +#define RADEON_REVISION_ID 0x0f08 /* PCI */ + +#define RADEON_SC_BOTTOM 0x164c +#define RADEON_SC_BOTTOM_RIGHT 0x16f0 +#define RADEON_SC_BOTTOM_RIGHT_C 0x1c8c +#define RADEON_SC_LEFT 0x1640 +#define RADEON_SC_RIGHT 0x1644 +#define RADEON_SC_TOP 0x1648 +#define RADEON_SC_TOP_LEFT 0x16ec +#define RADEON_SC_TOP_LEFT_C 0x1c88 +# define RADEON_SC_SIGN_MASK_LO 0x8000 +# define RADEON_SC_SIGN_MASK_HI 0x80000000 +#define RADEON_SCLK_CNTL 0x000d /* PLL */ +# define RADEON_SCLK_SRC_SEL_MASK 0x0007 +# define RADEON_DYN_STOP_LAT_MASK 0x00007ff8 +# define RADEON_CP_MAX_DYN_STOP_LAT 0x0008 +# define RADEON_SCLK_FORCEON_MASK 0xffff8000 +# define RADEON_SCLK_FORCE_DISP2 (1<<15) +# define RADEON_SCLK_FORCE_CP (1<<16) +# define RADEON_SCLK_FORCE_HDP (1<<17) +# define RADEON_SCLK_FORCE_DISP1 (1<<18) +# define RADEON_SCLK_FORCE_TOP (1<<19) +# define RADEON_SCLK_FORCE_E2 (1<<20) +# define RADEON_SCLK_FORCE_SE (1<<21) +# define RADEON_SCLK_FORCE_IDCT (1<<22) +# define RADEON_SCLK_FORCE_VIP (1<<23) +# define RADEON_SCLK_FORCE_RE (1<<24) +# define RADEON_SCLK_FORCE_PB (1<<25) +# define RADEON_SCLK_FORCE_TAM (1<<26) +# define RADEON_SCLK_FORCE_TDM (1<<27) +# define RADEON_SCLK_FORCE_RB (1<<28) +# define RADEON_SCLK_FORCE_TV_SCLK (1<<29) +# define RADEON_SCLK_FORCE_SUBPIC (1<<30) +# define RADEON_SCLK_FORCE_OV0 (1<<31) +# define R300_SCLK_FORCE_VAP (1<<21) +# define R300_SCLK_FORCE_SR (1<<25) +# define R300_SCLK_FORCE_PX (1<<26) +# define R300_SCLK_FORCE_TX (1<<27) +# define R300_SCLK_FORCE_US (1<<28) +# define R300_SCLK_FORCE_SU (1<<30) +#define R300_SCLK_CNTL2 0x1e /* PLL */ +# define R300_SCLK_TCL_MAX_DYN_STOP_LAT (1<<10) +# define R300_SCLK_GA_MAX_DYN_STOP_LAT (1<<11) +# define R300_SCLK_CBA_MAX_DYN_STOP_LAT (1<<12) +# define R300_SCLK_FORCE_TCL (1<<13) +# define R300_SCLK_FORCE_CBA (1<<14) +# define R300_SCLK_FORCE_GA (1<<15) +#define RADEON_SCLK_MORE_CNTL 0x0035 /* PLL */ +# define RADEON_SCLK_MORE_MAX_DYN_STOP_LAT 0x0007 +# define RADEON_SCLK_MORE_FORCEON 0x0700 +#define RADEON_SDRAM_MODE_REG 0x0158 +#define RADEON_SEQ8_DATA 0x03c5 /* VGA */ +#define RADEON_SEQ8_IDX 0x03c4 /* VGA */ +#define RADEON_SNAPSHOT_F_COUNT 0x0244 +#define RADEON_SNAPSHOT_VH_COUNTS 0x0240 +#define RADEON_SNAPSHOT_VIF_COUNT 0x024c +#define RADEON_SRC_OFFSET 0x15ac +#define RADEON_SRC_PITCH 0x15b0 +#define RADEON_SRC_PITCH_OFFSET 0x1428 +#define RADEON_SRC_SC_BOTTOM 0x165c +#define RADEON_SRC_SC_BOTTOM_RIGHT 0x16f4 +#define RADEON_SRC_SC_RIGHT 0x1654 +#define RADEON_SRC_X 0x1414 +#define RADEON_SRC_X_Y 0x1590 +#define RADEON_SRC_Y 0x1418 +#define RADEON_SRC_Y_X 0x1434 +#define RADEON_STATUS 0x0f06 /* PCI */ +#define RADEON_SUBPIC_CNTL 0x0540 /* ? */ +#define RADEON_SUB_CLASS 0x0f0a /* PCI */ +#define RADEON_SURFACE_CNTL 0x0b00 +# define RADEON_SURF_TRANSLATION_DIS (1 << 8) +# define RADEON_NONSURF_AP0_SWP_16BPP (1 << 20) +# define RADEON_NONSURF_AP0_SWP_32BPP (1 << 21) +# define RADEON_NONSURF_AP1_SWP_16BPP (1 << 22) +# define RADEON_NONSURF_AP1_SWP_32BPP (1 << 23) +#define RADEON_SURFACE0_INFO 0x0b0c +# define RADEON_SURF_TILE_COLOR_MACRO (0 << 16) +# define RADEON_SURF_TILE_COLOR_BOTH (1 << 16) +# define RADEON_SURF_TILE_DEPTH_32BPP (2 << 16) +# define RADEON_SURF_TILE_DEPTH_16BPP (3 << 16) +# define R200_SURF_TILE_NONE (0 << 16) +# define R200_SURF_TILE_COLOR_MACRO (1 << 16) +# define R200_SURF_TILE_COLOR_MICRO (2 << 16) +# define R200_SURF_TILE_COLOR_BOTH (3 << 16) +# define R200_SURF_TILE_DEPTH_32BPP (4 << 16) +# define R200_SURF_TILE_DEPTH_16BPP (5 << 16) +# define R300_SURF_TILE_NONE (0 << 16) +# define R300_SURF_TILE_COLOR_MACRO (1 << 16) +# define R300_SURF_TILE_DEPTH_32BPP (2 << 16) +# define RADEON_SURF_AP0_SWP_16BPP (1 << 20) +# define RADEON_SURF_AP0_SWP_32BPP (1 << 21) +# define RADEON_SURF_AP1_SWP_16BPP (1 << 22) +# define RADEON_SURF_AP1_SWP_32BPP (1 << 23) +#define RADEON_SURFACE0_LOWER_BOUND 0x0b04 +#define RADEON_SURFACE0_UPPER_BOUND 0x0b08 +#define RADEON_SURFACE1_INFO 0x0b1c +#define RADEON_SURFACE1_LOWER_BOUND 0x0b14 +#define RADEON_SURFACE1_UPPER_BOUND 0x0b18 +#define RADEON_SURFACE2_INFO 0x0b2c +#define RADEON_SURFACE2_LOWER_BOUND 0x0b24 +#define RADEON_SURFACE2_UPPER_BOUND 0x0b28 +#define RADEON_SURFACE3_INFO 0x0b3c +#define RADEON_SURFACE3_LOWER_BOUND 0x0b34 +#define RADEON_SURFACE3_UPPER_BOUND 0x0b38 +#define RADEON_SURFACE4_INFO 0x0b4c +#define RADEON_SURFACE4_LOWER_BOUND 0x0b44 +#define RADEON_SURFACE4_UPPER_BOUND 0x0b48 +#define RADEON_SURFACE5_INFO 0x0b5c +#define RADEON_SURFACE5_LOWER_BOUND 0x0b54 +#define RADEON_SURFACE5_UPPER_BOUND 0x0b58 +#define RADEON_SURFACE6_INFO 0x0b6c +#define RADEON_SURFACE6_LOWER_BOUND 0x0b64 +#define RADEON_SURFACE6_UPPER_BOUND 0x0b68 +#define RADEON_SURFACE7_INFO 0x0b7c +#define RADEON_SURFACE7_LOWER_BOUND 0x0b74 +#define RADEON_SURFACE7_UPPER_BOUND 0x0b78 +#define RADEON_SW_SEMAPHORE 0x013c + +#define RADEON_TEST_DEBUG_CNTL 0x0120 +#define RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN 0x00000001 + +#define RADEON_TEST_DEBUG_MUX 0x0124 +#define RADEON_TEST_DEBUG_OUT 0x012c +#define RADEON_TMDS_PLL_CNTL 0x02a8 +#define RADEON_TMDS_TRANSMITTER_CNTL 0x02a4 +# define RADEON_TMDS_TRANSMITTER_PLLEN 1 +# define RADEON_TMDS_TRANSMITTER_PLLRST 2 +#define RADEON_TRAIL_BRES_DEC 0x1614 +#define RADEON_TRAIL_BRES_ERR 0x160c +#define RADEON_TRAIL_BRES_INC 0x1610 +#define RADEON_TRAIL_X 0x1618 +#define RADEON_TRAIL_X_SUB 0x1620 + +#define RADEON_VCLK_ECP_CNTL 0x0008 /* PLL */ +# define RADEON_VCLK_SRC_SEL_MASK 0x03 +# define RADEON_VCLK_SRC_SEL_CPUCLK 0x00 +# define RADEON_VCLK_SRC_SEL_PSCANCLK 0x01 +# define RADEON_VCLK_SRC_SEL_BYTECLK 0x02 +# define RADEON_VCLK_SRC_SEL_PPLLCLK 0x03 +# define RADEON_PIXCLK_ALWAYS_ONb (1<<6) +# define RADEON_PIXCLK_DAC_ALWAYS_ONb (1<<7) +# define R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF (1<<23) + +#define RADEON_VENDOR_ID 0x0f00 /* PCI */ +#define RADEON_VGA_DDA_CONFIG 0x02e8 +#define RADEON_VGA_DDA_ON_OFF 0x02ec +#define RADEON_VID_BUFFER_CONTROL 0x0900 +#define RADEON_VIDEOMUX_CNTL 0x0190 + + /* VIP bus */ +#define RADEON_VIPH_CH0_DATA 0x0c00 +#define RADEON_VIPH_CH1_DATA 0x0c04 +#define RADEON_VIPH_CH2_DATA 0x0c08 +#define RADEON_VIPH_CH3_DATA 0x0c0c +#define RADEON_VIPH_CH0_ADDR 0x0c10 +#define RADEON_VIPH_CH1_ADDR 0x0c14 +#define RADEON_VIPH_CH2_ADDR 0x0c18 +#define RADEON_VIPH_CH3_ADDR 0x0c1c +#define RADEON_VIPH_CH0_SBCNT 0x0c20 +#define RADEON_VIPH_CH1_SBCNT 0x0c24 +#define RADEON_VIPH_CH2_SBCNT 0x0c28 +#define RADEON_VIPH_CH3_SBCNT 0x0c2c +#define RADEON_VIPH_CH0_ABCNT 0x0c30 +#define RADEON_VIPH_CH1_ABCNT 0x0c34 +#define RADEON_VIPH_CH2_ABCNT 0x0c38 +#define RADEON_VIPH_CH3_ABCNT 0x0c3c +#define RADEON_VIPH_CONTROL 0x0c40 +# define RADEON_VIP_BUSY 0 +# define RADEON_VIP_IDLE 1 +# define RADEON_VIP_RESET 2 +# define RADEON_VIPH_EN (1 << 21) +#define RADEON_VIPH_DV_LAT 0x0c44 +#define RADEON_VIPH_BM_CHUNK 0x0c48 +#define RADEON_VIPH_DV_INT 0x0c4c +#define RADEON_VIPH_TIMEOUT_STAT 0x0c50 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_STAT 0x00000010 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_AK 0x00000010 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS 0x01000000 + +#define RADEON_VIPH_REG_DATA 0x0084 +#define RADEON_VIPH_REG_ADDR 0x0080 + + +#define RADEON_WAIT_UNTIL 0x1720 +# define RADEON_WAIT_CRTC_PFLIP (1 << 0) +# define RADEON_WAIT_RE_CRTC_VLINE (1 << 1) +# define RADEON_WAIT_FE_CRTC_VLINE (1 << 2) +# define RADEON_WAIT_CRTC_VLINE (1 << 3) +# define RADEON_WAIT_DMA_VID_IDLE (1 << 8) +# define RADEON_WAIT_DMA_GUI_IDLE (1 << 9) +# define RADEON_WAIT_CMDFIFO (1 << 10) /* wait for CMDFIFO_ENTRIES */ +# define RADEON_WAIT_OV0_FLIP (1 << 11) +# define RADEON_WAIT_AGP_FLUSH (1 << 13) +# define RADEON_WAIT_2D_IDLE (1 << 14) +# define RADEON_WAIT_3D_IDLE (1 << 15) +# define RADEON_WAIT_2D_IDLECLEAN (1 << 16) +# define RADEON_WAIT_3D_IDLECLEAN (1 << 17) +# define RADEON_WAIT_HOST_IDLECLEAN (1 << 18) +# define RADEON_CMDFIFO_ENTRIES_SHIFT 10 +# define RADEON_CMDFIFO_ENTRIES_MASK 0x7f +# define RADEON_WAIT_VAP_IDLE (1 << 28) +# define RADEON_WAIT_BOTH_CRTC_PFLIP (1 << 30) +# define RADEON_ENG_DISPLAY_SELECT_CRTC0 (0 << 31) +# define RADEON_ENG_DISPLAY_SELECT_CRTC1 (1 << 31) + +#define RADEON_X_MPLL_REF_FB_DIV 0x000a /* PLL */ +#define RADEON_XCLK_CNTL 0x000d /* PLL */ +#define RADEON_XDLL_CNTL 0x000c /* PLL */ +#define RADEON_XPLL_CNTL 0x000b /* PLL */ + + + + /* Registers for 3D/TCL */ +#define RADEON_PP_BORDER_COLOR_0 0x1d40 +#define RADEON_PP_BORDER_COLOR_1 0x1d44 +#define RADEON_PP_BORDER_COLOR_2 0x1d48 +#define RADEON_PP_CNTL 0x1c38 +# define RADEON_STIPPLE_ENABLE (1 << 0) +# define RADEON_SCISSOR_ENABLE (1 << 1) +# define RADEON_PATTERN_ENABLE (1 << 2) +# define RADEON_SHADOW_ENABLE (1 << 3) +# define RADEON_TEX_ENABLE_MASK (0xf << 4) +# define RADEON_TEX_0_ENABLE (1 << 4) +# define RADEON_TEX_1_ENABLE (1 << 5) +# define RADEON_TEX_2_ENABLE (1 << 6) +# define RADEON_TEX_3_ENABLE (1 << 7) +# define RADEON_TEX_BLEND_ENABLE_MASK (0xf << 12) +# define RADEON_TEX_BLEND_0_ENABLE (1 << 12) +# define RADEON_TEX_BLEND_1_ENABLE (1 << 13) +# define RADEON_TEX_BLEND_2_ENABLE (1 << 14) +# define RADEON_TEX_BLEND_3_ENABLE (1 << 15) +# define RADEON_PLANAR_YUV_ENABLE (1 << 20) +# define RADEON_SPECULAR_ENABLE (1 << 21) +# define RADEON_FOG_ENABLE (1 << 22) +# define RADEON_ALPHA_TEST_ENABLE (1 << 23) +# define RADEON_ANTI_ALIAS_NONE (0 << 24) +# define RADEON_ANTI_ALIAS_LINE (1 << 24) +# define RADEON_ANTI_ALIAS_POLY (2 << 24) +# define RADEON_ANTI_ALIAS_LINE_POLY (3 << 24) +# define RADEON_BUMP_MAP_ENABLE (1 << 26) +# define RADEON_BUMPED_MAP_T0 (0 << 27) +# define RADEON_BUMPED_MAP_T1 (1 << 27) +# define RADEON_BUMPED_MAP_T2 (2 << 27) +# define RADEON_TEX_3D_ENABLE_0 (1 << 29) +# define RADEON_TEX_3D_ENABLE_1 (1 << 30) +# define RADEON_MC_ENABLE (1 << 31) +#define RADEON_PP_FOG_COLOR 0x1c18 +# define RADEON_FOG_COLOR_MASK 0x00ffffff +# define RADEON_FOG_VERTEX (0 << 24) +# define RADEON_FOG_TABLE (1 << 24) +# define RADEON_FOG_USE_DEPTH (0 << 25) +# define RADEON_FOG_USE_DIFFUSE_ALPHA (2 << 25) +# define RADEON_FOG_USE_SPEC_ALPHA (3 << 25) +#define RADEON_PP_LUM_MATRIX 0x1d00 +#define RADEON_PP_MISC 0x1c14 +# define RADEON_REF_ALPHA_MASK 0x000000ff +# define RADEON_ALPHA_TEST_FAIL (0 << 8) +# define RADEON_ALPHA_TEST_LESS (1 << 8) +# define RADEON_ALPHA_TEST_LEQUAL (2 << 8) +# define RADEON_ALPHA_TEST_EQUAL (3 << 8) +# define RADEON_ALPHA_TEST_GEQUAL (4 << 8) +# define RADEON_ALPHA_TEST_GREATER (5 << 8) +# define RADEON_ALPHA_TEST_NEQUAL (6 << 8) +# define RADEON_ALPHA_TEST_PASS (7 << 8) +# define RADEON_ALPHA_TEST_OP_MASK (7 << 8) +# define RADEON_CHROMA_FUNC_FAIL (0 << 16) +# define RADEON_CHROMA_FUNC_PASS (1 << 16) +# define RADEON_CHROMA_FUNC_NEQUAL (2 << 16) +# define RADEON_CHROMA_FUNC_EQUAL (3 << 16) +# define RADEON_CHROMA_KEY_NEAREST (0 << 18) +# define RADEON_CHROMA_KEY_ZERO (1 << 18) +# define RADEON_SHADOW_ID_AUTO_INC (1 << 20) +# define RADEON_SHADOW_FUNC_EQUAL (0 << 21) +# define RADEON_SHADOW_FUNC_NEQUAL (1 << 21) +# define RADEON_SHADOW_PASS_1 (0 << 22) +# define RADEON_SHADOW_PASS_2 (1 << 22) +# define RADEON_RIGHT_HAND_CUBE_D3D (0 << 24) +# define RADEON_RIGHT_HAND_CUBE_OGL (1 << 24) +#define RADEON_PP_ROT_MATRIX_0 0x1d58 +#define RADEON_PP_ROT_MATRIX_1 0x1d5c +#define RADEON_PP_TXFILTER_0 0x1c54 +#define RADEON_PP_TXFILTER_1 0x1c6c +#define RADEON_PP_TXFILTER_2 0x1c84 +# define RADEON_MAG_FILTER_NEAREST (0 << 0) +# define RADEON_MAG_FILTER_LINEAR (1 << 0) +# define RADEON_MAG_FILTER_MASK (1 << 0) +# define RADEON_MIN_FILTER_NEAREST (0 << 1) +# define RADEON_MIN_FILTER_LINEAR (1 << 1) +# define RADEON_MIN_FILTER_NEAREST_MIP_NEAREST (2 << 1) +# define RADEON_MIN_FILTER_NEAREST_MIP_LINEAR (3 << 1) +# define RADEON_MIN_FILTER_LINEAR_MIP_NEAREST (6 << 1) +# define RADEON_MIN_FILTER_LINEAR_MIP_LINEAR (7 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST (8 << 1) +# define RADEON_MIN_FILTER_ANISO_LINEAR (9 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (11 << 1) +# define RADEON_MIN_FILTER_MASK (15 << 1) +# define RADEON_MAX_ANISO_1_TO_1 (0 << 5) +# define RADEON_MAX_ANISO_2_TO_1 (1 << 5) +# define RADEON_MAX_ANISO_4_TO_1 (2 << 5) +# define RADEON_MAX_ANISO_8_TO_1 (3 << 5) +# define RADEON_MAX_ANISO_16_TO_1 (4 << 5) +# define RADEON_MAX_ANISO_MASK (7 << 5) +# define RADEON_LOD_BIAS_MASK (0xff << 8) +# define RADEON_LOD_BIAS_SHIFT 8 +# define RADEON_MAX_MIP_LEVEL_MASK (0x0f << 16) +# define RADEON_MAX_MIP_LEVEL_SHIFT 16 +# define RADEON_YUV_TO_RGB (1 << 20) +# define RADEON_YUV_TEMPERATURE_COOL (0 << 21) +# define RADEON_YUV_TEMPERATURE_HOT (1 << 21) +# define RADEON_YUV_TEMPERATURE_MASK (1 << 21) +# define RADEON_WRAPEN_S (1 << 22) +# define RADEON_CLAMP_S_WRAP (0 << 23) +# define RADEON_CLAMP_S_MIRROR (1 << 23) +# define RADEON_CLAMP_S_CLAMP_LAST (2 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23) +# define RADEON_CLAMP_S_CLAMP_BORDER (4 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23) +# define RADEON_CLAMP_S_CLAMP_GL (6 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_GL (7 << 23) +# define RADEON_CLAMP_S_MASK (7 << 23) +# define RADEON_WRAPEN_T (1 << 26) +# define RADEON_CLAMP_T_WRAP (0 << 27) +# define RADEON_CLAMP_T_MIRROR (1 << 27) +# define RADEON_CLAMP_T_CLAMP_LAST (2 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27) +# define RADEON_CLAMP_T_CLAMP_BORDER (4 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27) +# define RADEON_CLAMP_T_CLAMP_GL (6 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_GL (7 << 27) +# define RADEON_CLAMP_T_MASK (7 << 27) +# define RADEON_BORDER_MODE_OGL (0 << 31) +# define RADEON_BORDER_MODE_D3D (1 << 31) +#define RADEON_PP_TXFORMAT_0 0x1c58 +#define RADEON_PP_TXFORMAT_1 0x1c70 +#define RADEON_PP_TXFORMAT_2 0x1c88 +# define RADEON_TXFORMAT_I8 (0 << 0) +# define RADEON_TXFORMAT_AI88 (1 << 0) +# define RADEON_TXFORMAT_RGB332 (2 << 0) +# define RADEON_TXFORMAT_ARGB1555 (3 << 0) +# define RADEON_TXFORMAT_RGB565 (4 << 0) +# define RADEON_TXFORMAT_ARGB4444 (5 << 0) +# define RADEON_TXFORMAT_ARGB8888 (6 << 0) +# define RADEON_TXFORMAT_RGBA8888 (7 << 0) +# define RADEON_TXFORMAT_Y8 (8 << 0) +# define RADEON_TXFORMAT_VYUY422 (10 << 0) +# define RADEON_TXFORMAT_YVYU422 (11 << 0) +# define RADEON_TXFORMAT_DXT1 (12 << 0) +# define RADEON_TXFORMAT_DXT23 (14 << 0) +# define RADEON_TXFORMAT_DXT45 (15 << 0) +# define RADEON_TXFORMAT_FORMAT_MASK (31 << 0) +# define RADEON_TXFORMAT_FORMAT_SHIFT 0 +# define RADEON_TXFORMAT_APPLE_YUV_MODE (1 << 5) +# define RADEON_TXFORMAT_ALPHA_IN_MAP (1 << 6) +# define RADEON_TXFORMAT_NON_POWER2 (1 << 7) +# define RADEON_TXFORMAT_WIDTH_MASK (15 << 8) +# define RADEON_TXFORMAT_WIDTH_SHIFT 8 +# define RADEON_TXFORMAT_HEIGHT_MASK (15 << 12) +# define RADEON_TXFORMAT_HEIGHT_SHIFT 12 +# define RADEON_TXFORMAT_F5_WIDTH_MASK (15 << 16) +# define RADEON_TXFORMAT_F5_WIDTH_SHIFT 16 +# define RADEON_TXFORMAT_F5_HEIGHT_MASK (15 << 20) +# define RADEON_TXFORMAT_F5_HEIGHT_SHIFT 20 +# define RADEON_TXFORMAT_ST_ROUTE_STQ0 (0 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_MASK (3 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_STQ1 (1 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_STQ2 (2 << 24) +# define RADEON_TXFORMAT_ENDIAN_NO_SWAP (0 << 26) +# define RADEON_TXFORMAT_ENDIAN_16BPP_SWAP (1 << 26) +# define RADEON_TXFORMAT_ENDIAN_32BPP_SWAP (2 << 26) +# define RADEON_TXFORMAT_ENDIAN_HALFDW_SWAP (3 << 26) +# define RADEON_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28) +# define RADEON_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) +# define RADEON_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) +# define RADEON_TXFORMAT_PERSPECTIVE_ENABLE (1 << 31) +#define RADEON_PP_CUBIC_FACES_0 0x1d24 +#define RADEON_PP_CUBIC_FACES_1 0x1d28 +#define RADEON_PP_CUBIC_FACES_2 0x1d2c +# define RADEON_FACE_WIDTH_1_SHIFT 0 +# define RADEON_FACE_HEIGHT_1_SHIFT 4 +# define RADEON_FACE_WIDTH_1_MASK (0xf << 0) +# define RADEON_FACE_HEIGHT_1_MASK (0xf << 4) +# define RADEON_FACE_WIDTH_2_SHIFT 8 +# define RADEON_FACE_HEIGHT_2_SHIFT 12 +# define RADEON_FACE_WIDTH_2_MASK (0xf << 8) +# define RADEON_FACE_HEIGHT_2_MASK (0xf << 12) +# define RADEON_FACE_WIDTH_3_SHIFT 16 +# define RADEON_FACE_HEIGHT_3_SHIFT 20 +# define RADEON_FACE_WIDTH_3_MASK (0xf << 16) +# define RADEON_FACE_HEIGHT_3_MASK (0xf << 20) +# define RADEON_FACE_WIDTH_4_SHIFT 24 +# define RADEON_FACE_HEIGHT_4_SHIFT 28 +# define RADEON_FACE_WIDTH_4_MASK (0xf << 24) +# define RADEON_FACE_HEIGHT_4_MASK (0xf << 28) + +#define RADEON_PP_TXOFFSET_0 0x1c5c +#define RADEON_PP_TXOFFSET_1 0x1c74 +#define RADEON_PP_TXOFFSET_2 0x1c8c +# define RADEON_TXO_ENDIAN_NO_SWAP (0 << 0) +# define RADEON_TXO_ENDIAN_BYTE_SWAP (1 << 0) +# define RADEON_TXO_ENDIAN_WORD_SWAP (2 << 0) +# define RADEON_TXO_ENDIAN_HALFDW_SWAP (3 << 0) +# define RADEON_TXO_MACRO_LINEAR (0 << 2) +# define RADEON_TXO_MACRO_TILE (1 << 2) +# define RADEON_TXO_MICRO_LINEAR (0 << 3) +# define RADEON_TXO_MICRO_TILE_X2 (1 << 3) +# define RADEON_TXO_MICRO_TILE_OPT (2 << 3) +# define RADEON_TXO_OFFSET_MASK 0xffffffe0 +# define RADEON_TXO_OFFSET_SHIFT 5 + +#define RADEON_PP_CUBIC_OFFSET_T0_0 0x1dd0 /* bits [31:5] */ +#define RADEON_PP_CUBIC_OFFSET_T0_1 0x1dd4 +#define RADEON_PP_CUBIC_OFFSET_T0_2 0x1dd8 +#define RADEON_PP_CUBIC_OFFSET_T0_3 0x1ddc +#define RADEON_PP_CUBIC_OFFSET_T0_4 0x1de0 +#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00 +#define RADEON_PP_CUBIC_OFFSET_T1_1 0x1e04 +#define RADEON_PP_CUBIC_OFFSET_T1_2 0x1e08 +#define RADEON_PP_CUBIC_OFFSET_T1_3 0x1e0c +#define RADEON_PP_CUBIC_OFFSET_T1_4 0x1e10 +#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14 +#define RADEON_PP_CUBIC_OFFSET_T2_1 0x1e18 +#define RADEON_PP_CUBIC_OFFSET_T2_2 0x1e1c +#define RADEON_PP_CUBIC_OFFSET_T2_3 0x1e20 +#define RADEON_PP_CUBIC_OFFSET_T2_4 0x1e24 + +#define RADEON_PP_TEX_SIZE_0 0x1d04 /* NPOT */ +#define RADEON_PP_TEX_SIZE_1 0x1d0c +#define RADEON_PP_TEX_SIZE_2 0x1d14 +# define RADEON_TEX_USIZE_MASK (0x7ff << 0) +# define RADEON_TEX_USIZE_SHIFT 0 +# define RADEON_TEX_VSIZE_MASK (0x7ff << 16) +# define RADEON_TEX_VSIZE_SHIFT 16 +# define RADEON_SIGNED_RGB_MASK (1 << 30) +# define RADEON_SIGNED_RGB_SHIFT 30 +# define RADEON_SIGNED_ALPHA_MASK (1 << 31) +# define RADEON_SIGNED_ALPHA_SHIFT 31 +#define RADEON_PP_TEX_PITCH_0 0x1d08 /* NPOT */ +#define RADEON_PP_TEX_PITCH_1 0x1d10 /* NPOT */ +#define RADEON_PP_TEX_PITCH_2 0x1d18 /* NPOT */ +/* note: bits 13-5: 32 byte aligned stride of texture map */ + +#define RADEON_PP_TXCBLEND_0 0x1c60 +#define RADEON_PP_TXCBLEND_1 0x1c78 +#define RADEON_PP_TXCBLEND_2 0x1c90 +# define RADEON_COLOR_ARG_A_SHIFT 0 +# define RADEON_COLOR_ARG_A_MASK (0x1f << 0) +# define RADEON_COLOR_ARG_A_ZERO (0 << 0) +# define RADEON_COLOR_ARG_A_CURRENT_COLOR (2 << 0) +# define RADEON_COLOR_ARG_A_CURRENT_ALPHA (3 << 0) +# define RADEON_COLOR_ARG_A_DIFFUSE_COLOR (4 << 0) +# define RADEON_COLOR_ARG_A_DIFFUSE_ALPHA (5 << 0) +# define RADEON_COLOR_ARG_A_SPECULAR_COLOR (6 << 0) +# define RADEON_COLOR_ARG_A_SPECULAR_ALPHA (7 << 0) +# define RADEON_COLOR_ARG_A_TFACTOR_COLOR (8 << 0) +# define RADEON_COLOR_ARG_A_TFACTOR_ALPHA (9 << 0) +# define RADEON_COLOR_ARG_A_T0_COLOR (10 << 0) +# define RADEON_COLOR_ARG_A_T0_ALPHA (11 << 0) +# define RADEON_COLOR_ARG_A_T1_COLOR (12 << 0) +# define RADEON_COLOR_ARG_A_T1_ALPHA (13 << 0) +# define RADEON_COLOR_ARG_A_T2_COLOR (14 << 0) +# define RADEON_COLOR_ARG_A_T2_ALPHA (15 << 0) +# define RADEON_COLOR_ARG_A_T3_COLOR (16 << 0) +# define RADEON_COLOR_ARG_A_T3_ALPHA (17 << 0) +# define RADEON_COLOR_ARG_B_SHIFT 5 +# define RADEON_COLOR_ARG_B_MASK (0x1f << 5) +# define RADEON_COLOR_ARG_B_ZERO (0 << 5) +# define RADEON_COLOR_ARG_B_CURRENT_COLOR (2 << 5) +# define RADEON_COLOR_ARG_B_CURRENT_ALPHA (3 << 5) +# define RADEON_COLOR_ARG_B_DIFFUSE_COLOR (4 << 5) +# define RADEON_COLOR_ARG_B_DIFFUSE_ALPHA (5 << 5) +# define RADEON_COLOR_ARG_B_SPECULAR_COLOR (6 << 5) +# define RADEON_COLOR_ARG_B_SPECULAR_ALPHA (7 << 5) +# define RADEON_COLOR_ARG_B_TFACTOR_COLOR (8 << 5) +# define RADEON_COLOR_ARG_B_TFACTOR_ALPHA (9 << 5) +# define RADEON_COLOR_ARG_B_T0_COLOR (10 << 5) +# define RADEON_COLOR_ARG_B_T0_ALPHA (11 << 5) +# define RADEON_COLOR_ARG_B_T1_COLOR (12 << 5) +# define RADEON_COLOR_ARG_B_T1_ALPHA (13 << 5) +# define RADEON_COLOR_ARG_B_T2_COLOR (14 << 5) +# define RADEON_COLOR_ARG_B_T2_ALPHA (15 << 5) +# define RADEON_COLOR_ARG_B_T3_COLOR (16 << 5) +# define RADEON_COLOR_ARG_B_T3_ALPHA (17 << 5) +# define RADEON_COLOR_ARG_C_SHIFT 10 +# define RADEON_COLOR_ARG_C_MASK (0x1f << 10) +# define RADEON_COLOR_ARG_C_ZERO (0 << 10) +# define RADEON_COLOR_ARG_C_CURRENT_COLOR (2 << 10) +# define RADEON_COLOR_ARG_C_CURRENT_ALPHA (3 << 10) +# define RADEON_COLOR_ARG_C_DIFFUSE_COLOR (4 << 10) +# define RADEON_COLOR_ARG_C_DIFFUSE_ALPHA (5 << 10) +# define RADEON_COLOR_ARG_C_SPECULAR_COLOR (6 << 10) +# define RADEON_COLOR_ARG_C_SPECULAR_ALPHA (7 << 10) +# define RADEON_COLOR_ARG_C_TFACTOR_COLOR (8 << 10) +# define RADEON_COLOR_ARG_C_TFACTOR_ALPHA (9 << 10) +# define RADEON_COLOR_ARG_C_T0_COLOR (10 << 10) +# define RADEON_COLOR_ARG_C_T0_ALPHA (11 << 10) +# define RADEON_COLOR_ARG_C_T1_COLOR (12 << 10) +# define RADEON_COLOR_ARG_C_T1_ALPHA (13 << 10) +# define RADEON_COLOR_ARG_C_T2_COLOR (14 << 10) +# define RADEON_COLOR_ARG_C_T2_ALPHA (15 << 10) +# define RADEON_COLOR_ARG_C_T3_COLOR (16 << 10) +# define RADEON_COLOR_ARG_C_T3_ALPHA (17 << 10) +# define RADEON_COMP_ARG_A (1 << 15) +# define RADEON_COMP_ARG_A_SHIFT 15 +# define RADEON_COMP_ARG_B (1 << 16) +# define RADEON_COMP_ARG_B_SHIFT 16 +# define RADEON_COMP_ARG_C (1 << 17) +# define RADEON_COMP_ARG_C_SHIFT 17 +# define RADEON_BLEND_CTL_MASK (7 << 18) +# define RADEON_BLEND_CTL_ADD (0 << 18) +# define RADEON_BLEND_CTL_SUBTRACT (1 << 18) +# define RADEON_BLEND_CTL_ADDSIGNED (2 << 18) +# define RADEON_BLEND_CTL_BLEND (3 << 18) +# define RADEON_BLEND_CTL_DOT3 (4 << 18) +# define RADEON_SCALE_SHIFT 21 +# define RADEON_SCALE_MASK (3 << 21) +# define RADEON_SCALE_1X (0 << 21) +# define RADEON_SCALE_2X (1 << 21) +# define RADEON_SCALE_4X (2 << 21) +# define RADEON_CLAMP_TX (1 << 23) +# define RADEON_T0_EQ_TCUR (1 << 24) +# define RADEON_T1_EQ_TCUR (1 << 25) +# define RADEON_T2_EQ_TCUR (1 << 26) +# define RADEON_T3_EQ_TCUR (1 << 27) +# define RADEON_COLOR_ARG_MASK 0x1f +# define RADEON_COMP_ARG_SHIFT 15 +#define RADEON_PP_TXABLEND_0 0x1c64 +#define RADEON_PP_TXABLEND_1 0x1c7c +#define RADEON_PP_TXABLEND_2 0x1c94 +# define RADEON_ALPHA_ARG_A_SHIFT 0 +# define RADEON_ALPHA_ARG_A_MASK (0xf << 0) +# define RADEON_ALPHA_ARG_A_ZERO (0 << 0) +# define RADEON_ALPHA_ARG_A_CURRENT_ALPHA (1 << 0) +# define RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA (2 << 0) +# define RADEON_ALPHA_ARG_A_SPECULAR_ALPHA (3 << 0) +# define RADEON_ALPHA_ARG_A_TFACTOR_ALPHA (4 << 0) +# define RADEON_ALPHA_ARG_A_T0_ALPHA (5 << 0) +# define RADEON_ALPHA_ARG_A_T1_ALPHA (6 << 0) +# define RADEON_ALPHA_ARG_A_T2_ALPHA (7 << 0) +# define RADEON_ALPHA_ARG_A_T3_ALPHA (8 << 0) +# define RADEON_ALPHA_ARG_B_SHIFT 4 +# define RADEON_ALPHA_ARG_B_MASK (0xf << 4) +# define RADEON_ALPHA_ARG_B_ZERO (0 << 4) +# define RADEON_ALPHA_ARG_B_CURRENT_ALPHA (1 << 4) +# define RADEON_ALPHA_ARG_B_DIFFUSE_ALPHA (2 << 4) +# define RADEON_ALPHA_ARG_B_SPECULAR_ALPHA (3 << 4) +# define RADEON_ALPHA_ARG_B_TFACTOR_ALPHA (4 << 4) +# define RADEON_ALPHA_ARG_B_T0_ALPHA (5 << 4) +# define RADEON_ALPHA_ARG_B_T1_ALPHA (6 << 4) +# define RADEON_ALPHA_ARG_B_T2_ALPHA (7 << 4) +# define RADEON_ALPHA_ARG_B_T3_ALPHA (8 << 4) +# define RADEON_ALPHA_ARG_C_SHIFT 8 +# define RADEON_ALPHA_ARG_C_MASK (0xf << 8) +# define RADEON_ALPHA_ARG_C_ZERO (0 << 8) +# define RADEON_ALPHA_ARG_C_CURRENT_ALPHA (1 << 8) +# define RADEON_ALPHA_ARG_C_DIFFUSE_ALPHA (2 << 8) +# define RADEON_ALPHA_ARG_C_SPECULAR_ALPHA (3 << 8) +# define RADEON_ALPHA_ARG_C_TFACTOR_ALPHA (4 << 8) +# define RADEON_ALPHA_ARG_C_T0_ALPHA (5 << 8) +# define RADEON_ALPHA_ARG_C_T1_ALPHA (6 << 8) +# define RADEON_ALPHA_ARG_C_T2_ALPHA (7 << 8) +# define RADEON_ALPHA_ARG_C_T3_ALPHA (8 << 8) +# define RADEON_DOT_ALPHA_DONT_REPLICATE (1 << 9) +# define RADEON_ALPHA_ARG_MASK 0xf + +#define RADEON_PP_TFACTOR_0 0x1c68 +#define RADEON_PP_TFACTOR_1 0x1c80 +#define RADEON_PP_TFACTOR_2 0x1c98 + +#define RADEON_RB3D_BLENDCNTL 0x1c20 +# define RADEON_COMB_FCN_MASK (3 << 12) +# define RADEON_COMB_FCN_ADD_CLAMP (0 << 12) +# define RADEON_COMB_FCN_ADD_NOCLAMP (1 << 12) +# define RADEON_COMB_FCN_SUB_CLAMP (2 << 12) +# define RADEON_COMB_FCN_SUB_NOCLAMP (3 << 12) +# define RADEON_SRC_BLEND_GL_ZERO (32 << 16) +# define RADEON_SRC_BLEND_GL_ONE (33 << 16) +# define RADEON_SRC_BLEND_GL_SRC_COLOR (34 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 16) +# define RADEON_SRC_BLEND_GL_DST_COLOR (36 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 16) +# define RADEON_SRC_BLEND_GL_SRC_ALPHA (38 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 16) +# define RADEON_SRC_BLEND_GL_DST_ALPHA (40 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 16) +# define RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE (42 << 16) +# define RADEON_SRC_BLEND_MASK (63 << 16) +# define RADEON_DST_BLEND_GL_ZERO (32 << 24) +# define RADEON_DST_BLEND_GL_ONE (33 << 24) +# define RADEON_DST_BLEND_GL_SRC_COLOR (34 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 24) +# define RADEON_DST_BLEND_GL_DST_COLOR (36 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 24) +# define RADEON_DST_BLEND_GL_SRC_ALPHA (38 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 24) +# define RADEON_DST_BLEND_GL_DST_ALPHA (40 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 24) +# define RADEON_DST_BLEND_MASK (63 << 24) +#define RADEON_RB3D_CNTL 0x1c3c +# define RADEON_ALPHA_BLEND_ENABLE (1 << 0) +# define RADEON_PLANE_MASK_ENABLE (1 << 1) +# define RADEON_DITHER_ENABLE (1 << 2) +# define RADEON_ROUND_ENABLE (1 << 3) +# define RADEON_SCALE_DITHER_ENABLE (1 << 4) +# define RADEON_DITHER_INIT (1 << 5) +# define RADEON_ROP_ENABLE (1 << 6) +# define RADEON_STENCIL_ENABLE (1 << 7) +# define RADEON_Z_ENABLE (1 << 8) +# define RADEON_DEPTH_XZ_OFFEST_ENABLE (1 << 9) +# define RADEON_COLOR_FORMAT_ARGB1555 (3 << 10) +# define RADEON_COLOR_FORMAT_RGB565 (4 << 10) +# define RADEON_COLOR_FORMAT_ARGB8888 (6 << 10) +# define RADEON_COLOR_FORMAT_RGB332 (7 << 10) +# define RADEON_COLOR_FORMAT_Y8 (8 << 10) +# define RADEON_COLOR_FORMAT_RGB8 (9 << 10) +# define RADEON_COLOR_FORMAT_YUV422_VYUY (11 << 10) +# define RADEON_COLOR_FORMAT_YUV422_YVYU (12 << 10) +# define RADEON_COLOR_FORMAT_aYUV444 (14 << 10) +# define RADEON_COLOR_FORMAT_ARGB4444 (15 << 10) +# define RADEON_CLRCMP_FLIP_ENABLE (1 << 14) +#define RADEON_RB3D_COLOROFFSET 0x1c40 +# define RADEON_COLOROFFSET_MASK 0xfffffff0 +#define RADEON_RB3D_COLORPITCH 0x1c48 +# define RADEON_COLORPITCH_MASK 0x000001ff8 +# define RADEON_COLOR_TILE_ENABLE (1 << 16) +# define RADEON_COLOR_MICROTILE_ENABLE (1 << 17) +# define RADEON_COLOR_ENDIAN_NO_SWAP (0 << 18) +# define RADEON_COLOR_ENDIAN_WORD_SWAP (1 << 18) +# define RADEON_COLOR_ENDIAN_DWORD_SWAP (2 << 18) +#define RADEON_RB3D_DEPTHOFFSET 0x1c24 +#define RADEON_RB3D_DEPTHPITCH 0x1c28 +# define RADEON_DEPTHPITCH_MASK 0x00001ff8 +# define RADEON_DEPTH_ENDIAN_NO_SWAP (0 << 18) +# define RADEON_DEPTH_ENDIAN_WORD_SWAP (1 << 18) +# define RADEON_DEPTH_ENDIAN_DWORD_SWAP (2 << 18) +#define RADEON_RB3D_PLANEMASK 0x1d84 +#define RADEON_RB3D_ROPCNTL 0x1d80 +# define RADEON_ROP_MASK (15 << 8) +# define RADEON_ROP_CLEAR (0 << 8) +# define RADEON_ROP_NOR (1 << 8) +# define RADEON_ROP_AND_INVERTED (2 << 8) +# define RADEON_ROP_COPY_INVERTED (3 << 8) +# define RADEON_ROP_AND_REVERSE (4 << 8) +# define RADEON_ROP_INVERT (5 << 8) +# define RADEON_ROP_XOR (6 << 8) +# define RADEON_ROP_NAND (7 << 8) +# define RADEON_ROP_AND (8 << 8) +# define RADEON_ROP_EQUIV (9 << 8) +# define RADEON_ROP_NOOP (10 << 8) +# define RADEON_ROP_OR_INVERTED (11 << 8) +# define RADEON_ROP_COPY (12 << 8) +# define RADEON_ROP_OR_REVERSE (13 << 8) +# define RADEON_ROP_OR (14 << 8) +# define RADEON_ROP_SET (15 << 8) +#define RADEON_RB3D_STENCILREFMASK 0x1d7c +# define RADEON_STENCIL_REF_SHIFT 0 +# define RADEON_STENCIL_REF_MASK (0xff << 0) +# define RADEON_STENCIL_MASK_SHIFT 16 +# define RADEON_STENCIL_VALUE_MASK (0xff << 16) +# define RADEON_STENCIL_WRITEMASK_SHIFT 24 +# define RADEON_STENCIL_WRITE_MASK (0xff << 24) +#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c +# define RADEON_DEPTH_FORMAT_MASK (0xf << 0) +# define RADEON_DEPTH_FORMAT_16BIT_INT_Z (0 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_INT_Z (2 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_FLOAT_Z (3 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_INT_Z (4 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_FLOAT_Z (5 << 0) +# define RADEON_DEPTH_FORMAT_16BIT_FLOAT_W (7 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_FLOAT_W (9 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_FLOAT_W (11 << 0) +# define RADEON_Z_TEST_NEVER (0 << 4) +# define RADEON_Z_TEST_LESS (1 << 4) +# define RADEON_Z_TEST_LEQUAL (2 << 4) +# define RADEON_Z_TEST_EQUAL (3 << 4) +# define RADEON_Z_TEST_GEQUAL (4 << 4) +# define RADEON_Z_TEST_GREATER (5 << 4) +# define RADEON_Z_TEST_NEQUAL (6 << 4) +# define RADEON_Z_TEST_ALWAYS (7 << 4) +# define RADEON_Z_TEST_MASK (7 << 4) +# define RADEON_STENCIL_TEST_NEVER (0 << 12) +# define RADEON_STENCIL_TEST_LESS (1 << 12) +# define RADEON_STENCIL_TEST_LEQUAL (2 << 12) +# define RADEON_STENCIL_TEST_EQUAL (3 << 12) +# define RADEON_STENCIL_TEST_GEQUAL (4 << 12) +# define RADEON_STENCIL_TEST_GREATER (5 << 12) +# define RADEON_STENCIL_TEST_NEQUAL (6 << 12) +# define RADEON_STENCIL_TEST_ALWAYS (7 << 12) +# define RADEON_STENCIL_TEST_MASK (0x7 << 12) +# define RADEON_STENCIL_FAIL_KEEP (0 << 16) +# define RADEON_STENCIL_FAIL_ZERO (1 << 16) +# define RADEON_STENCIL_FAIL_REPLACE (2 << 16) +# define RADEON_STENCIL_FAIL_INC (3 << 16) +# define RADEON_STENCIL_FAIL_DEC (4 << 16) +# define RADEON_STENCIL_FAIL_INVERT (5 << 16) +# define RADEON_STENCIL_FAIL_MASK (0x7 << 16) +# define RADEON_STENCIL_ZPASS_KEEP (0 << 20) +# define RADEON_STENCIL_ZPASS_ZERO (1 << 20) +# define RADEON_STENCIL_ZPASS_REPLACE (2 << 20) +# define RADEON_STENCIL_ZPASS_INC (3 << 20) +# define RADEON_STENCIL_ZPASS_DEC (4 << 20) +# define RADEON_STENCIL_ZPASS_INVERT (5 << 20) +# define RADEON_STENCIL_ZPASS_MASK (0x7 << 20) +# define RADEON_STENCIL_ZFAIL_KEEP (0 << 24) +# define RADEON_STENCIL_ZFAIL_ZERO (1 << 24) +# define RADEON_STENCIL_ZFAIL_REPLACE (2 << 24) +# define RADEON_STENCIL_ZFAIL_INC (3 << 24) +# define RADEON_STENCIL_ZFAIL_DEC (4 << 24) +# define RADEON_STENCIL_ZFAIL_INVERT (5 << 24) +# define RADEON_STENCIL_ZFAIL_MASK (0x7 << 24) +# define RADEON_Z_COMPRESSION_ENABLE (1 << 28) +# define RADEON_FORCE_Z_DIRTY (1 << 29) +# define RADEON_Z_WRITE_ENABLE (1 << 30) +#define RADEON_RE_LINE_PATTERN 0x1cd0 +# define RADEON_LINE_PATTERN_MASK 0x0000ffff +# define RADEON_LINE_REPEAT_COUNT_SHIFT 16 +# define RADEON_LINE_PATTERN_START_SHIFT 24 +# define RADEON_LINE_PATTERN_LITTLE_BIT_ORDER (0 << 28) +# define RADEON_LINE_PATTERN_BIG_BIT_ORDER (1 << 28) +# define RADEON_LINE_PATTERN_AUTO_RESET (1 << 29) +#define RADEON_RE_LINE_STATE 0x1cd4 +# define RADEON_LINE_CURRENT_PTR_SHIFT 0 +# define RADEON_LINE_CURRENT_COUNT_SHIFT 8 +#define RADEON_RE_MISC 0x26c4 +# define RADEON_STIPPLE_COORD_MASK 0x1f +# define RADEON_STIPPLE_X_OFFSET_SHIFT 0 +# define RADEON_STIPPLE_X_OFFSET_MASK (0x1f << 0) +# define RADEON_STIPPLE_Y_OFFSET_SHIFT 8 +# define RADEON_STIPPLE_Y_OFFSET_MASK (0x1f << 8) +# define RADEON_STIPPLE_LITTLE_BIT_ORDER (0 << 16) +# define RADEON_STIPPLE_BIG_BIT_ORDER (1 << 16) +#define RADEON_RE_SOLID_COLOR 0x1c1c +#define RADEON_RE_TOP_LEFT 0x26c0 +# define RADEON_RE_LEFT_SHIFT 0 +# define RADEON_RE_TOP_SHIFT 16 +#define RADEON_RE_WIDTH_HEIGHT 0x1c44 +# define RADEON_RE_WIDTH_SHIFT 0 +# define RADEON_RE_HEIGHT_SHIFT 16 + +#define RADEON_SE_CNTL 0x1c4c +# define RADEON_FFACE_CULL_CW (0 << 0) +# define RADEON_FFACE_CULL_CCW (1 << 0) +# define RADEON_FFACE_CULL_DIR_MASK (1 << 0) +# define RADEON_BFACE_CULL (0 << 1) +# define RADEON_BFACE_SOLID (3 << 1) +# define RADEON_FFACE_CULL (0 << 3) +# define RADEON_FFACE_SOLID (3 << 3) +# define RADEON_FFACE_CULL_MASK (3 << 3) +# define RADEON_BADVTX_CULL_DISABLE (1 << 5) +# define RADEON_FLAT_SHADE_VTX_0 (0 << 6) +# define RADEON_FLAT_SHADE_VTX_1 (1 << 6) +# define RADEON_FLAT_SHADE_VTX_2 (2 << 6) +# define RADEON_FLAT_SHADE_VTX_LAST (3 << 6) +# define RADEON_DIFFUSE_SHADE_SOLID (0 << 8) +# define RADEON_DIFFUSE_SHADE_FLAT (1 << 8) +# define RADEON_DIFFUSE_SHADE_GOURAUD (2 << 8) +# define RADEON_DIFFUSE_SHADE_MASK (3 << 8) +# define RADEON_ALPHA_SHADE_SOLID (0 << 10) +# define RADEON_ALPHA_SHADE_FLAT (1 << 10) +# define RADEON_ALPHA_SHADE_GOURAUD (2 << 10) +# define RADEON_ALPHA_SHADE_MASK (3 << 10) +# define RADEON_SPECULAR_SHADE_SOLID (0 << 12) +# define RADEON_SPECULAR_SHADE_FLAT (1 << 12) +# define RADEON_SPECULAR_SHADE_GOURAUD (2 << 12) +# define RADEON_SPECULAR_SHADE_MASK (3 << 12) +# define RADEON_FOG_SHADE_SOLID (0 << 14) +# define RADEON_FOG_SHADE_FLAT (1 << 14) +# define RADEON_FOG_SHADE_GOURAUD (2 << 14) +# define RADEON_FOG_SHADE_MASK (3 << 14) +# define RADEON_ZBIAS_ENABLE_POINT (1 << 16) +# define RADEON_ZBIAS_ENABLE_LINE (1 << 17) +# define RADEON_ZBIAS_ENABLE_TRI (1 << 18) +# define RADEON_WIDELINE_ENABLE (1 << 20) +# define RADEON_VPORT_XY_XFORM_ENABLE (1 << 24) +# define RADEON_VPORT_Z_XFORM_ENABLE (1 << 25) +# define RADEON_VTX_PIX_CENTER_D3D (0 << 27) +# define RADEON_VTX_PIX_CENTER_OGL (1 << 27) +# define RADEON_ROUND_MODE_TRUNC (0 << 28) +# define RADEON_ROUND_MODE_ROUND (1 << 28) +# define RADEON_ROUND_MODE_ROUND_EVEN (2 << 28) +# define RADEON_ROUND_MODE_ROUND_ODD (3 << 28) +# define RADEON_ROUND_PREC_16TH_PIX (0 << 30) +# define RADEON_ROUND_PREC_8TH_PIX (1 << 30) +# define RADEON_ROUND_PREC_4TH_PIX (2 << 30) +# define RADEON_ROUND_PREC_HALF_PIX (3 << 30) +#define R200_RE_CNTL 0x1c50 +# define R200_STIPPLE_ENABLE 0x1 +# define R200_SCISSOR_ENABLE 0x2 +# define R200_PATTERN_ENABLE 0x4 +# define R200_PERSPECTIVE_ENABLE 0x8 +# define R200_POINT_SMOOTH 0x20 +# define R200_VTX_STQ0_D3D 0x00010000 +# define R200_VTX_STQ1_D3D 0x00040000 +# define R200_VTX_STQ2_D3D 0x00100000 +# define R200_VTX_STQ3_D3D 0x00400000 +# define R200_VTX_STQ4_D3D 0x01000000 +# define R200_VTX_STQ5_D3D 0x04000000 +#define RADEON_SE_CNTL_STATUS 0x2140 +# define RADEON_VC_NO_SWAP (0 << 0) +# define RADEON_VC_16BIT_SWAP (1 << 0) +# define RADEON_VC_32BIT_SWAP (2 << 0) +# define RADEON_VC_HALF_DWORD_SWAP (3 << 0) +# define RADEON_TCL_BYPASS (1 << 8) +#define RADEON_SE_COORD_FMT 0x1c50 +# define RADEON_VTX_XY_PRE_MULT_1_OVER_W0 (1 << 0) +# define RADEON_VTX_Z_PRE_MULT_1_OVER_W0 (1 << 1) +# define RADEON_VTX_ST0_NONPARAMETRIC (1 << 8) +# define RADEON_VTX_ST1_NONPARAMETRIC (1 << 9) +# define RADEON_VTX_ST2_NONPARAMETRIC (1 << 10) +# define RADEON_VTX_ST3_NONPARAMETRIC (1 << 11) +# define RADEON_VTX_W0_NORMALIZE (1 << 12) +# define RADEON_VTX_W0_IS_NOT_1_OVER_W0 (1 << 16) +# define RADEON_VTX_ST0_PRE_MULT_1_OVER_W0 (1 << 17) +# define RADEON_VTX_ST1_PRE_MULT_1_OVER_W0 (1 << 19) +# define RADEON_VTX_ST2_PRE_MULT_1_OVER_W0 (1 << 21) +# define RADEON_VTX_ST3_PRE_MULT_1_OVER_W0 (1 << 23) +# define RADEON_TEX1_W_ROUTING_USE_W0 (0 << 26) +# define RADEON_TEX1_W_ROUTING_USE_Q1 (1 << 26) +#define RADEON_SE_LINE_WIDTH 0x1db8 +#define RADEON_SE_TCL_LIGHT_MODEL_CTL 0x226c +# define RADEON_LIGHTING_ENABLE (1 << 0) +# define RADEON_LIGHT_IN_MODELSPACE (1 << 1) +# define RADEON_LOCAL_VIEWER (1 << 2) +# define RADEON_NORMALIZE_NORMALS (1 << 3) +# define RADEON_RESCALE_NORMALS (1 << 4) +# define RADEON_SPECULAR_LIGHTS (1 << 5) +# define RADEON_DIFFUSE_SPECULAR_COMBINE (1 << 6) +# define RADEON_LIGHT_ALPHA (1 << 7) +# define RADEON_LOCAL_LIGHT_VEC_GL (1 << 8) +# define RADEON_LIGHT_NO_NORMAL_AMBIENT_ONLY (1 << 9) +# define RADEON_LM_SOURCE_STATE_PREMULT 0 +# define RADEON_LM_SOURCE_STATE_MULT 1 +# define RADEON_LM_SOURCE_VERTEX_DIFFUSE 2 +# define RADEON_LM_SOURCE_VERTEX_SPECULAR 3 +# define RADEON_EMISSIVE_SOURCE_SHIFT 16 +# define RADEON_AMBIENT_SOURCE_SHIFT 18 +# define RADEON_DIFFUSE_SOURCE_SHIFT 20 +# define RADEON_SPECULAR_SOURCE_SHIFT 22 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_RED 0x2220 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_GREEN 0x2224 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_BLUE 0x2228 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_ALPHA 0x222c +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_RED 0x2230 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_GREEN 0x2234 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_BLUE 0x2238 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_ALPHA 0x223c +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED 0x2210 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_GREEN 0x2214 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_BLUE 0x2218 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_ALPHA 0x221c +#define RADEON_SE_TCL_MATERIAL_SPECULAR_RED 0x2240 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_GREEN 0x2244 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_BLUE 0x2248 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_ALPHA 0x224c +#define RADEON_SE_TCL_MATRIX_SELECT_0 0x225c +# define RADEON_MODELVIEW_0_SHIFT 0 +# define RADEON_MODELVIEW_1_SHIFT 4 +# define RADEON_MODELVIEW_2_SHIFT 8 +# define RADEON_MODELVIEW_3_SHIFT 12 +# define RADEON_IT_MODELVIEW_0_SHIFT 16 +# define RADEON_IT_MODELVIEW_1_SHIFT 20 +# define RADEON_IT_MODELVIEW_2_SHIFT 24 +# define RADEON_IT_MODELVIEW_3_SHIFT 28 +#define RADEON_SE_TCL_MATRIX_SELECT_1 0x2260 +# define RADEON_MODELPROJECT_0_SHIFT 0 +# define RADEON_MODELPROJECT_1_SHIFT 4 +# define RADEON_MODELPROJECT_2_SHIFT 8 +# define RADEON_MODELPROJECT_3_SHIFT 12 +# define RADEON_TEXMAT_0_SHIFT 16 +# define RADEON_TEXMAT_1_SHIFT 20 +# define RADEON_TEXMAT_2_SHIFT 24 +# define RADEON_TEXMAT_3_SHIFT 28 + + +#define RADEON_SE_TCL_OUTPUT_VTX_FMT 0x2254 +# define RADEON_TCL_VTX_W0 (1 << 0) +# define RADEON_TCL_VTX_FP_DIFFUSE (1 << 1) +# define RADEON_TCL_VTX_FP_ALPHA (1 << 2) +# define RADEON_TCL_VTX_PK_DIFFUSE (1 << 3) +# define RADEON_TCL_VTX_FP_SPEC (1 << 4) +# define RADEON_TCL_VTX_FP_FOG (1 << 5) +# define RADEON_TCL_VTX_PK_SPEC (1 << 6) +# define RADEON_TCL_VTX_ST0 (1 << 7) +# define RADEON_TCL_VTX_ST1 (1 << 8) +# define RADEON_TCL_VTX_Q1 (1 << 9) +# define RADEON_TCL_VTX_ST2 (1 << 10) +# define RADEON_TCL_VTX_Q2 (1 << 11) +# define RADEON_TCL_VTX_ST3 (1 << 12) +# define RADEON_TCL_VTX_Q3 (1 << 13) +# define RADEON_TCL_VTX_Q0 (1 << 14) +# define RADEON_TCL_VTX_WEIGHT_COUNT_SHIFT 15 +# define RADEON_TCL_VTX_NORM0 (1 << 18) +# define RADEON_TCL_VTX_XY1 (1 << 27) +# define RADEON_TCL_VTX_Z1 (1 << 28) +# define RADEON_TCL_VTX_W1 (1 << 29) +# define RADEON_TCL_VTX_NORM1 (1 << 30) +# define RADEON_TCL_VTX_Z0 (1 << 31) + +#define RADEON_SE_TCL_OUTPUT_VTX_SEL 0x2258 +# define RADEON_TCL_COMPUTE_XYZW (1 << 0) +# define RADEON_TCL_COMPUTE_DIFFUSE (1 << 1) +# define RADEON_TCL_COMPUTE_SPECULAR (1 << 2) +# define RADEON_TCL_FORCE_NAN_IF_COLOR_NAN (1 << 3) +# define RADEON_TCL_FORCE_INORDER_PROC (1 << 4) +# define RADEON_TCL_TEX_INPUT_TEX_0 0 +# define RADEON_TCL_TEX_INPUT_TEX_1 1 +# define RADEON_TCL_TEX_INPUT_TEX_2 2 +# define RADEON_TCL_TEX_INPUT_TEX_3 3 +# define RADEON_TCL_TEX_COMPUTED_TEX_0 8 +# define RADEON_TCL_TEX_COMPUTED_TEX_1 9 +# define RADEON_TCL_TEX_COMPUTED_TEX_2 10 +# define RADEON_TCL_TEX_COMPUTED_TEX_3 11 +# define RADEON_TCL_TEX_0_OUTPUT_SHIFT 16 +# define RADEON_TCL_TEX_1_OUTPUT_SHIFT 20 +# define RADEON_TCL_TEX_2_OUTPUT_SHIFT 24 +# define RADEON_TCL_TEX_3_OUTPUT_SHIFT 28 + +#define RADEON_SE_TCL_PER_LIGHT_CTL_0 0x2270 +# define RADEON_LIGHT_0_ENABLE (1 << 0) +# define RADEON_LIGHT_0_ENABLE_AMBIENT (1 << 1) +# define RADEON_LIGHT_0_ENABLE_SPECULAR (1 << 2) +# define RADEON_LIGHT_0_IS_LOCAL (1 << 3) +# define RADEON_LIGHT_0_IS_SPOT (1 << 4) +# define RADEON_LIGHT_0_DUAL_CONE (1 << 5) +# define RADEON_LIGHT_0_ENABLE_RANGE_ATTEN (1 << 6) +# define RADEON_LIGHT_0_CONSTANT_RANGE_ATTEN (1 << 7) +# define RADEON_LIGHT_0_SHIFT 0 +# define RADEON_LIGHT_1_ENABLE (1 << 16) +# define RADEON_LIGHT_1_ENABLE_AMBIENT (1 << 17) +# define RADEON_LIGHT_1_ENABLE_SPECULAR (1 << 18) +# define RADEON_LIGHT_1_IS_LOCAL (1 << 19) +# define RADEON_LIGHT_1_IS_SPOT (1 << 20) +# define RADEON_LIGHT_1_DUAL_CONE (1 << 21) +# define RADEON_LIGHT_1_ENABLE_RANGE_ATTEN (1 << 22) +# define RADEON_LIGHT_1_CONSTANT_RANGE_ATTEN (1 << 23) +# define RADEON_LIGHT_1_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_1 0x2274 +# define RADEON_LIGHT_2_SHIFT 0 +# define RADEON_LIGHT_3_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_2 0x2278 +# define RADEON_LIGHT_4_SHIFT 0 +# define RADEON_LIGHT_5_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_3 0x227c +# define RADEON_LIGHT_6_SHIFT 0 +# define RADEON_LIGHT_7_SHIFT 16 + +#define RADEON_SE_TCL_SHININESS 0x2250 + +#define RADEON_SE_TCL_TEXTURE_PROC_CTL 0x2268 +# define RADEON_TEXGEN_TEXMAT_0_ENABLE (1 << 0) +# define RADEON_TEXGEN_TEXMAT_1_ENABLE (1 << 1) +# define RADEON_TEXGEN_TEXMAT_2_ENABLE (1 << 2) +# define RADEON_TEXGEN_TEXMAT_3_ENABLE (1 << 3) +# define RADEON_TEXMAT_0_ENABLE (1 << 4) +# define RADEON_TEXMAT_1_ENABLE (1 << 5) +# define RADEON_TEXMAT_2_ENABLE (1 << 6) +# define RADEON_TEXMAT_3_ENABLE (1 << 7) +# define RADEON_TEXGEN_INPUT_MASK 0xf +# define RADEON_TEXGEN_INPUT_TEXCOORD_0 0 +# define RADEON_TEXGEN_INPUT_TEXCOORD_1 1 +# define RADEON_TEXGEN_INPUT_TEXCOORD_2 2 +# define RADEON_TEXGEN_INPUT_TEXCOORD_3 3 +# define RADEON_TEXGEN_INPUT_OBJ 4 +# define RADEON_TEXGEN_INPUT_EYE 5 +# define RADEON_TEXGEN_INPUT_EYE_NORMAL 6 +# define RADEON_TEXGEN_INPUT_EYE_REFLECT 7 +# define RADEON_TEXGEN_INPUT_EYE_NORMALIZED 8 +# define RADEON_TEXGEN_0_INPUT_SHIFT 16 +# define RADEON_TEXGEN_1_INPUT_SHIFT 20 +# define RADEON_TEXGEN_2_INPUT_SHIFT 24 +# define RADEON_TEXGEN_3_INPUT_SHIFT 28 + +#define RADEON_SE_TCL_UCP_VERT_BLEND_CTL 0x2264 +# define RADEON_UCP_IN_CLIP_SPACE (1 << 0) +# define RADEON_UCP_IN_MODEL_SPACE (1 << 1) +# define RADEON_UCP_ENABLE_0 (1 << 2) +# define RADEON_UCP_ENABLE_1 (1 << 3) +# define RADEON_UCP_ENABLE_2 (1 << 4) +# define RADEON_UCP_ENABLE_3 (1 << 5) +# define RADEON_UCP_ENABLE_4 (1 << 6) +# define RADEON_UCP_ENABLE_5 (1 << 7) +# define RADEON_TCL_FOG_MASK (3 << 8) +# define RADEON_TCL_FOG_DISABLE (0 << 8) +# define RADEON_TCL_FOG_EXP (1 << 8) +# define RADEON_TCL_FOG_EXP2 (2 << 8) +# define RADEON_TCL_FOG_LINEAR (3 << 8) +# define RADEON_RNG_BASED_FOG (1 << 10) +# define RADEON_LIGHT_TWOSIDE (1 << 11) +# define RADEON_BLEND_OP_COUNT_MASK (7 << 12) +# define RADEON_BLEND_OP_COUNT_SHIFT 12 +# define RADEON_POSITION_BLEND_OP_ENABLE (1 << 16) +# define RADEON_NORMAL_BLEND_OP_ENABLE (1 << 17) +# define RADEON_VERTEX_BLEND_SRC_0_PRIMARY (1 << 18) +# define RADEON_VERTEX_BLEND_SRC_0_SECONDARY (1 << 18) +# define RADEON_VERTEX_BLEND_SRC_1_PRIMARY (1 << 19) +# define RADEON_VERTEX_BLEND_SRC_1_SECONDARY (1 << 19) +# define RADEON_VERTEX_BLEND_SRC_2_PRIMARY (1 << 20) +# define RADEON_VERTEX_BLEND_SRC_2_SECONDARY (1 << 20) +# define RADEON_VERTEX_BLEND_SRC_3_PRIMARY (1 << 21) +# define RADEON_VERTEX_BLEND_SRC_3_SECONDARY (1 << 21) +# define RADEON_VERTEX_BLEND_WGT_MINUS_ONE (1 << 22) +# define RADEON_CULL_FRONT_IS_CW (0 << 28) +# define RADEON_CULL_FRONT_IS_CCW (1 << 28) +# define RADEON_CULL_FRONT (1 << 29) +# define RADEON_CULL_BACK (1 << 30) +# define RADEON_FORCE_W_TO_ONE (1 << 31) + +#define RADEON_SE_VPORT_XSCALE 0x1d98 +#define RADEON_SE_VPORT_XOFFSET 0x1d9c +#define RADEON_SE_VPORT_YSCALE 0x1da0 +#define RADEON_SE_VPORT_YOFFSET 0x1da4 +#define RADEON_SE_VPORT_ZSCALE 0x1da8 +#define RADEON_SE_VPORT_ZOFFSET 0x1dac +#define RADEON_SE_ZBIAS_FACTOR 0x1db0 +#define RADEON_SE_ZBIAS_CONSTANT 0x1db4 + +#define RADEON_SE_VTX_FMT 0x2080 +# define RADEON_SE_VTX_FMT_XY 0x00000000 +# define RADEON_SE_VTX_FMT_W0 0x00000001 +# define RADEON_SE_VTX_FMT_FPCOLOR 0x00000002 +# define RADEON_SE_VTX_FMT_FPALPHA 0x00000004 +# define RADEON_SE_VTX_FMT_PKCOLOR 0x00000008 +# define RADEON_SE_VTX_FMT_FPSPEC 0x00000010 +# define RADEON_SE_VTX_FMT_FPFOG 0x00000020 +# define RADEON_SE_VTX_FMT_PKSPEC 0x00000040 +# define RADEON_SE_VTX_FMT_ST0 0x00000080 +# define RADEON_SE_VTX_FMT_ST1 0x00000100 +# define RADEON_SE_VTX_FMT_Q1 0x00000200 +# define RADEON_SE_VTX_FMT_ST2 0x00000400 +# define RADEON_SE_VTX_FMT_Q2 0x00000800 +# define RADEON_SE_VTX_FMT_ST3 0x00001000 +# define RADEON_SE_VTX_FMT_Q3 0x00002000 +# define RADEON_SE_VTX_FMT_Q0 0x00004000 +# define RADEON_SE_VTX_FMT_BLND_WEIGHT_CNT_MASK 0x00038000 +# define RADEON_SE_VTX_FMT_N0 0x00040000 +# define RADEON_SE_VTX_FMT_XY1 0x08000000 +# define RADEON_SE_VTX_FMT_Z1 0x10000000 +# define RADEON_SE_VTX_FMT_W1 0x20000000 +# define RADEON_SE_VTX_FMT_N1 0x40000000 +# define RADEON_SE_VTX_FMT_Z 0x80000000 + +#define RADEON_SE_VF_CNTL 0x2084 +# define RADEON_VF_PRIM_TYPE_POINT_LIST 1 +# define RADEON_VF_PRIM_TYPE_LINE_LIST 2 +# define RADEON_VF_PRIM_TYPE_LINE_STRIP 3 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_LIST 4 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_FAN 5 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_STRIP 6 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_FLAG 7 +# define RADEON_VF_PRIM_TYPE_RECTANGLE_LIST 8 +# define RADEON_VF_PRIM_TYPE_POINT_LIST_3 9 +# define RADEON_VF_PRIM_TYPE_LINE_LIST_3 10 +# define RADEON_VF_PRIM_TYPE_SPIRIT_LIST 11 +# define RADEON_VF_PRIM_TYPE_LINE_LOOP 12 +# define RADEON_VF_PRIM_TYPE_QUAD_LIST 13 +# define RADEON_VF_PRIM_TYPE_QUAD_STRIP 14 +# define RADEON_VF_PRIM_TYPE_POLYGON 15 +# define RADEON_VF_PRIM_WALK_STATE (0<<4) +# define RADEON_VF_PRIM_WALK_INDEX (1<<4) +# define RADEON_VF_PRIM_WALK_LIST (2<<4) +# define RADEON_VF_PRIM_WALK_DATA (3<<4) +# define RADEON_VF_COLOR_ORDER_RGBA (1<<6) +# define RADEON_VF_RADEON_MODE (1<<8) +# define RADEON_VF_TCL_OUTPUT_CTL_ENA (1<<9) +# define RADEON_VF_PROG_STREAM_ENA (1<<10) +# define RADEON_VF_INDEX_SIZE_SHIFT 11 +# define RADEON_VF_NUM_VERTICES_SHIFT 16 + +#define RADEON_SE_PORT_DATA0 0x2000 + +#define R200_SE_VAP_CNTL 0x2080 +# define R200_VAP_TCL_ENABLE 0x00000001 +# define R200_VAP_SINGLE_BUF_STATE_ENABLE 0x00000010 +# define R200_VAP_FORCE_W_TO_ONE 0x00010000 +# define R200_VAP_D3D_TEX_DEFAULT 0x00020000 +# define R200_VAP_VF_MAX_VTX_NUM__SHIFT 18 +# define R200_VAP_VF_MAX_VTX_NUM (9 << 18) +# define R200_VAP_DX_CLIP_SPACE_DEF 0x00400000 +#define R200_VF_MAX_VTX_INDX 0x210c +#define R200_VF_MIN_VTX_INDX 0x2110 +#define R200_SE_VTE_CNTL 0x20b0 +# define R200_VPORT_X_SCALE_ENA 0x00000001 +# define R200_VPORT_X_OFFSET_ENA 0x00000002 +# define R200_VPORT_Y_SCALE_ENA 0x00000004 +# define R200_VPORT_Y_OFFSET_ENA 0x00000008 +# define R200_VPORT_Z_SCALE_ENA 0x00000010 +# define R200_VPORT_Z_OFFSET_ENA 0x00000020 +# define R200_VTX_XY_FMT 0x00000100 +# define R200_VTX_Z_FMT 0x00000200 +# define R200_VTX_W0_FMT 0x00000400 +# define R200_VTX_W0_NORMALIZE 0x00000800 +# define R200_VTX_ST_DENORMALIZED 0x00001000 +#define R200_SE_VAP_CNTL_STATUS 0x2140 +# define R200_VC_NO_SWAP (0 << 0) +# define R200_VC_16BIT_SWAP (1 << 0) +# define R200_VC_32BIT_SWAP (2 << 0) +#define R200_PP_TXFILTER_0 0x2c00 +#define R200_PP_TXFILTER_1 0x2c20 +#define R200_PP_TXFILTER_2 0x2c40 +#define R200_PP_TXFILTER_3 0x2c60 +#define R200_PP_TXFILTER_4 0x2c80 +#define R200_PP_TXFILTER_5 0x2ca0 +# define R200_MAG_FILTER_NEAREST (0 << 0) +# define R200_MAG_FILTER_LINEAR (1 << 0) +# define R200_MAG_FILTER_MASK (1 << 0) +# define R200_MIN_FILTER_NEAREST (0 << 1) +# define R200_MIN_FILTER_LINEAR (1 << 1) +# define R200_MIN_FILTER_NEAREST_MIP_NEAREST (2 << 1) +# define R200_MIN_FILTER_NEAREST_MIP_LINEAR (3 << 1) +# define R200_MIN_FILTER_LINEAR_MIP_NEAREST (6 << 1) +# define R200_MIN_FILTER_LINEAR_MIP_LINEAR (7 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST (8 << 1) +# define R200_MIN_FILTER_ANISO_LINEAR (9 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (11 << 1) +# define R200_MIN_FILTER_MASK (15 << 1) +# define R200_MAX_ANISO_1_TO_1 (0 << 5) +# define R200_MAX_ANISO_2_TO_1 (1 << 5) +# define R200_MAX_ANISO_4_TO_1 (2 << 5) +# define R200_MAX_ANISO_8_TO_1 (3 << 5) +# define R200_MAX_ANISO_16_TO_1 (4 << 5) +# define R200_MAX_ANISO_MASK (7 << 5) +# define R200_MAX_MIP_LEVEL_MASK (0x0f << 16) +# define R200_MAX_MIP_LEVEL_SHIFT 16 +# define R200_YUV_TO_RGB (1 << 20) +# define R200_YUV_TEMPERATURE_COOL (0 << 21) +# define R200_YUV_TEMPERATURE_HOT (1 << 21) +# define R200_YUV_TEMPERATURE_MASK (1 << 21) +# define R200_WRAPEN_S (1 << 22) +# define R200_CLAMP_S_WRAP (0 << 23) +# define R200_CLAMP_S_MIRROR (1 << 23) +# define R200_CLAMP_S_CLAMP_LAST (2 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23) +# define R200_CLAMP_S_CLAMP_BORDER (4 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23) +# define R200_CLAMP_S_CLAMP_GL (6 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_GL (7 << 23) +# define R200_CLAMP_S_MASK (7 << 23) +# define R200_WRAPEN_T (1 << 26) +# define R200_CLAMP_T_WRAP (0 << 27) +# define R200_CLAMP_T_MIRROR (1 << 27) +# define R200_CLAMP_T_CLAMP_LAST (2 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27) +# define R200_CLAMP_T_CLAMP_BORDER (4 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27) +# define R200_CLAMP_T_CLAMP_GL (6 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_GL (7 << 27) +# define R200_CLAMP_T_MASK (7 << 27) +# define R200_KILL_LT_ZERO (1 << 30) +# define R200_BORDER_MODE_OGL (0 << 31) +# define R200_BORDER_MODE_D3D (1 << 31) +#define R200_PP_TXFORMAT_0 0x2c04 +#define R200_PP_TXFORMAT_1 0x2c24 +#define R200_PP_TXFORMAT_2 0x2c44 +#define R200_PP_TXFORMAT_3 0x2c64 +#define R200_PP_TXFORMAT_4 0x2c84 +#define R200_PP_TXFORMAT_5 0x2ca4 +# define R200_TXFORMAT_I8 (0 << 0) +# define R200_TXFORMAT_AI88 (1 << 0) +# define R200_TXFORMAT_RGB332 (2 << 0) +# define R200_TXFORMAT_ARGB1555 (3 << 0) +# define R200_TXFORMAT_RGB565 (4 << 0) +# define R200_TXFORMAT_ARGB4444 (5 << 0) +# define R200_TXFORMAT_ARGB8888 (6 << 0) +# define R200_TXFORMAT_RGBA8888 (7 << 0) +# define R200_TXFORMAT_Y8 (8 << 0) +# define R200_TXFORMAT_AVYU4444 (9 << 0) +# define R200_TXFORMAT_VYUY422 (10 << 0) +# define R200_TXFORMAT_YVYU422 (11 << 0) +# define R200_TXFORMAT_DXT1 (12 << 0) +# define R200_TXFORMAT_DXT23 (14 << 0) +# define R200_TXFORMAT_DXT45 (15 << 0) +# define R200_TXFORMAT_ABGR8888 (22 << 0) +# define R200_TXFORMAT_FORMAT_MASK (31 << 0) +# define R200_TXFORMAT_FORMAT_SHIFT 0 +# define R200_TXFORMAT_ALPHA_IN_MAP (1 << 6) +# define R200_TXFORMAT_NON_POWER2 (1 << 7) +# define R200_TXFORMAT_WIDTH_MASK (15 << 8) +# define R200_TXFORMAT_WIDTH_SHIFT 8 +# define R200_TXFORMAT_HEIGHT_MASK (15 << 12) +# define R200_TXFORMAT_HEIGHT_SHIFT 12 +# define R200_TXFORMAT_F5_WIDTH_MASK (15 << 16) /* cube face 5 */ +# define R200_TXFORMAT_F5_WIDTH_SHIFT 16 +# define R200_TXFORMAT_F5_HEIGHT_MASK (15 << 20) +# define R200_TXFORMAT_F5_HEIGHT_SHIFT 20 +# define R200_TXFORMAT_ST_ROUTE_STQ0 (0 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ1 (1 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ2 (2 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ3 (3 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ4 (4 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ5 (5 << 24) +# define R200_TXFORMAT_ST_ROUTE_MASK (7 << 24) +# define R200_TXFORMAT_ST_ROUTE_SHIFT 24 +# define R200_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28) +# define R200_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) +# define R200_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) +#define R200_PP_TXFORMAT_X_0 0x2c08 +#define R200_PP_TXFORMAT_X_1 0x2c28 +#define R200_PP_TXFORMAT_X_2 0x2c48 +#define R200_PP_TXFORMAT_X_3 0x2c68 +#define R200_PP_TXFORMAT_X_4 0x2c88 +#define R200_PP_TXFORMAT_X_5 0x2ca8 + +#define R200_PP_TXSIZE_0 0x2c0c /* NPOT only */ +#define R200_PP_TXSIZE_1 0x2c2c /* NPOT only */ +#define R200_PP_TXSIZE_2 0x2c4c /* NPOT only */ +#define R200_PP_TXSIZE_3 0x2c6c /* NPOT only */ +#define R200_PP_TXSIZE_4 0x2c8c /* NPOT only */ +#define R200_PP_TXSIZE_5 0x2cac /* NPOT only */ + +#define R200_PP_TXPITCH_0 0x2c10 /* NPOT only */ +#define R200_PP_TXPITCH_1 0x2c30 /* NPOT only */ +#define R200_PP_TXPITCH_2 0x2c50 /* NPOT only */ +#define R200_PP_TXPITCH_3 0x2c70 /* NPOT only */ +#define R200_PP_TXPITCH_4 0x2c90 /* NPOT only */ +#define R200_PP_TXPITCH_5 0x2cb0 /* NPOT only */ + +#define R200_PP_TXOFFSET_0 0x2d00 +# define R200_TXO_ENDIAN_NO_SWAP (0 << 0) +# define R200_TXO_ENDIAN_BYTE_SWAP (1 << 0) +# define R200_TXO_ENDIAN_WORD_SWAP (2 << 0) +# define R200_TXO_ENDIAN_HALFDW_SWAP (3 << 0) +# define R200_TXO_MACRO_LINEAR (0 << 2) +# define R200_TXO_MACRO_TILE (1 << 2) +# define R200_TXO_MICRO_LINEAR (0 << 3) +# define R200_TXO_MICRO_TILE (1 << 3) +# define R200_TXO_OFFSET_MASK 0xffffffe0 +# define R200_TXO_OFFSET_SHIFT 5 +#define R200_PP_TXOFFSET_1 0x2d18 +#define R200_PP_TXOFFSET_2 0x2d30 +#define R200_PP_TXOFFSET_3 0x2d48 +#define R200_PP_TXOFFSET_4 0x2d60 +#define R200_PP_TXOFFSET_5 0x2d78 + +#define R200_PP_TFACTOR_0 0x2ee0 +#define R200_PP_TFACTOR_1 0x2ee4 +#define R200_PP_TFACTOR_2 0x2ee8 +#define R200_PP_TFACTOR_3 0x2eec +#define R200_PP_TFACTOR_4 0x2ef0 +#define R200_PP_TFACTOR_5 0x2ef4 + +#define R200_PP_TXCBLEND_0 0x2f00 +# define R200_TXC_ARG_A_ZERO (0) +# define R200_TXC_ARG_A_CURRENT_COLOR (2) +# define R200_TXC_ARG_A_CURRENT_ALPHA (3) +# define R200_TXC_ARG_A_DIFFUSE_COLOR (4) +# define R200_TXC_ARG_A_DIFFUSE_ALPHA (5) +# define R200_TXC_ARG_A_SPECULAR_COLOR (6) +# define R200_TXC_ARG_A_SPECULAR_ALPHA (7) +# define R200_TXC_ARG_A_TFACTOR_COLOR (8) +# define R200_TXC_ARG_A_TFACTOR_ALPHA (9) +# define R200_TXC_ARG_A_R0_COLOR (10) +# define R200_TXC_ARG_A_R0_ALPHA (11) +# define R200_TXC_ARG_A_R1_COLOR (12) +# define R200_TXC_ARG_A_R1_ALPHA (13) +# define R200_TXC_ARG_A_R2_COLOR (14) +# define R200_TXC_ARG_A_R2_ALPHA (15) +# define R200_TXC_ARG_A_R3_COLOR (16) +# define R200_TXC_ARG_A_R3_ALPHA (17) +# define R200_TXC_ARG_A_R4_COLOR (18) +# define R200_TXC_ARG_A_R4_ALPHA (19) +# define R200_TXC_ARG_A_R5_COLOR (20) +# define R200_TXC_ARG_A_R5_ALPHA (21) +# define R200_TXC_ARG_A_TFACTOR1_COLOR (26) +# define R200_TXC_ARG_A_TFACTOR1_ALPHA (27) +# define R200_TXC_ARG_A_MASK (31 << 0) +# define R200_TXC_ARG_A_SHIFT 0 +# define R200_TXC_ARG_B_ZERO (0 << 5) +# define R200_TXC_ARG_B_CURRENT_COLOR (2 << 5) +# define R200_TXC_ARG_B_CURRENT_ALPHA (3 << 5) +# define R200_TXC_ARG_B_DIFFUSE_COLOR (4 << 5) +# define R200_TXC_ARG_B_DIFFUSE_ALPHA (5 << 5) +# define R200_TXC_ARG_B_SPECULAR_COLOR (6 << 5) +# define R200_TXC_ARG_B_SPECULAR_ALPHA (7 << 5) +# define R200_TXC_ARG_B_TFACTOR_COLOR (8 << 5) +# define R200_TXC_ARG_B_TFACTOR_ALPHA (9 << 5) +# define R200_TXC_ARG_B_R0_COLOR (10 << 5) +# define R200_TXC_ARG_B_R0_ALPHA (11 << 5) +# define R200_TXC_ARG_B_R1_COLOR (12 << 5) +# define R200_TXC_ARG_B_R1_ALPHA (13 << 5) +# define R200_TXC_ARG_B_R2_COLOR (14 << 5) +# define R200_TXC_ARG_B_R2_ALPHA (15 << 5) +# define R200_TXC_ARG_B_R3_COLOR (16 << 5) +# define R200_TXC_ARG_B_R3_ALPHA (17 << 5) +# define R200_TXC_ARG_B_R4_COLOR (18 << 5) +# define R200_TXC_ARG_B_R4_ALPHA (19 << 5) +# define R200_TXC_ARG_B_R5_COLOR (20 << 5) +# define R200_TXC_ARG_B_R5_ALPHA (21 << 5) +# define R200_TXC_ARG_B_TFACTOR1_COLOR (26 << 5) +# define R200_TXC_ARG_B_TFACTOR1_ALPHA (27 << 5) +# define R200_TXC_ARG_B_MASK (31 << 5) +# define R200_TXC_ARG_B_SHIFT 5 +# define R200_TXC_ARG_C_ZERO (0 << 10) +# define R200_TXC_ARG_C_CURRENT_COLOR (2 << 10) +# define R200_TXC_ARG_C_CURRENT_ALPHA (3 << 10) +# define R200_TXC_ARG_C_DIFFUSE_COLOR (4 << 10) +# define R200_TXC_ARG_C_DIFFUSE_ALPHA (5 << 10) +# define R200_TXC_ARG_C_SPECULAR_COLOR (6 << 10) +# define R200_TXC_ARG_C_SPECULAR_ALPHA (7 << 10) +# define R200_TXC_ARG_C_TFACTOR_COLOR (8 << 10) +# define R200_TXC_ARG_C_TFACTOR_ALPHA (9 << 10) +# define R200_TXC_ARG_C_R0_COLOR (10 << 10) +# define R200_TXC_ARG_C_R0_ALPHA (11 << 10) +# define R200_TXC_ARG_C_R1_COLOR (12 << 10) +# define R200_TXC_ARG_C_R1_ALPHA (13 << 10) +# define R200_TXC_ARG_C_R2_COLOR (14 << 10) +# define R200_TXC_ARG_C_R2_ALPHA (15 << 10) +# define R200_TXC_ARG_C_R3_COLOR (16 << 10) +# define R200_TXC_ARG_C_R3_ALPHA (17 << 10) +# define R200_TXC_ARG_C_R4_COLOR (18 << 10) +# define R200_TXC_ARG_C_R4_ALPHA (19 << 10) +# define R200_TXC_ARG_C_R5_COLOR (20 << 10) +# define R200_TXC_ARG_C_R5_ALPHA (21 << 10) +# define R200_TXC_ARG_C_TFACTOR1_COLOR (26 << 10) +# define R200_TXC_ARG_C_TFACTOR1_ALPHA (27 << 10) +# define R200_TXC_ARG_C_MASK (31 << 10) +# define R200_TXC_ARG_C_SHIFT 10 +# define R200_TXC_COMP_ARG_A (1 << 16) +# define R200_TXC_COMP_ARG_A_SHIFT (16) +# define R200_TXC_BIAS_ARG_A (1 << 17) +# define R200_TXC_SCALE_ARG_A (1 << 18) +# define R200_TXC_NEG_ARG_A (1 << 19) +# define R200_TXC_COMP_ARG_B (1 << 20) +# define R200_TXC_COMP_ARG_B_SHIFT (20) +# define R200_TXC_BIAS_ARG_B (1 << 21) +# define R200_TXC_SCALE_ARG_B (1 << 22) +# define R200_TXC_NEG_ARG_B (1 << 23) +# define R200_TXC_COMP_ARG_C (1 << 24) +# define R200_TXC_COMP_ARG_C_SHIFT (24) +# define R200_TXC_BIAS_ARG_C (1 << 25) +# define R200_TXC_SCALE_ARG_C (1 << 26) +# define R200_TXC_NEG_ARG_C (1 << 27) +# define R200_TXC_OP_MADD (0 << 28) +# define R200_TXC_OP_CND0 (2 << 28) +# define R200_TXC_OP_LERP (3 << 28) +# define R200_TXC_OP_DOT3 (4 << 28) +# define R200_TXC_OP_DOT4 (5 << 28) +# define R200_TXC_OP_CONDITIONAL (6 << 28) +# define R200_TXC_OP_DOT2_ADD (7 << 28) +# define R200_TXC_OP_MASK (7 << 28) +#define R200_PP_TXCBLEND2_0 0x2f04 +# define R200_TXC_TFACTOR_SEL_SHIFT 0 +# define R200_TXC_TFACTOR_SEL_MASK 0x7 +# define R200_TXC_TFACTOR1_SEL_SHIFT 4 +# define R200_TXC_TFACTOR1_SEL_MASK (0x7 << 4) +# define R200_TXC_SCALE_SHIFT 8 +# define R200_TXC_SCALE_MASK (7 << 8) +# define R200_TXC_SCALE_1X (0 << 8) +# define R200_TXC_SCALE_2X (1 << 8) +# define R200_TXC_SCALE_4X (2 << 8) +# define R200_TXC_SCALE_8X (3 << 8) +# define R200_TXC_SCALE_INV2 (5 << 8) +# define R200_TXC_SCALE_INV4 (6 << 8) +# define R200_TXC_SCALE_INV8 (7 << 8) +# define R200_TXC_CLAMP_SHIFT 12 +# define R200_TXC_CLAMP_MASK (3 << 12) +# define R200_TXC_CLAMP_WRAP (0 << 12) +# define R200_TXC_CLAMP_0_1 (1 << 12) +# define R200_TXC_CLAMP_8_8 (2 << 12) +# define R200_TXC_OUTPUT_REG_MASK (7 << 16) +# define R200_TXC_OUTPUT_REG_NONE (0 << 16) +# define R200_TXC_OUTPUT_REG_R0 (1 << 16) +# define R200_TXC_OUTPUT_REG_R1 (2 << 16) +# define R200_TXC_OUTPUT_REG_R2 (3 << 16) +# define R200_TXC_OUTPUT_REG_R3 (4 << 16) +# define R200_TXC_OUTPUT_REG_R4 (5 << 16) +# define R200_TXC_OUTPUT_REG_R5 (6 << 16) +# define R200_TXC_OUTPUT_MASK_MASK (7 << 20) +# define R200_TXC_OUTPUT_MASK_RGB (0 << 20) +# define R200_TXC_OUTPUT_MASK_RG (1 << 20) +# define R200_TXC_OUTPUT_MASK_RB (2 << 20) +# define R200_TXC_OUTPUT_MASK_R (3 << 20) +# define R200_TXC_OUTPUT_MASK_GB (4 << 20) +# define R200_TXC_OUTPUT_MASK_G (5 << 20) +# define R200_TXC_OUTPUT_MASK_B (6 << 20) +# define R200_TXC_OUTPUT_MASK_NONE (7 << 20) +# define R200_TXC_REPL_NORMAL 0 +# define R200_TXC_REPL_RED 1 +# define R200_TXC_REPL_GREEN 2 +# define R200_TXC_REPL_BLUE 3 +# define R200_TXC_REPL_ARG_A_SHIFT 26 +# define R200_TXC_REPL_ARG_A_MASK (3 << 26) +# define R200_TXC_REPL_ARG_B_SHIFT 28 +# define R200_TXC_REPL_ARG_B_MASK (3 << 28) +# define R200_TXC_REPL_ARG_C_SHIFT 30 +# define R200_TXC_REPL_ARG_C_MASK (3 << 30) +#define R200_PP_TXABLEND_0 0x2f08 +# define R200_TXA_ARG_A_ZERO (0) +# define R200_TXA_ARG_A_CURRENT_ALPHA (2) /* guess */ +# define R200_TXA_ARG_A_CURRENT_BLUE (3) /* guess */ +# define R200_TXA_ARG_A_DIFFUSE_ALPHA (4) +# define R200_TXA_ARG_A_DIFFUSE_BLUE (5) +# define R200_TXA_ARG_A_SPECULAR_ALPHA (6) +# define R200_TXA_ARG_A_SPECULAR_BLUE (7) +# define R200_TXA_ARG_A_TFACTOR_ALPHA (8) +# define R200_TXA_ARG_A_TFACTOR_BLUE (9) +# define R200_TXA_ARG_A_R0_ALPHA (10) +# define R200_TXA_ARG_A_R0_BLUE (11) +# define R200_TXA_ARG_A_R1_ALPHA (12) +# define R200_TXA_ARG_A_R1_BLUE (13) +# define R200_TXA_ARG_A_R2_ALPHA (14) +# define R200_TXA_ARG_A_R2_BLUE (15) +# define R200_TXA_ARG_A_R3_ALPHA (16) +# define R200_TXA_ARG_A_R3_BLUE (17) +# define R200_TXA_ARG_A_R4_ALPHA (18) +# define R200_TXA_ARG_A_R4_BLUE (19) +# define R200_TXA_ARG_A_R5_ALPHA (20) +# define R200_TXA_ARG_A_R5_BLUE (21) +# define R200_TXA_ARG_A_TFACTOR1_ALPHA (26) +# define R200_TXA_ARG_A_TFACTOR1_BLUE (27) +# define R200_TXA_ARG_A_MASK (31 << 0) +# define R200_TXA_ARG_A_SHIFT 0 +# define R200_TXA_ARG_B_ZERO (0 << 5) +# define R200_TXA_ARG_B_CURRENT_ALPHA (2 << 5) /* guess */ +# define R200_TXA_ARG_B_CURRENT_BLUE (3 << 5) /* guess */ +# define R200_TXA_ARG_B_DIFFUSE_ALPHA (4 << 5) +# define R200_TXA_ARG_B_DIFFUSE_BLUE (5 << 5) +# define R200_TXA_ARG_B_SPECULAR_ALPHA (6 << 5) +# define R200_TXA_ARG_B_SPECULAR_BLUE (7 << 5) +# define R200_TXA_ARG_B_TFACTOR_ALPHA (8 << 5) +# define R200_TXA_ARG_B_TFACTOR_BLUE (9 << 5) +# define R200_TXA_ARG_B_R0_ALPHA (10 << 5) +# define R200_TXA_ARG_B_R0_BLUE (11 << 5) +# define R200_TXA_ARG_B_R1_ALPHA (12 << 5) +# define R200_TXA_ARG_B_R1_BLUE (13 << 5) +# define R200_TXA_ARG_B_R2_ALPHA (14 << 5) +# define R200_TXA_ARG_B_R2_BLUE (15 << 5) +# define R200_TXA_ARG_B_R3_ALPHA (16 << 5) +# define R200_TXA_ARG_B_R3_BLUE (17 << 5) +# define R200_TXA_ARG_B_R4_ALPHA (18 << 5) +# define R200_TXA_ARG_B_R4_BLUE (19 << 5) +# define R200_TXA_ARG_B_R5_ALPHA (20 << 5) +# define R200_TXA_ARG_B_R5_BLUE (21 << 5) +# define R200_TXA_ARG_B_TFACTOR1_ALPHA (26 << 5) +# define R200_TXA_ARG_B_TFACTOR1_BLUE (27 << 5) +# define R200_TXA_ARG_B_MASK (31 << 5) +# define R200_TXA_ARG_B_SHIFT 5 +# define R200_TXA_ARG_C_ZERO (0 << 10) +# define R200_TXA_ARG_C_CURRENT_ALPHA (2 << 10) /* guess */ +# define R200_TXA_ARG_C_CURRENT_BLUE (3 << 10) /* guess */ +# define R200_TXA_ARG_C_DIFFUSE_ALPHA (4 << 10) +# define R200_TXA_ARG_C_DIFFUSE_BLUE (5 << 10) +# define R200_TXA_ARG_C_SPECULAR_ALPHA (6 << 10) +# define R200_TXA_ARG_C_SPECULAR_BLUE (7 << 10) +# define R200_TXA_ARG_C_TFACTOR_ALPHA (8 << 10) +# define R200_TXA_ARG_C_TFACTOR_BLUE (9 << 10) +# define R200_TXA_ARG_C_R0_ALPHA (10 << 10) +# define R200_TXA_ARG_C_R0_BLUE (11 << 10) +# define R200_TXA_ARG_C_R1_ALPHA (12 << 10) +# define R200_TXA_ARG_C_R1_BLUE (13 << 10) +# define R200_TXA_ARG_C_R2_ALPHA (14 << 10) +# define R200_TXA_ARG_C_R2_BLUE (15 << 10) +# define R200_TXA_ARG_C_R3_ALPHA (16 << 10) +# define R200_TXA_ARG_C_R3_BLUE (17 << 10) +# define R200_TXA_ARG_C_R4_ALPHA (18 << 10) +# define R200_TXA_ARG_C_R4_BLUE (19 << 10) +# define R200_TXA_ARG_C_R5_ALPHA (20 << 10) +# define R200_TXA_ARG_C_R5_BLUE (21 << 10) +# define R200_TXA_ARG_C_TFACTOR1_ALPHA (26 << 10) +# define R200_TXA_ARG_C_TFACTOR1_BLUE (27 << 10) +# define R200_TXA_ARG_C_MASK (31 << 10) +# define R200_TXA_ARG_C_SHIFT 10 +# define R200_TXA_COMP_ARG_A (1 << 16) +# define R200_TXA_COMP_ARG_A_SHIFT (16) +# define R200_TXA_BIAS_ARG_A (1 << 17) +# define R200_TXA_SCALE_ARG_A (1 << 18) +# define R200_TXA_NEG_ARG_A (1 << 19) +# define R200_TXA_COMP_ARG_B (1 << 20) +# define R200_TXA_COMP_ARG_B_SHIFT (20) +# define R200_TXA_BIAS_ARG_B (1 << 21) +# define R200_TXA_SCALE_ARG_B (1 << 22) +# define R200_TXA_NEG_ARG_B (1 << 23) +# define R200_TXA_COMP_ARG_C (1 << 24) +# define R200_TXA_COMP_ARG_C_SHIFT (24) +# define R200_TXA_BIAS_ARG_C (1 << 25) +# define R200_TXA_SCALE_ARG_C (1 << 26) +# define R200_TXA_NEG_ARG_C (1 << 27) +# define R200_TXA_OP_MADD (0 << 28) +# define R200_TXA_OP_CND0 (2 << 28) +# define R200_TXA_OP_LERP (3 << 28) +# define R200_TXA_OP_CONDITIONAL (6 << 28) +# define R200_TXA_OP_MASK (7 << 28) +#define R200_PP_TXABLEND2_0 0x2f0c +# define R200_TXA_TFACTOR_SEL_SHIFT 0 +# define R200_TXA_TFACTOR_SEL_MASK 0x7 +# define R200_TXA_TFACTOR1_SEL_SHIFT 4 +# define R200_TXA_TFACTOR1_SEL_MASK (0x7 << 4) +# define R200_TXA_SCALE_SHIFT 8 +# define R200_TXA_SCALE_MASK (7 << 8) +# define R200_TXA_SCALE_1X (0 << 8) +# define R200_TXA_SCALE_2X (1 << 8) +# define R200_TXA_SCALE_4X (2 << 8) +# define R200_TXA_SCALE_8X (3 << 8) +# define R200_TXA_SCALE_INV2 (5 << 8) +# define R200_TXA_SCALE_INV4 (6 << 8) +# define R200_TXA_SCALE_INV8 (7 << 8) +# define R200_TXA_CLAMP_SHIFT 12 +# define R200_TXA_CLAMP_MASK (3 << 12) +# define R200_TXA_CLAMP_WRAP (0 << 12) +# define R200_TXA_CLAMP_0_1 (1 << 12) +# define R200_TXA_CLAMP_8_8 (2 << 12) +# define R200_TXA_OUTPUT_REG_MASK (7 << 16) +# define R200_TXA_OUTPUT_REG_NONE (0 << 16) +# define R200_TXA_OUTPUT_REG_R0 (1 << 16) +# define R200_TXA_OUTPUT_REG_R1 (2 << 16) +# define R200_TXA_OUTPUT_REG_R2 (3 << 16) +# define R200_TXA_OUTPUT_REG_R3 (4 << 16) +# define R200_TXA_OUTPUT_REG_R4 (5 << 16) +# define R200_TXA_OUTPUT_REG_R5 (6 << 16) +# define R200_TXA_DOT_ALPHA (1 << 20) +# define R200_TXA_REPL_NORMAL 0 +# define R200_TXA_REPL_RED 1 +# define R200_TXA_REPL_GREEN 2 +# define R200_TXA_REPL_ARG_A_SHIFT 26 +# define R200_TXA_REPL_ARG_A_MASK (3 << 26) +# define R200_TXA_REPL_ARG_B_SHIFT 28 +# define R200_TXA_REPL_ARG_B_MASK (3 << 28) +# define R200_TXA_REPL_ARG_C_SHIFT 30 +# define R200_TXA_REPL_ARG_C_MASK (3 << 30) + +#define R200_SE_VTX_FMT_0 0x2088 +# define R200_VTX_XY 0 /* always have xy */ +# define R200_VTX_Z0 (1<<0) +# define R200_VTX_W0 (1<<1) +# define R200_VTX_WEIGHT_COUNT_SHIFT (2) +# define R200_VTX_PV_MATRIX_SEL (1<<5) +# define R200_VTX_N0 (1<<6) +# define R200_VTX_POINT_SIZE (1<<7) +# define R200_VTX_DISCRETE_FOG (1<<8) +# define R200_VTX_SHININESS_0 (1<<9) +# define R200_VTX_SHININESS_1 (1<<10) +# define R200_VTX_COLOR_NOT_PRESENT 0 +# define R200_VTX_PK_RGBA 1 +# define R200_VTX_FP_RGB 2 +# define R200_VTX_FP_RGBA 3 +# define R200_VTX_COLOR_MASK 3 +# define R200_VTX_COLOR_0_SHIFT 11 +# define R200_VTX_COLOR_1_SHIFT 13 +# define R200_VTX_COLOR_2_SHIFT 15 +# define R200_VTX_COLOR_3_SHIFT 17 +# define R200_VTX_COLOR_4_SHIFT 19 +# define R200_VTX_COLOR_5_SHIFT 21 +# define R200_VTX_COLOR_6_SHIFT 23 +# define R200_VTX_COLOR_7_SHIFT 25 +# define R200_VTX_XY1 (1<<28) +# define R200_VTX_Z1 (1<<29) +# define R200_VTX_W1 (1<<30) +# define R200_VTX_N1 (1<<31) +#define R200_SE_VTX_FMT_1 0x208c +# define R200_VTX_TEX0_COMP_CNT_SHIFT 0 +# define R200_VTX_TEX1_COMP_CNT_SHIFT 3 +# define R200_VTX_TEX2_COMP_CNT_SHIFT 6 +# define R200_VTX_TEX3_COMP_CNT_SHIFT 9 +# define R200_VTX_TEX4_COMP_CNT_SHIFT 12 +# define R200_VTX_TEX5_COMP_CNT_SHIFT 15 + +#define R200_SE_TCL_OUTPUT_VTX_FMT_0 0x2090 +#define R200_SE_TCL_OUTPUT_VTX_FMT_1 0x2094 +#define R200_SE_TCL_OUTPUT_VTX_COMP_SEL 0x2250 +# define R200_OUTPUT_XYZW (1<<0) +# define R200_OUTPUT_COLOR_0 (1<<8) +# define R200_OUTPUT_COLOR_1 (1<<9) +# define R200_OUTPUT_TEX_0 (1<<16) +# define R200_OUTPUT_TEX_1 (1<<17) +# define R200_OUTPUT_TEX_2 (1<<18) +# define R200_OUTPUT_TEX_3 (1<<19) +# define R200_OUTPUT_TEX_4 (1<<20) +# define R200_OUTPUT_TEX_5 (1<<21) +# define R200_OUTPUT_TEX_MASK (0x3f<<16) +# define R200_OUTPUT_DISCRETE_FOG (1<<24) +# define R200_OUTPUT_PT_SIZE (1<<25) +# define R200_FORCE_INORDER_PROC (1<<31) +#define R200_PP_CNTL_X 0x2cc4 +#define R200_PP_TXMULTI_CTL_0 0x2c1c +#define R200_SE_VTX_STATE_CNTL 0x2180 +# define R200_UPDATE_USER_COLOR_0_ENA_MASK (1<<16) + + /* Registers for CP and Microcode Engine */ +#define RADEON_CP_ME_RAM_ADDR 0x07d4 +#define RADEON_CP_ME_RAM_RADDR 0x07d8 +#define RADEON_CP_ME_RAM_DATAH 0x07dc +#define RADEON_CP_ME_RAM_DATAL 0x07e0 + +#define RADEON_CP_RB_BASE 0x0700 +#define RADEON_CP_RB_CNTL 0x0704 +#define RADEON_CP_RB_RPTR_ADDR 0x070c +#define RADEON_CP_RB_RPTR 0x0710 +#define RADEON_CP_RB_WPTR 0x0714 + +#define RADEON_CP_IB_BASE 0x0738 +#define RADEON_CP_IB_BUFSZ 0x073c + +#define RADEON_CP_CSQ_CNTL 0x0740 +# define RADEON_CSQ_CNT_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_PRIDIS_INDDIS (0 << 28) +# define RADEON_CSQ_PRIPIO_INDDIS (1 << 28) +# define RADEON_CSQ_PRIBM_INDDIS (2 << 28) +# define RADEON_CSQ_PRIPIO_INDBM (3 << 28) +# define RADEON_CSQ_PRIBM_INDBM (4 << 28) +# define RADEON_CSQ_PRIPIO_INDPIO (15 << 28) +#define RADEON_CP_CSQ_STAT 0x07f8 +# define RADEON_CSQ_RPTR_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_WPTR_PRIMARY_MASK (0xff << 8) +# define RADEON_CSQ_RPTR_INDIRECT_MASK (0xff << 16) +# define RADEON_CSQ_WPTR_INDIRECT_MASK (0xff << 24) +#define RADEON_CP_CSQ_ADDR 0x07f0 +#define RADEON_CP_CSQ_DATA 0x07f4 +#define RADEON_CP_CSQ_APER_PRIMARY 0x1000 +#define RADEON_CP_CSQ_APER_INDIRECT 0x1300 + +#define RADEON_CP_RB_WPTR_DELAY 0x0718 +# define RADEON_PRE_WRITE_TIMER_SHIFT 0 +# define RADEON_PRE_WRITE_LIMIT_SHIFT 23 + +#define RADEON_AIC_CNTL 0x01d0 +# define RADEON_PCIGART_TRANSLATE_EN (1 << 0) +#define RADEON_AIC_LO_ADDR 0x01dc + + + + /* Constants */ +//#define RADEON_LAST_FRAME_REG RADEON_GUI_SCRATCH_REG0 +//efine RADEON_LAST_CLEAR_REG RADEON_GUI_SCRATCH_REG2 + + + + /* CP packet types */ +#define RADEON_CP_PACKET0 0x00000000 +#define RADEON_CP_PACKET1 0x40000000 +#define RADEON_CP_PACKET2 0x80000000 +#define RADEON_CP_PACKET3 0xC0000000 +# define RADEON_CP_PACKET_MASK 0xC0000000 +# define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000 +# define RADEON_CP_PACKET_MAX_DWORDS (1 << 12) +# define RADEON_CP_PACKET0_REG_MASK 0x000007ff +# define RADEON_CP_PACKET1_REG0_MASK 0x000007ff +# define RADEON_CP_PACKET1_REG1_MASK 0x003ff800 + +#define RADEON_CP_PACKET0_ONE_REG_WR 0x00008000 + +#define RADEON_CP_PACKET3_NOP 0xC0001000 +#define RADEON_CP_PACKET3_NEXT_CHAR 0xC0001900 +#define RADEON_CP_PACKET3_PLY_NEXTSCAN 0xC0001D00 +#define RADEON_CP_PACKET3_SET_SCISSORS 0xC0001E00 +#define RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM 0xC0002300 +#define RADEON_CP_PACKET3_LOAD_MICROCODE 0xC0002400 +#define RADEON_CP_PACKET3_WAIT_FOR_IDLE 0xC0002600 +#define RADEON_CP_PACKET3_3D_DRAW_VBUF 0xC0002800 +#define RADEON_CP_PACKET3_3D_DRAW_IMMD 0xC0002900 +#define RADEON_CP_PACKET3_3D_DRAW_INDX 0xC0002A00 +#define RADEON_CP_PACKET3_LOAD_PALETTE 0xC0002C00 +#define R200_CP_PACKET3_3D_DRAW_IMMD_2 0xc0003500 +#define RADEON_CP_PACKET3_3D_LOAD_VBPNTR 0xC0002F00 +#define RADEON_CP_PACKET3_CNTL_PAINT 0xC0009100 +#define RADEON_CP_PACKET3_CNTL_BITBLT 0xC0009200 +#define RADEON_CP_PACKET3_CNTL_SMALLTEXT 0xC0009300 +#define RADEON_CP_PACKET3_CNTL_HOSTDATA_BLT 0xC0009400 +#define RADEON_CP_PACKET3_CNTL_POLYLINE 0xC0009500 +#define RADEON_CP_PACKET3_CNTL_POLYSCANLINES 0xC0009800 +#define RADEON_CP_PACKET3_CNTL_PAINT_MULTI 0xC0009A00 +#define RADEON_CP_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 +#define RADEON_CP_PACKET3_CNTL_TRANS_BITBLT 0xC0009C00 + + +#define RADEON_CP_VC_FRMT_XY 0x00000000 +#define RADEON_CP_VC_FRMT_W0 0x00000001 +#define RADEON_CP_VC_FRMT_FPCOLOR 0x00000002 +#define RADEON_CP_VC_FRMT_FPALPHA 0x00000004 +#define RADEON_CP_VC_FRMT_PKCOLOR 0x00000008 +#define RADEON_CP_VC_FRMT_FPSPEC 0x00000010 +#define RADEON_CP_VC_FRMT_FPFOG 0x00000020 +#define RADEON_CP_VC_FRMT_PKSPEC 0x00000040 +#define RADEON_CP_VC_FRMT_ST0 0x00000080 +#define RADEON_CP_VC_FRMT_ST1 0x00000100 +#define RADEON_CP_VC_FRMT_Q1 0x00000200 +#define RADEON_CP_VC_FRMT_ST2 0x00000400 +#define RADEON_CP_VC_FRMT_Q2 0x00000800 +#define RADEON_CP_VC_FRMT_ST3 0x00001000 +#define RADEON_CP_VC_FRMT_Q3 0x00002000 +#define RADEON_CP_VC_FRMT_Q0 0x00004000 +#define RADEON_CP_VC_FRMT_BLND_WEIGHT_CNT_MASK 0x00038000 +#define RADEON_CP_VC_FRMT_N0 0x00040000 +#define RADEON_CP_VC_FRMT_XY1 0x08000000 +#define RADEON_CP_VC_FRMT_Z1 0x10000000 +#define RADEON_CP_VC_FRMT_W1 0x20000000 +#define RADEON_CP_VC_FRMT_N1 0x40000000 +#define RADEON_CP_VC_FRMT_Z 0x80000000 + +#define RADEON_CP_VC_CNTL_PRIM_TYPE_NONE 0x00000000 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_POINT 0x00000001 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE 0x00000002 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP 0x00000003 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_TYPE_2 0x00000007 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST 0x00000008 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_POINT_LIST 0x00000009 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST 0x0000000a +#define RADEON_CP_VC_CNTL_PRIM_WALK_IND 0x00000010 +#define RADEON_CP_VC_CNTL_PRIM_WALK_LIST 0x00000020 +#define RADEON_CP_VC_CNTL_PRIM_WALK_RING 0x00000030 +#define RADEON_CP_VC_CNTL_COLOR_ORDER_BGRA 0x00000000 +#define RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA 0x00000040 +#define RADEON_CP_VC_CNTL_MAOS_ENABLE 0x00000080 +#define RADEON_CP_VC_CNTL_VTX_FMT_NON_RADEON_MODE 0x00000000 +#define RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE 0x00000100 +#define RADEON_CP_VC_CNTL_TCL_DISABLE 0x00000000 +#define RADEON_CP_VC_CNTL_TCL_ENABLE 0x00000200 +#define RADEON_CP_VC_CNTL_NUM_SHIFT 16 + +#define RADEON_VS_MATRIX_0_ADDR 0 +#define RADEON_VS_MATRIX_1_ADDR 4 +#define RADEON_VS_MATRIX_2_ADDR 8 +#define RADEON_VS_MATRIX_3_ADDR 12 +#define RADEON_VS_MATRIX_4_ADDR 16 +#define RADEON_VS_MATRIX_5_ADDR 20 +#define RADEON_VS_MATRIX_6_ADDR 24 +#define RADEON_VS_MATRIX_7_ADDR 28 +#define RADEON_VS_MATRIX_8_ADDR 32 +#define RADEON_VS_MATRIX_9_ADDR 36 +#define RADEON_VS_MATRIX_10_ADDR 40 +#define RADEON_VS_MATRIX_11_ADDR 44 +#define RADEON_VS_MATRIX_12_ADDR 48 +#define RADEON_VS_MATRIX_13_ADDR 52 +#define RADEON_VS_MATRIX_14_ADDR 56 +#define RADEON_VS_MATRIX_15_ADDR 60 +#define RADEON_VS_LIGHT_AMBIENT_ADDR 64 +#define RADEON_VS_LIGHT_DIFFUSE_ADDR 72 +#define RADEON_VS_LIGHT_SPECULAR_ADDR 80 +#define RADEON_VS_LIGHT_DIRPOS_ADDR 88 +#define RADEON_VS_LIGHT_HWVSPOT_ADDR 96 +#define RADEON_VS_LIGHT_ATTENUATION_ADDR 104 +#define RADEON_VS_MATRIX_EYE2CLIP_ADDR 112 +#define RADEON_VS_UCP_ADDR 116 +#define RADEON_VS_GLOBAL_AMBIENT_ADDR 122 +#define RADEON_VS_FOG_PARAM_ADDR 123 +#define RADEON_VS_EYE_VECTOR_ADDR 124 + +#define RADEON_SS_LIGHT_DCD_ADDR 0 +#define RADEON_SS_LIGHT_SPOT_EXPONENT_ADDR 8 +#define RADEON_SS_LIGHT_SPOT_CUTOFF_ADDR 16 +#define RADEON_SS_LIGHT_SPECULAR_THRESH_ADDR 24 +#define RADEON_SS_LIGHT_RANGE_CUTOFF_ADDR 32 +#define RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR 48 +#define RADEON_SS_VERT_GUARD_DISCARD_ADJ_ADDR 49 +#define RADEON_SS_HORZ_GUARD_CLIP_ADJ_ADDR 50 +#define RADEON_SS_HORZ_GUARD_DISCARD_ADJ_ADDR 51 +#define RADEON_SS_SHININESS 60 + +#define RADEON_TV_MASTER_CNTL 0x0800 +# define RADEON_TV_ASYNC_RST (1 << 0) +# define RADEON_CRT_ASYNC_RST (1 << 1) +# define RADEON_RESTART_PHASE_FIX (1 << 3) +# define RADEON_TV_FIFO_ASYNC_RST (1 << 4) +# define RADEON_VIN_ASYNC_RST (1 << 5) +# define RADEON_AUD_ASYNC_RST (1 << 6) +# define RADEON_DVS_ASYNC_RST (1 << 7) +# define RADEON_CRT_FIFO_CE_EN (1 << 9) +# define RADEON_TV_FIFO_CE_EN (1 << 10) +# define RADEON_RE_SYNC_NOW_SEL_MASK (3 << 14) +# define RADEON_TVCLK_ALWAYS_ONb (1 << 30) +# define RADEON_TV_ON (1 << 31) +#define RADEON_TV_PRE_DAC_MUX_CNTL 0x0888 +# define RADEON_Y_RED_EN (1 << 0) +# define RADEON_C_GRN_EN (1 << 1) +# define RADEON_CMP_BLU_EN (1 << 2) +# define RADEON_DAC_DITHER_EN (1 << 3) +# define RADEON_RED_MX_FORCE_DAC_DATA (6 << 4) +# define RADEON_GRN_MX_FORCE_DAC_DATA (6 << 8) +# define RADEON_BLU_MX_FORCE_DAC_DATA (6 << 12) +# define RADEON_TV_FORCE_DAC_DATA_SHIFT 16 +#define RADEON_TV_RGB_CNTL 0x0804 +# define RADEON_SWITCH_TO_BLUE (1 << 4) +# define RADEON_RGB_DITHER_EN (1 << 5) +# define RADEON_RGB_SRC_SEL_MASK (3 << 8) +# define RADEON_RGB_SRC_SEL_CRTC1 (0 << 8) +# define RADEON_RGB_SRC_SEL_RMX (1 << 8) +# define RADEON_RGB_SRC_SEL_CRTC2 (2 << 8) +# define RADEON_RGB_CONVERT_BY_PASS (1 << 10) +# define RADEON_UVRAM_READ_MARGIN_SHIFT 16 +# define RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT 20 +# define RADEON_TVOUT_SCALE_EN (1 << 26) +#define RADEON_TV_SYNC_CNTL 0x0808 +# define RADEON_SYNC_OE (1 << 0) +# define RADEON_SYNC_OUT (1 << 1) +# define RADEON_SYNC_IN (1 << 2) +# define RADEON_SYNC_PUB (1 << 3) +# define RADEON_SYNC_PD (1 << 4) +# define RADEON_TV_SYNC_IO_DRIVE (1 << 5) +#define RADEON_TV_HTOTAL 0x080c +#define RADEON_TV_HDISP 0x0810 +#define RADEON_TV_HSTART 0x0818 +#define RADEON_TV_HCOUNT 0x081C +#define RADEON_TV_VTOTAL 0x0820 +#define RADEON_TV_VDISP 0x0824 +#define RADEON_TV_VCOUNT 0x0828 +#define RADEON_TV_FTOTAL 0x082c +#define RADEON_TV_FCOUNT 0x0830 +#define RADEON_TV_FRESTART 0x0834 +#define RADEON_TV_HRESTART 0x0838 +#define RADEON_TV_VRESTART 0x083c +#define RADEON_TV_HOST_READ_DATA 0x0840 +#define RADEON_TV_HOST_WRITE_DATA 0x0844 +#define RADEON_TV_HOST_RD_WT_CNTL 0x0848 +# define RADEON_HOST_FIFO_RD (1 << 12) +# define RADEON_HOST_FIFO_RD_ACK (1 << 13) +# define RADEON_HOST_FIFO_WT (1 << 14) +# define RADEON_HOST_FIFO_WT_ACK (1 << 15) +#define RADEON_TV_VSCALER_CNTL1 0x084c +# define RADEON_UV_INC_MASK 0xffff +# define RADEON_UV_INC_SHIFT 0 +# define RADEON_Y_W_EN (1 << 24) +# define RADEON_RESTART_FIELD (1 << 29) /* restart on field 0 */ +# define RADEON_Y_DEL_W_SIG_SHIFT 26 +#define RADEON_TV_TIMING_CNTL 0x0850 +# define RADEON_H_INC_MASK 0xfff +# define RADEON_H_INC_SHIFT 0 +# define RADEON_REQ_Y_FIRST (1 << 19) +# define RADEON_FORCE_BURST_ALWAYS (1 << 21) +# define RADEON_UV_POST_SCALE_BYPASS (1 << 23) +# define RADEON_UV_OUTPUT_POST_SCALE_SHIFT 24 +#define RADEON_TV_VSCALER_CNTL2 0x0854 +# define RADEON_DITHER_MODE (1 << 0) +# define RADEON_Y_OUTPUT_DITHER_EN (1 << 1) +# define RADEON_UV_OUTPUT_DITHER_EN (1 << 2) +# define RADEON_UV_TO_BUF_DITHER_EN (1 << 3) +#define RADEON_TV_Y_FALL_CNTL 0x0858 +# define RADEON_Y_FALL_PING_PONG (1 << 16) +# define RADEON_Y_COEF_EN (1 << 17) +#define RADEON_TV_Y_RISE_CNTL 0x085c +# define RADEON_Y_RISE_PING_PONG (1 << 16) +#define RADEON_TV_Y_SAW_TOOTH_CNTL 0x0860 +#define RADEON_TV_UPSAMP_AND_GAIN_CNTL 0x0864 +# define RADEON_YUPSAMP_EN (1 << 0) +# define RADEON_UVUPSAMP_EN (1 << 2) +#define RADEON_TV_GAIN_LIMIT_SETTINGS 0x0868 +# define RADEON_Y_GAIN_LIMIT_SHIFT 0 +# define RADEON_UV_GAIN_LIMIT_SHIFT 16 +#define RADEON_TV_LINEAR_GAIN_SETTINGS 0x086c +# define RADEON_Y_GAIN_SHIFT 0 +# define RADEON_UV_GAIN_SHIFT 16 +#define RADEON_TV_MODULATOR_CNTL1 0x0870 +# define RADEON_YFLT_EN (1 << 2) +# define RADEON_UVFLT_EN (1 << 3) +# define RADEON_ALT_PHASE_EN (1 << 6) +# define RADEON_SYNC_TIP_LEVEL (1 << 7) +# define RADEON_BLANK_LEVEL_SHIFT 8 +# define RADEON_SET_UP_LEVEL_SHIFT 16 +# define RADEON_SLEW_RATE_LIMIT (1 << 23) +# define RADEON_CY_FILT_BLEND_SHIFT 28 +#define RADEON_TV_MODULATOR_CNTL2 0x0874 +# define RADEON_TV_U_BURST_LEVEL_MASK 0x1ff +# define RADEON_TV_V_BURST_LEVEL_MASK 0x1ff +# define RADEON_TV_V_BURST_LEVEL_SHIFT 16 +#define RADEON_TV_CRC_CNTL 0x0890 +#define RADEON_TV_UV_ADR 0x08ac +# define RADEON_MAX_UV_ADR_MASK 0x000000ff +# define RADEON_MAX_UV_ADR_SHIFT 0 +# define RADEON_TABLE1_BOT_ADR_MASK 0x0000ff00 +# define RADEON_TABLE1_BOT_ADR_SHIFT 8 +# define RADEON_TABLE3_TOP_ADR_MASK 0x00ff0000 +# define RADEON_TABLE3_TOP_ADR_SHIFT 16 +# define RADEON_HCODE_TABLE_SEL_MASK 0x06000000 +# define RADEON_HCODE_TABLE_SEL_SHIFT 25 +# define RADEON_VCODE_TABLE_SEL_MASK 0x18000000 +# define RADEON_VCODE_TABLE_SEL_SHIFT 27 +# define RADEON_TV_MAX_FIFO_ADDR 0x1a7 +# define RADEON_TV_MAX_FIFO_ADDR_INTERNAL 0x1ff +#define RADEON_TV_PLL_FINE_CNTL 0x0020 /* PLL */ +#define RADEON_TV_PLL_CNTL 0x0021 /* PLL */ +# define RADEON_TV_M0LO_MASK 0xff +# define RADEON_TV_M0HI_MASK 0x7 +# define RADEON_TV_M0HI_SHIFT 18 +# define RADEON_TV_N0LO_MASK 0x1ff +# define RADEON_TV_N0LO_SHIFT 8 +# define RADEON_TV_N0HI_MASK 0x3 +# define RADEON_TV_N0HI_SHIFT 21 +# define RADEON_TV_P_MASK 0xf +# define RADEON_TV_P_SHIFT 24 +# define RADEON_TV_SLIP_EN (1 << 23) +# define RADEON_TV_DTO_EN (1 << 28) +#define RADEON_TV_PLL_CNTL1 0x0022 /* PLL */ +# define RADEON_TVPLL_RESET (1 << 1) +# define RADEON_TVPLL_SLEEP (1 << 3) +# define RADEON_TVPLL_REFCLK_SEL (1 << 4) +# define RADEON_TVPCP_SHIFT 8 +# define RADEON_TVPCP_MASK (7 << 8) +# define RADEON_TVPVG_SHIFT 11 +# define RADEON_TVPVG_MASK (7 << 11) +# define RADEON_TVPDC_SHIFT 14 +# define RADEON_TVPDC_MASK (3 << 14) +# define RADEON_TVPLL_TEST_DIS (1 << 31) +# define RADEON_TVCLK_SRC_SEL_TVPLL (1 << 30) + +#define RS400_DISP2_REQ_CNTL1 0xe30 +# define RS400_DISP2_START_REQ_LEVEL_SHIFT 0 +# define RS400_DISP2_START_REQ_LEVEL_MASK 0x3ff +# define RS400_DISP2_STOP_REQ_LEVEL_SHIFT 12 +# define RS400_DISP2_STOP_REQ_LEVEL_MASK 0x3ff +# define RS400_DISP2_ALLOW_FID_LEVEL_SHIFT 22 +# define RS400_DISP2_ALLOW_FID_LEVEL_MASK 0x3ff +#define RS400_DISP2_REQ_CNTL2 0xe34 +# define RS400_DISP2_CRITICAL_POINT_START_SHIFT 12 +# define RS400_DISP2_CRITICAL_POINT_START_MASK 0x3ff +# define RS400_DISP2_CRITICAL_POINT_STOP_SHIFT 22 +# define RS400_DISP2_CRITICAL_POINT_STOP_MASK 0x3ff +#define RS400_DMIF_MEM_CNTL1 0xe38 +# define RS400_DISP2_START_ADR_SHIFT 0 +# define RS400_DISP2_START_ADR_MASK 0x3ff +# define RS400_DISP1_CRITICAL_POINT_START_SHIFT 12 +# define RS400_DISP1_CRITICAL_POINT_START_MASK 0x3ff +# define RS400_DISP1_CRITICAL_POINT_STOP_SHIFT 22 +# define RS400_DISP1_CRITICAL_POINT_STOP_MASK 0x3ff +#define RS400_DISP1_REQ_CNTL1 0xe3c +# define RS400_DISP1_START_REQ_LEVEL_SHIFT 0 +# define RS400_DISP1_START_REQ_LEVEL_MASK 0x3ff +# define RS400_DISP1_STOP_REQ_LEVEL_SHIFT 12 +# define RS400_DISP1_STOP_REQ_LEVEL_MASK 0x3ff +# define RS400_DISP1_ALLOW_FID_LEVEL_SHIFT 22 +# define RS400_DISP1_ALLOW_FID_LEVEL_MASK 0x3ff + +#define RS690_MC_INDEX 0x78 +# define RS690_MC_INDEX_MASK 0x1ff +# define RS690_MC_INDEX_WR_EN (1 << 9) +# define RS690_MC_INDEX_WR_ACK 0x7f +#define RS690_MC_DATA 0x7c + +#define RS690_MC_FB_LOCATION 0x100 +#define RS690_MC_AGP_LOCATION 0x101 +#define RS690_MC_AGP_BASE 0x102 +#define RS690_MC_AGP_BASE_2 0x103 +#define RS690_MC_STATUS 0x90 +#define RS690_MC_STATUS_IDLE (1 << 0) + +#define RS600_MC_INDEX 0x78 +# define RS600_MC_INDEX_MASK 0xff +# define RS600_MC_INDEX_WR_EN (1 << 8) +# define RS600_MC_INDEX_WR_ACK 0xff +#define RS600_MC_DATA 0x7c + +#define RS600_MC_FB_LOCATION 0xA +#define RS600_MC_STATUS 0x0 +#define RS600_MC_STATUS_IDLE (1 << 0) + +#define AVIVO_MC_INDEX 0x0070 +#define R520_MC_STATUS 0x00 +#define R520_MC_STATUS_IDLE (1<<1) +#define RV515_MC_STATUS 0x08 +#define RV515_MC_STATUS_IDLE (1<<4) +#define AVIVO_MC_DATA 0x0074 + +#define RV515_MC_FB_LOCATION 0x1 +#define RV515_MC_AGP_LOCATION 0x2 +#define RV515_MC_AGP_BASE 0x3 +#define RV515_MC_AGP_BASE_2 0x4 +#define RV515_MC_CNTL 0x5 +# define RV515_MEM_NUM_CHANNELS_MASK 0x3 +#define R520_MC_FB_LOCATION 0x4 +#define R520_MC_AGP_LOCATION 0x5 +#define R520_MC_AGP_BASE 0x6 +#define R520_MC_AGP_BASE_2 0x7 +#define R520_MC_CNTL0 0x8 +# define R520_MEM_NUM_CHANNELS_MASK (0x3 << 24) +# define R520_MEM_NUM_CHANNELS_SHIFT 24 +# define R520_MC_CHANNEL_SIZE (1 << 23) + +#define R600_RAMCFG 0x2408 +# define R600_CHANSIZE (1 << 7) +# define R600_CHANSIZE_OVERRIDE (1 << 10) + +#define AVIVO_HDP_FB_LOCATION 0x134 + +#define AVIVO_VGA_RENDER_CONTROL 0x0300 +# define AVIVO_VGA_VSTATUS_CNTL_MASK (3 << 16) +#define AVIVO_D1VGA_CONTROL 0x0330 +# define AVIVO_DVGA_CONTROL_MODE_ENABLE (1<<0) +# define AVIVO_DVGA_CONTROL_TIMING_SELECT (1<<8) +# define AVIVO_DVGA_CONTROL_SYNC_POLARITY_SELECT (1<<9) +# define AVIVO_DVGA_CONTROL_OVERSCAN_TIMING_SELECT (1<<10) +# define AVIVO_DVGA_CONTROL_OVERSCAN_COLOR_EN (1<<16) +# define AVIVO_DVGA_CONTROL_ROTATE (1<<24) +#define AVIVO_D2VGA_CONTROL 0x0338 + +#define AVIVO_EXT1_PPLL_REF_DIV_SRC 0x400 +#define AVIVO_EXT1_PPLL_REF_DIV 0x404 +#define AVIVO_EXT1_PPLL_UPDATE_LOCK 0x408 +#define AVIVO_EXT1_PPLL_UPDATE_CNTL 0x40c + +#define AVIVO_EXT2_PPLL_REF_DIV_SRC 0x410 +#define AVIVO_EXT2_PPLL_REF_DIV 0x414 +#define AVIVO_EXT2_PPLL_UPDATE_LOCK 0x418 +#define AVIVO_EXT2_PPLL_UPDATE_CNTL 0x41c + +#define AVIVO_EXT1_PPLL_FB_DIV 0x430 +#define AVIVO_EXT2_PPLL_FB_DIV 0x434 + +#define AVIVO_EXT1_PPLL_POST_DIV_SRC 0x438 +#define AVIVO_EXT1_PPLL_POST_DIV 0x43c + +#define AVIVO_EXT2_PPLL_POST_DIV_SRC 0x440 +#define AVIVO_EXT2_PPLL_POST_DIV 0x444 + +#define AVIVO_EXT1_PPLL_CNTL 0x448 +#define AVIVO_EXT2_PPLL_CNTL 0x44c + +#define AVIVO_P1PLL_CNTL 0x450 +#define AVIVO_P2PLL_CNTL 0x454 +#define AVIVO_P1PLL_INT_SS_CNTL 0x458 +#define AVIVO_P2PLL_INT_SS_CNTL 0x45c +#define AVIVO_P1PLL_TMDSA_CNTL 0x460 +#define AVIVO_P2PLL_LVTMA_CNTL 0x464 + +#define AVIVO_PCLK_CRTC1_CNTL 0x480 +#define AVIVO_PCLK_CRTC2_CNTL 0x484 + +#define AVIVO_D1CRTC_H_TOTAL 0x6000 +#define AVIVO_D1CRTC_H_BLANK_START_END 0x6004 +#define AVIVO_D1CRTC_H_SYNC_A 0x6008 +#define AVIVO_D1CRTC_H_SYNC_A_CNTL 0x600c +#define AVIVO_D1CRTC_H_SYNC_B 0x6010 +#define AVIVO_D1CRTC_H_SYNC_B_CNTL 0x6014 + +#define AVIVO_D1CRTC_V_TOTAL 0x6020 +#define AVIVO_D1CRTC_V_BLANK_START_END 0x6024 +#define AVIVO_D1CRTC_V_SYNC_A 0x6028 +#define AVIVO_D1CRTC_V_SYNC_A_CNTL 0x602c +#define AVIVO_D1CRTC_V_SYNC_B 0x6030 +#define AVIVO_D1CRTC_V_SYNC_B_CNTL 0x6034 + +#define AVIVO_D1CRTC_CONTROL 0x6080 +# define AVIVO_CRTC_EN (1<<0) +#define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 +#define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 +#define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c +#define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 + +/* master controls */ +#define AVIVO_DC_CRTC_MASTER_EN 0x60f8 +#define AVIVO_DC_CRTC_TV_CONTROL 0x60fc + +#define AVIVO_D1GRPH_ENABLE 0x6100 +#define AVIVO_D1GRPH_CONTROL 0x6104 +# define AVIVO_D1GRPH_CONTROL_DEPTH_8BPP (0<<0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_16BPP (1<<0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_32BPP (2<<0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_64BPP (3<<0) + +# define AVIVO_D1GRPH_CONTROL_8BPP_INDEXED (0<<8) + +# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555 (0<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_RGB565 (1<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444 (2<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_AI88 (3<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_MONO16 (4<<8) + +# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888 (0<<8) +# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010 (1<<8) +# define AVIVO_D1GRPH_CONTROL_32BPP_DIGITAL (2<<8) +# define AVIVO_D1GRPH_CONTROL_32BPP_8B_ARGB2101010 (3<<8) + + +# define AVIVO_D1GRPH_CONTROL_64BPP_ARGB16161616 (0<<8) + +# define AVIVO_D1GRPH_SWAP_RB (1<<16) +# define AVIVO_D1GRPH_TILED (1<<20) +# define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1<<21) + +#define AVIVO_D1GRPH_LUT_SEL 0x6108 +#define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 +#define AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 +#define AVIVO_D1GRPH_PITCH 0x6120 +#define AVIVO_D1GRPH_SURFACE_OFFSET_X 0x6124 +#define AVIVO_D1GRPH_SURFACE_OFFSET_Y 0x6128 +#define AVIVO_D1GRPH_X_START 0x612c +#define AVIVO_D1GRPH_Y_START 0x6130 +#define AVIVO_D1GRPH_X_END 0x6134 +#define AVIVO_D1GRPH_Y_END 0x6138 +#define AVIVO_D1GRPH_UPDATE 0x6144 +# define AVIVO_D1GRPH_UPDATE_LOCK (1<<16) +#define AVIVO_D1GRPH_FLIP_CONTROL 0x6148 + +#define AVIVO_D1CUR_CONTROL 0x6400 +# define AVIVO_D1CURSOR_EN (1<<0) +# define AVIVO_D1CURSOR_MODE_SHIFT 8 +# define AVIVO_D1CURSOR_MODE_MASK (0x3<<8) +# define AVIVO_D1CURSOR_MODE_24BPP (0x2) +#define AVIVO_D1CUR_SURFACE_ADDRESS 0x6408 +#define AVIVO_D1CUR_SIZE 0x6410 +#define AVIVO_D1CUR_POSITION 0x6414 +#define AVIVO_D1CUR_HOT_SPOT 0x6418 +#define AVIVO_D1CUR_UPDATE 0x6424 +# define AVIVO_D1CURSOR_UPDATE_LOCK (1 << 16) + +#define AVIVO_DC_LUT_RW_SELECT 0x6480 +#define AVIVO_DC_LUT_RW_MODE 0x6484 +#define AVIVO_DC_LUT_RW_INDEX 0x6488 +#define AVIVO_DC_LUT_SEQ_COLOR 0x648c +#define AVIVO_DC_LUT_PWL_DATA 0x6490 +#define AVIVO_DC_LUT_30_COLOR 0x6494 +#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 +#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c +#define AVIVO_DC_LUT_AUTOFILL 0x64a0 + +#define AVIVO_DC_LUTA_CONTROL 0x64c0 +#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 +#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 +#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc +#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 +#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 +#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 + + +#define AVIVO_D1MODE_DESKTOP_HEIGHT 0x652C +#define AVIVO_D1MODE_VIEWPORT_START 0x6580 +#define AVIVO_D1MODE_VIEWPORT_SIZE 0x6584 +#define AVIVO_D1MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6588 +#define AVIVO_D1MODE_EXT_OVERSCAN_TOP_BOTTOM 0x658c + +#define AVIVO_D1SCL_SCALER_ENABLE 0x6590 +#define AVIVO_D1SCL_SCALER_TAP_CONTROL 0x6594 +#define AVIVO_D1SCL_UPDATE 0x65cc +# define AVIVO_D1SCL_UPDATE_LOCK (1<<16) + +/* second crtc */ +#define AVIVO_D2CRTC_H_TOTAL 0x6800 +#define AVIVO_D2CRTC_H_BLANK_START_END 0x6804 +#define AVIVO_D2CRTC_H_SYNC_A 0x6808 +#define AVIVO_D2CRTC_H_SYNC_A_CNTL 0x680c +#define AVIVO_D2CRTC_H_SYNC_B 0x6810 +#define AVIVO_D2CRTC_H_SYNC_B_CNTL 0x6814 + +#define AVIVO_D2CRTC_V_TOTAL 0x6820 +#define AVIVO_D2CRTC_V_BLANK_START_END 0x6824 +#define AVIVO_D2CRTC_V_SYNC_A 0x6828 +#define AVIVO_D2CRTC_V_SYNC_A_CNTL 0x682c +#define AVIVO_D2CRTC_V_SYNC_B 0x6830 +#define AVIVO_D2CRTC_V_SYNC_B_CNTL 0x6834 + +#define AVIVO_D2CRTC_CONTROL 0x6880 +#define AVIVO_D2CRTC_BLANK_CONTROL 0x6884 +#define AVIVO_D2CRTC_INTERLACE_CONTROL 0x6888 +#define AVIVO_D2CRTC_INTERLACE_STATUS 0x688c +#define AVIVO_D2CRTC_STEREO_CONTROL 0x68c4 + +#define AVIVO_D2GRPH_ENABLE 0x6900 +#define AVIVO_D2GRPH_CONTROL 0x6904 +#define AVIVO_D2GRPH_LUT_SEL 0x6908 +#define AVIVO_D2GRPH_PRIMARY_SURFACE_ADDRESS 0x6910 +#define AVIVO_D2GRPH_SECONDARY_SURFACE_ADDRESS 0x6918 +#define AVIVO_D2GRPH_PITCH 0x6920 +#define AVIVO_D2GRPH_SURFACE_OFFSET_X 0x6924 +#define AVIVO_D2GRPH_SURFACE_OFFSET_Y 0x6928 +#define AVIVO_D2GRPH_X_START 0x692c +#define AVIVO_D2GRPH_Y_START 0x6930 +#define AVIVO_D2GRPH_X_END 0x6934 +#define AVIVO_D2GRPH_Y_END 0x6938 +#define AVIVO_D2GRPH_UPDATE 0x6944 +#define AVIVO_D2GRPH_FLIP_CONTROL 0x6948 + +#define AVIVO_D2CUR_CONTROL 0x6c00 +#define AVIVO_D2CUR_SURFACE_ADDRESS 0x6c08 +#define AVIVO_D2CUR_SIZE 0x6c10 +#define AVIVO_D2CUR_POSITION 0x6c14 + +#define AVIVO_D2MODE_VIEWPORT_START 0x6d80 +#define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84 +#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88 +#define AVIVO_D2MODE_EXT_OVERSCAN_TOP_BOTTOM 0x6d8c + +#define AVIVO_D2SCL_SCALER_ENABLE 0x6d90 +#define AVIVO_D2SCL_SCALER_TAP_CONTROL 0x6d94 + +#define AVIVO_DDIA_BIT_DEPTH_CONTROL 0x7214 + +#define AVIVO_DACA_ENABLE 0x7800 +# define AVIVO_DAC_ENABLE (1 << 0) +#define AVIVO_DACA_SOURCE_SELECT 0x7804 +# define AVIVO_DAC_SOURCE_CRTC1 (0 << 0) +# define AVIVO_DAC_SOURCE_CRTC2 (1 << 0) +# define AVIVO_DAC_SOURCE_TV (2 << 0) + +#define AVIVO_DACA_FORCE_OUTPUT_CNTL 0x783c +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_FORCE_DATA_EN (1 << 0) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_SHIFT (8) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_BLUE (1 << 0) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_GREEN (1 << 1) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_RED (1 << 2) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_ON_BLANKB_ONLY (1 << 24) +#define AVIVO_DACA_POWERDOWN 0x7850 +# define AVIVO_DACA_POWERDOWN_POWERDOWN (1 << 0) +# define AVIVO_DACA_POWERDOWN_BLUE (1 << 8) +# define AVIVO_DACA_POWERDOWN_GREEN (1 << 16) +# define AVIVO_DACA_POWERDOWN_RED (1 << 24) + +#define AVIVO_DACB_ENABLE 0x7a00 +#define AVIVO_DACB_SOURCE_SELECT 0x7a04 +#define AVIVO_DACB_FORCE_OUTPUT_CNTL 0x7a3c +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_FORCE_DATA_EN (1 << 0) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_SHIFT (8) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_BLUE (1 << 0) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_GREEN (1 << 1) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_RED (1 << 2) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_ON_BLANKB_ONLY (1 << 24) +#define AVIVO_DACB_POWERDOWN 0x7a50 +# define AVIVO_DACB_POWERDOWN_POWERDOWN (1 << 0) +# define AVIVO_DACB_POWERDOWN_BLUE (1 << 8) +# define AVIVO_DACB_POWERDOWN_GREEN (1 << 16) +# define AVIVO_DACB_POWERDOWN_RED + +#define AVIVO_TMDSA_CNTL 0x7880 +# define AVIVO_TMDSA_CNTL_ENABLE (1 << 0) +# define AVIVO_TMDSA_CNTL_HPD_MASK (1 << 4) +# define AVIVO_TMDSA_CNTL_HPD_SELECT (1 << 8) +# define AVIVO_TMDSA_CNTL_SYNC_PHASE (1 << 12) +# define AVIVO_TMDSA_CNTL_PIXEL_ENCODING (1 << 16) +# define AVIVO_TMDSA_CNTL_DUAL_LINK_ENABLE (1 << 24) +# define AVIVO_TMDSA_CNTL_SWAP (1 << 28) +#define AVIVO_TMDSA_SOURCE_SELECT 0x7884 +/* 78a8 appears to be some kind of (reasonably tolerant) clock? + * 78d0 definitely hits the transmitter, definitely clock. */ +/* MYSTERY1 This appears to control dithering? */ +#define AVIVO_TMDSA_BIT_DEPTH_CONTROL 0x7894 +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN (1 << 0) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH (1 << 4) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN (1 << 8) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH (1 << 12) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_EN (1 << 16) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_DEPTH (1 << 20) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_LEVEL (1 << 24) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_RESET (1 << 26) +#define AVIVO_TMDSA_DCBALANCER_CONTROL 0x78d0 +# define AVIVO_TMDSA_DCBALANCER_CONTROL_EN (1 << 0) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_TEST_EN (1 << 8) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_TEST_IN_SHIFT (16) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_FORCE (1 << 24) +#define AVIVO_TMDSA_DATA_SYNCHRONIZATION 0x78d8 +# define AVIVO_TMDSA_DATA_SYNCHRONIZATION_DSYNSEL (1 << 0) +# define AVIVO_TMDSA_DATA_SYNCHRONIZATION_PFREQCHG (1 << 8) +#define AVIVO_TMDSA_CLOCK_ENABLE 0x7900 +#define AVIVO_TMDSA_TRANSMITTER_ENABLE 0x7904 +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX0_ENABLE (1 << 0) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKC0EN (1 << 1) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD00EN (1 << 2) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD01EN (1 << 3) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD02EN (1 << 4) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX1_ENABLE (1 << 8) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD10EN (1 << 10) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD11EN (1 << 11) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD12EN (1 << 12) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX_ENABLE_HPD_MASK (1 << 16) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKCEN_HPD_MASK (1 << 17) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKDEN_HPD_MASK (1 << 18) + +#define AVIVO_TMDSA_TRANSMITTER_CONTROL 0x7910 +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_ENABLE (1 << 0) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_RESET (1 << 1) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_HPD_MASK_SHIFT (2) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_IDSCKSEL (1 << 4) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_BGSLEEP (1 << 5) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_PWRUP_SEQ_EN (1 << 6) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TMCLK (1 << 8) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TMCLK_FROM_PADS (1 << 13) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TDCLK (1 << 14) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TDCLK_FROM_PADS (1 << 15) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_CLK_PATTERN_SHIFT (16) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_BYPASS_PLL (1 << 28) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_USE_CLK_DATA (1 << 29) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_INPUT_TEST_CLK_SEL (1 << 31) + +#define AVIVO_LVTMA_CNTL 0x7a80 +# define AVIVO_LVTMA_CNTL_ENABLE (1 << 0) +# define AVIVO_LVTMA_CNTL_HPD_MASK (1 << 4) +# define AVIVO_LVTMA_CNTL_HPD_SELECT (1 << 8) +# define AVIVO_LVTMA_CNTL_SYNC_PHASE (1 << 12) +# define AVIVO_LVTMA_CNTL_PIXEL_ENCODING (1 << 16) +# define AVIVO_LVTMA_CNTL_DUAL_LINK_ENABLE (1 << 24) +# define AVIVO_LVTMA_CNTL_SWAP (1 << 28) +#define AVIVO_LVTMA_SOURCE_SELECT 0x7a84 +#define AVIVO_LVTMA_COLOR_FORMAT 0x7a88 +#define AVIVO_LVTMA_BIT_DEPTH_CONTROL 0x7a94 +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN (1 << 0) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH (1 << 4) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN (1 << 8) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH (1 << 12) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_EN (1 << 16) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_DEPTH (1 << 20) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_LEVEL (1 << 24) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_RESET (1 << 26) + + + +#define AVIVO_LVTMA_DCBALANCER_CONTROL 0x7ad0 +# define AVIVO_LVTMA_DCBALANCER_CONTROL_EN (1 << 0) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_TEST_EN (1 << 8) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_TEST_IN_SHIFT (16) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_FORCE (1 << 24) + +#define AVIVO_LVTMA_DATA_SYNCHRONIZATION 0x78d8 +# define AVIVO_LVTMA_DATA_SYNCHRONIZATION_DSYNSEL (1 << 0) +# define AVIVO_LVTMA_DATA_SYNCHRONIZATION_PFREQCHG (1 << 8) +#define R500_LVTMA_CLOCK_ENABLE 0x7b00 +#define R600_LVTMA_CLOCK_ENABLE 0x7b04 + +#define R500_LVTMA_TRANSMITTER_ENABLE 0x7b04 +#define R600_LVTMA_TRANSMITTER_ENABLE 0x7b08 +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKC0EN (1 << 1) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD00EN (1 << 2) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD01EN (1 << 3) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD02EN (1 << 4) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD03EN (1 << 5) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKC1EN (1 << 9) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD10EN (1 << 10) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD11EN (1 << 11) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD12EN (1 << 12) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKCEN_HPD_MASK (1 << 17) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKDEN_HPD_MASK (1 << 18) + +#define R500_LVTMA_TRANSMITTER_CONTROL 0x7b10 +#define R600_LVTMA_TRANSMITTER_CONTROL 0x7b14 +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_ENABLE (1 << 0) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_RESET (1 << 1) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_HPD_MASK_SHIFT (2) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_IDSCKSEL (1 << 4) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_BGSLEEP (1 << 5) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_PWRUP_SEQ_EN (1 << 6) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TMCLK (1 << 8) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TMCLK_FROM_PADS (1 << 13) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TDCLK (1 << 14) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TDCLK_FROM_PADS (1 << 15) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_CLK_PATTERN_SHIFT (16) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_BYPASS_PLL (1 << 28) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_USE_CLK_DATA (1 << 29) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_INPUT_TEST_CLK_SEL (1 << 31) + +#define R500_LVTMA_PWRSEQ_CNTL 0x7af0 +#define R600_LVTMA_PWRSEQ_CNTL 0x7af4 +# define AVIVO_LVTMA_PWRSEQ_EN (1 << 0) +# define AVIVO_LVTMA_PWRSEQ_PLL_ENABLE_MASK (1 << 2) +# define AVIVO_LVTMA_PWRSEQ_PLL_RESET_MASK (1 << 3) +# define AVIVO_LVTMA_PWRSEQ_TARGET_STATE (1 << 4) +# define AVIVO_LVTMA_SYNCEN (1 << 8) +# define AVIVO_LVTMA_SYNCEN_OVRD (1 << 9) +# define AVIVO_LVTMA_SYNCEN_POL (1 << 10) +# define AVIVO_LVTMA_DIGON (1 << 16) +# define AVIVO_LVTMA_DIGON_OVRD (1 << 17) +# define AVIVO_LVTMA_DIGON_POL (1 << 18) +# define AVIVO_LVTMA_BLON (1 << 24) +# define AVIVO_LVTMA_BLON_OVRD (1 << 25) +# define AVIVO_LVTMA_BLON_POL (1 << 26) + +#define R500_LVTMA_PWRSEQ_STATE 0x7af4 +#define R600_LVTMA_PWRSEQ_STATE 0x7af8 +# define AVIVO_LVTMA_PWRSEQ_STATE_TARGET_STATE_R (1 << 0) +# define AVIVO_LVTMA_PWRSEQ_STATE_DIGON (1 << 1) +# define AVIVO_LVTMA_PWRSEQ_STATE_SYNCEN (1 << 2) +# define AVIVO_LVTMA_PWRSEQ_STATE_BLON (1 << 3) +# define AVIVO_LVTMA_PWRSEQ_STATE_DONE (1 << 4) +# define AVIVO_LVTMA_PWRSEQ_STATE_STATUS_SHIFT (8) + +#define AVIVO_LVDS_BACKLIGHT_CNTL 0x7af8 +# define AVIVO_LVDS_BACKLIGHT_CNTL_EN (1 << 0) +# define AVIVO_LVDS_BACKLIGHT_LEVEL_MASK 0x0000ff00 +# define AVIVO_LVDS_BACKLIGHT_LEVEL_SHIFT 8 + +#define AVIVO_DVOA_BIT_DEPTH_CONTROL 0x7988 + +#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_I2C_STATUS 0x7d30 +# define AVIVO_I2C_STATUS_DONE (1 << 0) +# define AVIVO_I2C_STATUS_NACK (1 << 1) +# define AVIVO_I2C_STATUS_HALT (1 << 2) +# define AVIVO_I2C_STATUS_GO (1 << 3) +# define AVIVO_I2C_STATUS_MASK 0x7 +/* If radeon_mm_i2c is to be believed, this is HALT, NACK, and maybe + * DONE? */ +# define AVIVO_I2C_STATUS_CMD_RESET 0x7 +# define AVIVO_I2C_STATUS_CMD_WAIT (1 << 3) +#define AVIVO_I2C_STOP 0x7d34 +#define AVIVO_I2C_START_CNTL 0x7d38 +# define AVIVO_I2C_START (1 << 8) +# define AVIVO_I2C_CONNECTOR0 (0 << 16) +# define AVIVO_I2C_CONNECTOR1 (1 << 16) +#define R520_I2C_START (1<<0) +#define R520_I2C_STOP (1<<1) +#define R520_I2C_RX (1<<2) +#define R520_I2C_EN (1<<8) +#define R520_I2C_DDC1 (0<<16) +#define R520_I2C_DDC2 (1<<16) +#define R520_I2C_DDC3 (2<<16) +#define R520_I2C_DDC_MASK (3<<16) +#define AVIVO_I2C_CONTROL2 0x7d3c +# define AVIVO_I2C_7D3C_SIZE_SHIFT 8 +# define AVIVO_I2C_7D3C_SIZE_MASK (0xf << 8) +#define AVIVO_I2C_CONTROL3 0x7d40 +/* Reading is done 4 bytes at a time: read the bottom 8 bits from + * 7d44, four times in a row. + * Writing is a little more complex. First write DATA with + * 0xnnnnnnzz, then 0xnnnnnnyy, where nnnnnn is some non-deterministic + * magic number, zz is, I think, the slave address, and yy is the byte + * you want to write. */ +#define AVIVO_I2C_DATA 0x7d44 +#define R520_I2C_ADDR_COUNT_MASK (0x7) +#define R520_I2C_DATA_COUNT_SHIFT (8) +#define R520_I2C_DATA_COUNT_MASK (0xF00) +#define AVIVO_I2C_CNTL 0x7d50 +# define AVIVO_I2C_EN (1 << 0) +# define AVIVO_I2C_RESET (1 << 8) + +#define R600_GENERAL_PWRMGT 0x618 +# define R600_OPEN_DRAIN_PADS (1 << 11) + +#define R600_LOWER_GPIO_ENABLE 0x710 +#define R600_CTXSW_VID_LOWER_GPIO_CNTL 0x718 +#define R600_HIGH_VID_LOWER_GPIO_CNTL 0x71c +#define R600_MEDIUM_VID_LOWER_GPIO_CNTL 0x720 +#define R600_LOW_VID_LOWER_GPIO_CNTL 0x724 + +#define R600_MC_VM_FB_LOCATION 0x2180 +#define R600_MC_VM_AGP_TOP 0x2184 +#define R600_MC_VM_AGP_BOT 0x2188 +#define R600_MC_VM_AGP_BASE 0x218c +#define R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2190 +#define R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194 +#define R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198 + +#define R700_MC_VM_FB_LOCATION 0x2024 + +#define R600_HDP_NONSURFACE_BASE 0x2c04 + +#define R600_BUS_CNTL 0x5420 +#define R600_CONFIG_CNTL 0x5424 +#define R600_CONFIG_MEMSIZE 0x5428 +#define R600_CONFIG_F0_BASE 0x542C +#define R600_CONFIG_APER_SIZE 0x5430 + +#define R600_ROM_CNTL 0x1600 +# define R600_SCK_OVERWRITE (1 << 1) +# define R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT 28 +# define R600_SCK_PRESCALE_CRYSTAL_CLK_MASK (0xf << 28) + +#define R600_BIOS_0_SCRATCH 0x1724 +#define R600_BIOS_1_SCRATCH 0x1728 +#define R600_BIOS_2_SCRATCH 0x172c +#define R600_BIOS_3_SCRATCH 0x1730 +#define R600_BIOS_4_SCRATCH 0x1734 +#define R600_BIOS_5_SCRATCH 0x1738 +#define R600_BIOS_6_SCRATCH 0x173c +#define R600_BIOS_7_SCRATCH 0x1740 + +#define R300_GB_TILE_CONFIG 0x4018 +# define R300_ENABLE_TILING (1 << 0) +# define R300_PIPE_COUNT_RV350 (0 << 1) +# define R300_PIPE_COUNT_R300 (3 << 1) +# define R300_PIPE_COUNT_R420_3P (6 << 1) +# define R300_PIPE_COUNT_R420 (7 << 1) +# define R300_TILE_SIZE_8 (0 << 4) +# define R300_TILE_SIZE_16 (1 << 4) +# define R300_TILE_SIZE_32 (2 << 4) +# define R300_SUBPIXEL_1_12 (0 << 16) +# define R300_SUBPIXEL_1_16 (1 << 16) +#define R300_GB_SELECT 0x401c +#define R300_GB_ENABLE 0x4008 +#define R300_GB_AA_CONFIG 0x4020 +#define R400_GB_PIPE_SELECT 0x402c +#define R300_GB_MSPOS0 0x4010 +# define R300_MS_X0_SHIFT 0 +# define R300_MS_Y0_SHIFT 4 +# define R300_MS_X1_SHIFT 8 +# define R300_MS_Y1_SHIFT 12 +# define R300_MS_X2_SHIFT 16 +# define R300_MS_Y2_SHIFT 20 +# define R300_MSBD0_Y_SHIFT 24 +# define R300_MSBD0_X_SHIFT 28 +#define R300_GB_MSPOS1 0x4014 +# define R300_MS_X3_SHIFT 0 +# define R300_MS_Y3_SHIFT 4 +# define R300_MS_X4_SHIFT 8 +# define R300_MS_Y4_SHIFT 12 +# define R300_MS_X5_SHIFT 16 +# define R300_MS_Y5_SHIFT 20 +# define R300_MSBD1_SHIFT 24 + +#define R300_GA_ENHANCE 0x4274 +# define R300_GA_DEADLOCK_CNTL (1 << 0) +# define R300_GA_FASTSYNC_CNTL (1 << 1) + +#define R300_GA_POLY_MODE 0x4288 +# define R300_FRONT_PTYPE_POINT (0 << 4) +# define R300_FRONT_PTYPE_LINE (1 << 4) +# define R300_FRONT_PTYPE_TRIANGE (2 << 4) +# define R300_BACK_PTYPE_POINT (0 << 7) +# define R300_BACK_PTYPE_LINE (1 << 7) +# define R300_BACK_PTYPE_TRIANGE (2 << 7) +#define R300_GA_ROUND_MODE 0x428c +# define R300_GEOMETRY_ROUND_TRUNC (0 << 0) +# define R300_GEOMETRY_ROUND_NEAREST (1 << 0) +# define R300_COLOR_ROUND_TRUNC (0 << 2) +# define R300_COLOR_ROUND_NEAREST (1 << 2) +#define R300_GA_COLOR_CONTROL 0x4278 +# define R300_RGB0_SHADING_SOLID (0 << 0) +# define R300_RGB0_SHADING_FLAT (1 << 0) +# define R300_RGB0_SHADING_GOURAUD (2 << 0) +# define R300_ALPHA0_SHADING_SOLID (0 << 2) +# define R300_ALPHA0_SHADING_FLAT (1 << 2) +# define R300_ALPHA0_SHADING_GOURAUD (2 << 2) +# define R300_RGB1_SHADING_SOLID (0 << 4) +# define R300_RGB1_SHADING_FLAT (1 << 4) +# define R300_RGB1_SHADING_GOURAUD (2 << 4) +# define R300_ALPHA1_SHADING_SOLID (0 << 6) +# define R300_ALPHA1_SHADING_FLAT (1 << 6) +# define R300_ALPHA1_SHADING_GOURAUD (2 << 6) +# define R300_RGB2_SHADING_SOLID (0 << 8) +# define R300_RGB2_SHADING_FLAT (1 << 8) +# define R300_RGB2_SHADING_GOURAUD (2 << 8) +# define R300_ALPHA2_SHADING_SOLID (0 << 10) +# define R300_ALPHA2_SHADING_FLAT (1 << 10) +# define R300_ALPHA2_SHADING_GOURAUD (2 << 10) +# define R300_RGB3_SHADING_SOLID (0 << 12) +# define R300_RGB3_SHADING_FLAT (1 << 12) +# define R300_RGB3_SHADING_GOURAUD (2 << 12) +# define R300_ALPHA3_SHADING_SOLID (0 << 14) +# define R300_ALPHA3_SHADING_FLAT (1 << 14) +# define R300_ALPHA3_SHADING_GOURAUD (2 << 14) +#define R300_GA_OFFSET 0x4290 + +#define R500_SU_REG_DEST 0x42c8 + +#define R300_VAP_CNTL_STATUS 0x2140 +# define R300_PVS_BYPASS (1 << 8) +#define R300_VAP_PVS_STATE_FLUSH_REG 0x2284 +#define R300_VAP_CNTL 0x2080 +# define R300_PVS_NUM_SLOTS_SHIFT 0 +# define R300_PVS_NUM_CNTLRS_SHIFT 4 +# define R300_PVS_NUM_FPUS_SHIFT 8 +# define R300_VF_MAX_VTX_NUM_SHIFT 18 +# define R300_GL_CLIP_SPACE_DEF (0 << 22) +# define R300_DX_CLIP_SPACE_DEF (1 << 22) +# define R500_TCL_STATE_OPTIMIZATION (1 << 23) +#define R300_VAP_VTE_CNTL 0x20B0 +# define R300_VPORT_X_SCALE_ENA (1 << 0) +# define R300_VPORT_X_OFFSET_ENA (1 << 1) +# define R300_VPORT_Y_SCALE_ENA (1 << 2) +# define R300_VPORT_Y_OFFSET_ENA (1 << 3) +# define R300_VPORT_Z_SCALE_ENA (1 << 4) +# define R300_VPORT_Z_OFFSET_ENA (1 << 5) +# define R300_VTX_XY_FMT (1 << 8) +# define R300_VTX_Z_FMT (1 << 9) +# define R300_VTX_W0_FMT (1 << 10) +#define R300_VAP_VTX_STATE_CNTL 0x2180 +#define R300_VAP_PSC_SGN_NORM_CNTL 0x21DC +#define R300_VAP_PROG_STREAM_CNTL_0 0x2150 +# define R300_DATA_TYPE_0_SHIFT 0 +# define R300_DATA_TYPE_FLOAT_1 0 +# define R300_DATA_TYPE_FLOAT_2 1 +# define R300_DATA_TYPE_FLOAT_3 2 +# define R300_DATA_TYPE_FLOAT_4 3 +# define R300_DATA_TYPE_BYTE 4 +# define R300_DATA_TYPE_D3DCOLOR 5 +# define R300_DATA_TYPE_SHORT_2 6 +# define R300_DATA_TYPE_SHORT_4 7 +# define R300_DATA_TYPE_VECTOR_3_TTT 8 +# define R300_DATA_TYPE_VECTOR_3_EET 9 +# define R300_SKIP_DWORDS_0_SHIFT 4 +# define R300_DST_VEC_LOC_0_SHIFT 8 +# define R300_LAST_VEC_0 (1 << 13) +# define R300_SIGNED_0 (1 << 14) +# define R300_NORMALIZE_0 (1 << 15) +# define R300_DATA_TYPE_1_SHIFT 16 +# define R300_SKIP_DWORDS_1_SHIFT 20 +# define R300_DST_VEC_LOC_1_SHIFT 24 +# define R300_LAST_VEC_1 (1 << 29) +# define R300_SIGNED_1 (1 << 30) +# define R300_NORMALIZE_1 (1 << 31) +#define R300_VAP_PROG_STREAM_CNTL_1 0x2154 +# define R300_DATA_TYPE_2_SHIFT 0 +# define R300_SKIP_DWORDS_2_SHIFT 4 +# define R300_DST_VEC_LOC_2_SHIFT 8 +# define R300_LAST_VEC_2 (1 << 13) +# define R300_SIGNED_2 (1 << 14) +# define R300_NORMALIZE_2 (1 << 15) +# define R300_DATA_TYPE_3_SHIFT 16 +# define R300_SKIP_DWORDS_3_SHIFT 20 +# define R300_DST_VEC_LOC_3_SHIFT 24 +# define R300_LAST_VEC_3 (1 << 29) +# define R300_SIGNED_3 (1 << 30) +# define R300_NORMALIZE_3 (1 << 31) +#define R300_VAP_PROG_STREAM_CNTL_EXT_0 0x21e0 +# define R300_SWIZZLE_SELECT_X_0_SHIFT 0 +# define R300_SWIZZLE_SELECT_Y_0_SHIFT 3 +# define R300_SWIZZLE_SELECT_Z_0_SHIFT 6 +# define R300_SWIZZLE_SELECT_W_0_SHIFT 9 +# define R300_SWIZZLE_SELECT_X 0 +# define R300_SWIZZLE_SELECT_Y 1 +# define R300_SWIZZLE_SELECT_Z 2 +# define R300_SWIZZLE_SELECT_W 3 +# define R300_SWIZZLE_SELECT_FP_ZERO 4 +# define R300_SWIZZLE_SELECT_FP_ONE 5 +# define R300_WRITE_ENA_0_SHIFT 12 +# define R300_WRITE_ENA_X 1 +# define R300_WRITE_ENA_Y 2 +# define R300_WRITE_ENA_Z 4 +# define R300_WRITE_ENA_W 8 +# define R300_SWIZZLE_SELECT_X_1_SHIFT 16 +# define R300_SWIZZLE_SELECT_Y_1_SHIFT 19 +# define R300_SWIZZLE_SELECT_Z_1_SHIFT 22 +# define R300_SWIZZLE_SELECT_W_1_SHIFT 25 +# define R300_WRITE_ENA_1_SHIFT 28 +#define R300_VAP_PROG_STREAM_CNTL_EXT_1 0x21e4 +# define R300_SWIZZLE_SELECT_X_2_SHIFT 0 +# define R300_SWIZZLE_SELECT_Y_2_SHIFT 3 +# define R300_SWIZZLE_SELECT_Z_2_SHIFT 6 +# define R300_SWIZZLE_SELECT_W_2_SHIFT 9 +# define R300_WRITE_ENA_2_SHIFT 12 +# define R300_SWIZZLE_SELECT_X_3_SHIFT 16 +# define R300_SWIZZLE_SELECT_Y_3_SHIFT 19 +# define R300_SWIZZLE_SELECT_Z_3_SHIFT 22 +# define R300_SWIZZLE_SELECT_W_3_SHIFT 25 +# define R300_WRITE_ENA_3_SHIFT 28 +#define R300_VAP_PVS_CODE_CNTL_0 0x22D0 +# define R300_PVS_FIRST_INST_SHIFT 0 +# define R300_PVS_XYZW_VALID_INST_SHIFT 10 +# define R300_PVS_LAST_INST_SHIFT 20 +#define R300_VAP_PVS_CODE_CNTL_1 0x22D8 +# define R300_PVS_LAST_VTX_SRC_INST_SHIFT 0 +#define R300_VAP_PVS_VECTOR_INDX_REG 0x2200 +#define R300_VAP_PVS_VECTOR_DATA_REG 0x2204 +/* PVS instructions */ +/* Opcode and dst instruction */ +#define R300_PVS_DST_OPCODE(x) (x << 0) +/* Vector ops */ +# define R300_VECTOR_NO_OP 0 +# define R300_VE_DOT_PRODUCT 1 +# define R300_VE_MULTIPLY 2 +# define R300_VE_ADD 3 +# define R300_VE_MULTIPLY_ADD 4 +# define R300_VE_DISTANCE_VECTOR 5 +# define R300_VE_FRACTION 6 +# define R300_VE_MAXIMUM 7 +# define R300_VE_MINIMUM 8 +# define R300_VE_SET_GREATER_THAN_EQUAL 9 +# define R300_VE_SET_LESS_THAN 10 +# define R300_VE_MULTIPLYX2_ADD 11 +# define R300_VE_MULTIPLY_CLAMP 12 +# define R300_VE_FLT2FIX_DX 13 +# define R300_VE_FLT2FIX_DX_RND 14 +/* R500 additions */ +# define R500_VE_PRED_SET_EQ_PUSH 15 +# define R500_VE_PRED_SET_GT_PUSH 16 +# define R500_VE_PRED_SET_GTE_PUSH 17 +# define R500_VE_PRED_SET_NEQ_PUSH 18 +# define R500_VE_COND_WRITE_EQ 19 +# define R500_VE_COND_WRITE_GT 20 +# define R500_VE_COND_WRITE_GTE 21 +# define R500_VE_COND_WRITE_NEQ 22 +# define R500_VE_COND_MUX_EQ 23 +# define R500_VE_COND_MUX_GT 24 +# define R500_VE_COND_MUX_GTE 25 +# define R500_VE_SET_GREATER_THAN 26 +# define R500_VE_SET_EQUAL 27 +# define R500_VE_SET_NOT_EQUAL 28 +/* Math ops */ +# define R300_MATH_NO_OP 0 +# define R300_ME_EXP_BASE2_DX 1 +# define R300_ME_LOG_BASE2_DX 2 +# define R300_ME_EXP_BASEE_FF 3 +# define R300_ME_LIGHT_COEFF_DX 4 +# define R300_ME_POWER_FUNC_FF 5 +# define R300_ME_RECIP_DX 6 +# define R300_ME_RECIP_FF 7 +# define R300_ME_RECIP_SQRT_DX 8 +# define R300_ME_RECIP_SQRT_FF 9 +# define R300_ME_MULTIPLY 10 +# define R300_ME_EXP_BASE2_FULL_DX 11 +# define R300_ME_LOG_BASE2_FULL_DX 12 +# define R300_ME_POWER_FUNC_FF_CLAMP_B 13 +# define R300_ME_POWER_FUNC_FF_CLAMP_B1 14 +# define R300_ME_POWER_FUNC_FF_CLAMP_01 15 +# define R300_ME_SIN 16 +# define R300_ME_COS 17 +/* R500 additions */ +# define R500_ME_LOG_BASE2_IEEE 18 +# define R500_ME_RECIP_IEEE 19 +# define R500_ME_RECIP_SQRT_IEEE 20 +# define R500_ME_PRED_SET_EQ 21 +# define R500_ME_PRED_SET_GT 22 +# define R500_ME_PRED_SET_GTE 23 +# define R500_ME_PRED_SET_NEQ 24 +# define R500_ME_PRED_SET_CLR 25 +# define R500_ME_PRED_SET_INV 26 +# define R500_ME_PRED_SET_POP 27 +# define R500_ME_PRED_SET_RESTORE 28 +/* macro */ +# define R300_PVS_MACRO_OP_2CLK_MADD 0 +# define R300_PVS_MACRO_OP_2CLK_M2X_ADD 1 +#define R300_PVS_DST_MATH_INST (1 << 6) +#define R300_PVS_DST_MACRO_INST (1 << 7) +#define R300_PVS_DST_REG_TYPE(x) (x << 8) +# define R300_PVS_DST_REG_TEMPORARY 0 +# define R300_PVS_DST_REG_A0 1 +# define R300_PVS_DST_REG_OUT 2 +# define R500_PVS_DST_REG_OUT_REPL_X 3 +# define R300_PVS_DST_REG_ALT_TEMPORARY 4 +# define R300_PVS_DST_REG_INPUT 5 +#define R300_PVS_DST_ADDR_MODE_1 (1 << 12) +#define R300_PVS_DST_OFFSET(x) (x << 13) +#define R300_PVS_DST_WE_X (1 << 20) +#define R300_PVS_DST_WE_Y (1 << 21) +#define R300_PVS_DST_WE_Z (1 << 22) +#define R300_PVS_DST_WE_W (1 << 23) +#define R300_PVS_DST_VE_SAT (1 << 24) +#define R300_PVS_DST_ME_SAT (1 << 25) +#define R300_PVS_DST_PRED_ENABLE (1 << 26) +#define R300_PVS_DST_PRED_SENSE (1 << 27) +#define R300_PVS_DST_DUAL_MATH_OP (1 << 28) +#define R300_PVS_DST_ADDR_SEL(x) (x << 29) +#define R300_PVS_DST_ADDR_MODE_0 (1 << 31) +/* src operand instruction */ +#define R300_PVS_SRC_REG_TYPE(x) (x << 0) +# define R300_PVS_SRC_REG_TEMPORARY 0 +# define R300_PVS_SRC_REG_INPUT 1 +# define R300_PVS_SRC_REG_CONSTANT 2 +# define R300_PVS_SRC_REG_ALT_TEMPORARY 3 +#define R300_SPARE_0 (1 << 2) +#define R300_PVS_SRC_ABS_XYZW (1 << 3) +#define R300_PVS_SRC_ADDR_MODE_0 (1 << 4) +#define R300_PVS_SRC_OFFSET(x) (x << 5) +#define R300_PVS_SRC_SWIZZLE_X(x) (x << 13) +#define R300_PVS_SRC_SWIZZLE_Y(x) (x << 16) +#define R300_PVS_SRC_SWIZZLE_Z(x) (x << 19) +#define R300_PVS_SRC_SWIZZLE_W(x) (x << 22) +# define R300_PVS_SRC_SELECT_X 0 +# define R300_PVS_SRC_SELECT_Y 1 +# define R300_PVS_SRC_SELECT_Z 2 +# define R300_PVS_SRC_SELECT_W 3 +# define R300_PVS_SRC_SELECT_FORCE_0 4 +# define R300_PVS_SRC_SELECT_FORCE_1 5 +#define R300_PVS_SRC_NEG_X (1 << 25) +#define R300_PVS_SRC_NEG_Y (1 << 26) +#define R300_PVS_SRC_NEG_Z (1 << 27) +#define R300_PVS_SRC_NEG_W (1 << 28) +#define R300_PVS_SRC_ADDR_SEL(x) (x << 29) +#define R300_PVS_SRC_ADDR_MODE_1 (1 << 31) + +#define R300_VAP_PVS_FLOW_CNTL_OPC 0x22DC +#define R300_VAP_OUT_VTX_FMT_0 0x2090 +# define R300_VTX_POS_PRESENT (1 << 0) +# define R300_VTX_COLOR_0_PRESENT (1 << 1) +# define R300_VTX_COLOR_1_PRESENT (1 << 2) +# define R300_VTX_COLOR_2_PRESENT (1 << 3) +# define R300_VTX_COLOR_3_PRESENT (1 << 4) +# define R300_VTX_PT_SIZE_PRESENT (1 << 16) +#define R300_VAP_OUT_VTX_FMT_1 0x2094 +# define R300_TEX_0_COMP_CNT_SHIFT 0 +# define R300_TEX_1_COMP_CNT_SHIFT 3 +# define R300_TEX_2_COMP_CNT_SHIFT 6 +# define R300_TEX_3_COMP_CNT_SHIFT 9 +# define R300_TEX_4_COMP_CNT_SHIFT 12 +# define R300_TEX_5_COMP_CNT_SHIFT 15 +# define R300_TEX_6_COMP_CNT_SHIFT 18 +# define R300_TEX_7_COMP_CNT_SHIFT 21 +#define R300_VAP_VTX_SIZE 0x20b4 +#define R300_VAP_GB_VERT_CLIP_ADJ 0x2220 +#define R300_VAP_GB_VERT_DISC_ADJ 0x2224 +#define R300_VAP_GB_HORZ_CLIP_ADJ 0x2228 +#define R300_VAP_GB_HORZ_DISC_ADJ 0x222c +#define R300_VAP_CLIP_CNTL 0x221c +# define R300_UCP_ENA_0 (1 << 0) +# define R300_UCP_ENA_1 (1 << 1) +# define R300_UCP_ENA_2 (1 << 2) +# define R300_UCP_ENA_3 (1 << 3) +# define R300_UCP_ENA_4 (1 << 4) +# define R300_UCP_ENA_5 (1 << 5) +# define R300_PS_UCP_MODE_SHIFT 14 +# define R300_CLIP_DISABLE (1 << 16) +# define R300_UCP_CULL_ONLY_ENA (1 << 17) +# define R300_BOUNDARY_EDGE_FLAG_ENA (1 << 18) +#define R300_VAP_PVS_STATE_FLUSH_REG 0x2284 + +#define R500_VAP_INDEX_OFFSET 0x208c + +#define R300_SU_TEX_WRAP 0x42a0 +#define R300_SU_POLY_OFFSET_ENABLE 0x42b4 +#define R300_SU_CULL_MODE 0x42b8 +# define R300_CULL_FRONT (1 << 0) +# define R300_CULL_BACK (1 << 1) +# define R300_FACE_POS (0 << 2) +# define R300_FACE_NEG (1 << 2) +#define R300_SU_DEPTH_SCALE 0x42c0 +#define R300_SU_DEPTH_OFFSET 0x42c4 + +#define R300_RS_COUNT 0x4300 +# define R300_RS_COUNT_IT_COUNT_SHIFT 0 +# define R300_RS_COUNT_IC_COUNT_SHIFT 7 +# define R300_RS_COUNT_HIRES_EN (1 << 18) + +#define R300_RS_IP_0 0x4310 +#define R300_RS_IP_1 0x4314 +# define R300_RS_TEX_PTR(x) (x << 0) +# define R300_RS_COL_PTR(x) (x << 6) +# define R300_RS_COL_FMT(x) (x << 9) +# define R300_RS_COL_FMT_RGBA 0 +# define R300_RS_COL_FMT_RGB0 2 +# define R300_RS_COL_FMT_RGB1 3 +# define R300_RS_COL_FMT_000A 4 +# define R300_RS_COL_FMT_0000 5 +# define R300_RS_COL_FMT_0001 6 +# define R300_RS_COL_FMT_111A 8 +# define R300_RS_COL_FMT_1110 9 +# define R300_RS_COL_FMT_1111 10 +# define R300_RS_SEL_S(x) (x << 13) +# define R300_RS_SEL_T(x) (x << 16) +# define R300_RS_SEL_R(x) (x << 19) +# define R300_RS_SEL_Q(x) (x << 22) +# define R300_RS_SEL_C0 0 +# define R300_RS_SEL_C1 1 +# define R300_RS_SEL_C2 2 +# define R300_RS_SEL_C3 3 +# define R300_RS_SEL_K0 4 +# define R300_RS_SEL_K1 5 +#define R300_RS_INST_COUNT 0x4304 +# define R300_INST_COUNT_RS(x) (x << 0) +# define R300_RS_W_EN (1 << 4) +# define R300_TX_OFFSET_RS(x) (x << 5) +#define R300_RS_INST_0 0x4330 +#define R300_RS_INST_1 0x4334 +# define R300_INST_TEX_ID(x) (x << 0) +# define R300_RS_INST_TEX_CN_WRITE (1 << 3) +# define R300_INST_TEX_ADDR(x) (x << 6) + +#define R300_TX_INVALTAGS 0x4100 +#define R300_TX_FILTER0_0 0x4400 +# define R300_TX_CLAMP_S(x) (x << 0) +# define R300_TX_CLAMP_T(x) (x << 3) +# define R300_TX_CLAMP_R(x) (x << 6) +# define R300_TX_CLAMP_WRAP 0 +# define R300_TX_CLAMP_MIRROR 1 +# define R300_TX_CLAMP_CLAMP_LAST 2 +# define R300_TX_CLAMP_MIRROR_CLAMP_LAST 3 +# define R300_TX_CLAMP_CLAMP_BORDER 4 +# define R300_TX_CLAMP_MIRROR_CLAMP_BORDER 5 +# define R300_TX_CLAMP_CLAMP_GL 6 +# define R300_TX_CLAMP_MIRROR_CLAMP_GL 7 +# define R300_TX_MAG_FILTER_NEAREST (1 << 9) +# define R300_TX_MIN_FILTER_NEAREST (1 << 11) +# define R300_TX_MAG_FILTER_LINEAR (2 << 9) +# define R300_TX_MIN_FILTER_LINEAR (2 << 11) +# define R300_TX_ID_SHIFT 28 +#define R300_TX_FILTER1_0 0x4440 +#define R300_TX_FORMAT0_0 0x4480 +# define R300_TXWIDTH_SHIFT 0 +# define R300_TXHEIGHT_SHIFT 11 +# define R300_NUM_LEVELS_SHIFT 26 +# define R300_NUM_LEVELS_MASK 0x +# define R300_TXPROJECTED (1 << 30) +# define R300_TXPITCH_EN (1 << 31) +#define R300_TX_FORMAT1_0 0x44c0 +# define R300_TX_FORMAT_X8 0x0 +# define R300_TX_FORMAT_X16 0x1 +# define R300_TX_FORMAT_Y4X4 0x2 +# define R300_TX_FORMAT_Y8X8 0x3 +# define R300_TX_FORMAT_Y16X16 0x4 +# define R300_TX_FORMAT_Z3Y3X2 0x5 +# define R300_TX_FORMAT_Z5Y6X5 0x6 +# define R300_TX_FORMAT_Z6Y5X5 0x7 +# define R300_TX_FORMAT_Z11Y11X10 0x8 +# define R300_TX_FORMAT_Z10Y11X11 0x9 +# define R300_TX_FORMAT_W4Z4Y4X4 0xA +# define R300_TX_FORMAT_W1Z5Y5X5 0xB +# define R300_TX_FORMAT_W8Z8Y8X8 0xC +# define R300_TX_FORMAT_W2Z10Y10X10 0xD +# define R300_TX_FORMAT_W16Z16Y16X16 0xE +# define R300_TX_FORMAT_DXT1 0xF +# define R300_TX_FORMAT_DXT3 0x10 +# define R300_TX_FORMAT_DXT5 0x11 +# define R300_TX_FORMAT_D3DMFT_CxV8U8 0x12 /* no swizzle */ +# define R300_TX_FORMAT_A8R8G8B8 0x13 /* no swizzle */ +# define R300_TX_FORMAT_B8G8_B8G8 0x14 /* no swizzle */ +# define R300_TX_FORMAT_G8R8_G8B8 0x15 /* no swizzle */ +# define R300_TX_FORMAT_VYUY422 0x14 /* no swizzle */ +# define R300_TX_FORMAT_YVYU422 0x15 /* no swizzle */ +# define R300_TX_FORMAT_X24_Y8 0x1e +# define R300_TX_FORMAT_X32 0x1e + /* Floating point formats */ + /* Note - hardware supports both 16 and 32 bit floating point */ +# define R300_TX_FORMAT_FL_I16 0x18 +# define R300_TX_FORMAT_FL_I16A16 0x19 +# define R300_TX_FORMAT_FL_R16G16B16A16 0x1A +# define R300_TX_FORMAT_FL_I32 0x1B +# define R300_TX_FORMAT_FL_I32A32 0x1C +# define R300_TX_FORMAT_FL_R32G32B32A32 0x1D + /* alpha modes, convenience mostly */ + /* if you have alpha, pick constant appropriate to the + number of channels (1 for I8, 2 for I8A8, 4 for R8G8B8A8, etc */ +# define R300_TX_FORMAT_ALPHA_1CH 0x000 +# define R300_TX_FORMAT_ALPHA_2CH 0x200 +# define R300_TX_FORMAT_ALPHA_4CH 0x600 +# define R300_TX_FORMAT_ALPHA_NONE 0xA00 + /* Swizzling */ + /* constants */ +# define R300_TX_FORMAT_X 0 +# define R300_TX_FORMAT_Y 1 +# define R300_TX_FORMAT_Z 2 +# define R300_TX_FORMAT_W 3 +# define R300_TX_FORMAT_ZERO 4 +# define R300_TX_FORMAT_ONE 5 + /* 2.0*Z, everything above 1.0 is set to 0.0 */ +# define R300_TX_FORMAT_CUT_Z 6 + /* 2.0*W, everything above 1.0 is set to 0.0 */ +# define R300_TX_FORMAT_CUT_W 7 + +# define R300_TX_FORMAT_B_SHIFT 18 +# define R300_TX_FORMAT_G_SHIFT 15 +# define R300_TX_FORMAT_R_SHIFT 12 +# define R300_TX_FORMAT_A_SHIFT 9 + + /* Convenience macro to take care of layout and swizzling */ +# define R300_EASY_TX_FORMAT(B, G, R, A, FMT) ( \ + ((R300_TX_FORMAT_##B)<dev_private; drm_radeon_buf_priv_t *buf_priv = buf->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; - buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; + buf_priv->age = ++master_priv->sarea_priv->last_dispatch; buf->pending = 1; buf->used = 0; } @@ -898,6 +898,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, drm_radeon_kcmd_buffer_t *cmdbuf) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf = NULL; int emit_dispatch_age = 0; @@ -1005,7 +1006,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, } emit_dispatch_age = 1; - r300_discard_buffer(dev, buf); + r300_discard_buffer(dev, file_priv->master, buf); break; case R300_CMD_WAIT: @@ -1060,7 +1061,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, /* Emit the vertex buffer age */ BEGIN_RING(2); - RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch); + RADEON_DISPATCH_AGE(master_priv->sarea_priv->last_dispatch); ADVANCE_RING(); } diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 819a61ae..80951e91 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -31,6 +31,7 @@ #include "drmP.h" #include "drm.h" +#include "drm_sarea.h" #include "radeon_drm.h" #include "radeon_drv.h" #include "r300_reg.h" @@ -75,6 +76,23 @@ static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) return RS480_READ_MCIND(dev_priv, addr); } +u32 radeon_read_mc_reg(drm_radeon_private_t *dev_priv, int addr) +{ + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + return IGP_READ_MCIND(dev_priv, addr); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) + return R500_READ_MCIND(dev_priv, addr); + return 0; +} + +void radeon_write_mc_reg(drm_radeon_private_t *dev_priv, u32 addr, u32 val) +{ + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) + IGP_WRITE_MCIND(addr, val); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) + R500_WRITE_MCIND(addr, val); +} + u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) { @@ -133,12 +151,57 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) } } -static int RADEON_READ_PLL(struct drm_device * dev, int addr) + +void radeon_pll_errata_after_index(struct drm_radeon_private *dev_priv) { - drm_radeon_private_t *dev_priv = dev->dev_private; + if (!(dev_priv->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS)) + return; + + (void)RADEON_READ(RADEON_CLOCK_CNTL_DATA); + (void)RADEON_READ(RADEON_CRTC_GEN_CNTL); +} + +void radeon_pll_errata_after_data(struct drm_radeon_private *dev_priv) +{ + /* This workarounds is necessary on RV100, RS100 and RS200 chips + * or the chip could hang on a subsequent access + */ + if (dev_priv->pll_errata & CHIP_ERRATA_PLL_DELAY) + udelay(5000); + + /* This function is required to workaround a hardware bug in some (all?) + * revisions of the R300. This workaround should be called after every + * CLOCK_CNTL_INDEX register access. If not, register reads afterward + * may not be correct. + */ + if (dev_priv->pll_errata & CHIP_ERRATA_R300_CG) { + uint32_t save, tmp; + + save = RADEON_READ(RADEON_CLOCK_CNTL_INDEX); + tmp = save & ~(0x3f | RADEON_PLL_WR_EN); + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, tmp); + tmp = RADEON_READ(RADEON_CLOCK_CNTL_DATA); + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, save); + } +} + +int RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr) +{ + uint32_t data; - RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x1f); - return RADEON_READ(RADEON_CLOCK_CNTL_DATA); + RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x3f); + radeon_pll_errata_after_index(dev_priv); + data = RADEON_READ(RADEON_CLOCK_CNTL_DATA); + radeon_pll_errata_after_data(dev_priv); + return data; +} + +void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data) +{ + RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, ((addr & 0x3f) | RADEON_PLL_WR_EN)); + radeon_pll_errata_after_index(dev_priv); + RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, data); + radeon_pll_errata_after_data(dev_priv); } static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) @@ -147,6 +210,39 @@ static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) return RADEON_READ(RADEON_PCIE_DATA); } +/* ATOM accessor methods */ +static uint32_t cail_mc_read(struct card_info *info, uint32_t reg) +{ + uint32_t ret = radeon_read_mc_reg(info->dev->dev_private, reg); + + // DRM_DEBUG("(%x) = %x\n", reg, ret); + return ret; +} + +static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + // DRM_DEBUG("(%x, %x)\n", reg, val); + radeon_write_mc_reg(info->dev->dev_private, reg, val); +} + +static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + drm_radeon_private_t *dev_priv = info->dev->dev_private; + + // DRM_DEBUG("(%x, %x)\n", reg*4, val); + RADEON_WRITE(reg*4, val); +} + +static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) +{ + uint32_t ret; + drm_radeon_private_t *dev_priv = info->dev->dev_private; + + ret = RADEON_READ(reg*4); + // DRM_DEBUG("(%x) = %x\n", reg*4, ret); + return ret; +} + #if RADEON_FIFO_DEBUG static void radeon_status(drm_radeon_private_t * dev_priv) { @@ -298,7 +394,7 @@ static void radeon_init_pipes(drm_radeon_private_t * dev_priv) } if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) { - RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4)); + RADEON_WRITE_PLL(dev_priv, R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4)); RADEON_WRITE(R500_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1)); } RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config); @@ -491,15 +587,15 @@ static int radeon_do_engine_reset(struct drm_device * dev) if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) { /* may need something similar for newer chips */ clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX); - mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL); - - RADEON_WRITE_PLL(RADEON_MCLK_CNTL, (mclk_cntl | - RADEON_FORCEON_MCLKA | - RADEON_FORCEON_MCLKB | - RADEON_FORCEON_YCLKA | - RADEON_FORCEON_YCLKB | - RADEON_FORCEON_MC | - RADEON_FORCEON_AIC)); + mclk_cntl = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, (mclk_cntl | + RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB | + RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | + RADEON_FORCEON_MC | + RADEON_FORCEON_AIC)); } rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET); @@ -524,7 +620,7 @@ static int radeon_do_engine_reset(struct drm_device * dev) RADEON_READ(RADEON_RBBM_SOFT_RESET); if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) { - RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, mclk_cntl); RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index); RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset); } @@ -540,7 +636,8 @@ static int radeon_do_engine_reset(struct drm_device * dev) dev_priv->cp_running = 0; /* Reset any pending vertex, indirect buffers */ - radeon_freelist_reset(dev); + if (dev->dma) + radeon_freelist_reset(dev); return 0; } @@ -558,9 +655,13 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, */ if (!dev_priv->new_memmap) radeon_write_fb_location(dev_priv, - ((dev_priv->gart_vm_start - 1) & 0xffff0000) - | (dev_priv->fb_location >> 16)); - + ((dev_priv->gart_vm_start - 1) & 0xffff0000) + | (dev_priv->fb_location >> 16)); + + if (dev_priv->mm.ring) { + ring_start = dev_priv->mm.ring->offset + + dev_priv->gart_vm_start; + } else #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { radeon_write_agp_base(dev_priv, dev->agp->base); @@ -590,6 +691,12 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, SET_RING_HEAD(dev_priv, cur_read_ptr); dev_priv->ring.tail = cur_read_ptr; + + if (dev_priv->mm.ring_read_ptr) { + RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, + dev_priv->mm.ring_read_ptr->offset + + dev_priv->gart_vm_start); + } else #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, @@ -638,9 +745,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR) + RADEON_SCRATCH_REG_OFFSET); - dev_priv->scratch = ((__volatile__ u32 *) - dev_priv->ring_rptr->handle + - (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); + if (dev_priv->mm.ring_read_ptr) + dev_priv->scratch = ((__volatile__ u32 *) + dev_priv->mm.ring_read_ptr_map.virtual + + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); + else + dev_priv->scratch = ((__volatile__ u32 *) + dev_priv->ring_rptr->handle + + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); @@ -648,15 +760,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; RADEON_WRITE(RADEON_BUS_CNTL, tmp); - dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; - RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); + dev_priv->scratch[0] = 0; + RADEON_WRITE(RADEON_LAST_FRAME_REG, 0); - dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; - RADEON_WRITE(RADEON_LAST_DISPATCH_REG, - dev_priv->sarea_priv->last_dispatch); + dev_priv->scratch[1] = 0; + RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0); - dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; - RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); + dev_priv->scratch[2] = 0; + RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0); radeon_do_wait_for_idle(dev_priv); @@ -672,15 +783,21 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, static void radeon_test_writeback(drm_radeon_private_t * dev_priv) { u32 tmp; + void *ring_read_ptr; + + if (dev_priv->mm.ring_read_ptr) + ring_read_ptr = dev_priv->mm.ring_read_ptr_map.virtual; + else + ring_read_ptr = dev_priv->ring_rptr->handle; /* Writeback doesn't seem to work everywhere, test it here and possibly * enable it if it appears to work */ - DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0); + writel(0, ring_read_ptr + RADEON_SCRATCHOFF(1)); RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef); for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) { - if (DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)) == + if (readl(ring_read_ptr + RADEON_SCRATCHOFF(1)) == 0xdeadbeef) break; DRM_UDELAY(1); @@ -813,7 +930,7 @@ static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) } /* Enable or disable PCI GART on the chip */ -static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) +void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; @@ -854,9 +971,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) } } -static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) +static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, + struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; DRM_DEBUG("\n"); @@ -897,17 +1016,6 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) */ dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1; - switch(init->func) { - case RADEON_INIT_R200_CP: - dev_priv->microcode_version = UCODE_R200; - break; - case RADEON_INIT_R300_CP: - dev_priv->microcode_version = UCODE_R300; - break; - default: - dev_priv->microcode_version = UCODE_R100; - } - dev_priv->do_boxes = 0; dev_priv->cp_mode = init->cp_mode; @@ -955,9 +1063,8 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) */ dev_priv->depth_clear.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE | (dev_priv->color_fmt << 10) | - (dev_priv->microcode_version == - UCODE_R100 ? RADEON_ZBLOCK16 : 0)); - + (dev_priv->chip_family < CHIP_R200 ? RADEON_ZBLOCK16 : 0)); + dev_priv->depth_clear.rb3d_zstencilcntl = (dev_priv->depth_fmt | RADEON_Z_TEST_ALWAYS | @@ -984,8 +1091,8 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) dev_priv->buffers_offset = init->buffers_offset; dev_priv->gart_textures_offset = init->gart_textures_offset; - dev_priv->sarea = drm_getsarea(dev); - if (!dev_priv->sarea) { + master_priv->sarea = drm_getsarea(dev); + if (!master_priv->sarea) { DRM_ERROR("could not find sarea!\n"); radeon_do_cleanup_cp(dev); return -EINVAL; @@ -1021,10 +1128,6 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) } } - dev_priv->sarea_priv = - (drm_radeon_sarea_t *) ((u8 *) dev_priv->sarea->handle + - init->sarea_priv_offset); - #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { drm_core_ioremap(dev_priv->cp_ring, dev); @@ -1155,28 +1258,41 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); /* if we have an offset set from userspace */ if (dev_priv->pcigart_offset_set) { - dev_priv->gart_info.bus_addr = - dev_priv->pcigart_offset + dev_priv->fb_location; - dev_priv->gart_info.mapping.offset = - dev_priv->pcigart_offset + dev_priv->fb_aper_offset; - dev_priv->gart_info.mapping.size = - dev_priv->gart_info.table_size; - - drm_core_ioremap(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = - dev_priv->gart_info.mapping.handle; - - if (dev_priv->flags & RADEON_IS_PCIE) - dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; - else - dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; - dev_priv->gart_info.gart_table_location = - DRM_ATI_GART_FB; - DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n", - dev_priv->gart_info.addr, - dev_priv->pcigart_offset); + /* if it came from userspace - remap it */ + if (dev_priv->pcigart_offset_set == 1) { + dev_priv->gart_info.bus_addr = + dev_priv->pcigart_offset + dev_priv->fb_location; + dev_priv->gart_info.mapping.offset = + dev_priv->pcigart_offset + dev_priv->fb_aper_offset; + dev_priv->gart_info.mapping.size = + dev_priv->gart_info.table_size; + + /* this is done by the mm now */ + drm_core_ioremap(&dev_priv->gart_info.mapping, dev); + dev_priv->gart_info.addr = + dev_priv->gart_info.mapping.handle; + + memset(dev_priv->gart_info.addr, 0, dev_priv->gart_info.table_size); + if (dev_priv->flags & RADEON_IS_PCIE) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; + dev_priv->gart_info.gart_table_location = + DRM_ATI_GART_FB; + + DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n", + dev_priv->gart_info.addr, + dev_priv->pcigart_offset); + } } else { + + if (dev_priv->flags & RADEON_IS_PCIE) { + DRM_ERROR + ("Cannot use PCI Express without GART in FB memory\n"); + radeon_do_cleanup_cp(dev); + return -EINVAL; + } if (dev_priv->flags & RADEON_IS_IGPGART) dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; else @@ -1185,12 +1301,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) DRM_ATI_GART_MAIN; dev_priv->gart_info.addr = NULL; dev_priv->gart_info.bus_addr = 0; - if (dev_priv->flags & RADEON_IS_PCIE) { - DRM_ERROR - ("Cannot use PCI Express without GART in FB memory\n"); - radeon_do_cleanup_cp(dev); - return -EINVAL; - } + } if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) { @@ -1253,8 +1364,10 @@ static int radeon_do_cleanup_cp(struct drm_device * dev) if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { - drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = 0; + if (dev_priv->pcigart_offset_set == 1) { + drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); + dev_priv->gart_info.addr = NULL; + } } } /* only clear to the start of flags */ @@ -1305,6 +1418,10 @@ static int radeon_do_resume_cp(struct drm_device * dev) int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_init_t *init = data; + + /* on a modesetting driver ignore this stuff */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -1315,7 +1432,7 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri case RADEON_INIT_CP: case RADEON_INIT_R200_CP: case RADEON_INIT_R300_CP: - return radeon_do_init_cp(dev, init); + return radeon_do_init_cp(dev, init, file_priv); case RADEON_CLEANUP_CP: return radeon_do_cleanup_cp(dev); } @@ -1328,6 +1445,9 @@ int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_pr drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (dev_priv->cp_running) { @@ -1355,6 +1475,9 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri int ret; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv->cp_running) @@ -1393,6 +1516,9 @@ void radeon_do_release(struct drm_device * dev) drm_radeon_private_t *dev_priv = dev->dev_private; int i, ret; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + if (dev_priv) { if (dev_priv->cp_running) { /* Stop the cp */ @@ -1431,6 +1557,9 @@ void radeon_do_release(struct drm_device * dev) radeon_mem_takedown(&(dev_priv->gart_heap)); radeon_mem_takedown(&(dev_priv->fb_heap)); + + radeon_gem_mm_fini(dev); + /* deallocate kernel resources */ radeon_do_cleanup_cp(dev); } @@ -1443,6 +1572,9 @@ int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_pr drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { @@ -1463,7 +1595,9 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, file_priv); + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + LOCK_TEST_WITH_RETURN(dev, file_priv); return radeon_do_cp_idle(dev_priv); } @@ -1473,6 +1607,9 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + return radeon_do_resume_cp(dev); } @@ -1480,6 +1617,9 @@ int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *fil { DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); return radeon_do_engine_reset(dev); @@ -1702,6 +1842,541 @@ int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_ return ret; } +static void radeon_get_vram_type(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + if (dev_priv->flags & RADEON_IS_IGP || (dev_priv->chip_family >= CHIP_R300)) + dev_priv->is_ddr = true; + else if (RADEON_READ(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR) + dev_priv->is_ddr = true; + else + dev_priv->is_ddr = false; + + if ((dev_priv->chip_family >= CHIP_R600) && + (dev_priv->chip_family <= CHIP_RV635)) { + int chansize; + + tmp = RADEON_READ(R600_RAMCFG); + if (tmp & R600_CHANSIZE_OVERRIDE) + chansize = 16; + else if (tmp & R600_CHANSIZE) + chansize = 64; + else + chansize = 32; + + if (dev_priv->chip_family == CHIP_R600) + dev_priv->ram_width = 8 * chansize; + else if (dev_priv->chip_family == CHIP_RV670) + dev_priv->ram_width = 4 * chansize; + else if ((dev_priv->chip_family == CHIP_RV610) || + (dev_priv->chip_family == CHIP_RV620)) + dev_priv->ram_width = chansize; + else if ((dev_priv->chip_family == CHIP_RV630) || + (dev_priv->chip_family == CHIP_RV635)) + dev_priv->ram_width = 2 * chansize; + } else if (dev_priv->chip_family == CHIP_RV515) { + tmp = radeon_read_mc_reg(dev_priv, RV515_MC_CNTL); + tmp &= RV515_MEM_NUM_CHANNELS_MASK; + switch (tmp) { + case 0: dev_priv->ram_width = 64; break; + case 1: dev_priv->ram_width = 128; break; + default: dev_priv->ram_width = 128; break; + } + } else if ((dev_priv->chip_family >= CHIP_R520) && + (dev_priv->chip_family <= CHIP_RV570)) { + tmp = radeon_read_mc_reg(dev_priv, R520_MC_CNTL0); + switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) { + case 0: dev_priv->ram_width = 32; break; + case 1: dev_priv->ram_width = 64; break; + case 2: dev_priv->ram_width = 128; break; + case 3: dev_priv->ram_width = 256; break; + default: dev_priv->ram_width = 128; break; + } + } else if ((dev_priv->chip_family == CHIP_RV100) || + (dev_priv->chip_family == CHIP_RS100) || + (dev_priv->chip_family == CHIP_RS200)) { + tmp = RADEON_READ(RADEON_MEM_CNTL); + if (tmp & RV100_HALF_MODE) + dev_priv->ram_width = 32; + else + dev_priv->ram_width = 64; + + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + dev_priv->ram_width /= 4; + dev_priv->is_ddr = true; + } + } else if (dev_priv->chip_family <= CHIP_RV280) { + tmp = RADEON_READ(RADEON_MEM_CNTL); + if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) + dev_priv->ram_width = 128; + else + dev_priv->ram_width = 64; + } else { + /* newer IGPs */ + dev_priv->ram_width = 128; + } + DRM_DEBUG("RAM width %d bits %cDR\n", dev_priv->ram_width, dev_priv->is_ddr ? 'D' : 'S'); +} + +static void radeon_force_some_clocks(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); +} + +static void radeon_set_dynamic_clock(struct drm_device *dev, int mode) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + switch(mode) { + case 0: + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_E2 | RADEON_SCLK_FORCE_SE | + RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_VIP | + RADEON_SCLK_FORCE_RE | RADEON_SCLK_FORCE_PB | + RADEON_SCLK_FORCE_TAM | RADEON_SCLK_FORCE_TDM | + RADEON_SCLK_FORCE_RB); + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + } else if (dev_priv->chip_family == CHIP_RV350) { + /* for RV350/M10, no delays are required. */ + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp |= (R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | + R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | + R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | + R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); + tmp |= RADEON_DYN_STOP_LAT_MASK; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_E2); + tmp |= RADEON_SCLK_FORCE_SE; + + if ( dev_priv->flags & RADEON_SINGLE_CRTC ) { + tmp |= ( RADEON_SCLK_FORCE_RB | + RADEON_SCLK_FORCE_TDM | + RADEON_SCLK_FORCE_TAM | + RADEON_SCLK_FORCE_PB | + RADEON_SCLK_FORCE_RE | + RADEON_SCLK_FORCE_VIP | + RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_HDP ); + } else if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350)) { + tmp |= ( RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP); + } + + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + udelay(16000); + + if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350)) { + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp |= ( R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + udelay(16000); + } + + if (dev_priv->flags & RADEON_IS_IGP) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + tmp &= ~(RADEON_FORCEON_MCLKA | + RADEON_FORCEON_YCLKA); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, tmp); + udelay(16000); + } + + if ((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250) || + (dev_priv->chip_family == CHIP_RV280)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp |= RADEON_SCLK_MORE_FORCEON; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + udelay(16000); + } + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + udelay(16000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + } + DRM_DEBUG("Dynamic Clock Scaling Disabled\n"); + break; + case 1: + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + if ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) > + RADEON_CFG_ATI_REV_A13) { + tmp &= ~(RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_RB); + } + tmp &= ~(RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_SE | + RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_RE | + RADEON_SCLK_FORCE_PB | RADEON_SCLK_FORCE_TAM | + RADEON_SCLK_FORCE_TDM); + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + } else if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350) || + (dev_priv->chip_family == CHIP_RV350)) { + if (dev_priv->chip_family == CHIP_RV350) { + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp &= ~(R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + tmp |= (R300_SCLK_TCL_MAX_DYN_STOP_LAT | + R300_SCLK_GA_MAX_DYN_STOP_LAT | + R300_SCLK_CBA_MAX_DYN_STOP_LAT); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | + R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | + R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | + R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); + tmp |= RADEON_DYN_STOP_LAT_MASK; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_MISC); + tmp |= (RADEON_MC_MCLK_DYN_ENABLE | + RADEON_IO_MCLK_DYN_ENABLE); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_MISC, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + tmp |= (RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB); + + tmp &= ~(RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | + RADEON_FORCEON_MC); + + /* Some releases of vbios have set DISABLE_MC_MCLKA + and DISABLE_MC_MCLKB bits in the vbios table. Setting these + bits will cause H/W hang when reading video memory with dynamic clocking + enabled. */ + if ((tmp & R300_DISABLE_MC_MCLKA) && + (tmp & R300_DISABLE_MC_MCLKB)) { + /* If both bits are set, then check the active channels */ + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + if (dev_priv->ram_width == 64) { + if (RADEON_READ(RADEON_MEM_CNTL) & R300_MEM_USE_CD_CH_ONLY) + tmp &= ~R300_DISABLE_MC_MCLKB; + else + tmp &= ~R300_DISABLE_MC_MCLKA; + } else { + tmp &= ~(R300_DISABLE_MC_MCLKA | + R300_DISABLE_MC_MCLKB); + } + } + + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, tmp); + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(R300_SCLK_FORCE_VAP); + tmp |= RADEON_SCLK_FORCE_CP; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp &= ~(R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + } + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL); + tmp &= ~(RADEON_ACTIVE_HILO_LAT_MASK | + RADEON_DISP_DYN_STOP_LAT_MASK | + RADEON_DYN_STOP_MODE_MASK); + + tmp |= (RADEON_ENGIN_DYNCLK_MODE | + (0x01 << RADEON_ACTIVE_HILO_LAT_SHIFT)); + RADEON_WRITE_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_CLK_PIN_CNTL); + tmp |= RADEON_SCLK_DYN_START_CNTL; + RADEON_WRITE_PLL(dev_priv, RADEON_CLK_PIN_CNTL, tmp); + udelay(15000); + + /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200 + to lockup randomly, leave them as set by BIOS. + */ + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + /*tmp &= RADEON_SCLK_SRC_SEL_MASK;*/ + tmp &= ~RADEON_SCLK_FORCEON_MASK; + + /*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300*/ + if (((dev_priv->chip_family == CHIP_RV250) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) || + ((dev_priv->chip_family == CHIP_RV100) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <= + RADEON_CFG_ATI_REV_A13))){ + tmp |= RADEON_SCLK_FORCE_CP; + tmp |= RADEON_SCLK_FORCE_VIP; + } + + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + if ((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250) || + (dev_priv->chip_family == CHIP_RV280)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + + /* RV200::A11 A12 RV250::A11 A12 */ + if (((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250)) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) { + tmp |= RADEON_SCLK_MORE_FORCEON; + } + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + udelay(15000); + } + + /* RV200::A11 A12, RV250::A11 A12 */ + if (((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250)) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_PLL_PWRMGT_CNTL); + tmp |= RADEON_TCL_BYPASS_DISABLE; + RADEON_WRITE_PLL(dev_priv, RADEON_PLL_PWRMGT_CNTL, tmp); + } + udelay(15000); + + /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK)*/ + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + udelay(15000); + } + DRM_DEBUG("Dynamic Clock Scaling Enabled\n"); + break; + default: + break; + } + +} + +int radeon_modeset_cp_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + /* allocate a ring and ring rptr bits from GART space */ + /* these are allocated in GEM files */ + + dev_priv->usec_timeout = RADEON_DEFAULT_CP_TIMEOUT; + dev_priv->ring.size = RADEON_DEFAULT_RING_SIZE; + dev_priv->cp_mode = RADEON_CSQ_PRIBM_INDBM; + + dev_priv->ring.start = (u32 *)(void *)(unsigned long)dev_priv->mm.ring_map.virtual; + dev_priv->ring.end = (u32 *)(void *)(unsigned long)dev_priv->mm.ring_map.virtual + + dev_priv->ring.size / sizeof(u32); + dev_priv->ring.size_l2qw = drm_order(dev_priv->ring.size / 8); + dev_priv->ring.rptr_update = 4096; + dev_priv->ring.rptr_update_l2qw = drm_order(4096 / 8); + dev_priv->ring.fetch_size = 32; + dev_priv->ring.fetch_size_l2ow = drm_order(32 / 16); + dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; + dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; + + dev_priv->new_memmap = 1; + + radeon_cp_load_microcode(dev_priv); + + DRM_DEBUG("ring offset is %x %x\n", dev_priv->mm.ring->offset, dev_priv->mm.ring_read_ptr->offset); + + radeon_cp_init_ring_buffer(dev, dev_priv); + + radeon_do_engine_reset(dev); + radeon_test_writeback(dev_priv); + + radeon_do_cp_start(dev_priv); + return 0; +} + +static bool radeon_get_bios(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + u8 __iomem *bios; + size_t size; + uint16_t tmp; + + bios = pci_map_rom(dev->pdev, &size); + if (!bios) + return -1; + + dev_priv->bios = kmalloc(size, GFP_KERNEL); + if (!dev_priv->bios) { + pci_unmap_rom(dev->pdev, bios); + return -1; + } + + memcpy(dev_priv->bios, bios, size); + + pci_unmap_rom(dev->pdev, bios); + + if (dev_priv->bios[0] != 0x55 || dev_priv->bios[1] != 0xaa) + goto free_bios; + + dev_priv->bios_header_start = radeon_bios16(dev_priv, 0x48); + + if (!dev_priv->bios_header_start) + goto free_bios; + + tmp = dev_priv->bios_header_start + 4; + + if (!memcmp(dev_priv->bios + tmp, "ATOM", 4) || + !memcmp(dev_priv->bios + tmp, "MOTA", 4)) + dev_priv->is_atom_bios = true; + else + dev_priv->is_atom_bios = false; + + DRM_DEBUG("%sBIOS detected\n", dev_priv->is_atom_bios ? "ATOM" : "COM"); + return true; +free_bios: + kfree(dev_priv->bios); + dev_priv->bios = NULL; + return false; +} + +int radeon_modeset_preinit(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + static struct card_info card; + int ret; + + card.dev = dev; + card.reg_read = cail_reg_read; + card.reg_write = cail_reg_write; + card.mc_read = cail_mc_read; + card.mc_write = cail_mc_write; + + ret = radeon_get_bios(dev); + if (!ret) + return -1; + + if (dev_priv->is_atom_bios) { + dev_priv->mode_info.atom_context = atom_parse(&card, dev_priv->bios); + radeon_get_clock_info(dev); + } + return 0; +} + + int radeon_driver_load(struct drm_device *dev, unsigned long flags) { drm_radeon_private_t *dev_priv; @@ -1734,6 +2409,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) break; } + dev_priv->chip_family = flags & RADEON_FAMILY_MASK; if (drm_device_is_agp(dev)) dev_priv->flags |= RADEON_IS_AGP; else if (drm_device_is_pcie(dev)) @@ -1741,11 +2417,122 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) else dev_priv->flags |= RADEON_IS_PCI; + + DRM_DEBUG("%s card detected\n", ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); + + ret = drm_addmap(dev, drm_get_resource_start(dev, 2), + drm_get_resource_len(dev, 2), _DRM_REGISTERS, + _DRM_DRIVER | _DRM_READ_ONLY, &dev_priv->mmio); + if (ret != 0) + return ret; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + radeon_modeset_preinit(dev); + + + radeon_get_vram_type(dev); + + dev_priv->pll_errata = 0; + + if (dev_priv->chip_family == CHIP_R300 && + (RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) == RADEON_CFG_ATI_REV_A11) + dev_priv->pll_errata |= CHIP_ERRATA_R300_CG; + + if (dev_priv->chip_family == CHIP_RV200 || + dev_priv->chip_family == CHIP_RS200) + dev_priv->pll_errata |= CHIP_ERRATA_PLL_DUMMYREADS; + + + if (dev_priv->chip_family == CHIP_RV100 || + dev_priv->chip_family == CHIP_RS100 || + dev_priv->chip_family == CHIP_RS200) + dev_priv->pll_errata |= CHIP_ERRATA_PLL_DELAY; + + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + if ((dev_priv->flags & RADEON_IS_MOBILITY) && !radeon_is_avivo(dev_priv)) { + radeon_set_dynamic_clock(dev, radeon_dynclks); + } else if (radeon_is_avivo(dev_priv)) { + if (radeon_dynclks) { + radeon_atom_static_pwrmgt_setup(dev, 1); + radeon_atom_dyn_clk_setup(dev, 1); + } + } + radeon_force_some_clocks(dev); + } + + /* init memory manager - start with all of VRAM and a 32MB GART aperture for now */ + dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); + + drm_bo_driver_init(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + + dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16; + dev_priv->fb_size = + ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000) + - dev_priv->fb_location; + radeon_gem_mm_init(dev); + radeon_modeset_init(dev); + + radeon_modeset_cp_init(dev); + dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); + + drm_irq_install(dev); + } + + return ret; } + +int radeon_master_create(struct drm_device *dev, struct drm_master *master) +{ + struct drm_radeon_master_private *master_priv; + unsigned long sareapage; + int ret; + + master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + if (!master_priv) + return -ENOMEM; + + /* prebuild the SAREA */ + sareapage = max(SAREA_MAX, PAGE_SIZE); + ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER, + &master_priv->sarea); + if (ret) { + DRM_ERROR("SAREA setup failed\n"); + return ret; + } + master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea); + master_priv->sarea_priv->pfCurrentPage = 0; + + master->driver_priv = master_priv; + return 0; +} + +void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) +{ + struct drm_radeon_master_private *master_priv = master->driver_priv; + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (!master_priv) + return; + + if (master_priv->sarea_priv && + master_priv->sarea_priv->pfCurrentPage != 0) + radeon_cp_dispatch_flip(dev, master); + + master_priv->sarea_priv = NULL; + if (master_priv->sarea) + drm_rmmap(dev, master_priv->sarea); + + drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + + master->driver_priv = NULL; +} /* Create mappings for registers and framebuffer so userland doesn't necessarily * have to find them. */ @@ -1757,13 +2544,9 @@ int radeon_driver_firstopen(struct drm_device *dev) dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; - ret = drm_addmap(dev, drm_get_resource_start(dev, 2), - drm_get_resource_len(dev, 2), _DRM_REGISTERS, - _DRM_READ_ONLY, &dev_priv->mmio); - if (ret != 0) - return ret; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + radeon_gem_mm_init(dev); - dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); ret = drm_addmap(dev, dev_priv->fb_aper_offset, drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING, &map); @@ -1777,9 +2560,40 @@ int radeon_driver_unload(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_irq_uninstall(dev); + radeon_modeset_cleanup(dev); + radeon_gem_mm_fini(dev); + } + + drm_bo_driver_finish(dev); + drm_rmmap(dev, dev_priv->mmio); + DRM_DEBUG("\n"); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); dev->dev_private = NULL; return 0; } + +void radeon_gart_flush(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (dev_priv->flags & RADEON_IS_IGPGART) { + IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, RS480_GART_CACHE_INVALIDATE); + IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0); + } else if (dev_priv->flags & RADEON_IS_PCIE) { + u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); + tmp |= RADEON_PCIE_TX_GART_INVALIDATE_TLB; + RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + tmp &= ~RADEON_PCIE_TX_GART_INVALIDATE_TLB; + RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + } else { + + + } + +} diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index 81944061..7fcf9305 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -457,12 +457,6 @@ typedef struct { unsigned int last_fence; } drm_radeon_sarea_t; -/* The only fence class we support */ -#define DRM_RADEON_FENCE_CLASS_ACCEL 0 -/* Fence type that guarantees read-write flush */ -#define DRM_RADEON_FENCE_TYPE_RW 2 -/* cache flushes programmed just before the fence */ -#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000 /* WARNING: If you change any of these defines, make sure to change the * defines in the Xserver file (xf86drmRadeon.h) @@ -502,6 +496,17 @@ typedef struct { #define DRM_RADEON_SURF_ALLOC 0x1a #define DRM_RADEON_SURF_FREE 0x1b +#define DRM_RADEON_GEM_INFO 0x1c +#define DRM_RADEON_GEM_CREATE 0x1d +#define DRM_RADEON_GEM_MMAP 0x1e +#define DRM_RADEON_GEM_PIN 0x1f +#define DRM_RADEON_GEM_UNPIN 0x20 +#define DRM_RADEON_GEM_PREAD 0x21 +#define DRM_RADEON_GEM_PWRITE 0x22 +#define DRM_RADEON_GEM_SET_DOMAIN 0x23 +#define DRM_RADEON_GEM_INDIRECT 0x24 // temporary for X server + + #define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t) #define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START) #define DRM_IOCTL_RADEON_CP_STOP DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_STOP, drm_radeon_cp_stop_t) @@ -530,6 +535,18 @@ typedef struct { #define DRM_IOCTL_RADEON_SURF_ALLOC DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_ALLOC, drm_radeon_surface_alloc_t) #define DRM_IOCTL_RADEON_SURF_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_FREE, drm_radeon_surface_free_t) +#define DRM_IOCTL_RADEON_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INFO, struct drm_radeon_gem_info) +#define DRM_IOCTL_RADEON_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_CREATE, struct drm_radeon_gem_create) +#define DRM_IOCTL_RADEON_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_MMAP, struct drm_radeon_gem_mmap) +#define DRM_IOCTL_RADEON_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PIN, struct drm_radeon_gem_pin) +#define DRM_IOCTL_RADEON_GEM_UNPIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_UNPIN, struct drm_radeon_gem_unpin) +#define DRM_IOCTL_RADEON_GEM_PREAD DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PREAD, struct drm_radeon_gem_pread) +#define DRM_IOCTL_RADEON_GEM_PWRITE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PWRITE, struct drm_radeon_gem_pwrite) +#define DRM_IOCTL_RADEON_GEM_SET_DOMAIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_DOMAIN, struct drm_radeon_gem_set_domain) +#define DRM_IOCTL_RADEON_GEM_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INDIRECT, struct drm_radeon_gem_indirect) + + + typedef struct drm_radeon_init { enum { RADEON_INIT_CP = 0x01, @@ -756,4 +773,92 @@ typedef struct drm_radeon_surface_free { #define DRM_RADEON_VBLANK_CRTC1 1 #define DRM_RADEON_VBLANK_CRTC2 2 +#define RADEON_GEM_DOMAIN_CPU 0x1 +#define RADEON_GEM_DOMAIN_VRAM 0x2 +#define RADEON_GEM_DOMAIN_2D 0x4 +#define RADEON_GEM_DOMAIN_3D 0x8 +#define RADEON_GEM_DOMAIN_TEXTURE 0x10 +#define RADEON_GEM_DOMAIN_GPU 0x20 // for vertex buffers + +/* return to userspace start/size of gtt and vram apertures */ +struct drm_radeon_gem_info { + uint64_t gart_start; + uint64_t gart_size; + uint64_t vram_start; + uint64_t vram_size; + uint64_t vram_visible; +}; + +struct drm_radeon_gem_create { + uint64_t size; + uint64_t alignment; + uint32_t handle; + uint32_t initial_domain; // to allow VRAM to be created + uint32_t no_backing_store; // for VRAM objects - select whether they need backing store + // pretty much front/back/depth don't need it - other things do +}; + +struct drm_radeon_gem_mmap { + uint32_t handle; + uint32_t pad; + uint64_t offset; + uint64_t size; + uint64_t addr_ptr; +}; + +struct drm_radeon_gem_set_domain { + uint32_t handle; + uint32_t read_domains; + uint32_t write_domain; +}; + +struct drm_radeon_gem_exec_buffer { +}; + +struct drm_radeon_gem_pin { + uint32_t handle; + uint32_t pad; + uint64_t alignment; + uint64_t offset; +}; + +struct drm_radeon_gem_unpin { + uint32_t handle; + uint32_t pad; +}; + +struct drm_radeon_gem_busy { + uint32_t handle; + uint32_t busy; +}; + +struct drm_radeon_gem_pread { + /** Handle for the object being read. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to read from */ + uint64_t offset; + /** Length of data to read */ + uint64_t size; + /** Pointer to write the data into. */ + uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_radeon_gem_pwrite { + /** Handle for the object being written to. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to write to */ + uint64_t offset; + /** Length of data to write */ + uint64_t size; + /** Pointer to read the data from. */ + uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ +}; + +struct drm_radeon_gem_indirect { + uint32_t handle; + uint32_t used; +}; + #endif diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index e263c610..b8f49404 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -31,6 +31,7 @@ #ifndef __RADEON_DRV_H__ #define __RADEON_DRV_H__ +#include "atom.h" /* General customization: */ @@ -96,13 +97,13 @@ * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL, * new packet type) * 1.26- Add support for variable size PCI(E) gart aperture - * 1.27- Add support for IGP GART + * 1.27- Add support for IGPGART * 1.28- Add support for VBL on CRTC2 * 1.29- R500 3D cmd buffer support */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 29 +#define DRIVER_MINOR 30 #define DRIVER_PATCHLEVEL 0 /* @@ -124,23 +125,29 @@ enum radeon_family { CHIP_RV380, CHIP_R420, CHIP_RV410, + CHIP_RS400, CHIP_RS480, + CHIP_RS600, CHIP_RS690, + CHIP_RS740, CHIP_RV515, CHIP_R520, CHIP_RV530, CHIP_RV560, CHIP_RV570, CHIP_R580, + CHIP_R600, + CHIP_R630, + CHIP_RV610, + CHIP_RV630, + CHIP_RV670, + CHIP_RV620, + CHIP_RV635, + CHIP_RS780, + CHIP_RV770, CHIP_LAST, }; -enum radeon_cp_microcode_version { - UCODE_R100, - UCODE_R200, - UCODE_R300, -}; - /* * Chip flags */ @@ -158,9 +165,42 @@ enum radeon_chip_flags { RADEON_IS_IGPGART = 0x01000000UL, }; +/* + * Errata workarounds + */ +enum radeon_pll_errata { + CHIP_ERRATA_R300_CG = 0x00000001, + CHIP_ERRATA_PLL_DUMMYREADS = 0x00000002, + CHIP_ERRATA_PLL_DELAY = 0x00000004 +}; + +enum radeon_ext_tmds_chip { + RADEON_DVOCHIP_NONE, + RADEON_SIL_164, + RADEON_SIL_1178 +}; + +#if defined(__powerpc__) +enum radeon_mac_model { + RADEON_MAC_NONE, + RADEON_MAC_IBOOK, + RADEON_MAC_POWERBOOK_EXTERNAL, + RADEON_MAC_POWERBOOK_INTERNAL, + RADEON_MAC_POWERBOOK_VGA, + RADEON_MAC_MINI_EXTERNAL, + RADEON_MAC_MINI_INTERNAL, + RADEON_MAC_IMAC_G5_ISIGHT +}; +#endif + + #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ - DRM_READ32( (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR)) -#define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) + (dev_priv->mm.ring_read_ptr ? readl(dev_priv->mm.ring_read_ptr_map.virtual + 0) : DRM_READ32((dev_priv)->ring_rptr, 0 )) : \ + RADEON_READ(RADEON_CP_RB_RPTR)) + +#define SET_RING_HEAD(dev_priv,val) (dev_priv->mm.ring_read_ptr ? \ + writel((val), dev_priv->mm.ring_read_ptr_map.virtual) : \ + DRM_WRITE32((dev_priv)->ring_rptr, 0, (val))) typedef struct drm_radeon_freelist { unsigned int age; @@ -221,13 +261,35 @@ struct radeon_virt_surface { struct drm_file *file_priv; }; +struct radeon_mm_info { + uint64_t vram_offset; // Offset into GPU space + uint64_t vram_size; + uint64_t vram_visible; + + uint64_t gart_start; + uint64_t gart_size; + + struct drm_buffer_object *pcie_table; + struct drm_bo_kmap_obj pcie_table_map; + + struct drm_buffer_object *ring; + struct drm_bo_kmap_obj ring_map; + + struct drm_buffer_object *ring_read_ptr; + struct drm_bo_kmap_obj ring_read_ptr_map; +}; + +#include "radeon_mode.h" + +struct drm_radeon_master_private { + drm_local_map_t *sarea; + drm_radeon_sarea_t *sarea_priv; +}; + typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; - drm_radeon_sarea_t *sarea_priv; - u32 fb_location; - u32 fb_size; int new_memmap; int gart_size; @@ -245,8 +307,6 @@ typedef struct drm_radeon_private { int usec_timeout; - int microcode_version; - struct { u32 boxes; int freelist_timeouts; @@ -282,8 +342,6 @@ typedef struct drm_radeon_private { unsigned long buffers_offset; unsigned long gart_textures_offset; - drm_local_map_t *sarea; - drm_local_map_t *mmio; drm_local_map_t *cp_ring; drm_local_map_t *ring_rptr; drm_local_map_t *gart_textures; @@ -292,8 +350,8 @@ typedef struct drm_radeon_private { struct mem_block *fb_heap; /* SW interrupt */ + int counter; wait_queue_head_t swi_queue; - atomic_t swi_emitted; int vblank_crtc; uint32_t irq_enable_reg; int irq_enabled; @@ -302,9 +360,6 @@ typedef struct drm_radeon_private { struct radeon_surface surfaces[RADEON_MAX_SURFACES]; struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES]; - unsigned long pcigart_offset; - unsigned int pcigart_offset_set; - struct drm_ati_pcigart_info gart_info; u32 scratch_ages[5]; @@ -316,6 +371,28 @@ typedef struct drm_radeon_private { unsigned long fb_aper_offset; int num_gb_pipes; + + struct radeon_mm_info mm; + drm_local_map_t *mmio; + + uint32_t chip_family; + + unsigned long pcigart_offset; + unsigned int pcigart_offset_set; + struct drm_ati_pcigart_info gart_info; + + struct radeon_mode_info mode_info; + + uint8_t *bios; /* copy of the BIOS image */ + bool is_atom_bios; + uint16_t bios_header_start; + u32 fb_location; + u32 fb_size; + bool is_ddr; + u32 ram_width; + + enum radeon_pll_errata pll_errata; + } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { @@ -330,6 +407,7 @@ typedef struct drm_radeon_kcmd_buffer { } drm_radeon_kcmd_buffer_t; extern int radeon_no_wb; +extern int radeon_dynclks; extern struct drm_ioctl_desc radeon_ioctls[]; extern int radeon_max_ioctl; @@ -417,9 +495,14 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_BOX_WAIT_IDLE 0x8 #define RADEON_BOX_TEXTURE_LOAD 0x10 +#define R600_CONFIG_MEMSIZE 0x5428 +#define R600_CONFIG_APER_SIZE 0x5430 /* Register definitions, register access macros and drmAddMap constants * for Radeon kernel driver. */ + +#include "radeon_reg.h" + #define RADEON_AGP_COMMAND 0x0f60 #define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config */ # define RADEON_AGP_ENABLE (1<<8) @@ -522,16 +605,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define R520_MC_IND_WR_EN (1 << 24) #define R520_MC_IND_DATA 0x74 -#define RV515_MC_FB_LOCATION 0x01 -#define RV515_MC_AGP_LOCATION 0x02 -#define RV515_MC_AGP_BASE 0x03 -#define RV515_MC_AGP_BASE_2 0x04 - -#define R520_MC_FB_LOCATION 0x04 -#define R520_MC_AGP_LOCATION 0x05 -#define R520_MC_AGP_BASE 0x06 -#define R520_MC_AGP_BASE_2 0x07 - #define RADEON_MPP_TB_CONFIG 0x01c0 #define RADEON_MEM_CNTL 0x0140 #define RADEON_MEM_SDRAM_MODE_REG 0x0158 @@ -601,9 +674,11 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_SCRATCHOFF( x ) (RADEON_SCRATCH_REG_OFFSET + 4*(x)) -#define GET_SCRATCH( x ) (dev_priv->writeback_works \ - ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ - : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) +#define GET_SCRATCH( x ) (dev_priv->writeback_works ? \ + (dev_priv->mm.ring_read_ptr ? \ + readl(dev_priv->mm.ring_read_ptr_map.virtual + RADEON_SCRATCHOFF(0)) : \ + DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(x))) : \ + RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x))) #define RADEON_CRTC_CRNT_FRAME 0x0214 #define RADEON_CRTC2_CRNT_FRAME 0x0314 @@ -628,11 +703,11 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, # define RADEON_SW_INT_FIRE (1 << 26) # define R500_DISPLAY_INT_STATUS (1 << 0) +#define RADEON_HOST_PATH_CNTL 0x0130 +# define RADEON_HDP_SOFT_RESET (1 << 26) +# define RADEON_HDP_APER_CNTL (1 << 23) -#define RADEON_HOST_PATH_CNTL 0x0130 -# define RADEON_HDP_SOFT_RESET (1 << 26) -# define RADEON_HDP_WC_TIMEOUT_MASK (7 << 28) -# define RADEON_HDP_WC_TIMEOUT_28BCLK (7 << 28) +#define RADEON_NB_TOM 0x15c #define RADEON_ISYNC_CNTL 0x1724 # define RADEON_ISYNC_ANY2D_IDLE3D (1 << 0) @@ -703,11 +778,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, # define R300_ZC_FREE (1 << 1) # define R300_ZC_FLUSH_ALL 0x3 # define R300_ZC_BUSY (1 << 31) -#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c -# define RADEON_RB3D_DC_FLUSH (3 << 0) -# define RADEON_RB3D_DC_FREE (3 << 2) -# define RADEON_RB3D_DC_FLUSH_ALL 0xf -# define RADEON_RB3D_DC_BUSY (1 << 31) #define R300_RB3D_DSTCACHE_CTLSTAT 0x4e4c # define R300_RB3D_DC_FINISH (1 << 4) #define RADEON_RB3D_ZSTENCILCNTL 0x1c2c @@ -981,27 +1051,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_NUM_VERTICES_SHIFT 16 #define RADEON_COLOR_FORMAT_CI8 2 -#define RADEON_COLOR_FORMAT_ARGB1555 3 -#define RADEON_COLOR_FORMAT_RGB565 4 -#define RADEON_COLOR_FORMAT_ARGB8888 6 -#define RADEON_COLOR_FORMAT_RGB332 7 -#define RADEON_COLOR_FORMAT_RGB8 9 -#define RADEON_COLOR_FORMAT_ARGB4444 15 - -#define RADEON_TXFORMAT_I8 0 -#define RADEON_TXFORMAT_AI88 1 -#define RADEON_TXFORMAT_RGB332 2 -#define RADEON_TXFORMAT_ARGB1555 3 -#define RADEON_TXFORMAT_RGB565 4 -#define RADEON_TXFORMAT_ARGB4444 5 -#define RADEON_TXFORMAT_ARGB8888 6 -#define RADEON_TXFORMAT_RGBA8888 7 -#define RADEON_TXFORMAT_Y8 8 -#define RADEON_TXFORMAT_VYUY422 10 -#define RADEON_TXFORMAT_YVYU422 11 -#define RADEON_TXFORMAT_DXT1 12 -#define RADEON_TXFORMAT_DXT23 14 -#define RADEON_TXFORMAT_DXT45 15 #define R200_PP_TXCBLEND_0 0x2f00 #define R200_PP_TXCBLEND_1 0x2f10 @@ -1187,18 +1236,16 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_RING_HIGH_MARK 128 #define RADEON_PCIGART_TABLE_SIZE (32*1024) +#define RADEON_DEFAULT_RING_SIZE (1024*1024) +#define RADEON_DEFAULT_CP_TIMEOUT 100000 /* usecs */ #define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) #define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) #define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) #define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) -#define RADEON_WRITE_PLL( addr, val ) \ -do { \ - RADEON_WRITE8( RADEON_CLOCK_CNTL_INDEX, \ - ((addr) & 0x1f) | RADEON_PLL_WR_EN ); \ - RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \ -} while (0) +extern int RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr); +extern void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data); #define RADEON_WRITE_PCIE( addr, val ) \ do { \ @@ -1311,7 +1358,7 @@ do { \ OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ OUT_RING( RADEON_RB3D_ZC_FLUSH_ALL ); \ } else { \ - OUT_RING( CP_PACKET0( R300_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ + OUT_RING( CP_PACKET0( R300_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ OUT_RING( R300_ZC_FLUSH_ALL ); \ } \ } while (0) @@ -1333,7 +1380,8 @@ do { \ #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ do { \ - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; \ + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \ + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \ if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ int __ret = radeon_do_cp_idle( dev_priv ); \ if ( __ret ) return __ret; \ @@ -1439,4 +1487,110 @@ do { \ write &= mask; \ } while (0) +/* radeon GEM->TTM munger */ +struct drm_radeon_gem_object { + /* wrap a TTM bo */ + struct drm_buffer_object *bo; + struct drm_fence_object *fence; + struct drm_gem_object *obj; + +}; + +extern int radeon_gem_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern void radeon_fence_handler(struct drm_device *dev); +extern int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type); +extern void radeon_poke_flush(struct drm_device *dev, uint32_t class); +extern int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags); + +/* radeon_buffer.c */ +extern struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device *dev); +extern int radeon_fence_types(struct drm_buffer_object *bo, uint32_t *class, uint32_t *type); +extern int radeon_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags); +extern int radeon_init_mem_type(struct drm_device * dev, uint32_t type, + struct drm_mem_type_manager * man); +extern int radeon_move(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg * new_mem); + +extern void radeon_gart_flush(struct drm_device *dev); +extern uint64_t radeon_evict_flags(struct drm_buffer_object *bo); + +#define BREADCRUMB_BITS 31 +#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) + +/* Breadcrumb - swi irq */ +#define READ_BREADCRUMB(dev_priv) RADEON_READ(RADEON_LAST_SWI_REG) + +static inline int radeon_update_breadcrumb(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv; + + ++dev_priv->counter; + if (dev_priv->counter > BREADCRUMB_MASK) + dev_priv->counter = 1; + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_fence = dev_priv->counter; + } + return dev_priv->counter; +} + +#define radeon_is_avivo(dev_priv) ((dev_priv->chip_family >= CHIP_RS600)) + +#define radeon_is_dce3(dev_priv) ((dev_priv->chip_family >= CHIP_RV620)) + +#define radeon_bios8(dev_priv, v) (dev_priv->bios[v]) +#define radeon_bios16(dev_priv, v) (dev_priv->bios[v] | (dev_priv->bios[(v) + 1] << 8)) +#define radeon_bios32(dev_priv, v) ((dev_priv->bios[v]) | \ + (dev_priv->bios[(v) + 1] << 8) | \ + (dev_priv->bios[(v) + 2] << 16) | \ + (dev_priv->bios[(v) + 3] << 24)) + +extern int radeon_emit_irq(struct drm_device * dev); + +extern void radeon_gem_free_object(struct drm_gem_object *obj); +extern int radeon_gem_init_object(struct drm_gem_object *obj); +extern int radeon_gem_mm_init(struct drm_device *dev); +extern void radeon_gem_mm_fini(struct drm_device *dev); +extern int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_object_pin(struct drm_gem_object *obj, + uint32_t alignment); +int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, + int initial_domain); +int radeon_modeset_init(struct drm_device *dev); +void radeon_modeset_cleanup(struct drm_device *dev); +extern u32 radeon_read_mc_reg(drm_radeon_private_t *dev_priv, int addr); +extern void radeon_write_mc_reg(drm_radeon_private_t *dev_priv, u32 addr, u32 val); + +extern void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on); +#define RADEONFB_CONN_LIMIT 4 + +extern int radeon_master_create(struct drm_device *dev, struct drm_master *master); +extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master); +extern void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master); #endif /* __RADEON_DRV_H__ */ diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index d21761fb..f5f7f75d 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -198,8 +198,10 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) stat &= dev_priv->irq_enable_reg; /* SW interrupt */ - if (stat & RADEON_SW_INT_TEST) + if (stat & RADEON_SW_INT_TEST) { DRM_WAKEUP(&dev_priv->swi_queue); + radeon_fence_handler(dev); + } /* VBLANK interrupt */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { @@ -216,14 +218,13 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_HANDLED; } -static int radeon_emit_irq(struct drm_device * dev) +int radeon_emit_irq(struct drm_device * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; unsigned int ret; RING_LOCALS; - atomic_inc(&dev_priv->swi_emitted); - ret = atomic_read(&dev_priv->swi_emitted); + ret = radeon_update_breadcrumb(dev); BEGIN_RING(4); OUT_RING_REG(RADEON_LAST_SWI_REG, ret); @@ -240,13 +241,13 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) (drm_radeon_private_t *) dev->dev_private; int ret = 0; - if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) + if (READ_BREADCRUMB(dev_priv) >= swi_nr) return 0; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, - RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); + READ_BREADCRUMB(dev_priv) >= swi_nr); return ret; } @@ -349,7 +350,6 @@ int radeon_driver_irq_postinstall(struct drm_device * dev) (drm_radeon_private_t *) dev->dev_private; int ret; - atomic_set(&dev_priv->swi_emitted, 0); DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); ret = drm_vblank_init(dev, 2); diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 1d550a9f..6de4b135 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -305,8 +305,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * case RADEON_CP_3D_DRAW_INDX_2: case RADEON_3D_CLEAR_HIZ: /* safe but r200 only */ - if (dev_priv->microcode_version != UCODE_R200) { - DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + if ((dev_priv->chip_family < CHIP_R200) || + (dev_priv->chip_family > CHIP_RV280)) { + DRM_ERROR("Invalid 3d packet for non r200-class chip\n"); return -EINVAL; } break; @@ -359,8 +360,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * break; case RADEON_3D_RNDR_GEN_INDX_PRIM: - if (dev_priv->microcode_version != UCODE_R100) { - DRM_ERROR("Invalid 3d packet for r200-class chip\n"); + if (dev_priv->chip_family > CHIP_RS200) { + DRM_ERROR("Invalid 3d packet for non-r100-class chip\n"); return -EINVAL; } if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) { @@ -370,8 +371,10 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * break; case RADEON_CP_INDX_BUFFER: - if (dev_priv->microcode_version != UCODE_R200) { - DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + /* safe but r200 only */ + if ((dev_priv->chip_family < CHIP_R200) || + (dev_priv->chip_family > CHIP_RV280)) { + DRM_ERROR("Invalid 3d packet for non-r200-class chip\n"); return -EINVAL; } if ((cmd[1] & 0x8000ffff) != 0x80000810) { @@ -742,13 +745,14 @@ static struct { */ static void radeon_clear_box(drm_radeon_private_t * dev_priv, + struct drm_radeon_master_private *master_priv, int x, int y, int w, int h, int r, int g, int b) { u32 color; RING_LOCALS; - x += dev_priv->sarea_priv->boxes[0].x1; - y += dev_priv->sarea_priv->boxes[0].y1; + x += master_priv->sarea_priv->boxes[0].x1; + y += master_priv->sarea_priv->boxes[0].y1; switch (dev_priv->color_fmt) { case RADEON_COLOR_FORMAT_RGB565: @@ -776,7 +780,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); - if (dev_priv->sarea_priv->pfCurrentPage == 1) { + if (master_priv->sarea_priv->pfCurrentPage == 1) { OUT_RING(dev_priv->front_pitch_offset); } else { OUT_RING(dev_priv->back_pitch_offset); @@ -790,7 +794,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, ADVANCE_RING(); } -static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) +static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv, struct drm_radeon_master_private *master_priv) { /* Collapse various things into a wait flag -- trying to * guess if userspase slept -- better just to have them tell us. @@ -807,12 +811,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) /* Purple box for page flipping */ if (dev_priv->stats.boxes & RADEON_BOX_FLIP) - radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255); + radeon_clear_box(dev_priv, master_priv, 4, 4, 8, 8, 255, 0, 255); /* Red box if we have to wait for idle at any point */ if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE) - radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0); + radeon_clear_box(dev_priv, master_priv, 16, 4, 8, 8, 255, 0, 0); /* Blue box: lost context? */ @@ -820,12 +824,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) /* Yellow box for texture swaps */ if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD) - radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0); + radeon_clear_box(dev_priv, master_priv, 40, 4, 8, 8, 255, 255, 0); /* Green box if hardware never idles (as far as we can tell) */ if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) - radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0); + radeon_clear_box(dev_priv, master_priv, 64, 4, 8, 8, 0, 255, 0); /* Draw bars indicating number of buffers allocated * (not a great measure, easily confused) @@ -834,7 +838,7 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) if (dev_priv->stats.requested_bufs > 100) dev_priv->stats.requested_bufs = 100; - radeon_clear_box(dev_priv, 4, 16, + radeon_clear_box(dev_priv, master_priv, 4, 16, dev_priv->stats.requested_bufs, 4, 196, 128, 128); } @@ -848,11 +852,13 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) */ static void radeon_cp_dispatch_clear(struct drm_device * dev, + struct drm_master *master, drm_radeon_clear_t * clear, drm_radeon_clear_rect_t * depth_boxes) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear; int nbox = sarea_priv->nbox; struct drm_clip_rect *pbox = sarea_priv->boxes; @@ -864,7 +870,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, dev_priv->stats.clears++; - if (dev_priv->sarea_priv->pfCurrentPage == 1) { + if (sarea_priv->pfCurrentPage == 1) { unsigned int tmp = flags; flags &= ~(RADEON_FRONT | RADEON_BACK); @@ -890,7 +896,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { int x = pbox[i].x1; @@ -967,7 +973,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. * we haven't touched any "normal" state - still need this? */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; if ((dev_priv->flags & RADEON_HAS_HIERZ) && (flags & RADEON_USE_HIERZ)) { @@ -1015,7 +1021,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, int tileoffset, nrtilesx, nrtilesy, j; /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */ if ((dev_priv->flags & RADEON_HAS_HIERZ) - && !(dev_priv->microcode_version == UCODE_R200)) { + && (dev_priv->chip_family < CHIP_R200)) { /* FIXME : figure this out for r200 (when hierz is enabled). Or maybe r200 actually doesn't need to put the low-res z value into the tile cache like r100, but just needs to clear the hi-level z-buffer? @@ -1044,7 +1050,8 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, ADVANCE_RING(); tileoffset += depthpixperline >> 6; } - } else if (dev_priv->microcode_version == UCODE_R200) { + } else if ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280)) { /* works for rv250. */ /* find first macro tile (8x2 4x4 z-pixels on rv250) */ tileoffset = @@ -1099,7 +1106,8 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* TODO don't always clear all hi-level z tiles */ if ((dev_priv->flags & RADEON_HAS_HIERZ) - && (dev_priv->microcode_version == UCODE_R200) + && ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280)) && (flags & RADEON_USE_HIERZ)) /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */ /* FIXME : the mask supposedly contains low-res z values. So can't set @@ -1119,8 +1127,9 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, * rendering a quad into just those buffers. Thus, we have to * make sure the 3D engine is configured correctly. */ - else if ((dev_priv->microcode_version == UCODE_R200) && - (flags & (RADEON_DEPTH | RADEON_STENCIL))) { + else if ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280) && + (flags & (RADEON_DEPTH | RADEON_STENCIL))) { int tempPP_CNTL; int tempRE_CNTL; @@ -1214,7 +1223,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { @@ -1285,7 +1294,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { @@ -1328,20 +1337,21 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, * wait on this value before performing the clear ioctl. We * need this because the card's so damned fast... */ - dev_priv->sarea_priv->last_clear++; + sarea_priv->last_clear++; BEGIN_RING(4); - RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear); + RADEON_CLEAR_AGE(sarea_priv->last_clear); RADEON_WAIT_UNTIL_IDLE(); ADVANCE_RING(); } -static void radeon_cp_dispatch_swap(struct drm_device * dev) +static void radeon_cp_dispatch_swap(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int nbox = sarea_priv->nbox; struct drm_clip_rect *pbox = sarea_priv->boxes; int i; @@ -1351,7 +1361,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) /* Do some trivial performance monitoring... */ if (dev_priv->do_boxes) - radeon_cp_performance_boxes(dev_priv); + radeon_cp_performance_boxes(dev_priv, master_priv); /* Wait for the 3D stream to idle before dispatching the bitblt. * This will prevent data corruption between the two streams. @@ -1385,7 +1395,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) /* Make this work even if front & back are flipped: */ OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); - if (dev_priv->sarea_priv->pfCurrentPage == 0) { + if (sarea_priv->pfCurrentPage == 0) { OUT_RING(dev_priv->back_pitch_offset); OUT_RING(dev_priv->front_pitch_offset); } else { @@ -1405,31 +1415,32 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) * throttle the framerate by waiting for this value before * performing the swapbuffer ioctl. */ - dev_priv->sarea_priv->last_frame++; + sarea_priv->last_frame++; BEGIN_RING(4); - RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); + RADEON_FRAME_AGE(sarea_priv->last_frame); RADEON_WAIT_UNTIL_2D_IDLE(); ADVANCE_RING(); } -static void radeon_cp_dispatch_flip(struct drm_device * dev) +void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_sarea *sarea = (struct drm_sarea *) dev_priv->sarea->handle; - int offset = (dev_priv->sarea_priv->pfCurrentPage == 1) + struct drm_radeon_master_private *master_priv = master->driver_priv; + struct drm_sarea *sarea = (struct drm_sarea *) master_priv->sarea->handle; + int offset = (master_priv->sarea_priv->pfCurrentPage == 1) ? dev_priv->front_offset : dev_priv->back_offset; RING_LOCALS; DRM_DEBUG("pfCurrentPage=%d\n", - dev_priv->sarea_priv->pfCurrentPage); + master_priv->sarea_priv->pfCurrentPage); /* Do some trivial performance monitoring... */ if (dev_priv->do_boxes) { dev_priv->stats.boxes |= RADEON_BOX_FLIP; - radeon_cp_performance_boxes(dev_priv); + radeon_cp_performance_boxes(dev_priv, master_priv); } /* Update the frame offsets for both CRTCs @@ -1441,7 +1452,7 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev) ((sarea->frame.y * dev_priv->front_pitch + sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) + offset); - OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base + OUT_RING_REG(RADEON_CRTC2_OFFSET, master_priv->sarea_priv->crtc2_base + offset); ADVANCE_RING(); @@ -1450,13 +1461,13 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev) * throttle the framerate by waiting for this value before * performing the swapbuffer ioctl. */ - dev_priv->sarea_priv->last_frame++; - dev_priv->sarea_priv->pfCurrentPage = - 1 - dev_priv->sarea_priv->pfCurrentPage; + master_priv->sarea_priv->last_frame++; + master_priv->sarea_priv->pfCurrentPage = + 1 - master_priv->sarea_priv->pfCurrentPage; BEGIN_RING(2); - RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); + RADEON_FRAME_AGE(master_priv->sarea_priv->last_frame); ADVANCE_RING(); } @@ -1494,11 +1505,13 @@ typedef struct { } drm_radeon_tcl_prim_t; static void radeon_cp_dispatch_vertex(struct drm_device * dev, + struct drm_file *file_priv, struct drm_buf * buf, drm_radeon_tcl_prim_t * prim) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; int numverts = (int)prim->numverts; int nbox = sarea_priv->nbox; @@ -1539,13 +1552,14 @@ static void radeon_cp_dispatch_vertex(struct drm_device * dev, } while (i < nbox); } -static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_buf * buf) +static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_master *master, struct drm_buf * buf) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; drm_radeon_buf_priv_t *buf_priv = buf->dev_private; RING_LOCALS; - buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; + buf_priv->age = ++master_priv->sarea_priv->last_dispatch; /* Emit the vertex buffer age */ BEGIN_RING(2); @@ -1590,12 +1604,14 @@ static void radeon_cp_dispatch_indirect(struct drm_device * dev, } } -static void radeon_cp_dispatch_indices(struct drm_device * dev, +static void radeon_cp_dispatch_indices(struct drm_device *dev, + struct drm_master *master, struct drm_buf * elt_buf, drm_radeon_tcl_prim_t * prim) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int offset = dev_priv->gart_buffers_offset + prim->offset; u32 *data; int dwords; @@ -1870,7 +1886,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev, ADVANCE_RING(); COMMIT_RING(); - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); /* Update the input parameters for next time */ image->y += height; @@ -2120,7 +2136,8 @@ static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_fi static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; drm_radeon_clear_t *clear = data; drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; DRM_DEBUG("\n"); @@ -2136,7 +2153,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * sarea_priv->nbox * sizeof(depth_boxes[0]))) return -EFAULT; - radeon_cp_dispatch_clear(dev, clear, depth_boxes); + radeon_cp_dispatch_clear(dev, file_priv->master, clear, depth_boxes); COMMIT_RING(); return 0; @@ -2144,9 +2161,10 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * /* Not sure why this isn't set all the time: */ -static int radeon_do_init_pageflip(struct drm_device * dev) +static int radeon_do_init_pageflip(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; RING_LOCALS; DRM_DEBUG("\n"); @@ -2163,8 +2181,8 @@ static int radeon_do_init_pageflip(struct drm_device * dev) dev_priv->page_flipping = 1; - if (dev_priv->sarea_priv->pfCurrentPage != 1) - dev_priv->sarea_priv->pfCurrentPage = 0; + if (master_priv->sarea_priv->pfCurrentPage != 1) + master_priv->sarea_priv->pfCurrentPage = 0; return 0; } @@ -2182,9 +2200,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f RING_SPACE_TEST_WITH_RETURN(dev_priv); if (!dev_priv->page_flipping) - radeon_do_init_pageflip(dev); + radeon_do_init_pageflip(dev, file_priv->master); - radeon_cp_dispatch_flip(dev); + radeon_cp_dispatch_flip(dev, file_priv->master); COMMIT_RING(); return 0; @@ -2193,7 +2211,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; + DRM_DEBUG("\n"); LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -2203,8 +2223,8 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; - radeon_cp_dispatch_swap(dev); - dev_priv->sarea_priv->ctx_owner = 0; + radeon_cp_dispatch_swap(dev, file_priv->master); + sarea_priv->ctx_owner = 0; COMMIT_RING(); return 0; @@ -2213,6 +2233,7 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2226,7 +2247,7 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file return -EINVAL; } - sarea_priv = dev_priv->sarea_priv; + sarea_priv = master_priv->sarea_priv; DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); @@ -2280,13 +2301,13 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file prim.finish = vertex->count; /* unused */ prim.prim = vertex->prim; prim.numverts = vertex->count; - prim.vc_format = dev_priv->sarea_priv->vc_format; + prim.vc_format = sarea_priv->vc_format; - radeon_cp_dispatch_vertex(dev, buf, &prim); + radeon_cp_dispatch_vertex(dev, file_priv, buf, &prim); } if (vertex->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2296,6 +2317,7 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2309,7 +2331,7 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file DRM_ERROR("called with no initialization\n"); return -EINVAL; } - sarea_priv = dev_priv->sarea_priv; + sarea_priv = master_priv->sarea_priv; DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n", DRM_CURRENTPID, elts->idx, elts->start, elts->end, @@ -2376,11 +2398,11 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file prim.prim = elts->prim; prim.offset = 0; /* offset from start of dma buffers */ prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ - prim.vc_format = dev_priv->sarea_priv->vc_format; + prim.vc_format = sarea_priv->vc_format; - radeon_cp_dispatch_indices(dev, buf, &prim); + radeon_cp_dispatch_indices(dev, file_priv->master, buf, &prim); if (elts->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2496,7 +2518,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil */ radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); if (indirect->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2506,6 +2528,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2520,7 +2543,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file return -EINVAL; } - sarea_priv = dev_priv->sarea_priv; + sarea_priv = master_priv->sarea_priv; DRM_DEBUG("pid=%d index=%d discard=%d\n", DRM_CURRENTPID, vertex->idx, vertex->discard); @@ -2582,12 +2605,12 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file tclprim.offset = prim.numverts * 64; tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ - radeon_cp_dispatch_indices(dev, buf, &tclprim); + radeon_cp_dispatch_indices(dev, file_priv->master, buf, &tclprim); } else { tclprim.numverts = prim.numverts; tclprim.offset = 0; /* not used */ - radeon_cp_dispatch_vertex(dev, buf, &tclprim); + radeon_cp_dispatch_vertex(dev, file_priv, buf, &tclprim); } if (sarea_priv->nbox == 1) @@ -2595,7 +2618,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file } if (vertex->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2889,7 +2912,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file orig_nbox = cmdbuf->nbox; - if (dev_priv->microcode_version == UCODE_R300) { + if (dev_priv->chip_family >= CHIP_R300) { int temp; temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf); @@ -2949,7 +2972,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file goto err; } - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); break; case RADEON_CMD_PACKET3: @@ -3110,6 +3133,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_setparam_t *sp = data; struct drm_radeon_driver_file_fields *radeon_priv; @@ -3129,14 +3153,14 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil DRM_DEBUG("color tiling disabled\n"); dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->tiling_enabled = 0; + if (master_priv->sarea_priv) + master_priv->sarea_priv->tiling_enabled = 0; } else if (sp->value == 1) { DRM_DEBUG("color tiling enabled\n"); dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO; dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->tiling_enabled = 1; + if (master_priv->sarea_priv) + master_priv->sarea_priv->tiling_enabled = 1; } break; case RADEON_SETPARAM_PCIGART_LOCATION: @@ -3183,14 +3207,6 @@ void radeon_driver_preclose(struct drm_device *dev, void radeon_driver_lastclose(struct drm_device *dev) { - if (dev->dev_private) { - drm_radeon_private_t *dev_priv = dev->dev_private; - - if (dev_priv->sarea_priv && - dev_priv->sarea_priv->pfCurrentPage != 0) - radeon_cp_dispatch_flip(dev); - } - radeon_do_release(dev); } @@ -3251,7 +3267,18 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH) + DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PIN, radeon_gem_pin_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_UNPIN, radeon_gem_unpin_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_INDIRECT, radeon_gem_indirect_ioctl, DRM_AUTH), }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); -- cgit v1.2.3 From 0443d2a32ab791867cb0ce361a3905357d6a87d9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 26 Jul 2008 08:56:43 +1000 Subject: tests: add some basic radeon gem tests --- tests/Makefile.am | 4 +- tests/radeon_gem_basic.c | 114 ++++++++++++++++++++++++++++++++++++++++ tests/radeon_gem_mmap.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 tests/radeon_gem_basic.c create mode 100644 tests/radeon_gem_mmap.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 718cc436..a5f9967b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -25,7 +25,9 @@ TESTS = auth \ updatedraw \ gem_basic \ gem_readwrite \ - gem_mmap + gem_mmap \ + radeon_gem_mmap \ + radeon_gem_basic EXTRA_PROGRAMS = $(TESTS) CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES) diff --git a/tests/radeon_gem_basic.c b/tests/radeon_gem_basic.c new file mode 100644 index 00000000..d8231879 --- /dev/null +++ b/tests/radeon_gem_basic.c @@ -0,0 +1,114 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "drm.h" +#include "radeon_drm.h" + +static void +test_bad_close(int fd) +{ + struct drm_gem_close close; + int ret; + + printf("Testing error return on bad close ioctl.\n"); + + close.handle = 0x10101010; + ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close); + + assert(ret == -1 && errno == EINVAL); +} + +static void +test_create_close(int fd) +{ + struct drm_radeon_gem_create create; + struct drm_gem_close close; + int ret; + + printf("Testing creating and closing an object.\n"); + + memset(&create, 0, sizeof(create)); + create.size = 16 * 1024; + ret = ioctl(fd, DRM_IOCTL_RADEON_GEM_CREATE, &create); + assert(ret == 0); + + close.handle = create.handle; + ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close); +} + +static void +test_create_fd_close(int fd) +{ + struct drm_radeon_gem_create create; + int ret; + + printf("Testing closing with an object allocated.\n"); + + memset(&create, 0, sizeof(create)); + create.size = 16 * 1024; + ret = ioctl(fd, DRM_IOCTL_RADEON_GEM_CREATE, &create); + assert(ret == 0); + + close(fd); +} + +int test_gem_info(int fd) +{ + struct drm_radeon_gem_info info; + int ret; + + ret = ioctl(fd, DRM_IOCTL_RADEON_GEM_INFO, &info); + assert(ret == 0); + + fprintf(stderr,"%lld %lld %lld %lld %lld\n", + info.gtt_start, info.gtt_size, + info.vram_start, info.vram_size, + info.vram_visible); + +} + +int main(int argc, char **argv) +{ + int fd; + + fd = drm_open_any(); + + test_gem_info(fd); + test_bad_close(fd); + test_create_close(fd); + test_create_fd_close(fd); + + return 0; +} diff --git a/tests/radeon_gem_mmap.c b/tests/radeon_gem_mmap.c new file mode 100644 index 00000000..aa7b0196 --- /dev/null +++ b/tests/radeon_gem_mmap.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "drm.h" +#include "radeon_drm.h" + +#define OBJECT_SIZE 16384 + +int do_read(int fd, int handle, void *buf, int offset, int size) +{ + struct drm_radeon_gem_pread read; + + /* Ensure that we don't have any convenient data in buf in case + * we fail. + */ + memset(buf, 0xd0, size); + + memset(&read, 0, sizeof(read)); + read.handle = handle; + read.data_ptr = (uintptr_t)buf; + read.size = size; + read.offset = offset; + + return ioctl(fd, DRM_IOCTL_RADEON_GEM_PREAD, &read); +} + +int do_write(int fd, int handle, void *buf, int offset, int size) +{ + struct drm_radeon_gem_pwrite write; + + memset(&write, 0, sizeof(write)); + write.handle = handle; + write.data_ptr = (uintptr_t)buf; + write.size = size; + write.offset = offset; + + return ioctl(fd, DRM_IOCTL_RADEON_GEM_PWRITE, &write); +} + +int main(int argc, char **argv) +{ + int fd; + struct drm_radeon_gem_create create; + struct drm_radeon_gem_mmap mmap; + struct drm_gem_close unref; + uint8_t expected[OBJECT_SIZE]; + uint8_t buf[OBJECT_SIZE]; + uint8_t *addr; + int ret; + int handle; + + fd = drm_open_any(); + + memset(&mmap, 0, sizeof(mmap)); + mmap.handle = 0x10101010; + mmap.offset = 0; + mmap.size = 4096; + printf("Testing mmaping of bad object.\n"); + ret = ioctl(fd, DRM_IOCTL_RADEON_GEM_MMAP, &mmap); + assert(ret == -1 && errno == EINVAL); + + memset(&create, 0, sizeof(create)); + create.size = OBJECT_SIZE; + ret = ioctl(fd, DRM_IOCTL_RADEON_GEM_CREATE, &create); + assert(ret == 0); + handle = create.handle; + + printf("Testing mmaping of newly created object.\n"); + mmap.handle = handle; + mmap.offset = 0; + mmap.size = OBJECT_SIZE; + ret = ioctl(fd, DRM_IOCTL_RADEON_GEM_MMAP, &mmap); + assert(ret == 0); + addr = (uint8_t *)(uintptr_t)mmap.addr_ptr; + + printf("Testing contents of newly created object.\n"); + memset(expected, 0, sizeof(expected)); + assert(memcmp(addr, expected, sizeof(expected)) == 0); + + printf("Testing coherency of writes and mmap reads.\n"); + memset(buf, 0, sizeof(buf)); + memset(buf + 1024, 0x01, 1024); + memset(expected + 1024, 0x01, 1024); + ret = do_write(fd, handle, buf, 0, OBJECT_SIZE); + assert(ret == 0); + assert(memcmp(buf, addr, sizeof(buf)) == 0); + + printf("Testing that mapping stays after close\n"); + unref.handle = handle; + ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, &unref); + assert(ret == 0); + assert(memcmp(buf, addr, sizeof(buf)) == 0); + + printf("Testing unmapping\n"); + munmap(addr, OBJECT_SIZE); + + close(fd); + + return 0; +} -- cgit v1.2.3 From 5282a505b6fd1f0e2bb772b15daf652f7149f370 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 26 Jul 2008 16:57:02 -0400 Subject: NV50: s/FALSE/false/ --- linux-core/nv50_kms_wrapper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 77271c1b..8ae72f48 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -944,7 +944,7 @@ static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector hpd_detect = connector->hpd_detect(connector); /* load detect */ - output = connector->to_output(connector, FALSE); /* analog */ + output = connector->to_output(connector, false); /* analog */ if (output && output->detect) load_detect = output->detect(output); @@ -1031,7 +1031,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u rval = drm_add_edid_modes(drm_connector, edid); /* Only update when relevant and when detect couldn't determine type. */ - nv50_kms_connector_set_digital(drm_connector, edid->digital ? 1 : 0, FALSE); + nv50_kms_connector_set_digital(drm_connector, edid->digital ? 1 : 0, false); kfree(edid); } -- cgit v1.2.3 From 38835f9cd2b44cfb6587a52ba1bfe292b958d0e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 28 Jul 2008 15:21:13 +1000 Subject: radeon command submission start take code from Jerome munge into a TTM IB re-use --- linux-core/Makefile.kernel | 2 +- linux-core/radeon_cs.c | 1 + linux-core/radeon_gem.c | 211 ++++++++++++++++++++++++++++++++++++++++----- linux-core/radeon_reg.h | 4 + shared-core/radeon_cp.c | 30 ++++--- shared-core/radeon_cs.c | 181 ++++++++++++++++++++++++++++++++++++++ shared-core/radeon_drm.h | 15 ++++ shared-core/radeon_drv.h | 56 ++++++++---- shared-core/radeon_state.c | 1 + 9 files changed, 450 insertions(+), 51 deletions(-) create mode 120000 linux-core/radeon_cs.c create mode 100644 shared-core/radeon_cs.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index d3668dfb..404944bf 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -41,7 +41,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv50_kms_wrapper.o \ nv50_fbcon.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_gem.o \ - radeon_buffer.o radeon_fence.o atom.o radeon_display.o radeon_atombios.o radeon_i2c.o radeon_connectors.o \ + radeon_buffer.o radeon_fence.o atom.o radeon_display.o radeon_atombios.o radeon_i2c.o radeon_connectors.o radeon_cs.o \ atombios_crtc.o radeon_encoders.o radeon_fb.o radeon_combios.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux-core/radeon_cs.c b/linux-core/radeon_cs.c new file mode 120000 index 00000000..0e3fa8ee --- /dev/null +++ b/linux-core/radeon_cs.c @@ -0,0 +1 @@ +../shared-core/radeon_cs.c \ No newline at end of file diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index d536aed2..021bb9f9 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -27,6 +27,9 @@ #include "radeon_drm.h" #include "radeon_drv.h" +static int radeon_gem_ib_init(struct drm_device *dev); +static int radeon_gem_ib_destroy(struct drm_device *dev); + int radeon_gem_init_object(struct drm_gem_object *obj) { struct drm_radeon_gem_object *obj_priv; @@ -513,19 +516,19 @@ static int radeon_gart_init(struct drm_device *dev) ret = drm_buffer_object_create(dev, RADEON_PCIGART_TABLE_SIZE, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_NO_EVICT, - 0, 1, 0, &dev_priv->mm.pcie_table); + 0, 1, 0, &dev_priv->mm.pcie_table.bo); if (ret) return -EINVAL; - DRM_DEBUG("pcie table bo created %p, %x\n", dev_priv->mm.pcie_table, dev_priv->mm.pcie_table->offset); - ret = drm_bo_kmap(dev_priv->mm.pcie_table, 0, RADEON_PCIGART_TABLE_SIZE >> PAGE_SHIFT, - &dev_priv->mm.pcie_table_map); + DRM_DEBUG("pcie table bo created %p, %x\n", dev_priv->mm.pcie_table.bo, dev_priv->mm.pcie_table.bo->offset); + ret = drm_bo_kmap(dev_priv->mm.pcie_table.bo, 0, RADEON_PCIGART_TABLE_SIZE >> PAGE_SHIFT, + &dev_priv->mm.pcie_table.kmap); if (ret) return -EINVAL; dev_priv->pcigart_offset_set = 2; - dev_priv->gart_info.bus_addr = dev_priv->fb_location + dev_priv->mm.pcie_table->offset; - dev_priv->gart_info.addr = dev_priv->mm.pcie_table_map.virtual; + dev_priv->gart_info.bus_addr = dev_priv->fb_location + dev_priv->mm.pcie_table.bo->offset; + dev_priv->gart_info.addr = dev_priv->mm.pcie_table.kmap.virtual; dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; dev_priv->gart_info.gart_table_location = DRM_ATI_GART_FB; memset(dev_priv->gart_info.addr, 0, RADEON_PCIGART_TABLE_SIZE); @@ -566,14 +569,14 @@ int radeon_alloc_gart_objects(struct drm_device *dev) drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_NO_EVICT, - 0, 1, 0, &dev_priv->mm.ring); + 0, 1, 0, &dev_priv->mm.ring.bo); if (ret) { DRM_ERROR("failed to allocate ring\n"); return -EINVAL; } - ret = drm_bo_kmap(dev_priv->mm.ring, 0, RADEON_DEFAULT_RING_SIZE >> PAGE_SHIFT, - &dev_priv->mm.ring_map); + ret = drm_bo_kmap(dev_priv->mm.ring.bo, 0, RADEON_DEFAULT_RING_SIZE >> PAGE_SHIFT, + &dev_priv->mm.ring.kmap); if (ret) { DRM_ERROR("failed to map ring\n"); return -EINVAL; @@ -583,24 +586,26 @@ int radeon_alloc_gart_objects(struct drm_device *dev) drm_bo_type_kernel, DRM_BO_FLAG_WRITE |DRM_BO_FLAG_READ | DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_NO_EVICT, - 0, 1, 0, &dev_priv->mm.ring_read_ptr); + 0, 1, 0, &dev_priv->mm.ring_read.bo); if (ret) { DRM_ERROR("failed to allocate ring read\n"); return -EINVAL; } - ret = drm_bo_kmap(dev_priv->mm.ring_read_ptr, 0, + ret = drm_bo_kmap(dev_priv->mm.ring_read.bo, 0, PAGE_SIZE >> PAGE_SHIFT, - &dev_priv->mm.ring_read_ptr_map); + &dev_priv->mm.ring_read.kmap); if (ret) { DRM_ERROR("failed to map ring read\n"); return -EINVAL; } DRM_DEBUG("Ring ptr %p mapped at %d %p, read ptr %p maped at %d %p\n", - dev_priv->mm.ring, dev_priv->mm.ring->offset, dev_priv->mm.ring_map.virtual, - dev_priv->mm.ring_read_ptr, dev_priv->mm.ring_read_ptr->offset, dev_priv->mm.ring_read_ptr_map.virtual); + dev_priv->mm.ring.bo, dev_priv->mm.ring.bo->offset, dev_priv->mm.ring.kmap.virtual, + dev_priv->mm.ring_read.bo, dev_priv->mm.ring_read.bo->offset, dev_priv->mm.ring_read.kmap.virtual); + /* init the indirect buffers */ + radeon_gem_ib_init(dev); return 0; } @@ -634,6 +639,8 @@ int radeon_gem_mm_init(struct drm_device *dev) ret = radeon_alloc_gart_objects(dev); if (ret) return -EINVAL; + + return 0; } @@ -641,16 +648,19 @@ void radeon_gem_mm_fini(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; + radeon_gem_ib_destroy(dev); + mutex_lock(&dev->struct_mutex); - if (dev_priv->mm.ring_read_ptr) { - drm_bo_kunmap(&dev_priv->mm.ring_read_ptr_map); - drm_bo_usage_deref_locked(&dev_priv->mm.ring_read_ptr); + + if (dev_priv->mm.ring_read.bo) { + drm_bo_kunmap(&dev_priv->mm.ring_read.kmap); + drm_bo_usage_deref_locked(&dev_priv->mm.ring_read.bo); } - if (dev_priv->mm.ring) { - drm_bo_kunmap(&dev_priv->mm.ring_map); - drm_bo_usage_deref_locked(&dev_priv->mm.ring); + if (dev_priv->mm.ring.bo) { + drm_bo_kunmap(&dev_priv->mm.ring.kmap); + drm_bo_usage_deref_locked(&dev_priv->mm.ring.bo); } if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) { @@ -658,9 +668,9 @@ void radeon_gem_mm_fini(struct drm_device *dev) } if (dev_priv->flags & RADEON_IS_PCIE) { - if (dev_priv->mm.pcie_table) { - drm_bo_kunmap(&dev_priv->mm.pcie_table_map); - drm_bo_usage_deref_locked(&dev_priv->mm.pcie_table); + if (dev_priv->mm.pcie_table.bo) { + drm_bo_kunmap(&dev_priv->mm.pcie_table.kmap); + drm_bo_usage_deref_locked(&dev_priv->mm.pcie_table.bo); } } @@ -685,3 +695,158 @@ int radeon_gem_object_pin(struct drm_gem_object *obj, return ret; } +#define RADEON_IB_MEMORY (1*1024*1024) +#define RADEON_IB_SIZE (65536) + +#define RADEON_NUM_IB (RADEON_IB_MEMORY / RADEON_IB_SIZE) + +int radeon_gem_ib_get(struct drm_device *dev, void **ib, uint32_t dwords) +{ + int i, index = -1; + int ret; + drm_radeon_private_t *dev_priv = dev->dev_private; + + for (i = 0; i < RADEON_NUM_IB; i++) { + if (!(dev_priv->ib_alloc_bitmap & (1 << i))){ + index = i; + break; + } + } + + /* if all in use we need to wait */ + if (index == -1) { + for (i = 0; i < RADEON_NUM_IB; i++) { + if (dev_priv->ib_alloc_bitmap & (1 << i)) { + mutex_lock(&dev_priv->ib_objs[i]->bo->mutex); + ret = drm_bo_wait(dev_priv->ib_objs[i]->bo, 0, 1, 0, 0); + mutex_unlock(&dev_priv->ib_objs[i]->bo->mutex); + if (ret) + continue; + dev_priv->ib_alloc_bitmap &= ~(1 << i); + index = i; + break; + } + } + } + + if (index == -1) { + DRM_ERROR("Major case fail to allocate IB from freelist %x\n", dev_priv->ib_alloc_bitmap); + return -EINVAL; + } + + + if (dwords > RADEON_IB_SIZE / sizeof(uint32_t)) + return -EINVAL; + + *ib = dev_priv->ib_objs[index]->kmap.virtual; + dev_priv->ib_alloc_bitmap |= (1 << i); + return 0; +} + +static void radeon_gem_ib_free(struct drm_device *dev, void *ib, uint32_t dwords) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_fence_object *fence; + int ret; + int i; + RING_LOCALS; + + for (i = 0; i < RADEON_NUM_IB; i++) { + + if (dev_priv->ib_objs[i]->kmap.virtual == ib) { + ret = drm_bo_do_validate(dev_priv->ib_objs[i]->bo, 0, + DRM_BO_FLAG_NO_EVICT, + 0, 0, NULL); + if (ret) + DRM_ERROR("FAiled to validate\n"); + + DRM_DEBUG("validated IB %x, %d\n", dev_priv->ib_objs[i]->bo->offset, dwords); + BEGIN_RING(4); + + OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); + OUT_RING(dev_priv->gart_vm_start + dev_priv->ib_objs[i]->bo->offset); + OUT_RING(dwords); + OUT_RING(CP_PACKET2()); + + ADVANCE_RING(); + + COMMIT_RING(); + + /* emit a fence object */ + ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); + if (ret) { + + drm_putback_buffer_objects(dev); + } + /* dereference the fence object */ + if (fence) + drm_fence_usage_deref_unlocked(&fence); + } + } + +} + +static int radeon_gem_ib_destroy(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int i; + + if (dev_priv->ib_objs) { + for (i = 0; i < RADEON_NUM_IB; i++) { + if (dev_priv->ib_objs[i]) { + drm_bo_kunmap(&dev_priv->ib_objs[i]->kmap); + drm_bo_usage_deref_unlocked(&dev_priv->ib_objs[i]->bo); + } + drm_free(dev_priv->ib_objs[i], sizeof(struct radeon_mm_obj), DRM_MEM_DRIVER); + } + drm_free(dev_priv->ib_objs, RADEON_NUM_IB*sizeof(struct radeon_mm_obj *), DRM_MEM_DRIVER); + } + dev_priv->ib_objs = NULL; + return 0; +} + +/* allocate 1MB of 64k IBs the the kernel can keep mapped */ +static int radeon_gem_ib_init(struct drm_device *dev) +{ + + drm_radeon_private_t *dev_priv = dev->dev_private; + int i; + int ret; + + dev_priv->ib_objs = drm_calloc(RADEON_NUM_IB, sizeof(struct radeon_mm_obj *), DRM_MEM_DRIVER); + if (!dev_priv->ib_objs) + goto free_all; + + for (i = 0; i < RADEON_NUM_IB; i++) { + dev_priv->ib_objs[i] = drm_calloc(1, sizeof(struct radeon_mm_obj), DRM_MEM_DRIVER); + if (!dev_priv->ib_objs[i]) + goto free_all; + + ret = drm_buffer_object_create(dev, RADEON_IB_SIZE, + drm_bo_type_kernel, + DRM_BO_FLAG_READ | DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_MAPPABLE, 0, + 0, 0, &dev_priv->ib_objs[i]->bo); + if (ret) + goto free_all; + + ret = drm_bo_kmap(dev_priv->ib_objs[i]->bo, 0, RADEON_IB_SIZE >> PAGE_SHIFT, + &dev_priv->ib_objs[i]->kmap); + + if (ret) + goto free_all; + } + + dev_priv->ib_alloc_bitmap = 0; + + dev_priv->cs.ib_get = radeon_gem_ib_get; + dev_priv->cs.ib_free = radeon_gem_ib_free; + + radeon_cs_init(dev); + return 0; + +free_all: + radeon_gem_ib_destroy(dev); + return -ENOMEM; +} + diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index 9b6bf1ec..a5be6a63 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -3086,6 +3086,10 @@ # define RADEON_CSQ_PRIPIO_INDBM (3 << 28) # define RADEON_CSQ_PRIBM_INDBM (4 << 28) # define RADEON_CSQ_PRIPIO_INDPIO (15 << 28) + +#define R300_CP_RESYNC_ADDR 0x778 +#define R300_CP_RESYNC_DATA 0x77c + #define RADEON_CP_CSQ_STAT 0x07f8 # define RADEON_CSQ_RPTR_PRIMARY_MASK (0xff << 0) # define RADEON_CSQ_WPTR_PRIMARY_MASK (0xff << 8) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 80951e91..46f4290a 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -658,8 +658,8 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, ((dev_priv->gart_vm_start - 1) & 0xffff0000) | (dev_priv->fb_location >> 16)); - if (dev_priv->mm.ring) { - ring_start = dev_priv->mm.ring->offset + + if (dev_priv->mm.ring.bo) { + ring_start = dev_priv->mm.ring.bo->offset + dev_priv->gart_vm_start; } else #if __OS_HAS_AGP @@ -692,9 +692,9 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, dev_priv->ring.tail = cur_read_ptr; - if (dev_priv->mm.ring_read_ptr) { + if (dev_priv->mm.ring_read.bo) { RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, - dev_priv->mm.ring_read_ptr->offset + + dev_priv->mm.ring_read.bo->offset + dev_priv->gart_vm_start); } else #if __OS_HAS_AGP @@ -745,9 +745,9 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR) + RADEON_SCRATCH_REG_OFFSET); - if (dev_priv->mm.ring_read_ptr) + if (dev_priv->mm.ring_read.bo) dev_priv->scratch = ((__volatile__ u32 *) - dev_priv->mm.ring_read_ptr_map.virtual + + dev_priv->mm.ring_read.kmap.virtual + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); else dev_priv->scratch = ((__volatile__ u32 *) @@ -772,12 +772,18 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, radeon_do_wait_for_idle(dev_priv); /* Sync everything up */ + if (dev_priv->chip_family > CHIP_RV280) { RADEON_WRITE(RADEON_ISYNC_CNTL, (RADEON_ISYNC_ANY2D_IDLE3D | RADEON_ISYNC_ANY3D_IDLE2D | RADEON_ISYNC_WAIT_IDLEGUI | RADEON_ISYNC_CPSCRATCH_IDLEGUI)); - + } else { + RADEON_WRITE(RADEON_ISYNC_CNTL, + (RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI)); + } } static void radeon_test_writeback(drm_radeon_private_t * dev_priv) @@ -785,8 +791,8 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv) u32 tmp; void *ring_read_ptr; - if (dev_priv->mm.ring_read_ptr) - ring_read_ptr = dev_priv->mm.ring_read_ptr_map.virtual; + if (dev_priv->mm.ring_read.bo) + ring_read_ptr = dev_priv->mm.ring_read.kmap.virtual; else ring_read_ptr = dev_priv->ring_rptr->handle; @@ -2282,8 +2288,8 @@ int radeon_modeset_cp_init(struct drm_device *dev) dev_priv->ring.size = RADEON_DEFAULT_RING_SIZE; dev_priv->cp_mode = RADEON_CSQ_PRIBM_INDBM; - dev_priv->ring.start = (u32 *)(void *)(unsigned long)dev_priv->mm.ring_map.virtual; - dev_priv->ring.end = (u32 *)(void *)(unsigned long)dev_priv->mm.ring_map.virtual + + dev_priv->ring.start = (u32 *)(void *)(unsigned long)dev_priv->mm.ring.kmap.virtual; + dev_priv->ring.end = (u32 *)(void *)(unsigned long)dev_priv->mm.ring.kmap.virtual + dev_priv->ring.size / sizeof(u32); dev_priv->ring.size_l2qw = drm_order(dev_priv->ring.size / 8); dev_priv->ring.rptr_update = 4096; @@ -2297,7 +2303,7 @@ int radeon_modeset_cp_init(struct drm_device *dev) radeon_cp_load_microcode(dev_priv); - DRM_DEBUG("ring offset is %x %x\n", dev_priv->mm.ring->offset, dev_priv->mm.ring_read_ptr->offset); + DRM_DEBUG("ring offset is %x %x\n", dev_priv->mm.ring.bo->offset, dev_priv->mm.ring_read.bo->offset); radeon_cp_init_ring_buffer(dev, dev_priv); diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c new file mode 100644 index 00000000..61fef79d --- /dev/null +++ b/shared-core/radeon_cs.c @@ -0,0 +1,181 @@ +/* + * Copyright 2008 Jerome Glisse. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" +#include "r300_reg.h" + +int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) +{ + struct drm_radeon_private *radeon = dev->dev_private; + struct drm_radeon_cs *cs = data; + uint32_t *packets = NULL; + uint32_t cs_id; + void *ib = NULL; + long size; + int r; + + /* set command stream id to 0 which is fake id */ + cs_id = 0; + DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); + + if (radeon == NULL) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + if (!cs->dwords) { + return 0; + } + /* limit cs to 64K ib */ + if (cs->dwords > (16 * 1024)) { + return -EINVAL; + } + /* copy cs from userspace maybe we should copy into ib to save + * one copy but ib will be mapped wc so not good for cmd checking + * somethings worth testing i guess (Jerome) + */ + size = cs->dwords * sizeof(uint32_t); + packets = drm_alloc(size, DRM_MEM_DRIVER); + if (packets == NULL) { + return -ENOMEM; + } + if (DRM_COPY_FROM_USER(packets, (void __user *)(unsigned long)cs->packets, size)) { + r = -EFAULT; + goto out; + } + /* get ib */ + r = radeon->cs.ib_get(dev, &ib, cs->dwords); + if (r) { + goto out; + } + + /* now parse command stream */ + r = radeon->cs.parse(dev, ib, packets, cs->dwords); + if (r) { + goto out; + } + + /* emit cs id sequence */ + radeon->cs.id_emit(dev, &cs_id); + DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); +out: + radeon->cs.ib_free(dev, ib, cs->dwords); + drm_free(packets, size, DRM_MEM_DRIVER); + return r; +} + +int radeon_cs_parse(struct drm_device *dev, void *ib, + uint32_t *packets, uint32_t dwords) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + volatile int rb; + + /* copy the packet into the IB */ + memcpy(ib, packets, dwords * sizeof(uint32_t)); + + /* read back last byte to flush WC buffers */ + rb = readl((ib + (dwords-1) * sizeof(uint32_t))); + + return 0; +} + +uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon) +{ + /* FIXME: protect with a spinlock */ + /* FIXME: check if wrap affect last reported wrap & sequence */ + radeon->cs.id_scnt = (radeon->cs.id_scnt + 1) & 0x00FFFFFF; + if (!radeon->cs.id_scnt) { + /* increment wrap counter */ + radeon->cs.id_wcnt += 0x01000000; + /* valid sequence counter start at 1 */ + radeon->cs.id_scnt = 1; + } + return (radeon->cs.id_scnt | radeon->cs.id_wcnt); +} + +void r100_cs_id_emit(struct drm_device *dev, uint32_t *id) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + /* ISYNC_CNTL should have CPSCRACTH bit set */ + *id = radeon_cs_id_get(dev_priv); + /* emit id in SCRATCH4 (not used yet in old drm) */ + BEGIN_RING(2); + OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG4, 0)); + OUT_RING(*id); + ADVANCE_RING(); +} + +void r300_cs_id_emit(struct drm_device *dev, uint32_t *id) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + /* ISYNC_CNTL should not have CPSCRACTH bit set */ + *id = radeon_cs_id_get(dev_priv); + /* emit id in SCRATCH6 */ + BEGIN_RING(6); + OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 0)); + OUT_RING(6); + OUT_RING(CP_PACKET0(R300_CP_RESYNC_DATA, 0)); + OUT_RING(*id); + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(R300_RB3D_DC_FINISH); + ADVANCE_RING(); +} + +uint32_t r100_cs_id_last_get(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + return RADEON_READ(RADEON_SCRATCH_REG4); +} + +uint32_t r300_cs_id_last_get(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + return RADEON_READ(RADEON_SCRATCH_REG6); +} + +int radeon_cs_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (dev_priv->chip_family < CHIP_RV280) { + dev_priv->cs.id_emit = r100_cs_id_emit; + dev_priv->cs.id_last_get = r100_cs_id_last_get; + } else if (dev_priv->chip_family < CHIP_R600) { + dev_priv->cs.id_emit = r300_cs_id_emit; + dev_priv->cs.id_last_get = r300_cs_id_last_get; + } + + dev_priv->cs.parse = radeon_cs_parse; + /* ib get depends on memory manager or not so memory manager */ + return 0; +} diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index 7fcf9305..c20de561 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -506,6 +506,7 @@ typedef struct { #define DRM_RADEON_GEM_SET_DOMAIN 0x23 #define DRM_RADEON_GEM_INDIRECT 0x24 // temporary for X server +#define DRM_RADEON_CS 0x25 #define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t) #define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START) @@ -545,6 +546,7 @@ typedef struct { #define DRM_IOCTL_RADEON_GEM_SET_DOMAIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_DOMAIN, struct drm_radeon_gem_set_domain) #define DRM_IOCTL_RADEON_GEM_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INDIRECT, struct drm_radeon_gem_indirect) +#define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs) typedef struct drm_radeon_init { @@ -861,4 +863,17 @@ struct drm_radeon_gem_indirect { uint32_t used; }; +/* New interface which obsolete all previous interface. + */ + + +struct drm_radeon_cs { +// uint32_t __user *packets; + uint32_t dwords; + uint32_t cs_id; + uint64_t packets; + +}; + + #endif diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index b8f49404..c431fe4a 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -195,11 +195,11 @@ enum radeon_mac_model { #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ - (dev_priv->mm.ring_read_ptr ? readl(dev_priv->mm.ring_read_ptr_map.virtual + 0) : DRM_READ32((dev_priv)->ring_rptr, 0 )) : \ + (dev_priv->mm.ring_read.bo ? readl(dev_priv->mm.ring_read.kmap.virtual + 0) : DRM_READ32((dev_priv)->ring_rptr, 0 )) : \ RADEON_READ(RADEON_CP_RB_RPTR)) -#define SET_RING_HEAD(dev_priv,val) (dev_priv->mm.ring_read_ptr ? \ - writel((val), dev_priv->mm.ring_read_ptr_map.virtual) : \ +#define SET_RING_HEAD(dev_priv,val) (dev_priv->mm.ring_read.bo ? \ + writel((val), dev_priv->mm.ring_read.kmap.virtual) : \ DRM_WRITE32((dev_priv)->ring_rptr, 0, (val))) typedef struct drm_radeon_freelist { @@ -261,6 +261,11 @@ struct radeon_virt_surface { struct drm_file *file_priv; }; +struct radeon_mm_obj { + struct drm_buffer_object *bo; + struct drm_bo_kmap_obj kmap; +}; + struct radeon_mm_info { uint64_t vram_offset; // Offset into GPU space uint64_t vram_size; @@ -268,15 +273,10 @@ struct radeon_mm_info { uint64_t gart_start; uint64_t gart_size; - - struct drm_buffer_object *pcie_table; - struct drm_bo_kmap_obj pcie_table_map; - - struct drm_buffer_object *ring; - struct drm_bo_kmap_obj ring_map; - - struct drm_buffer_object *ring_read_ptr; - struct drm_bo_kmap_obj ring_read_ptr_map; + + struct radeon_mm_obj pcie_table; + struct radeon_mm_obj ring; + struct radeon_mm_obj ring_read; }; #include "radeon_mode.h" @@ -286,6 +286,25 @@ struct drm_radeon_master_private { drm_radeon_sarea_t *sarea_priv; }; +/* command submission struct */ +struct drm_radeon_cs_priv { + uint32_t id_wcnt; + uint32_t id_scnt; + uint32_t id_last_wcnt; + uint32_t id_last_scnt; + + int (*parse)(struct drm_device *dev, void *ib, + uint32_t *packets, uint32_t dwords); + void (*id_emit)(struct drm_device *dev, uint32_t *id); + uint32_t (*id_last_get)(struct drm_device *dev); + /* this ib handling callback are for hidding memory manager drm + * from memory manager less drm, free have to emit ib discard + * sequence into the ring */ + int (*ib_get)(struct drm_device *dev, void **ib, uint32_t dwords); + uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib); + void (*ib_free)(struct drm_device *dev, void *ib, uint32_t dwords); +}; + typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; @@ -392,7 +411,11 @@ typedef struct drm_radeon_private { u32 ram_width; enum radeon_pll_errata pll_errata; - + + struct radeon_mm_obj **ib_objs; + /* ib bitmap */ + uint64_t ib_alloc_bitmap; // TO DO replace with a real bitmap + struct drm_radeon_cs_priv cs; } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { @@ -669,14 +692,15 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_SCRATCH_REG3 0x15ec #define RADEON_SCRATCH_REG4 0x15f0 #define RADEON_SCRATCH_REG5 0x15f4 +#define RADEON_SCRATCH_REG6 0x15f8 #define RADEON_SCRATCH_UMSK 0x0770 #define RADEON_SCRATCH_ADDR 0x0774 #define RADEON_SCRATCHOFF( x ) (RADEON_SCRATCH_REG_OFFSET + 4*(x)) #define GET_SCRATCH( x ) (dev_priv->writeback_works ? \ - (dev_priv->mm.ring_read_ptr ? \ - readl(dev_priv->mm.ring_read_ptr_map.virtual + RADEON_SCRATCHOFF(0)) : \ + (dev_priv->mm.ring_read.bo ? \ + readl(dev_priv->mm.ring_read.kmap.virtual + RADEON_SCRATCHOFF(0)) : \ DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(x))) : \ RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x))) @@ -1593,4 +1617,6 @@ extern void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on); extern int radeon_master_create(struct drm_device *dev, struct drm_master *master); extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master); extern void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master); +extern int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv); +extern int radeon_cs_init(struct drm_device *dev); #endif /* __RADEON_DRV_H__ */ diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 6de4b135..d56dac19 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3279,6 +3279,7 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_GEM_INDIRECT, radeon_gem_indirect_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH), }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); -- cgit v1.2.3 From dc3a7c023dd089150ee2dc40755fde348252bedb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 28 Jul 2008 17:27:24 +1000 Subject: r300: initial command stream parser for packet 0. this at least parses the DDX stream and lets me run gnome-terminal/metacity --- linux-core/radeon_reg.h | 1 + shared-core/r300_cmdbuf.c | 48 +++++++++++++++++++++++++++++-- shared-core/radeon_cp.c | 2 ++ shared-core/radeon_cs.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_drv.h | 7 +++++ 5 files changed, 128 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index a5be6a63..784b3b50 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -3125,6 +3125,7 @@ # define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000 # define RADEON_CP_PACKET_MAX_DWORDS (1 << 12) # define RADEON_CP_PACKET0_REG_MASK 0x000007ff +# define R300_CP_PACKET0_REG_MASK 0x00001fff # define RADEON_CP_PACKET1_REG0_MASK 0x000007ff # define RADEON_CP_PACKET1_REG1_MASK 0x003ff800 diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index e8f18dbc..f4111554 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -151,8 +151,6 @@ void r300_init_reg_flags(struct drm_device *dev) for(i=((reg)>>2);i<((reg)>>2)+(count);i++)\ r300_reg_flags[i]|=(mark); -#define MARK_SAFE 1 -#define MARK_CHECK_OFFSET 2 #define ADD_RANGE(reg, count) ADD_RANGE_MARK(reg, count, MARK_SAFE) @@ -234,6 +232,11 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8); ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8); + ADD_RANGE(R500_SU_REG_DEST, 1); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV410) { + ADD_RANGE(R300_DST_PIPE_CONFIG, 1); + } + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) { ADD_RANGE(R500_VAP_INDEX_OFFSET, 1); ADD_RANGE(R500_US_CONFIG, 2); @@ -243,6 +246,8 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R500_RS_INST_0, 16); ADD_RANGE(R500_RB3D_COLOR_CLEAR_VALUE_AR, 2); ADD_RANGE(R500_RB3D_CONSTANT_COLOR_AR, 2); + + ADD_RANGE(R500_GA_US_VECTOR_INDEX, 2); } else { ADD_RANGE(R300_PFS_CNTL_0, 3); ADD_RANGE(R300_PFS_NODE_0, 4); @@ -255,9 +260,39 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R300_RS_ROUTE_0, 8); } + + /* add 2d blit engine registers for DDX */ + ADD_RANGE(RADEON_SRC_Y_X, 3); /* 1434, 1438, 143c, + SRC_Y_X, DST_Y_X, DST_HEIGHT_WIDTH + */ + ADD_RANGE(RADEON_DP_GUI_MASTER_CNTL, 1); /* 146c */ + ADD_RANGE(RADEON_DP_BRUSH_BKGD_CLR, 2); /* 1478, 147c */ + ADD_RANGE(RADEON_DP_SRC_FRGD_CLR, 2); /* 15d8, 15dc */ + ADD_RANGE(RADEON_DP_CNTL, 1); /* 16c0 */ + ADD_RANGE(RADEON_DP_WRITE_MASK, 1); /* 16cc */ + ADD_RANGE(RADEON_DEFAULT_SC_BOTTOM_RIGHT, 1); /* 16e8 */ + + ADD_RANGE(RADEON_DSTCACHE_CTLSTAT, 1); + ADD_RANGE(RADEON_WAIT_UNTIL, 1); + + ADD_RANGE_MARK(RADEON_DST_OFFSET, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_SRC_OFFSET, 1, MARK_CHECK_OFFSET); + + ADD_RANGE_MARK(RADEON_DST_PITCH_OFFSET, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_SRC_PITCH_OFFSET, 1, MARK_CHECK_OFFSET); + + /* TODO SCISSOR */ + ADD_RANGE_MARK(R300_SC_SCISSOR0, 2, MARK_CHECK_SCISSOR); + + ADD_RANGE(R300_SC_CLIP_0_A, 2); + ADD_RANGE(R300_SC_CLIP_RULE, 1); + ADD_RANGE(R300_SC_SCREENDOOR, 1); + + ADD_RANGE(R300_VAP_PVS_CODE_CNTL_0, 4); + ADD_RANGE(R300_VAP_PVS_VECTOR_INDX_REG, 2); } -static __inline__ int r300_check_range(unsigned reg, int count) +int r300_check_range(unsigned reg, int count) { int i; if (reg & ~0xffff) @@ -268,6 +303,13 @@ static __inline__ int r300_check_range(unsigned reg, int count) return 0; } +int r300_get_reg_flags(unsigned reg) +{ + if (reg & ~0xffff) + return -1; + return r300_reg_flags[(reg >> 2)]; +} + static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * dev_priv, drm_radeon_kcmd_buffer_t diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 46f4290a..48f72ab0 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2301,6 +2301,8 @@ int radeon_modeset_cp_init(struct drm_device *dev) dev_priv->new_memmap = 1; + r300_init_reg_flags(dev); + radeon_cp_load_microcode(dev_priv); DRM_DEBUG("ring offset is %x %x\n", dev_priv->mm.ring.bo->offset, dev_priv->mm.ring_read.bo->offset); diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 61fef79d..8c2aea89 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -88,11 +88,84 @@ out: return r; } +int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, + uint32_t offset_dw) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int hdr = packets[offset_dw]; + int num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; + int need_reloc = 0; + int reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + int count_dw = 1; + int ret; + + while (count_dw < num_dw) { + /* need to have something like the r300 validation here - + list of allowed registers */ + int flags; + + ret = r300_check_range(reg, 1); + switch(ret) { + case -1: + DRM_ERROR("Illegal register %x\n", reg); + break; + case 0: + break; + case 1: + flags = r300_get_reg_flags(reg); + if (flags == MARK_CHECK_OFFSET) + DRM_DEBUG("need to relocate %x %d\n", reg, flags); + else if (flags == MARK_CHECK_SCISSOR) { + DRM_DEBUG("need to validate scissor %x %d\n", reg, flags); + } else { + DRM_DEBUG("illegal register %x %d\n", reg, flags); + return -EINVAL; + } + break; + } + count_dw++; + reg += 4; + } + return 0; +} + int radeon_cs_parse(struct drm_device *dev, void *ib, uint32_t *packets, uint32_t dwords) { drm_radeon_private_t *dev_priv = dev->dev_private; volatile int rb; + int size_dw = dwords; + /* scan the packet for various things */ + int count_dw = 0; + int ret = 0; + + while (count_dw < size_dw && ret == 0) { + int hdr = packets[count_dw]; + int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16; + int reg; + + switch (hdr & RADEON_CP_PACKET_MASK) { + case RADEON_CP_PACKET0: + ret = radeon_cs_packet0(dev, packets, count_dw); + break; + case RADEON_CP_PACKET1: + case RADEON_CP_PACKET2: + reg = hdr & RADEON_CP_PACKET0_REG_MASK; + DRM_DEBUG("Packet 1/2: %d %x\n", num_dw, reg); + break; + + case RADEON_CP_PACKET3: + reg = hdr & 0xff00; + DRM_DEBUG("Packet 3: %d %x\n", num_dw, reg); + break; + } + + count_dw += num_dw+2; + } + + if (ret) + return ret; + /* copy the packet into the IB */ memcpy(ib, packets, dwords * sizeof(uint32_t)); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index c431fe4a..232102d5 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1619,4 +1619,11 @@ extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *mas extern void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master); extern int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv); extern int radeon_cs_init(struct drm_device *dev); + +#define MARK_SAFE 1 +#define MARK_CHECK_OFFSET 2 +#define MARK_CHECK_SCISSOR 3 + +extern int r300_check_range(unsigned reg, int count); +extern int r300_get_reg_flags(unsigned reg); #endif /* __RADEON_DRV_H__ */ -- cgit v1.2.3 From 87520347b45e2f40a2d84831538a38d6a8d92439 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 28 Jul 2008 17:42:53 +1000 Subject: r300: add some packet 3 decodes --- shared-core/radeon_cs.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 8c2aea89..00860c2e 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -156,7 +156,25 @@ int radeon_cs_parse(struct drm_device *dev, void *ib, case RADEON_CP_PACKET3: reg = hdr & 0xff00; - DRM_DEBUG("Packet 3: %d %x\n", num_dw, reg); + + switch(reg) { + case RADEON_CNTL_HOSTDATA_BLT: + case RADEON_CNTL_BITBLT_MULTI: + case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */ + case RADEON_CP_INDX_BUFFER: + DRM_ERROR("need relocate packet 3 for %x\n", reg); + break; + + case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ + case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ + case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ + case RADEON_WAIT_FOR_IDLE: + case RADEON_CP_NOP: + break; + default: + DRM_ERROR("unknown packet 3 %x\n", reg); + ret = -EINVAL; + } break; } -- cgit v1.2.3 From 42e373e903d960b38c605229ab102933b18cff73 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 28 Jul 2008 18:18:28 +1000 Subject: radeon_cs: extract some offsets from packet data --- shared-core/radeon_cs.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 00860c2e..5cfe85be 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -88,6 +88,31 @@ out: return r; } +static __inline__ int radeon_cs_check_offset(struct drm_device *dev, + uint32_t reg, uint32_t val) +{ + uint32_t offset; + + switch(reg) { + case RADEON_DST_PITCH_OFFSET: + case RADEON_SRC_PITCH_OFFSET: + offset = val & ((1 << 22) - 1); + offset <<= 10; + break; + case R300_RB3D_COLOROFFSET0: + case R300_RB3D_DEPTHOFFSET: + offset = val; + break; + case R300_TX_OFFSET_0: + case R300_TX_OFFSET_0+4: + offset = val & 0xffffffe0; + break; + } + + DRM_ERROR("Offset check %x %x\n", reg, offset); + return 0; +} + int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, uint32_t offset_dw) { @@ -113,9 +138,11 @@ int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, break; case 1: flags = r300_get_reg_flags(reg); - if (flags == MARK_CHECK_OFFSET) + if (flags == MARK_CHECK_OFFSET) { + radeon_cs_check_offset(dev, reg, packets[offset_dw+count_dw]); + DRM_DEBUG("need to relocate %x %d\n", reg, flags); - else if (flags == MARK_CHECK_SCISSOR) { + } else if (flags == MARK_CHECK_SCISSOR) { DRM_DEBUG("need to validate scissor %x %d\n", reg, flags); } else { DRM_DEBUG("illegal register %x %d\n", reg, flags); @@ -159,6 +186,13 @@ int radeon_cs_parse(struct drm_device *dev, void *ib, switch(reg) { case RADEON_CNTL_HOSTDATA_BLT: + { + uint32_t offset; + offset = packets[count_dw+2] & ((1 << 22) - 1); + offset <<= 10; + DRM_ERROR("Offset check for Packet 3 %x %x\n", reg, offset); + break; + } case RADEON_CNTL_BITBLT_MULTI: case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */ case RADEON_CP_INDX_BUFFER: -- cgit v1.2.3 From 478e019cb7caa0c336b19a18eb3cb4e81896b493 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 28 Jul 2008 15:16:45 +0100 Subject: set to 2.4.0 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 78203343..987b0111 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libdrm], 2.3.1, [dri-devel@lists.sourceforge.net], libdrm) +AC_INIT([libdrm], 2.4.0, [dri-devel@lists.sourceforge.net], libdrm) AC_CONFIG_SRCDIR([Makefile.am]) AM_INIT_AUTOMAKE([dist-bzip2]) -- cgit v1.2.3 From 4234f82acc70f41e005d8cc301da56634352425c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 29 Jul 2008 16:51:47 +1000 Subject: radeon_cs: add relocate hook for mm and non-mm relocations --- linux-core/radeon_gem.c | 38 +++++++++++++++++++- shared-core/radeon_cs.c | 90 +++++++++++++++++++++++++++++++++++++++++++----- shared-core/radeon_drv.h | 8 +++-- 3 files changed, 124 insertions(+), 12 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 021bb9f9..859c1656 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -805,10 +805,45 @@ static int radeon_gem_ib_destroy(struct drm_device *dev) return 0; } +static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *reloc, uint32_t *offset) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + /* relocate the handle */ + int domains = reloc[2]; + struct drm_gem_object *obj; + int flags = 0; + int ret; + struct drm_radeon_gem_object *obj_priv; + + obj = drm_gem_object_lookup(dev, file_priv, reloc[1]); + if (!obj) + return false; + + obj_priv = obj->driver_private; + if (domains == RADEON_GEM_DOMAIN_VRAM) { + flags = DRM_BO_FLAG_MEM_VRAM; + } else { + flags = DRM_BO_FLAG_MEM_TT; + } + + ret = drm_bo_do_validate(obj_priv->bo, flags, DRM_BO_MASK_MEM, 0, 0, NULL); + if (ret) + return ret; + + if (flags == DRM_BO_FLAG_MEM_VRAM) + *offset = obj_priv->bo->offset + dev_priv->fb_location; + else + *offset = obj_priv->bo->offset + dev_priv->gart_vm_start; + + /* BAD BAD BAD - LINKED LIST THE OBJS and UNREF ONCE IB is SUBMITTED */ + drm_gem_object_unreference(obj); + return 0; +} + /* allocate 1MB of 64k IBs the the kernel can keep mapped */ static int radeon_gem_ib_init(struct drm_device *dev) { - drm_radeon_private_t *dev_priv = dev->dev_private; int i; int ret; @@ -843,6 +878,7 @@ static int radeon_gem_ib_init(struct drm_device *dev) dev_priv->cs.ib_free = radeon_gem_ib_free; radeon_cs_init(dev); + dev_priv->cs.relocate = radeon_gem_relocate; return 0; free_all: diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 5cfe85be..f01334bc 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -74,7 +74,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) } /* now parse command stream */ - r = radeon->cs.parse(dev, ib, packets, cs->dwords); + r = radeon->cs.parse(dev, fpriv, ib, packets, cs->dwords); if (r) { goto out; } @@ -88,6 +88,69 @@ out: return r; } +/* for non-mm */ +static int radeon_nomm_relocate(struct drm_device *dev, struct drm_file *file_priv, uint32_t *reloc, uint32_t *offset) +{ + *offset = reloc[1]; + return 0; +} +#define RELOC_SIZE 2 +#define RADEON_2D_OFFSET_MASK 0x3fffff + +static __inline__ int radeon_cs_relocate_offset(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *packets, uint32_t offset_dw) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t hdr = packets[offset_dw]; + uint32_t reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + uint32_t val = packets[offset_dw + 1]; + uint32_t packet3_hdr = packets[offset_dw+2]; + uint32_t tmp, offset; + int ret; + + /* this is too strict we may want to expand the length in the future and have + old kernels ignore it. */ + if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { + DRM_ERROR("Packet 3 was %x should have been %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16)); + return -EINVAL; + } + + switch(reg) { + case RADEON_DST_PITCH_OFFSET: + case RADEON_SRC_PITCH_OFFSET: + /* pass in the start of the reloc */ + ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset); + if (ret) + return ret; + tmp = (val & RADEON_2D_OFFSET_MASK) << 10; + val &= ~RADEON_2D_OFFSET_MASK; + offset += tmp; + offset >>= 10; + val |= offset; + break; + case R300_RB3D_COLOROFFSET0: + case R300_RB3D_DEPTHOFFSET: + case R300_TX_OFFSET_0: + case R300_TX_OFFSET_0+4: + offset = packets[offset_dw + 3]; + + ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset); + if (ret) + return ret; + + offset &= 0xffffffe0; + val += offset; + break; + default: + break; + } + + + DRM_ERROR("New offset %x %x %x\n", packets[offset_dw+1], val, offset); + packets[offset_dw + 1] = val; + + return 0; +} static __inline__ int radeon_cs_check_offset(struct drm_device *dev, uint32_t reg, uint32_t val) { @@ -113,11 +176,11 @@ static __inline__ int radeon_cs_check_offset(struct drm_device *dev, return 0; } -int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, - uint32_t offset_dw) +int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *packets, uint32_t offset_dw) { drm_radeon_private_t *dev_priv = dev->dev_private; - int hdr = packets[offset_dw]; + uint32_t hdr = packets[offset_dw]; int num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; int need_reloc = 0; int reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; @@ -139,9 +202,16 @@ int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, case 1: flags = r300_get_reg_flags(reg); if (flags == MARK_CHECK_OFFSET) { - radeon_cs_check_offset(dev, reg, packets[offset_dw+count_dw]); - + if (num_dw > 2) { + DRM_ERROR("Cannot relocate inside type stream of reg0 packets\n"); + return -EINVAL; + } + + ret = radeon_cs_relocate_offset(dev, file_priv, packets, offset_dw); + if (ret) + return ret; DRM_DEBUG("need to relocate %x %d\n", reg, flags); + /* okay it should be followed by a NOP */ } else if (flags == MARK_CHECK_SCISSOR) { DRM_DEBUG("need to validate scissor %x %d\n", reg, flags); } else { @@ -156,8 +226,8 @@ int radeon_cs_packet0(struct drm_device *dev, uint32_t *packets, return 0; } -int radeon_cs_parse(struct drm_device *dev, void *ib, - uint32_t *packets, uint32_t dwords) +int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv, + void *ib, uint32_t *packets, uint32_t dwords) { drm_radeon_private_t *dev_priv = dev->dev_private; volatile int rb; @@ -173,7 +243,7 @@ int radeon_cs_parse(struct drm_device *dev, void *ib, switch (hdr & RADEON_CP_PACKET_MASK) { case RADEON_CP_PACKET0: - ret = radeon_cs_packet0(dev, packets, count_dw); + ret = radeon_cs_packet0(dev, file_priv, packets, count_dw); break; case RADEON_CP_PACKET1: case RADEON_CP_PACKET2: @@ -191,6 +261,7 @@ int radeon_cs_parse(struct drm_device *dev, void *ib, offset = packets[count_dw+2] & ((1 << 22) - 1); offset <<= 10; DRM_ERROR("Offset check for Packet 3 %x %x\n", reg, offset); + /* okay it should be followed by a NOP */ break; } case RADEON_CNTL_BITBLT_MULTI: @@ -302,5 +373,6 @@ int radeon_cs_init(struct drm_device *dev) dev_priv->cs.parse = radeon_cs_parse; /* ib get depends on memory manager or not so memory manager */ + dev_priv->cs.relocate = radeon_nomm_relocate; return 0; } diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 232102d5..f79eade5 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -293,8 +293,8 @@ struct drm_radeon_cs_priv { uint32_t id_last_wcnt; uint32_t id_last_scnt; - int (*parse)(struct drm_device *dev, void *ib, - uint32_t *packets, uint32_t dwords); + int (*parse)(struct drm_device *dev, struct drm_file *file_priv, + void *ib, uint32_t *packets, uint32_t dwords); void (*id_emit)(struct drm_device *dev, uint32_t *id); uint32_t (*id_last_get)(struct drm_device *dev); /* this ib handling callback are for hidding memory manager drm @@ -303,6 +303,9 @@ struct drm_radeon_cs_priv { int (*ib_get)(struct drm_device *dev, void **ib, uint32_t dwords); uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib); void (*ib_free)(struct drm_device *dev, void *ib, uint32_t dwords); + /* do a relocation either MM or non-MM */ + bool (*relocate)(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *reloc, uint32_t *offset); }; typedef struct drm_radeon_private { @@ -391,6 +394,7 @@ typedef struct drm_radeon_private { int num_gb_pipes; + int mm_disabled; /* on OSes with no MM this will be 1*/ struct radeon_mm_info mm; drm_local_map_t *mmio; -- cgit v1.2.3 From 0452be882607f2d1601f4e592a11ccf543f5f9ca Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 29 Jul 2008 18:05:11 +1000 Subject: radeon: move code around putting emit into cs --- linux-core/radeon_gem.c | 29 +++++++----------- shared-core/radeon_cs.c | 76 ++++++++++++++++++++++++++++++++++++------------ shared-core/radeon_drv.h | 4 +-- 3 files changed, 69 insertions(+), 40 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 859c1656..9d122ac5 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -700,7 +700,7 @@ int radeon_gem_object_pin(struct drm_gem_object *obj, #define RADEON_NUM_IB (RADEON_IB_MEMORY / RADEON_IB_SIZE) -int radeon_gem_ib_get(struct drm_device *dev, void **ib, uint32_t dwords) +int radeon_gem_ib_get(struct drm_device *dev, void **ib, uint32_t dwords, uint32_t *card_offset) { int i, index = -1; int ret; @@ -738,6 +738,15 @@ int radeon_gem_ib_get(struct drm_device *dev, void **ib, uint32_t dwords) if (dwords > RADEON_IB_SIZE / sizeof(uint32_t)) return -EINVAL; + ret = drm_bo_do_validate(dev_priv->ib_objs[index]->bo, 0, + DRM_BO_FLAG_NO_EVICT, + 0, 0, NULL); + if (ret) { + DRM_ERROR("Failed to validate IB %d\n", index); + return -EINVAL; + } + + *card_offset = dev_priv->gart_vm_start + dev_priv->ib_objs[index]->bo->offset; *ib = dev_priv->ib_objs[index]->kmap.virtual; dev_priv->ib_alloc_bitmap |= (1 << i); return 0; @@ -754,24 +763,6 @@ static void radeon_gem_ib_free(struct drm_device *dev, void *ib, uint32_t dwords for (i = 0; i < RADEON_NUM_IB; i++) { if (dev_priv->ib_objs[i]->kmap.virtual == ib) { - ret = drm_bo_do_validate(dev_priv->ib_objs[i]->bo, 0, - DRM_BO_FLAG_NO_EVICT, - 0, 0, NULL); - if (ret) - DRM_ERROR("FAiled to validate\n"); - - DRM_DEBUG("validated IB %x, %d\n", dev_priv->ib_objs[i]->bo->offset, dwords); - BEGIN_RING(4); - - OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); - OUT_RING(dev_priv->gart_vm_start + dev_priv->ib_objs[i]->bo->offset); - OUT_RING(dwords); - OUT_RING(CP_PACKET2()); - - ADVANCE_RING(); - - COMMIT_RING(); - /* emit a fence object */ ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); if (ret) { diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index f01334bc..33a8ccd4 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -31,19 +31,21 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) { - struct drm_radeon_private *radeon = dev->dev_private; + struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_radeon_cs *cs = data; uint32_t *packets = NULL; uint32_t cs_id; + uint32_t card_offset; void *ib = NULL; long size; int r; + RING_LOCALS; /* set command stream id to 0 which is fake id */ cs_id = 0; DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); - if (radeon == NULL) { + if (dev_priv == NULL) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } @@ -68,22 +70,31 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) goto out; } /* get ib */ - r = radeon->cs.ib_get(dev, &ib, cs->dwords); + r = dev_priv->cs.ib_get(dev, &ib, cs->dwords, &card_offset); if (r) { goto out; } /* now parse command stream */ - r = radeon->cs.parse(dev, fpriv, ib, packets, cs->dwords); + r = dev_priv->cs.parse(dev, fpriv, ib, packets, cs->dwords); if (r) { goto out; } + BEGIN_RING(4); + OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); + OUT_RING(card_offset); + OUT_RING(cs->dwords); + OUT_RING(CP_PACKET2()); + ADVANCE_RING(); + /* emit cs id sequence */ - radeon->cs.id_emit(dev, &cs_id); + dev_priv->cs.id_emit(dev, &cs_id); + COMMIT_RING(); + DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); out: - radeon->cs.ib_free(dev, ib, cs->dwords); + dev_priv->cs.ib_free(dev, ib, cs->dwords); drm_free(packets, size, DRM_MEM_DRIVER); return r; } @@ -97,8 +108,8 @@ static int radeon_nomm_relocate(struct drm_device *dev, struct drm_file *file_pr #define RELOC_SIZE 2 #define RADEON_2D_OFFSET_MASK 0x3fffff -static __inline__ int radeon_cs_relocate_offset(struct drm_device *dev, struct drm_file *file_priv, - uint32_t *packets, uint32_t offset_dw) +static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *packets, uint32_t offset_dw) { drm_radeon_private_t *dev_priv = dev->dev_private; uint32_t hdr = packets[offset_dw]; @@ -107,7 +118,7 @@ static __inline__ int radeon_cs_relocate_offset(struct drm_device *dev, struct d uint32_t packet3_hdr = packets[offset_dw+2]; uint32_t tmp, offset; int ret; - + /* this is too strict we may want to expand the length in the future and have old kernels ignore it. */ if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { @@ -132,8 +143,6 @@ static __inline__ int radeon_cs_relocate_offset(struct drm_device *dev, struct d case R300_RB3D_DEPTHOFFSET: case R300_TX_OFFSET_0: case R300_TX_OFFSET_0+4: - offset = packets[offset_dw + 3]; - ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset); if (ret) return ret; @@ -151,6 +160,40 @@ static __inline__ int radeon_cs_relocate_offset(struct drm_device *dev, struct d return 0; } + +static int radeon_cs_relocate_packet3(struct drm_device *dev, struct drm_file *file_priv, + uint32_t *packets, uint32_t offset_dw) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t hdr = packets[offset_dw]; + int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16; + uint32_t reg = hdr & 0xff00; + uint32_t offset, val, tmp; + int ret; + + switch(reg) { + case RADEON_CNTL_HOSTDATA_BLT: + { + val = packets[offset_dw + 2]; + ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + num_dw + 2, &offset); + if (ret) + return ret; + + tmp = (val & RADEON_2D_OFFSET_MASK) << 10; + val &= ~RADEON_2D_OFFSET_MASK; + offset += tmp; + offset >>= 10; + val |= offset; + + DRM_ERROR("New offset %x %x %x\n", packets[offset_dw+2], val, offset); + packets[offset_dw + 2] = val; + } + default: + return -EINVAL; + } + return 0; +} + static __inline__ int radeon_cs_check_offset(struct drm_device *dev, uint32_t reg, uint32_t val) { @@ -207,7 +250,7 @@ int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv, return -EINVAL; } - ret = radeon_cs_relocate_offset(dev, file_priv, packets, offset_dw); + ret = radeon_cs_relocate_packet0(dev, file_priv, packets, offset_dw); if (ret) return ret; DRM_DEBUG("need to relocate %x %d\n", reg, flags); @@ -256,14 +299,9 @@ int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv, switch(reg) { case RADEON_CNTL_HOSTDATA_BLT: - { - uint32_t offset; - offset = packets[count_dw+2] & ((1 << 22) - 1); - offset <<= 10; - DRM_ERROR("Offset check for Packet 3 %x %x\n", reg, offset); - /* okay it should be followed by a NOP */ + radeon_cs_relocate_packet3(dev, file_priv, packets, count_dw); break; - } + case RADEON_CNTL_BITBLT_MULTI: case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */ case RADEON_CP_INDX_BUFFER: diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index f79eade5..e55a9697 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -300,11 +300,11 @@ struct drm_radeon_cs_priv { /* this ib handling callback are for hidding memory manager drm * from memory manager less drm, free have to emit ib discard * sequence into the ring */ - int (*ib_get)(struct drm_device *dev, void **ib, uint32_t dwords); + int (*ib_get)(struct drm_device *dev, void **ib, uint32_t dwords, uint32_t *card_offset); uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib); void (*ib_free)(struct drm_device *dev, void *ib, uint32_t dwords); /* do a relocation either MM or non-MM */ - bool (*relocate)(struct drm_device *dev, struct drm_file *file_priv, + int (*relocate)(struct drm_device *dev, struct drm_file *file_priv, uint32_t *reloc, uint32_t *offset); }; -- cgit v1.2.3 From d659302e0955598ae08316ab911a0fb74d5e2f2f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 30 Jul 2008 17:05:50 +1000 Subject: radeon: add some handles to the sarea + kernel mm available check --- shared-core/radeon_drm.h | 8 ++++++++ shared-core/radeon_state.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index c20de561..8ee1baa7 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -455,6 +455,13 @@ typedef struct { int tiling_enabled; /* set by drm, read by 2d + 3d clients */ unsigned int last_fence; + + uint32_t front_handle; + uint32_t back_handle; + uint32_t depth_handle; + uint32_t front_pitch; + uint32_t back_pitch; + uint32_t depth_pitch; } drm_radeon_sarea_t; @@ -705,6 +712,7 @@ typedef struct drm_radeon_indirect { #define RADEON_PARAM_VBLANK_CRTC 13 /* VBLANK CRTC */ #define RADEON_PARAM_FB_LOCATION 14 /* FB location */ #define RADEON_PARAM_NUM_GB_PIPES 15 /* num GB pipes */ +#define RADEON_PARAM_KERNEL_MM 16 typedef struct drm_radeon_getparam { int param; diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index d56dac19..00160fbf 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3117,6 +3117,10 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil case RADEON_PARAM_NUM_GB_PIPES: value = dev_priv->num_gb_pipes; break; + case RADEON_PARAM_KERNEL_MM: + /* BSD TODO */ + value = 1; + break; default: DRM_DEBUG( "Invalid parameter %d\n", param->param ); return -EINVAL; -- cgit v1.2.3 From fb5542aaa87aca9b6b312968abe0a6044812cf0e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 30 Jul 2008 17:06:11 +1000 Subject: radeon: hack gem to get an offset back for Mesa. --- linux-core/radeon_gem.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 9d122ac5..e06cba5b 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -243,9 +243,12 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, DRM_DEBUG("got here %p %p %d\n", obj, obj_priv->bo, atomic_read(&obj_priv->bo->usage)); /* validate into a pin with no fence */ - ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, - 0, NULL); + if (!(obj_priv->bo->type != drm_bo_type_kernel && !DRM_SUSER(DRM_CURPROC))) { + ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, + 0, NULL); + } else + ret = 0; args->offset = obj_priv->bo->offset; DRM_DEBUG("got here %p %p\n", obj, obj_priv->bo); -- cgit v1.2.3 From 6d4e147480a334d32fa59c7fde53e10d7ab6e106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 22 Jul 2008 14:24:32 -0400 Subject: Make it compile again. --- linux-core/drm_compat.h | 8 ++++++++ linux-core/drm_ttm.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index cfa4fc6d..564a9438 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -386,4 +386,12 @@ extern struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, unsigned long address, int *type); #endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) +#define drm_on_each_cpu(handler, data, wait) \ + on_each_cpu(handler, data, wait) +#else +#define drm_on_each_cpu(handler, data, wait) \ + on_each_cpu(handler, data, wait, 1) +#endif + #endif diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 80a8ff5d..aa137dda 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -72,7 +72,7 @@ void drm_ttm_cache_flush(struct page *pages[], unsigned long num_pages) return; } #endif - if (on_each_cpu(drm_ttm_ipi_handler, NULL, 1, 1) != 0) + if (drm_on_each_cpu(drm_ttm_ipi_handler, NULL, 1) != 0) DRM_ERROR("Timed out waiting for drm cache flush.\n"); } EXPORT_SYMBOL(drm_ttm_cache_flush); -- cgit v1.2.3 From 9b8d71b5eb09857b07409731d3de182751f712a2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 31 Jul 2008 12:54:48 +1000 Subject: TTM: remove API and userspace objects. This removes all the TTM userspace API and all userspace objects. It also removes the drm_bo_lock.c code --- linux-core/Makefile.kernel | 7 +- linux-core/drmP.h | 18 - linux-core/drm_bo.c | 729 +--------------------------------- linux-core/drm_bo_lock.c | 189 --------- linux-core/drm_crtc_helper.c | 44 --- linux-core/drm_drv.c | 30 -- linux-core/drm_fence.c | 298 +------------- linux-core/drm_fops.c | 43 -- linux-core/drm_object.c | 294 -------------- linux-core/drm_objects.h | 273 ++++++++----- linux-core/drm_ttm.c | 2 +- linux-core/i915_buffer.c | 311 --------------- linux-core/i915_execbuf.c | 921 ------------------------------------------- linux-core/i915_fence.c | 273 ------------- linux-core/radeon_gem.c | 15 +- shared-core/drm.h | 343 ---------------- shared-core/i915_dma.c | 32 +- shared-core/i915_drm.h | 52 --- 18 files changed, 190 insertions(+), 3684 deletions(-) delete mode 100644 linux-core/drm_bo_lock.c delete mode 100644 linux-core/drm_object.c delete mode 100644 linux-core/i915_buffer.c delete mode 100644 linux-core/i915_execbuf.c delete mode 100644 linux-core/i915_fence.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 404944bf..b15a12ab 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -12,16 +12,15 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ - drm_hashtab.o drm_memrange.o drm_object.o drm_compat.o \ - drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_bo_lock.o \ + drm_hashtab.o drm_memrange.o drm_compat.o \ + drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o \ drm_crtc.o drm_edid.o drm_modes.o drm_crtc_helper.o \ drm_regman.o drm_vm_nopage_compat.o drm_gem.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o -i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ - i915_buffer.o i915_execbuf.o i915_gem.o \ +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_gem.o \ intel_display.o intel_crt.o intel_lvds.o intel_bios.o \ intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o \ intel_tv.o i915_compat.o intel_dvo.o dvo_ch7xxx.o \ diff --git a/linux-core/drmP.h b/linux-core/drmP.h index e3a08e79..4938881f 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -405,14 +405,6 @@ struct drm_buf_entry { struct drm_freelist freelist; }; - -enum drm_ref_type { - _DRM_REF_USE = 0, - _DRM_REF_TYPE1, - _DRM_NO_REF_TYPES -}; - - /** File private data */ struct drm_file { int authenticated; @@ -424,21 +416,11 @@ struct drm_file { struct drm_minor *minor; unsigned long lock_count; - /* - * The user object hash table is global and resides in the - * drm_device structure. We protect the lists and hash tables with the - * device struct_mutex. A bit coarse-grained but probably the best - * option. - */ - - struct list_head refd_objects; - /** Mapping of mm object handles to object pointers. */ struct idr object_idr; /** Lock for synchronization of access to object_idr. */ spinlock_t table_lock; - struct drm_open_hash refd_object_hash[_DRM_NO_REF_TYPES]; struct file *filp; void *driver_priv; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 0021530b..84cf69bd 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -565,18 +565,6 @@ void drm_bo_usage_deref_locked(struct drm_buffer_object **bo) } EXPORT_SYMBOL(drm_bo_usage_deref_locked); -static void drm_bo_base_deref_locked(struct drm_file *file_priv, - struct drm_user_object *uo) -{ - struct drm_buffer_object *bo = - drm_user_object_entry(uo, struct drm_buffer_object, base); - - DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); - - drm_bo_takedown_vm_locked(bo); - drm_bo_usage_deref_locked(&bo); -} - void drm_bo_usage_deref_unlocked(struct drm_buffer_object **bo) { struct drm_buffer_object *tmp_bo = *bo; @@ -1067,34 +1055,6 @@ static int drm_bo_modify_proposed_flags (struct drm_buffer_object *bo, return 0; } -/* - * Call dev->struct_mutex locked. - */ - -struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file *file_priv, - uint32_t handle, int check_owner) -{ - struct drm_user_object *uo; - struct drm_buffer_object *bo; - - uo = drm_lookup_user_object(file_priv, handle); - - if (!uo || (uo->type != drm_buffer_type)) { - DRM_ERROR("Could not find buffer object 0x%08x\n", handle); - return NULL; - } - - if (check_owner && file_priv != uo->owner) { - if (!drm_lookup_ref_object(file_priv, uo, _DRM_REF_USE)) - return NULL; - } - - bo = drm_user_object_entry(uo, struct drm_buffer_object, base); - atomic_inc(&bo->usage); - return bo; -} -EXPORT_SYMBOL(drm_lookup_buffer_object); - /* * Call bo->mutex locked. * Returns -EBUSY if the buffer is currently rendered to or from. 0 otherwise. @@ -1157,149 +1117,6 @@ static int drm_bo_wait_unmapped(struct drm_buffer_object *bo, int no_wait) return ret; } -/* - * Fill in the ioctl reply argument with buffer info. - * Bo locked. - */ - -void drm_bo_fill_rep_arg(struct drm_buffer_object *bo, - struct drm_bo_info_rep *rep) -{ - if (!rep) - return; - - rep->handle = bo->base.hash.key; - rep->flags = bo->mem.flags; - rep->size = bo->num_pages * PAGE_SIZE; - rep->offset = bo->offset; - - /* - * drm_bo_type_device buffers have user-visible - * handles which can be used to share across - * processes. Hand that back to the application - */ - if (bo->type == drm_bo_type_device) - rep->arg_handle = bo->map_list.user_token; - else - rep->arg_handle = 0; - - rep->proposed_flags = bo->mem.proposed_flags; - rep->buffer_start = bo->buffer_start; - rep->fence_flags = bo->fence_type; - rep->rep_flags = 0; - rep->page_alignment = bo->mem.page_alignment; - - if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo, 1)) { - DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, - DRM_BO_REP_BUSY); - } -} -EXPORT_SYMBOL(drm_bo_fill_rep_arg); - -/* - * Wait for buffer idle and register that we've mapped the buffer. - * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, - * so that if the client dies, the mapping is automatically - * unregistered. - */ - -static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle, - uint32_t map_flags, unsigned hint, - struct drm_bo_info_rep *rep) -{ - struct drm_buffer_object *bo; - struct drm_device *dev = file_priv->minor->dev; - int ret = 0; - int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; - - mutex_lock(&dev->struct_mutex); - bo = drm_lookup_buffer_object(file_priv, handle, 1); - mutex_unlock(&dev->struct_mutex); - - if (!bo) - return -EINVAL; - - mutex_lock(&bo->mutex); - do { - bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; - - ret = drm_bo_wait(bo, 0, 1, no_wait, 1); - if (unlikely(ret)) - goto out; - - if (bo->mem.flags & DRM_BO_FLAG_CACHED_MAPPED) - drm_bo_evict_cached(bo); - - } while (unlikely(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED)); - - atomic_inc(&bo->mapped); - mutex_lock(&dev->struct_mutex); - ret = drm_add_ref_object(file_priv, &bo->base, _DRM_REF_TYPE1); - mutex_unlock(&dev->struct_mutex); - if (ret) { - if (atomic_dec_and_test(&bo->mapped)) - wake_up_all(&bo->event_queue); - - } else - drm_bo_fill_rep_arg(bo, rep); - - out: - mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(&bo); - - return ret; -} - -static int drm_buffer_object_unmap(struct drm_file *file_priv, uint32_t handle) -{ - struct drm_device *dev = file_priv->minor->dev; - struct drm_buffer_object *bo; - struct drm_ref_object *ro; - int ret = 0; - - mutex_lock(&dev->struct_mutex); - - bo = drm_lookup_buffer_object(file_priv, handle, 1); - if (!bo) { - ret = -EINVAL; - goto out; - } - - ro = drm_lookup_ref_object(file_priv, &bo->base, _DRM_REF_TYPE1); - if (!ro) { - ret = -EINVAL; - goto out; - } - - drm_remove_ref_object(file_priv, ro); - drm_bo_usage_deref_locked(&bo); -out: - mutex_unlock(&dev->struct_mutex); - return ret; -} - -/* - * Call struct-sem locked. - */ - -static void drm_buffer_user_object_unmap(struct drm_file *file_priv, - struct drm_user_object *uo, - enum drm_ref_type action) -{ - struct drm_buffer_object *bo = - drm_user_object_entry(uo, struct drm_buffer_object, base); - - /* - * We DON'T want to take the bo->lock here, because we want to - * hold it when we wait for unmapped buffer. - */ - - BUG_ON(action != _DRM_REF_TYPE1); - - if (atomic_dec_and_test(&bo->mapped)) - wake_up_all(&bo->event_queue); -} - /* * bo->mutex locked. * Note that new_mem_flags are NOT transferred to the bo->mem.proposed_flags. @@ -1594,8 +1411,7 @@ static int drm_bo_prepare_for_validate(struct drm_buffer_object *bo, int drm_bo_do_validate(struct drm_buffer_object *bo, uint64_t flags, uint64_t mask, uint32_t hint, - uint32_t fence_class, - struct drm_bo_info_rep *rep) + uint32_t fence_class) { int ret; int no_wait = (hint & DRM_BO_HINT_DONT_BLOCK) != 0; @@ -1622,132 +1438,12 @@ int drm_bo_do_validate(struct drm_buffer_object *bo, BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); out: - if (rep) - drm_bo_fill_rep_arg(bo, rep); - mutex_unlock(&bo->mutex); return ret; } EXPORT_SYMBOL(drm_bo_do_validate); -/** - * drm_bo_handle_validate - * - * @file_priv: the drm file private, used to get a handle to the user context - * - * @handle: the buffer object handle - * - * @flags: access rights, mapping parameters and cacheability. See - * the DRM_BO_FLAG_* values in drm.h - * - * @mask: Which flag values to change; this allows callers to modify - * things without knowing the current state of other flags. - * - * @hint: changes the proceedure for this operation, see the DRM_BO_HINT_* - * values in drm.h. - * - * @fence_class: a driver-specific way of doing fences. Presumably, - * this would be used if the driver had more than one submission and - * fencing mechanism. At this point, there isn't any use of this - * from the user mode code. - * - * @rep: To be stuffed with the reply from validation - * - * @bp_rep: To be stuffed with the buffer object pointer - * - * Perform drm_bo_do_validate on a buffer referenced by a user-space handle instead - * of a pointer to a buffer object. Optionally return a pointer to the buffer object. - * This is a convenience wrapper only. - */ - -int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, - uint64_t flags, uint64_t mask, - uint32_t hint, - uint32_t fence_class, - struct drm_bo_info_rep *rep, - struct drm_buffer_object **bo_rep) -{ - struct drm_device *dev = file_priv->minor->dev; - struct drm_buffer_object *bo; - int ret; - - mutex_lock(&dev->struct_mutex); - bo = drm_lookup_buffer_object(file_priv, handle, 1); - mutex_unlock(&dev->struct_mutex); - - if (!bo) - return -EINVAL; - - if (bo->base.owner != file_priv) - mask &= ~(DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE); - - ret = drm_bo_do_validate(bo, flags, mask, hint, fence_class, rep); - - if (!ret && bo_rep) - *bo_rep = bo; - else - drm_bo_usage_deref_unlocked(&bo); - - return ret; -} -EXPORT_SYMBOL(drm_bo_handle_validate); - - -static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle, - struct drm_bo_info_rep *rep) -{ - struct drm_device *dev = file_priv->minor->dev; - struct drm_buffer_object *bo; - - mutex_lock(&dev->struct_mutex); - bo = drm_lookup_buffer_object(file_priv, handle, 1); - mutex_unlock(&dev->struct_mutex); - - if (!bo) - return -EINVAL; - - mutex_lock(&bo->mutex); - - /* - * FIXME: Quick busy here? - */ - - drm_bo_busy(bo, 1); - drm_bo_fill_rep_arg(bo, rep); - mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(&bo); - return 0; -} - -static int drm_bo_handle_wait(struct drm_file *file_priv, uint32_t handle, - uint32_t hint, - struct drm_bo_info_rep *rep) -{ - struct drm_device *dev = file_priv->minor->dev; - struct drm_buffer_object *bo; - int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; - int ret; - - mutex_lock(&dev->struct_mutex); - bo = drm_lookup_buffer_object(file_priv, handle, 1); - mutex_unlock(&dev->struct_mutex); - - if (!bo) - return -EINVAL; - - mutex_lock(&bo->mutex); - ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, 1, no_wait, 1); - if (ret) - goto out; - - drm_bo_fill_rep_arg(bo, rep); -out: - mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(&bo); - return ret; -} - int drm_buffer_object_create(struct drm_device *dev, unsigned long size, enum drm_bo_type type, @@ -1822,7 +1518,7 @@ int drm_buffer_object_create(struct drm_device *dev, mutex_unlock(&bo->mutex); ret = drm_bo_do_validate(bo, 0, 0, hint | DRM_BO_HINT_DONT_FENCE, - 0, NULL); + 0); if (ret) goto out_err_unlocked; @@ -1837,230 +1533,6 @@ out_err_unlocked: } EXPORT_SYMBOL(drm_buffer_object_create); - -int drm_bo_add_user_object(struct drm_file *file_priv, - struct drm_buffer_object *bo, int shareable) -{ - struct drm_device *dev = file_priv->minor->dev; - int ret; - - mutex_lock(&dev->struct_mutex); - ret = drm_add_user_object(file_priv, &bo->base, shareable); - if (ret) - goto out; - - bo->base.remove = drm_bo_base_deref_locked; - bo->base.type = drm_buffer_type; - bo->base.ref_struct_locked = NULL; - bo->base.unref = drm_buffer_user_object_unmap; - -out: - mutex_unlock(&dev->struct_mutex); - return ret; -} -EXPORT_SYMBOL(drm_bo_add_user_object); - -int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_bo_create_arg *arg = data; - struct drm_bo_create_req *req = &arg->d.req; - struct drm_bo_info_rep *rep = &arg->d.rep; - struct drm_buffer_object *entry; - enum drm_bo_type bo_type; - int ret = 0; - - DRM_DEBUG("drm_bo_create_ioctl: %dkb, %dkb align\n", - (int)(req->size / 1024), req->page_alignment * 4); - - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized.\n"); - return -EINVAL; - } - - /* - * If the buffer creation request comes in with a starting address, - * that points at the desired user pages to map. Otherwise, create - * a drm_bo_type_device buffer, which uses pages allocated from the kernel - */ - bo_type = (req->buffer_start) ? drm_bo_type_user : drm_bo_type_device; - - /* - * User buffers cannot be shared - */ - if (bo_type == drm_bo_type_user) - req->flags &= ~DRM_BO_FLAG_SHAREABLE; - - ret = drm_buffer_object_create(file_priv->minor->dev, - req->size, bo_type, req->flags, - req->hint, req->page_alignment, - req->buffer_start, &entry); - if (ret) - goto out; - - ret = drm_bo_add_user_object(file_priv, entry, - req->flags & DRM_BO_FLAG_SHAREABLE); - if (ret) { - drm_bo_usage_deref_unlocked(&entry); - goto out; - } - - mutex_lock(&entry->mutex); - drm_bo_fill_rep_arg(entry, rep); - mutex_unlock(&entry->mutex); - -out: - return ret; -} - -int drm_bo_setstatus_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_bo_map_wait_idle_arg *arg = data; - struct drm_bo_info_req *req = &arg->d.req; - struct drm_bo_info_rep *rep = &arg->d.rep; - struct drm_buffer_object *bo; - int ret; - - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized.\n"); - return -EINVAL; - } - - ret = drm_bo_read_lock(&dev->bm.bm_lock, 1); - if (ret) - return ret; - - mutex_lock(&dev->struct_mutex); - bo = drm_lookup_buffer_object(file_priv, req->handle, 1); - mutex_unlock(&dev->struct_mutex); - - if (!bo) - return -EINVAL; - - if (bo->base.owner != file_priv) - req->mask &= ~(DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE); - - ret = drm_bo_do_validate(bo, req->flags, req->mask, - req->hint | DRM_BO_HINT_DONT_FENCE, - bo->fence_class, rep); - - drm_bo_usage_deref_unlocked(&bo); - - (void) drm_bo_read_unlock(&dev->bm.bm_lock); - - return ret; -} - -int drm_bo_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_bo_map_wait_idle_arg *arg = data; - struct drm_bo_info_req *req = &arg->d.req; - struct drm_bo_info_rep *rep = &arg->d.rep; - int ret; - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized.\n"); - return -EINVAL; - } - - ret = drm_buffer_object_map(file_priv, req->handle, req->mask, - req->hint, rep); - if (ret) - return ret; - - return 0; -} - -int drm_bo_unmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_bo_handle_arg *arg = data; - int ret; - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized.\n"); - return -EINVAL; - } - - ret = drm_buffer_object_unmap(file_priv, arg->handle); - return ret; -} - - -int drm_bo_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_bo_reference_info_arg *arg = data; - struct drm_bo_handle_arg *req = &arg->d.req; - struct drm_bo_info_rep *rep = &arg->d.rep; - struct drm_user_object *uo; - int ret; - - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized.\n"); - return -EINVAL; - } - - ret = drm_user_object_ref(file_priv, req->handle, - drm_buffer_type, &uo); - if (ret) - return ret; - - ret = drm_bo_handle_info(file_priv, req->handle, rep); - if (ret) - return ret; - - return 0; -} - -int drm_bo_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_bo_handle_arg *arg = data; - int ret = 0; - - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized.\n"); - return -EINVAL; - } - - ret = drm_user_object_unref(file_priv, arg->handle, drm_buffer_type); - return ret; -} - -int drm_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_bo_reference_info_arg *arg = data; - struct drm_bo_handle_arg *req = &arg->d.req; - struct drm_bo_info_rep *rep = &arg->d.rep; - int ret; - - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized.\n"); - return -EINVAL; - } - - ret = drm_bo_handle_info(file_priv, req->handle, rep); - if (ret) - return ret; - - return 0; -} - -int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_bo_map_wait_idle_arg *arg = data; - struct drm_bo_info_req *req = &arg->d.req; - struct drm_bo_info_rep *rep = &arg->d.rep; - int ret; - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized.\n"); - return -EINVAL; - } - - ret = drm_bo_handle_wait(file_priv, req->handle, - req->hint, rep); - if (ret) - return ret; - - return 0; -} - static int drm_bo_leave_list(struct drm_buffer_object *bo, uint32_t mem_type, int free_pinned, @@ -2435,191 +1907,6 @@ out_unlock: } EXPORT_SYMBOL(drm_bo_driver_init); -int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_mm_init_arg *arg = data; - struct drm_buffer_manager *bm = &dev->bm; - struct drm_bo_driver *driver = dev->driver->bo_driver; - int ret; - - if (!driver) { - DRM_ERROR("Buffer objects are not supported by this driver\n"); - return -EINVAL; - } - - ret = drm_bo_write_lock(&bm->bm_lock, 1, file_priv); - if (ret) - return ret; - - ret = -EINVAL; - if (arg->magic != DRM_BO_INIT_MAGIC) { - DRM_ERROR("You are using an old libdrm that is not compatible with\n" - "\tthe kernel DRM module. Please upgrade your libdrm.\n"); - return -EINVAL; - } - if (arg->major != DRM_BO_INIT_MAJOR) { - DRM_ERROR("libdrm and kernel DRM buffer object interface major\n" - "\tversion don't match. Got %d, expected %d.\n", - arg->major, DRM_BO_INIT_MAJOR); - return -EINVAL; - } - - mutex_lock(&dev->struct_mutex); - if (!bm->initialized) { - DRM_ERROR("DRM memory manager was not initialized.\n"); - goto out; - } - if (arg->mem_type == 0) { - DRM_ERROR("System memory buffers already initialized.\n"); - goto out; - } - ret = drm_bo_init_mm(dev, arg->mem_type, - arg->p_offset, arg->p_size, 0); - -out: - mutex_unlock(&dev->struct_mutex); - (void) drm_bo_write_unlock(&bm->bm_lock, file_priv); - - if (ret) - return ret; - - return 0; -} - -int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_mm_type_arg *arg = data; - struct drm_buffer_manager *bm = &dev->bm; - struct drm_bo_driver *driver = dev->driver->bo_driver; - int ret; - - if (!driver) { - DRM_ERROR("Buffer objects are not supported by this driver\n"); - return -EINVAL; - } - - ret = drm_bo_write_lock(&bm->bm_lock, 0, file_priv); - if (ret) - return ret; - - mutex_lock(&dev->struct_mutex); - ret = -EINVAL; - if (!bm->initialized) { - DRM_ERROR("DRM memory manager was not initialized\n"); - goto out; - } - if (arg->mem_type == 0) { - DRM_ERROR("No takedown for System memory buffers.\n"); - goto out; - } - ret = 0; - if ((ret = drm_bo_clean_mm(dev, arg->mem_type, 0))) { - if (ret == -EINVAL) - DRM_ERROR("Memory manager type %d not clean. " - "Delaying takedown\n", arg->mem_type); - ret = 0; - } -out: - mutex_unlock(&dev->struct_mutex); - (void) drm_bo_write_unlock(&bm->bm_lock, file_priv); - - if (ret) - return ret; - - return 0; -} - -int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_mm_type_arg *arg = data; - struct drm_bo_driver *driver = dev->driver->bo_driver; - int ret; - - if (!driver) { - DRM_ERROR("Buffer objects are not supported by this driver\n"); - return -EINVAL; - } - - if (arg->lock_flags & DRM_BO_LOCK_IGNORE_NO_EVICT) { - DRM_ERROR("Lock flag DRM_BO_LOCK_IGNORE_NO_EVICT not supported yet.\n"); - return -EINVAL; - } - - if (arg->lock_flags & DRM_BO_LOCK_UNLOCK_BM) { - ret = drm_bo_write_lock(&dev->bm.bm_lock, 1, file_priv); - if (ret) - return ret; - } - - mutex_lock(&dev->struct_mutex); - ret = drm_bo_lock_mm(dev, arg->mem_type); - mutex_unlock(&dev->struct_mutex); - if (ret) { - (void) drm_bo_write_unlock(&dev->bm.bm_lock, file_priv); - return ret; - } - - return 0; -} - -int drm_mm_unlock_ioctl(struct drm_device *dev, - void *data, - struct drm_file *file_priv) -{ - struct drm_mm_type_arg *arg = data; - struct drm_bo_driver *driver = dev->driver->bo_driver; - int ret; - - if (!driver) { - DRM_ERROR("Buffer objects are not supported by this driver\n"); - return -EINVAL; - } - - if (arg->lock_flags & DRM_BO_LOCK_UNLOCK_BM) { - ret = drm_bo_write_unlock(&dev->bm.bm_lock, file_priv); - if (ret) - return ret; - } - - return 0; -} - -int drm_mm_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_mm_info_arg *arg = data; - struct drm_buffer_manager *bm = &dev->bm; - struct drm_bo_driver *driver = dev->driver->bo_driver; - struct drm_mem_type_manager *man; - int ret = 0; - int mem_type = arg->mem_type; - - if (!driver) { - DRM_ERROR("Buffer objects are not supported by this driver\n"); - return -EINVAL; - } - - if (mem_type >= DRM_BO_MEM_TYPES) { - DRM_ERROR("Illegal memory type %d\n", arg->mem_type); - return -EINVAL; - } - - mutex_lock(&dev->struct_mutex); - if (!bm->initialized) { - DRM_ERROR("DRM memory manager was not initialized\n"); - ret = -EINVAL; - goto out; - } - - - man = &bm->man[arg->mem_type]; - - arg->p_size = man->size; - -out: - mutex_unlock(&dev->struct_mutex); - - return ret; -} /* * buffer object vm functions. */ @@ -2792,15 +2079,3 @@ static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo) return 0; } - -int drm_bo_version_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_bo_version_arg *arg = (struct drm_bo_version_arg *)data; - - arg->major = DRM_BO_INIT_MAJOR; - arg->minor = DRM_BO_INIT_MINOR; - arg->patchlevel = DRM_BO_INIT_PATCH; - - return 0; -} diff --git a/linux-core/drm_bo_lock.c b/linux-core/drm_bo_lock.c deleted file mode 100644 index 08b1c6be..00000000 --- a/linux-core/drm_bo_lock.c +++ /dev/null @@ -1,189 +0,0 @@ -/************************************************************************** - * - * Copyright (c) 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ -/* - * Authors: Thomas Hellström - */ - -/* - * This file implements a simple replacement for the buffer manager use - * of the heavyweight hardware lock. - * The lock is a read-write lock. Taking it in read mode is fast, and - * intended for in-kernel use only. - * Taking it in write mode is slow. - * - * The write mode is used only when there is a need to block all - * user-space processes from allocating a - * new memory area. - * Typical use in write mode is X server VT switching, and it's allowed - * to leave kernel space with the write lock held. If a user-space process - * dies while having the write-lock, it will be released during the file - * descriptor release. - * - * The read lock is typically placed at the start of an IOCTL- or - * user-space callable function that may end up allocating a memory area. - * This includes setstatus, super-ioctls and no_pfn; the latter may move - * unmappable regions to mappable. It's a bug to leave kernel space with the - * read lock held. - * - * Both read- and write lock taking may be interruptible for low signal-delivery - * latency. The locking functions will return -EAGAIN if interrupted by a - * signal. - * - * Locking order: The lock should be taken BEFORE any kernel mutexes - * or spinlocks. - */ - -#include "drmP.h" - -void drm_bo_init_lock(struct drm_bo_lock *lock) -{ - DRM_INIT_WAITQUEUE(&lock->queue); - atomic_set(&lock->write_lock_pending, 0); - atomic_set(&lock->readers, 0); -} - -void drm_bo_read_unlock(struct drm_bo_lock *lock) -{ - if (atomic_dec_and_test(&lock->readers)) - wake_up_all(&lock->queue); -} -EXPORT_SYMBOL(drm_bo_read_unlock); - -int drm_bo_read_lock(struct drm_bo_lock *lock, int interruptible) -{ - while (unlikely(atomic_read(&lock->write_lock_pending) != 0)) { - int ret; - - if (!interruptible) { - wait_event(lock->queue, - atomic_read(&lock->write_lock_pending) == 0); - continue; - } - ret = wait_event_interruptible - (lock->queue, atomic_read(&lock->write_lock_pending) == 0); - if (ret) - return -EAGAIN; - } - - while (unlikely(!atomic_add_unless(&lock->readers, 1, -1))) { - int ret; - if (!interruptible) { - wait_event(lock->queue, - atomic_read(&lock->readers) != -1); - continue; - } - ret = wait_event_interruptible - (lock->queue, atomic_read(&lock->readers) != -1); - if (ret) - return -EAGAIN; - } - return 0; -} -EXPORT_SYMBOL(drm_bo_read_lock); - -static int __drm_bo_write_unlock(struct drm_bo_lock *lock) -{ - if (unlikely(atomic_cmpxchg(&lock->readers, -1, 0) != -1)) - return -EINVAL; - wake_up_all(&lock->queue); - return 0; -} - -static void drm_bo_write_lock_remove(struct drm_file *file_priv, - struct drm_user_object *item) -{ - struct drm_bo_lock *lock = container_of(item, struct drm_bo_lock, base); - int ret; - - ret = __drm_bo_write_unlock(lock); - BUG_ON(ret); -} - -int drm_bo_write_lock(struct drm_bo_lock *lock, int interruptible, - struct drm_file *file_priv) -{ - int ret = 0; - struct drm_device *dev; - - atomic_inc(&lock->write_lock_pending); - - while (unlikely(atomic_cmpxchg(&lock->readers, 0, -1) != 0)) { - if (!interruptible) { - wait_event(lock->queue, - atomic_read(&lock->readers) == 0); - continue; - } - ret = wait_event_interruptible - (lock->queue, atomic_read(&lock->readers) == 0); - - if (ret) { - atomic_dec(&lock->write_lock_pending); - wake_up_all(&lock->queue); - return -EAGAIN; - } - } - - /* - * Add a dummy user-object, the destructor of which will - * make sure the lock is released if the client dies - * while holding it. - */ - - if (atomic_dec_and_test(&lock->write_lock_pending)) - wake_up_all(&lock->queue); - dev = file_priv->minor->dev; - mutex_lock(&dev->struct_mutex); - ret = drm_add_user_object(file_priv, &lock->base, 0); - lock->base.remove = &drm_bo_write_lock_remove; - lock->base.type = drm_lock_type; - if (ret) - (void)__drm_bo_write_unlock(lock); - - mutex_unlock(&dev->struct_mutex); - - return ret; -} - -int drm_bo_write_unlock(struct drm_bo_lock *lock, struct drm_file *file_priv) -{ - struct drm_device *dev = file_priv->minor->dev; - struct drm_ref_object *ro; - - mutex_lock(&dev->struct_mutex); - - if (lock->base.owner != file_priv) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - ro = drm_lookup_ref_object(file_priv, &lock->base, _DRM_REF_USE); - BUG_ON(!ro); - drm_remove_ref_object(file_priv, ro); - lock->base.owner = NULL; - - mutex_unlock(&dev->struct_mutex); - return 0; -} diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index e0d93606..ee1dc258 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -715,48 +715,4 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); -/** - * drm_get_buffer_object - find the buffer object for a given handle - * @dev: DRM device - * @bo: pointer to caller's buffer_object pointer - * @handle: handle to lookup - * - * LOCKING: - * Must take @dev's struct_mutex to protect buffer object lookup. - * - * Given @handle, lookup the buffer object in @dev and put it in the caller's - * @bo pointer. - * - * RETURNS: - * Zero on success, -EINVAL if the handle couldn't be found. - */ -int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle) -{ - struct drm_user_object *uo; - struct drm_hash_item *hash; - int ret; - - *bo = NULL; - - mutex_lock(&dev->struct_mutex); - ret = drm_ht_find_item(&dev->object_hash, handle, &hash); - if (ret) { - DRM_ERROR("Couldn't find handle.\n"); - ret = -EINVAL; - goto out_err; - } - - uo = drm_hash_entry(hash, struct drm_user_object, hash); - if (uo->type != drm_buffer_type) { - ret = -EINVAL; - goto out_err; - } - - *bo = drm_user_object_entry(uo, struct drm_buffer_object, base); - ret = 0; -out_err: - mutex_unlock(&dev->struct_mutex); - return ret; -} -EXPORT_SYMBOL(drm_get_buffer_object); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 9113fa54..2c3e29f0 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -146,36 +146,6 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER), - DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MM_LOCK, drm_mm_lock_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_MM_UNLOCK, drm_mm_unlock_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - - DRM_IOCTL_DEF(DRM_IOCTL_FENCE_CREATE, drm_fence_create_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FENCE_REFERENCE, drm_fence_reference_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FENCE_UNREFERENCE, drm_fence_unreference_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FENCE_SIGNALED, drm_fence_signaled_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FENCE_FLUSH, drm_fence_flush_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FENCE_WAIT, drm_fence_wait_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FENCE_EMIT, drm_fence_emit_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FENCE_BUFFERS, drm_fence_buffers_ioctl, DRM_AUTH), - - DRM_IOCTL_DEF(DRM_IOCTL_BO_CREATE, drm_bo_create_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_BO_MAP, drm_bo_map_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_BO_UNMAP, drm_bo_unmap_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_BO_REFERENCE, drm_bo_reference_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_BO_UNREFERENCE, drm_bo_unreference_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_BO_SETSTATUS, drm_bo_setstatus_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_BO_INFO, drm_bo_info_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_BO_WAIT_IDLE, drm_bo_wait_idle_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_BO_VERSION, drm_bo_version_ioctl, 0), - - DRM_IOCTL_DEF(DRM_IOCTL_MM_INFO, drm_mm_info_ioctl, 0), - DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 7c78e09f..7130d1b0 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -134,8 +134,8 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, if (new_type) { fence->signaled_types |= new_type; - DRM_DEBUG("Fence 0x%08lx signaled 0x%08x\n", - fence->base.hash.key, fence->signaled_types); + DRM_DEBUG("Fence %p signaled 0x%08x\n", + fence, fence->signaled_types); if (driver->needed_flush) fc->pending_flush |= driver->needed_flush(fence); @@ -147,8 +147,8 @@ void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, fc->waiting_types |= fence->waiting_types & ~fence->signaled_types; if (!(fence->type & ~fence->signaled_types)) { - DRM_DEBUG("Fence completely signaled 0x%08lx\n", - fence->base.hash.key); + DRM_DEBUG("Fence completely signaled %p\n", + fence); list_del_init(&fence->ring); } } @@ -196,10 +196,9 @@ void drm_fence_usage_deref_locked(struct drm_fence_object **fence) *fence = NULL; if (atomic_dec_and_test(&tmp_fence->usage)) { drm_fence_unring(dev, &tmp_fence->ring); - DRM_DEBUG("Destroyed a fence object 0x%08lx\n", - tmp_fence->base.hash.key); + DRM_DEBUG("Destroyed a fence object %p\n", + tmp_fence); atomic_dec(&fm->count); - BUG_ON(!list_empty(&tmp_fence->base.list)); drm_ctl_free(tmp_fence, sizeof(*tmp_fence), DRM_MEM_FENCE); } } @@ -217,7 +216,6 @@ void drm_fence_usage_deref_unlocked(struct drm_fence_object **fence) if (atomic_read(&tmp_fence->usage) == 0) { drm_fence_unring(dev, &tmp_fence->ring); atomic_dec(&fm->count); - BUG_ON(!list_empty(&tmp_fence->base.list)); drm_ctl_free(tmp_fence, sizeof(*tmp_fence), DRM_MEM_FENCE); } mutex_unlock(&dev->struct_mutex); @@ -244,15 +242,6 @@ void drm_fence_reference_unlocked(struct drm_fence_object **dst, } EXPORT_SYMBOL(drm_fence_reference_unlocked); -static void drm_fence_object_destroy(struct drm_file *priv, - struct drm_user_object *base) -{ - struct drm_fence_object *fence = - drm_user_object_entry(base, struct drm_fence_object, base); - - drm_fence_usage_deref_locked(&fence); -} - int drm_fence_object_signaled(struct drm_fence_object *fence, uint32_t mask) { unsigned long flags; @@ -477,7 +466,6 @@ static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class, * Avoid hitting BUG() for kernel-only fence objects. */ - INIT_LIST_HEAD(&fence->base.list); fence->fence_class = fence_class; fence->type = type; fence->signaled_types = 0; @@ -493,26 +481,6 @@ static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class, return ret; } -int drm_fence_add_user_object(struct drm_file *priv, - struct drm_fence_object *fence, int shareable) -{ - struct drm_device *dev = priv->minor->dev; - int ret; - - mutex_lock(&dev->struct_mutex); - ret = drm_add_user_object(priv, &fence->base, shareable); - if (ret) - goto out; - atomic_inc(&fence->usage); - fence->base.type = drm_fence_type; - fence->base.remove = &drm_fence_object_destroy; - DRM_DEBUG("Fence 0x%08lx created\n", fence->base.hash.key); -out: - mutex_unlock(&dev->struct_mutex); - return ret; -} -EXPORT_SYMBOL(drm_fence_add_user_object); - int drm_fence_object_create(struct drm_device *dev, uint32_t fence_class, uint32_t type, unsigned flags, struct drm_fence_object **c_fence) @@ -569,261 +537,7 @@ void drm_fence_manager_init(struct drm_device *dev) write_unlock_irqrestore(&fm->lock, flags); } -void drm_fence_fill_arg(struct drm_fence_object *fence, - struct drm_fence_arg *arg) -{ - struct drm_device *dev = fence->dev; - struct drm_fence_manager *fm = &dev->fm; - unsigned long irq_flags; - - read_lock_irqsave(&fm->lock, irq_flags); - arg->handle = fence->base.hash.key; - arg->fence_class = fence->fence_class; - arg->type = fence->type; - arg->signaled = fence->signaled_types; - arg->error = fence->error; - arg->sequence = fence->sequence; - read_unlock_irqrestore(&fm->lock, irq_flags); -} -EXPORT_SYMBOL(drm_fence_fill_arg); - void drm_fence_manager_takedown(struct drm_device *dev) { } -struct drm_fence_object *drm_lookup_fence_object(struct drm_file *priv, - uint32_t handle) -{ - struct drm_device *dev = priv->minor->dev; - struct drm_user_object *uo; - struct drm_fence_object *fence; - - mutex_lock(&dev->struct_mutex); - uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_fence_type)) { - mutex_unlock(&dev->struct_mutex); - return NULL; - } - fence = drm_fence_reference_locked(drm_user_object_entry(uo, struct drm_fence_object, base)); - mutex_unlock(&dev->struct_mutex); - return fence; -} - -int drm_fence_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - int ret; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_arg *arg = data; - struct drm_fence_object *fence; - ret = 0; - - if (!fm->initialized) { - DRM_ERROR("The DRM driver does not support fencing.\n"); - return -EINVAL; - } - - if (arg->flags & DRM_FENCE_FLAG_EMIT) - LOCK_TEST_WITH_RETURN(dev, file_priv); - ret = drm_fence_object_create(dev, arg->fence_class, - arg->type, arg->flags, &fence); - if (ret) - return ret; - ret = drm_fence_add_user_object(file_priv, fence, - arg->flags & - DRM_FENCE_FLAG_SHAREABLE); - if (ret) { - drm_fence_usage_deref_unlocked(&fence); - return ret; - } - - /* - * usage > 0. No need to lock dev->struct_mutex; - */ - - arg->handle = fence->base.hash.key; - - drm_fence_fill_arg(fence, arg); - drm_fence_usage_deref_unlocked(&fence); - - return ret; -} - -int drm_fence_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - int ret; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_arg *arg = data; - struct drm_fence_object *fence; - struct drm_user_object *uo; - ret = 0; - - if (!fm->initialized) { - DRM_ERROR("The DRM driver does not support fencing.\n"); - return -EINVAL; - } - - ret = drm_user_object_ref(file_priv, arg->handle, drm_fence_type, &uo); - if (ret) - return ret; - fence = drm_lookup_fence_object(file_priv, arg->handle); - drm_fence_fill_arg(fence, arg); - drm_fence_usage_deref_unlocked(&fence); - - return ret; -} - - -int drm_fence_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - int ret; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_arg *arg = data; - ret = 0; - - if (!fm->initialized) { - DRM_ERROR("The DRM driver does not support fencing.\n"); - return -EINVAL; - } - - return drm_user_object_unref(file_priv, arg->handle, drm_fence_type); -} - -int drm_fence_signaled_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - int ret; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_arg *arg = data; - struct drm_fence_object *fence; - ret = 0; - - if (!fm->initialized) { - DRM_ERROR("The DRM driver does not support fencing.\n"); - return -EINVAL; - } - - fence = drm_lookup_fence_object(file_priv, arg->handle); - if (!fence) - return -EINVAL; - - drm_fence_fill_arg(fence, arg); - drm_fence_usage_deref_unlocked(&fence); - - return ret; -} - -int drm_fence_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - int ret; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_arg *arg = data; - struct drm_fence_object *fence; - ret = 0; - - if (!fm->initialized) { - DRM_ERROR("The DRM driver does not support fencing.\n"); - return -EINVAL; - } - - fence = drm_lookup_fence_object(file_priv, arg->handle); - if (!fence) - return -EINVAL; - ret = drm_fence_object_flush(fence, arg->type); - - drm_fence_fill_arg(fence, arg); - drm_fence_usage_deref_unlocked(&fence); - - return ret; -} - - -int drm_fence_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - int ret; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_arg *arg = data; - struct drm_fence_object *fence; - ret = 0; - - if (!fm->initialized) { - DRM_ERROR("The DRM driver does not support fencing.\n"); - return -EINVAL; - } - - fence = drm_lookup_fence_object(file_priv, arg->handle); - if (!fence) - return -EINVAL; - ret = drm_fence_object_wait(fence, - arg->flags & DRM_FENCE_FLAG_WAIT_LAZY, - 0, arg->type); - - drm_fence_fill_arg(fence, arg); - drm_fence_usage_deref_unlocked(&fence); - - return ret; -} - - -int drm_fence_emit_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - int ret; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_arg *arg = data; - struct drm_fence_object *fence; - ret = 0; - - if (!fm->initialized) { - DRM_ERROR("The DRM driver does not support fencing.\n"); - return -EINVAL; - } - - LOCK_TEST_WITH_RETURN(dev, file_priv); - fence = drm_lookup_fence_object(file_priv, arg->handle); - if (!fence) - return -EINVAL; - ret = drm_fence_object_emit(fence, arg->flags, arg->fence_class, - arg->type); - - drm_fence_fill_arg(fence, arg); - drm_fence_usage_deref_unlocked(&fence); - - return ret; -} - -int drm_fence_buffers_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - int ret; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_arg *arg = data; - struct drm_fence_object *fence; - ret = 0; - - if (!fm->initialized) { - DRM_ERROR("The DRM driver does not support fencing.\n"); - return -EINVAL; - } - - if (!dev->bm.initialized) { - DRM_ERROR("Buffer object manager is not initialized\n"); - return -EINVAL; - } - LOCK_TEST_WITH_RETURN(dev, file_priv); - ret = drm_fence_buffer_objects(dev, NULL, arg->flags, - NULL, &fence); - if (ret) - return ret; - - if (!(arg->flags & DRM_FENCE_FLAG_NO_USER)) { - ret = drm_fence_add_user_object(file_priv, fence, - arg->flags & - DRM_FENCE_FLAG_SHAREABLE); - if (ret) - return ret; - } - - arg->handle = fence->base.hash.key; - - drm_fence_fill_arg(fence, arg); - drm_fence_usage_deref_unlocked(&fence); - - return ret; -} diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 3b3a0a3c..8eb20b47 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -221,7 +221,6 @@ static int drm_open_helper(struct inode *inode, struct file *filp, int minor_id = iminor(inode); struct drm_file *priv; int ret; - int i, j; if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ @@ -246,22 +245,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->lock_count = 0; INIT_LIST_HEAD(&priv->lhead); - INIT_LIST_HEAD(&priv->refd_objects); INIT_LIST_HEAD(&priv->fbs); - for (i = 0; i < _DRM_NO_REF_TYPES; ++i) { - ret = drm_ht_create(&priv->refd_object_hash[i], - DRM_FILE_HASH_ORDER); - if (ret) - break; - } - - if (ret) { - for (j = 0; j < i; ++j) - drm_ht_remove(&priv->refd_object_hash[j]); - goto out_free; - } - if (dev->driver->driver_features & DRIVER_GEM) drm_gem_open(dev, priv); @@ -346,33 +331,6 @@ int drm_fasync(int fd, struct file *filp, int on) } EXPORT_SYMBOL(drm_fasync); -static void drm_object_release(struct file *filp) -{ - struct drm_file *priv = filp->private_data; - struct list_head *head; - struct drm_ref_object *ref_object; - int i; - - /* - * Free leftover ref objects created by me. Note that we cannot use - * list_for_each() here, as the struct_mutex may be temporarily - * released by the remove_() functions, and thus the lists may be - * altered. - * Also, a drm_remove_ref_object() will not remove it - * from the list unless its refcount is 1. - */ - - head = &priv->refd_objects; - while (head->next != head) { - ref_object = list_entry(head->next, struct drm_ref_object, list); - drm_remove_ref_object(priv, ref_object); - head = &priv->refd_objects; - } - - for (i = 0; i < _DRM_NO_REF_TYPES; ++i) - drm_ht_remove(&priv->refd_object_hash[i]); -} - /** * Release file. * @@ -512,7 +470,6 @@ int drm_release(struct inode *inode, struct file *filp) file_priv->is_master = 0; mutex_lock(&dev->struct_mutex); - drm_object_release(filp); list_del(&file_priv->lhead); diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c deleted file mode 100644 index 2994b716..00000000 --- a/linux-core/drm_object.c +++ /dev/null @@ -1,294 +0,0 @@ -/************************************************************************** - * - * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ -/* - * Authors: Thomas Hellström - */ - -#include "drmP.h" - -int drm_add_user_object(struct drm_file *priv, struct drm_user_object *item, - int shareable) -{ - struct drm_device *dev = priv->minor->dev; - int ret; - - DRM_ASSERT_LOCKED(&dev->struct_mutex); - - /* The refcount will be bumped to 1 when we add the ref object below. */ - atomic_set(&item->refcount, 0); - item->shareable = shareable; - item->owner = priv; - - ret = drm_ht_just_insert_please(&dev->object_hash, &item->hash, - (unsigned long)item, 31, 0, 0); - if (ret) - return ret; - - ret = drm_add_ref_object(priv, item, _DRM_REF_USE); - if (ret) - ret = drm_ht_remove_item(&dev->object_hash, &item->hash); - - return ret; -} -EXPORT_SYMBOL(drm_add_user_object); - -struct drm_user_object *drm_lookup_user_object(struct drm_file *priv, uint32_t key) -{ - struct drm_device *dev = priv->minor->dev; - struct drm_hash_item *hash; - int ret; - struct drm_user_object *item; - - DRM_ASSERT_LOCKED(&dev->struct_mutex); - - ret = drm_ht_find_item(&dev->object_hash, key, &hash); - if (ret) - return NULL; - - item = drm_hash_entry(hash, struct drm_user_object, hash); - - if (priv != item->owner) { - struct drm_open_hash *ht = &priv->refd_object_hash[_DRM_REF_USE]; - ret = drm_ht_find_item(ht, (unsigned long)item, &hash); - if (ret) { - DRM_ERROR("Object not registered for usage\n"); - return NULL; - } - } - return item; -} -EXPORT_SYMBOL(drm_lookup_user_object); - -static void drm_deref_user_object(struct drm_file *priv, struct drm_user_object *item) -{ - struct drm_device *dev = priv->minor->dev; - int ret; - - if (atomic_dec_and_test(&item->refcount)) { - ret = drm_ht_remove_item(&dev->object_hash, &item->hash); - BUG_ON(ret); - item->remove(priv, item); - } -} - -static int drm_object_ref_action(struct drm_file *priv, struct drm_user_object *ro, - enum drm_ref_type action) -{ - int ret = 0; - - switch (action) { - case _DRM_REF_USE: - atomic_inc(&ro->refcount); - break; - default: - if (!ro->ref_struct_locked) { - break; - } else { - ro->ref_struct_locked(priv, ro, action); - } - } - return ret; -} - -int drm_add_ref_object(struct drm_file *priv, struct drm_user_object *referenced_object, - enum drm_ref_type ref_action) -{ - int ret = 0; - struct drm_ref_object *item; - struct drm_open_hash *ht = &priv->refd_object_hash[ref_action]; - - DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); - if (!referenced_object->shareable && priv != referenced_object->owner) { - DRM_ERROR("Not allowed to reference this object\n"); - return -EINVAL; - } - - /* - * If this is not a usage reference, Check that usage has been registered - * first. Otherwise strange things may happen on destruction. - */ - - if ((ref_action != _DRM_REF_USE) && priv != referenced_object->owner) { - item = - drm_lookup_ref_object(priv, referenced_object, - _DRM_REF_USE); - if (!item) { - DRM_ERROR - ("Object not registered for usage by this client\n"); - return -EINVAL; - } - } - - if (NULL != - (item = - drm_lookup_ref_object(priv, referenced_object, ref_action))) { - atomic_inc(&item->refcount); - return drm_object_ref_action(priv, referenced_object, - ref_action); - } - - item = drm_ctl_calloc(1, sizeof(*item), DRM_MEM_OBJECTS); - if (item == NULL) { - DRM_ERROR("Could not allocate reference object\n"); - return -ENOMEM; - } - - atomic_set(&item->refcount, 1); - item->hash.key = (unsigned long)referenced_object; - ret = drm_ht_insert_item(ht, &item->hash); - item->unref_action = ref_action; - - if (ret) - goto out; - - list_add(&item->list, &priv->refd_objects); - ret = drm_object_ref_action(priv, referenced_object, ref_action); -out: - return ret; -} - -struct drm_ref_object *drm_lookup_ref_object(struct drm_file *priv, - struct drm_user_object *referenced_object, - enum drm_ref_type ref_action) -{ - struct drm_hash_item *hash; - int ret; - - DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); - ret = drm_ht_find_item(&priv->refd_object_hash[ref_action], - (unsigned long)referenced_object, &hash); - if (ret) - return NULL; - - return drm_hash_entry(hash, struct drm_ref_object, hash); -} -EXPORT_SYMBOL(drm_lookup_ref_object); - -static void drm_remove_other_references(struct drm_file *priv, - struct drm_user_object *ro) -{ - int i; - struct drm_open_hash *ht; - struct drm_hash_item *hash; - struct drm_ref_object *item; - - for (i = _DRM_REF_USE + 1; i < _DRM_NO_REF_TYPES; ++i) { - ht = &priv->refd_object_hash[i]; - while (!drm_ht_find_item(ht, (unsigned long)ro, &hash)) { - item = drm_hash_entry(hash, struct drm_ref_object, hash); - drm_remove_ref_object(priv, item); - } - } -} - -void drm_remove_ref_object(struct drm_file *priv, struct drm_ref_object *item) -{ - int ret; - struct drm_user_object *user_object = (struct drm_user_object *) item->hash.key; - struct drm_open_hash *ht = &priv->refd_object_hash[item->unref_action]; - enum drm_ref_type unref_action; - - DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); - unref_action = item->unref_action; - if (atomic_dec_and_test(&item->refcount)) { - ret = drm_ht_remove_item(ht, &item->hash); - BUG_ON(ret); - list_del_init(&item->list); - if (unref_action == _DRM_REF_USE) - drm_remove_other_references(priv, user_object); - drm_ctl_free(item, sizeof(*item), DRM_MEM_OBJECTS); - } - - switch (unref_action) { - case _DRM_REF_USE: - drm_deref_user_object(priv, user_object); - break; - default: - BUG_ON(!user_object->unref); - user_object->unref(priv, user_object, unref_action); - break; - } - -} -EXPORT_SYMBOL(drm_remove_ref_object); - -int drm_user_object_ref(struct drm_file *priv, uint32_t user_token, - enum drm_object_type type, struct drm_user_object **object) -{ - struct drm_device *dev = priv->minor->dev; - struct drm_user_object *uo; - struct drm_hash_item *hash; - int ret; - - mutex_lock(&dev->struct_mutex); - ret = drm_ht_find_item(&dev->object_hash, user_token, &hash); - if (ret) { - DRM_ERROR("Could not find user object to reference.\n"); - goto out_err; - } - uo = drm_hash_entry(hash, struct drm_user_object, hash); - if (uo->type != type) { - ret = -EINVAL; - goto out_err; - } - ret = drm_add_ref_object(priv, uo, _DRM_REF_USE); - if (ret) - goto out_err; - mutex_unlock(&dev->struct_mutex); - *object = uo; - return 0; -out_err: - mutex_unlock(&dev->struct_mutex); - return ret; -} - -int drm_user_object_unref(struct drm_file *priv, uint32_t user_token, - enum drm_object_type type) -{ - struct drm_device *dev = priv->minor->dev; - struct drm_user_object *uo; - struct drm_ref_object *ro; - int ret; - - mutex_lock(&dev->struct_mutex); - uo = drm_lookup_user_object(priv, user_token); - if (!uo || (uo->type != type)) { - ret = -EINVAL; - goto out_err; - } - ro = drm_lookup_ref_object(priv, uo, _DRM_REF_USE); - if (!ro) { - ret = -EINVAL; - goto out_err; - } - drm_remove_ref_object(priv, ro); - mutex_unlock(&dev->struct_mutex); - return 0; -out_err: - mutex_unlock(&dev->struct_mutex); - return ret; -} diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 96cfc113..032687f7 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -34,110 +34,201 @@ struct drm_device; struct drm_bo_mem_reg; -/*************************************************** - * User space objects. (drm_object.c) - */ - -#define drm_user_object_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) - -enum drm_object_type { - drm_fence_type, - drm_buffer_type, - drm_lock_type, - /* - * Add other user space object types here. - */ - drm_driver_type0 = 256, - drm_driver_type1, - drm_driver_type2, - drm_driver_type3, - drm_driver_type4 +#define DRM_FENCE_FLAG_EMIT 0x00000001 +#define DRM_FENCE_FLAG_SHAREABLE 0x00000002 +/** + * On hardware with no interrupt events for operation completion, + * indicates that the kernel should sleep while waiting for any blocking + * operation to complete rather than spinning. + * + * Has no effect otherwise. + */ +#define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 +#define DRM_FENCE_FLAG_NO_USER 0x00000010 + +/* Reserved for driver use */ +#define DRM_FENCE_MASK_DRIVER 0xFF000000 + +#define DRM_FENCE_TYPE_EXE 0x00000001 + +struct drm_fence_arg { + unsigned int handle; + unsigned int fence_class; + unsigned int type; + unsigned int flags; + unsigned int signaled; + unsigned int error; + unsigned int sequence; + unsigned int pad64; + uint64_t expand_pad[2]; /*Future expansion */ }; +/* Buffer permissions, referring to how the GPU uses the buffers. + * these translate to fence types used for the buffers. + * Typically a texture buffer is read, A destination buffer is write and + * a command (batch-) buffer is exe. Can be or-ed together. + */ + +#define DRM_BO_FLAG_READ (1ULL << 0) +#define DRM_BO_FLAG_WRITE (1ULL << 1) +#define DRM_BO_FLAG_EXE (1ULL << 2) + /* - * A user object is a structure that helps the drm give out user handles - * to kernel internal objects and to keep track of these objects so that - * they can be destroyed, for example when the user space process exits. - * Designed to be accessible using a user space 32-bit handle. - */ - -struct drm_user_object { - struct drm_hash_item hash; - struct list_head list; - enum drm_object_type type; - atomic_t refcount; - int shareable; - struct drm_file *owner; - void (*ref_struct_locked) (struct drm_file *priv, - struct drm_user_object *obj, - enum drm_ref_type ref_action); - void (*unref) (struct drm_file *priv, struct drm_user_object *obj, - enum drm_ref_type unref_action); - void (*remove) (struct drm_file *priv, struct drm_user_object *obj); -}; + * All of the bits related to access mode + */ +#define DRM_BO_MASK_ACCESS (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE) +/* + * Status flags. Can be read to determine the actual state of a buffer. + * Can also be set in the buffer mask before validation. + */ /* - * A ref object is a structure which is used to - * keep track of references to user objects and to keep track of these - * references so that they can be destroyed for example when the user space - * process exits. Designed to be accessible using a pointer to the _user_ object. + * Mask: Never evict this buffer. Not even with force. This type of buffer is only + * available to root and must be manually removed before buffer manager shutdown + * or lock. + * Flags: Acknowledge */ +#define DRM_BO_FLAG_NO_EVICT (1ULL << 4) -struct drm_ref_object { - struct drm_hash_item hash; - struct list_head list; - atomic_t refcount; - enum drm_ref_type unref_action; -}; +/* + * Mask: Require that the buffer is placed in mappable memory when validated. + * If not set the buffer may or may not be in mappable memory when validated. + * Flags: If set, the buffer is in mappable memory. + */ +#define DRM_BO_FLAG_MAPPABLE (1ULL << 5) -/** - * Must be called with the struct_mutex held. +/* Mask: The buffer should be shareable with other processes. + * Flags: The buffer is shareable with other processes. */ +#define DRM_BO_FLAG_SHAREABLE (1ULL << 6) -extern int drm_add_user_object(struct drm_file *priv, struct drm_user_object *item, - int shareable); -/** - * Must be called with the struct_mutex held. +/* Mask: If set, place the buffer in cache-coherent memory if available. + * If clear, never place the buffer in cache coherent memory if validated. + * Flags: The buffer is currently in cache-coherent memory. + */ +#define DRM_BO_FLAG_CACHED (1ULL << 7) + +/* Mask: Make sure that every time this buffer is validated, + * it ends up on the same location provided that the memory mask is the same. + * The buffer will also not be evicted when claiming space for + * other buffers. Basically a pinned buffer but it may be thrown out as + * part of buffer manager shutdown or locking. + * Flags: Acknowledge. + */ +#define DRM_BO_FLAG_NO_MOVE (1ULL << 8) + +/* Mask: Make sure the buffer is in cached memory when mapped. In conjunction + * with DRM_BO_FLAG_CACHED it also allows the buffer to be bound into the GART + * with unsnooped PTEs instead of snooped, by using chipset-specific cache + * flushing at bind time. A better name might be DRM_BO_FLAG_TT_UNSNOOPED, + * as the eviction to local memory (TTM unbind) on map is just a side effect + * to prevent aggressive cache prefetch from the GPU disturbing the cache + * management that the DRM is doing. + * + * Flags: Acknowledge. + * Buffers allocated with this flag should not be used for suballocators + * This type may have issues on CPUs with over-aggressive caching + * http://marc.info/?l=linux-kernel&m=102376926732464&w=2 */ +#define DRM_BO_FLAG_CACHED_MAPPED (1ULL << 19) -extern struct drm_user_object *drm_lookup_user_object(struct drm_file *priv, - uint32_t key); + +/* Mask: Force DRM_BO_FLAG_CACHED flag strictly also if it is set. + * Flags: Acknowledge. + */ +#define DRM_BO_FLAG_FORCE_CACHING (1ULL << 13) + +/* + * Mask: Force DRM_BO_FLAG_MAPPABLE flag strictly also if it is clear. + * Flags: Acknowledge. + */ +#define DRM_BO_FLAG_FORCE_MAPPABLE (1ULL << 14) +#define DRM_BO_FLAG_TILE (1ULL << 15) /* - * Must be called with the struct_mutex held. May temporarily release it. + * Memory type flags that can be or'ed together in the mask, but only + * one appears in flags. */ -extern int drm_add_ref_object(struct drm_file *priv, - struct drm_user_object *referenced_object, - enum drm_ref_type ref_action); +/* System memory */ +#define DRM_BO_FLAG_MEM_LOCAL (1ULL << 24) +/* Translation table memory */ +#define DRM_BO_FLAG_MEM_TT (1ULL << 25) +/* Vram memory */ +#define DRM_BO_FLAG_MEM_VRAM (1ULL << 26) +/* Up to the driver to define. */ +#define DRM_BO_FLAG_MEM_PRIV0 (1ULL << 27) +#define DRM_BO_FLAG_MEM_PRIV1 (1ULL << 28) +#define DRM_BO_FLAG_MEM_PRIV2 (1ULL << 29) +#define DRM_BO_FLAG_MEM_PRIV3 (1ULL << 30) +#define DRM_BO_FLAG_MEM_PRIV4 (1ULL << 31) +/* We can add more of these now with a 64-bit flag type */ /* - * Must be called with the struct_mutex held. + * This is a mask covering all of the memory type flags; easier to just + * use a single constant than a bunch of | values. It covers + * DRM_BO_FLAG_MEM_LOCAL through DRM_BO_FLAG_MEM_PRIV4 */ +#define DRM_BO_MASK_MEM 0x00000000FF000000ULL +/* + * This adds all of the CPU-mapping options in with the memory + * type to label all bits which change how the page gets mapped + */ +#define DRM_BO_MASK_MEMTYPE (DRM_BO_MASK_MEM | \ + DRM_BO_FLAG_CACHED_MAPPED | \ + DRM_BO_FLAG_CACHED | \ + DRM_BO_FLAG_MAPPABLE) + +/* Driver-private flags */ +#define DRM_BO_MASK_DRIVER 0xFFFF000000000000ULL -struct drm_ref_object *drm_lookup_ref_object(struct drm_file *priv, - struct drm_user_object *referenced_object, - enum drm_ref_type ref_action); /* - * Must be called with the struct_mutex held. - * If "item" has been obtained by a call to drm_lookup_ref_object. You may not - * release the struct_mutex before calling drm_remove_ref_object. - * This function may temporarily release the struct_mutex. + * Don't block on validate and map. Instead, return EBUSY. + */ +#define DRM_BO_HINT_DONT_BLOCK 0x00000002 +/* + * Don't place this buffer on the unfenced list. This means + * that the buffer will not end up having a fence associated + * with it as a result of this operation */ +#define DRM_BO_HINT_DONT_FENCE 0x00000004 +/** + * On hardware with no interrupt events for operation completion, + * indicates that the kernel should sleep while waiting for any blocking + * operation to complete rather than spinning. + * + * Has no effect otherwise. + */ +#define DRM_BO_HINT_WAIT_LAZY 0x00000008 +/* + * The client has compute relocations refering to this buffer using the + * offset in the presumed_offset field. If that offset ends up matching + * where this buffer lands, the kernel is free to skip executing those + * relocations + */ +#define DRM_BO_HINT_PRESUMED_OFFSET 0x00000010 + + +#define DRM_BO_MEM_LOCAL 0 +#define DRM_BO_MEM_TT 1 +#define DRM_BO_MEM_VRAM 2 +#define DRM_BO_MEM_PRIV0 3 +#define DRM_BO_MEM_PRIV1 4 +#define DRM_BO_MEM_PRIV2 5 +#define DRM_BO_MEM_PRIV3 6 +#define DRM_BO_MEM_PRIV4 7 + +#define DRM_BO_MEM_TYPES 8 /* For now. */ + +#define DRM_BO_LOCK_UNLOCK_BM (1 << 0) +#define DRM_BO_LOCK_IGNORE_NO_EVICT (1 << 1) -extern void drm_remove_ref_object(struct drm_file *priv, struct drm_ref_object *item); -extern int drm_user_object_ref(struct drm_file *priv, uint32_t user_token, - enum drm_object_type type, - struct drm_user_object **object); -extern int drm_user_object_unref(struct drm_file *priv, uint32_t user_token, - enum drm_object_type type); /*************************************************** * Fence objects. (drm_fence.c) */ struct drm_fence_object { - struct drm_user_object base; struct drm_device *dev; atomic_t usage; @@ -470,7 +561,6 @@ enum drm_bo_type { struct drm_buffer_object { struct drm_device *dev; - struct drm_user_object base; /* * If there is a possibility that the usage variable is zero, @@ -546,7 +636,7 @@ struct drm_mem_type_manager { }; struct drm_bo_lock { - struct drm_user_object base; + // struct drm_user_object base; wait_queue_head_t queue; atomic_t write_lock_pending; atomic_t readers; @@ -655,22 +745,10 @@ struct drm_bo_driver { /* * buffer objects (drm_bo.c) */ -extern int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_bo_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_bo_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_bo_unmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_bo_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int drm_bo_do_validate(struct drm_buffer_object *bo, + uint64_t flags, uint64_t mask, uint32_t hint, + uint32_t fence_class); extern int drm_bo_set_pin(struct drm_device *dev, struct drm_buffer_object *bo, int pin); -extern int drm_bo_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_bo_setstatus_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mm_lock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mm_unlock_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mm_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_bo_version_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_bo_driver_finish(struct drm_device *dev); extern int drm_bo_driver_init(struct drm_device *dev); extern int drm_bo_pci_offset(struct drm_device *dev, @@ -707,18 +785,9 @@ extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_c extern int drm_bo_init_mm(struct drm_device *dev, unsigned type, unsigned long p_offset, unsigned long p_size, int kern_init); -extern int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, - uint64_t flags, uint64_t mask, uint32_t hint, - uint32_t fence_class, - struct drm_bo_info_rep *rep, - struct drm_buffer_object **bo_rep); extern struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file *file_priv, uint32_t handle, int check_owner); -extern int drm_bo_do_validate(struct drm_buffer_object *bo, - uint64_t flags, uint64_t mask, uint32_t hint, - uint32_t fence_class, - struct drm_bo_info_rep *rep); extern int drm_bo_evict_cached(struct drm_buffer_object *bo); extern void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo); @@ -766,8 +835,6 @@ extern int drm_bo_pfn_prot(struct drm_buffer_object *bo, unsigned long dst_offset, unsigned long *pfn, pgprot_t *prot); -extern void drm_bo_fill_rep_arg(struct drm_buffer_object *bo, - struct drm_bo_info_rep *rep); /* diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 80a8ff5d..b58a1ada 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -72,7 +72,7 @@ void drm_ttm_cache_flush(struct page *pages[], unsigned long num_pages) return; } #endif - if (on_each_cpu(drm_ttm_ipi_handler, NULL, 1, 1) != 0) + if (on_each_cpu(drm_ttm_ipi_handler, NULL,1) != 0) DRM_ERROR("Timed out waiting for drm cache flush.\n"); } EXPORT_SYMBOL(drm_ttm_cache_flush); diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c deleted file mode 100644 index 4224b737..00000000 --- a/linux-core/i915_buffer.c +++ /dev/null @@ -1,311 +0,0 @@ -/************************************************************************** - * - * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * - **************************************************************************/ -/* - * Authors: Thomas Hellström - */ - -#include "drmP.h" -#include "i915_drm.h" -#include "i915_drv.h" - -struct drm_ttm_backend *i915_create_ttm_backend_entry(struct drm_device *dev) -{ - return drm_agp_init_ttm(dev); -} - -int i915_fence_type(struct drm_buffer_object *bo, - uint32_t *fclass, - uint32_t *type) -{ - if (bo->mem.proposed_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) - *type = 3; - else - *type = 1; - return 0; -} - -int i915_invalidate_caches(struct drm_device *dev, uint64_t flags) -{ - /* - * FIXME: Only emit once per batchbuffer submission. - */ - - uint32_t flush_cmd = MI_NO_WRITE_FLUSH; - - if (flags & DRM_BO_FLAG_READ) - flush_cmd |= MI_READ_FLUSH; - if (flags & DRM_BO_FLAG_EXE) - flush_cmd |= MI_EXE_FLUSH; - - return i915_emit_mi_flush(dev, flush_cmd); -} - -int i915_init_mem_type(struct drm_device *dev, uint32_t type, - struct drm_mem_type_manager *man) -{ - switch (type) { - case DRM_BO_MEM_LOCAL: - man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_CACHED; - man->drm_bus_maptype = 0; - man->gpu_offset = 0; - break; - case DRM_BO_MEM_TT: - if (!(drm_core_has_AGP(dev) && dev->agp)) { - DRM_ERROR("AGP is not enabled for memory type %u\n", - (unsigned)type); - return -EINVAL; - } - man->io_offset = dev->agp->agp_info.aper_base; - man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; - man->io_addr = NULL; - man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP; - man->drm_bus_maptype = _DRM_AGP; - man->gpu_offset = 0; - break; - case DRM_BO_MEM_VRAM: - if (!(drm_core_has_AGP(dev) && dev->agp)) { - DRM_ERROR("AGP is not enabled for memory type %u\n", - (unsigned)type); - return -EINVAL; - } - man->io_offset = dev->agp->agp_info.aper_base; - man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024; - man->io_addr = NULL; - man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE | - _DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_NEEDS_IOREMAP; - man->drm_bus_maptype = _DRM_AGP; - man->gpu_offset = 0; - break; - case DRM_BO_MEM_PRIV0: /* for OS preallocated space */ - DRM_ERROR("PRIV0 not used yet.\n"); - break; - default: - DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); - return -EINVAL; - } - return 0; -} - -/* - * i915_evict_flags: - * - * @bo: the buffer object to be evicted - * - * Return the bo flags for a buffer which is not mapped to the hardware. - * These will be placed in proposed_flags so that when the move is - * finished, they'll end up in bo->mem.flags - */ -uint64_t i915_evict_flags(struct drm_buffer_object *bo) -{ - switch (bo->mem.mem_type) { - case DRM_BO_MEM_LOCAL: - case DRM_BO_MEM_TT: - return DRM_BO_FLAG_MEM_LOCAL; - default: - return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; - } -} - -#if 0 /* See comment below */ - -static void i915_emit_copy_blit(struct drm_device * dev, - uint32_t src_offset, - uint32_t dst_offset, - uint32_t pages, int direction) -{ - uint32_t cur_pages; - uint32_t stride = PAGE_SIZE; - struct drm_i915_private *dev_priv = dev->dev_private; - RING_LOCALS; - - if (!dev_priv) - return; - - i915_kernel_lost_context(dev); - while (pages > 0) { - cur_pages = pages; - if (cur_pages > 2048) - cur_pages = 2048; - pages -= cur_pages; - - BEGIN_LP_RING(6); - OUT_RING(SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | - XY_SRC_COPY_BLT_WRITE_RGB); - OUT_RING((stride & 0xffff) | (0xcc << 16) | (1 << 24) | - (1 << 25) | (direction ? (1 << 30) : 0)); - OUT_RING((cur_pages << 16) | PAGE_SIZE); - OUT_RING(dst_offset); - OUT_RING(stride & 0xffff); - OUT_RING(src_offset); - ADVANCE_LP_RING(); - } - return; -} - -static int i915_move_blit(struct drm_buffer_object * bo, - int evict, int no_wait, struct drm_bo_mem_reg * new_mem) -{ - struct drm_bo_mem_reg *old_mem = &bo->mem; - int dir = 0; - - if ((old_mem->mem_type == new_mem->mem_type) && - (new_mem->mm_node->start < - old_mem->mm_node->start + old_mem->mm_node->size)) { - dir = 1; - } - - i915_emit_copy_blit(bo->dev, - old_mem->mm_node->start << PAGE_SHIFT, - new_mem->mm_node->start << PAGE_SHIFT, - new_mem->num_pages, dir); - - i915_emit_mi_flush(bo->dev, MI_READ_FLUSH | MI_EXE_FLUSH); - - return drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, - DRM_FENCE_TYPE_EXE | - DRM_I915_FENCE_TYPE_RW, - DRM_I915_FENCE_FLAG_FLUSHED, new_mem); -} - -/* - * Flip destination ttm into cached-coherent AGP, - * then blit and subsequently move out again. - */ - -static int i915_move_flip(struct drm_buffer_object * bo, - int evict, int no_wait, struct drm_bo_mem_reg * new_mem) -{ - struct drm_device *dev = bo->dev; - struct drm_bo_mem_reg tmp_mem; - int ret; - - tmp_mem = *new_mem; - tmp_mem.mm_node = NULL; - tmp_mem.mask = DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING; - - ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); - if (ret) - return ret; - - ret = drm_bind_ttm(bo->ttm, &tmp_mem); - if (ret) - goto out_cleanup; - - ret = i915_move_blit(bo, 1, no_wait, &tmp_mem); - if (ret) - goto out_cleanup; - - ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); -out_cleanup: - if (tmp_mem.mm_node) { - mutex_lock(&dev->struct_mutex); - if (tmp_mem.mm_node != bo->pinned_node) - drm_mm_put_block(tmp_mem.mm_node); - tmp_mem.mm_node = NULL; - mutex_unlock(&dev->struct_mutex); - } - return ret; -} - -#endif - -/* - * Disable i915_move_flip for now, since we can't guarantee that the hardware - * lock is held here. To re-enable we need to make sure either - * a) The X server is using DRM to submit commands to the ring, or - * b) DRM can use the HP ring for these blits. This means i915 needs to - * implement a new ring submission mechanism and fence class. - */ -int i915_move(struct drm_buffer_object *bo, - int evict, int no_wait, struct drm_bo_mem_reg *new_mem) -{ - struct drm_bo_mem_reg *old_mem = &bo->mem; - - if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { - if (1) /*i915_move_flip(bo, evict, no_wait, new_mem)*/ - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else { - if (1) /*i915_move_blit(bo, evict, no_wait, new_mem)*/ - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } - return 0; -} - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)) -static inline void clflush(volatile void *__p) -{ - asm volatile("clflush %0" : "+m" (*(char __force *)__p)); -} -#endif - -static inline void drm_cache_flush_addr(void *virt) -{ -#ifdef cpu_has_clflush - int i; - - for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size) - clflush(virt+i); -#endif -} - -static inline void drm_cache_flush_page(struct page *p) -{ - drm_cache_flush_addr(page_address(p)); -} - -void i915_flush_ttm(struct drm_ttm *ttm) -{ - int i; - - if (!ttm) - return; - - DRM_MEMORYBARRIER(); - -#ifdef CONFIG_X86_32 -#ifndef cpu_has_clflush -#define cpu_has_clflush 0 -#endif - /* Hopefully nobody has built an x86-64 processor without clflush */ - if (!cpu_has_clflush) { - wbinvd(); - DRM_MEMORYBARRIER(); - return; - } -#endif - - for (i = ttm->num_pages - 1; i >= 0; i--) - drm_cache_flush_page(drm_ttm_get_page(ttm, i)); - - DRM_MEMORYBARRIER(); -} diff --git a/linux-core/i915_execbuf.c b/linux-core/i915_execbuf.c deleted file mode 100644 index 932882dd..00000000 --- a/linux-core/i915_execbuf.c +++ /dev/null @@ -1,921 +0,0 @@ -/* - * Copyright 2003-2008 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Thomas Hellstrom - * Dave Airlie - * Keith Packard - * ... ? - */ - -#include "drmP.h" -#include "drm.h" -#include "i915_drm.h" -#include "i915_drv.h" - -#if DRM_DEBUG_CODE -#define DRM_DEBUG_RELOCATION (drm_debug != 0) -#else -#define DRM_DEBUG_RELOCATION 0 -#endif - -enum i915_buf_idle { - I915_RELOC_UNCHECKED, - I915_RELOC_IDLE, - I915_RELOC_BUSY -}; - -struct i915_relocatee_info { - struct drm_buffer_object *buf; - unsigned long offset; - uint32_t *data_page; - unsigned page_offset; - struct drm_bo_kmap_obj kmap; - int is_iomem; - int dst; - int idle; - int performed_ring_relocs; -#ifdef DRM_KMAP_ATOMIC_PROT_PFN - unsigned long pfn; - pgprot_t pg_prot; -#endif -}; - -struct drm_i915_validate_buffer { - struct drm_buffer_object *buffer; - int presumed_offset_correct; - void __user *data; - int ret; - enum i915_buf_idle idle; -}; - -/* - * I'd like to use MI_STORE_DATA_IMM here, but I can't make - * it work. Seems like GART writes are broken with that - * instruction. Also I'm not sure that MI_FLUSH will - * act as a memory barrier for that instruction. It will - * for this single dword 2D blit. - */ - -static void i915_emit_ring_reloc(struct drm_device *dev, uint32_t offset, - uint32_t value) -{ - struct drm_i915_private *dev_priv = - (struct drm_i915_private *)dev->dev_private; - - RING_LOCALS; - i915_kernel_lost_context(dev); - BEGIN_LP_RING(6); - OUT_RING((0x02 << 29) | (0x40 << 22) | (0x3 << 20) | (0x3)); - OUT_RING((0x3 << 24) | (0xF0 << 16) | (0x40)); - OUT_RING((0x1 << 16) | (0x4)); - OUT_RING(offset); - OUT_RING(value); - OUT_RING(0); - ADVANCE_LP_RING(); -} - -static void i915_dereference_buffers_locked(struct drm_i915_validate_buffer - *buffers, unsigned num_buffers) -{ - while (num_buffers--) - drm_bo_usage_deref_locked(&buffers[num_buffers].buffer); -} - -int i915_apply_reloc(struct drm_file *file_priv, int num_buffers, - struct drm_i915_validate_buffer *buffers, - struct i915_relocatee_info *relocatee, uint32_t * reloc) -{ - unsigned index; - unsigned long new_cmd_offset; - u32 val; - int ret, i; - int buf_index = -1; - - /* - * FIXME: O(relocs * buffers) complexity. - */ - - for (i = 0; i <= num_buffers; i++) - if (buffers[i].buffer) - if (reloc[2] == buffers[i].buffer->base.hash.key) - buf_index = i; - - if (buf_index == -1) { - DRM_ERROR("Illegal relocation buffer %08X\n", reloc[2]); - return -EINVAL; - } - - /* - * Short-circuit relocations that were correctly - * guessed by the client - */ - if (buffers[buf_index].presumed_offset_correct && !DRM_DEBUG_RELOCATION) - return 0; - - new_cmd_offset = reloc[0]; - if (!relocatee->data_page || - !drm_bo_same_page(relocatee->offset, new_cmd_offset)) { - struct drm_bo_mem_reg *mem = &relocatee->buf->mem; - - drm_bo_kunmap(&relocatee->kmap); - relocatee->data_page = NULL; - relocatee->offset = new_cmd_offset; - - if (unlikely(relocatee->idle == I915_RELOC_UNCHECKED)) { - ret = drm_bo_wait(relocatee->buf, 0, 1, 0, 0); - if (ret) - return ret; - relocatee->idle = I915_RELOC_IDLE; - } - - if (unlikely((mem->mem_type != DRM_BO_MEM_LOCAL) && - (mem->flags & DRM_BO_FLAG_CACHED_MAPPED))) - drm_bo_evict_cached(relocatee->buf); - - ret = drm_bo_kmap(relocatee->buf, new_cmd_offset >> PAGE_SHIFT, - 1, &relocatee->kmap); - if (ret) { - DRM_ERROR - ("Could not map command buffer to apply relocs\n %08lx", - new_cmd_offset); - return ret; - } - relocatee->data_page = drm_bmo_virtual(&relocatee->kmap, - &relocatee->is_iomem); - relocatee->page_offset = (relocatee->offset & PAGE_MASK); - } - - val = buffers[buf_index].buffer->offset; - index = (reloc[0] - relocatee->page_offset) >> 2; - - /* add in validate */ - val = val + reloc[1]; - - if (DRM_DEBUG_RELOCATION) { - if (buffers[buf_index].presumed_offset_correct && - relocatee->data_page[index] != val) { - DRM_DEBUG - ("Relocation mismatch source %d target %d buffer %d user %08x kernel %08x\n", - reloc[0], reloc[1], buf_index, - relocatee->data_page[index], val); - } - } - - if (relocatee->is_iomem) - iowrite32(val, relocatee->data_page + index); - else - relocatee->data_page[index] = val; - return 0; -} - -int i915_process_relocs(struct drm_file *file_priv, - uint32_t buf_handle, - uint32_t __user ** reloc_user_ptr, - struct i915_relocatee_info *relocatee, - struct drm_i915_validate_buffer *buffers, - uint32_t num_buffers) -{ - int ret, reloc_stride; - uint32_t cur_offset; - uint32_t reloc_count; - uint32_t reloc_type; - uint32_t reloc_buf_size; - uint32_t *reloc_buf = NULL; - int i; - - /* do a copy from user from the user ptr */ - ret = get_user(reloc_count, *reloc_user_ptr); - if (ret) { - DRM_ERROR("Could not map relocation buffer.\n"); - goto out; - } - - ret = get_user(reloc_type, (*reloc_user_ptr) + 1); - if (ret) { - DRM_ERROR("Could not map relocation buffer.\n"); - goto out; - } - - if (reloc_type != 0) { - DRM_ERROR("Unsupported relocation type requested\n"); - ret = -EINVAL; - goto out; - } - - reloc_buf_size = - (I915_RELOC_HEADER + - (reloc_count * I915_RELOC0_STRIDE)) * sizeof(uint32_t); - reloc_buf = kmalloc(reloc_buf_size, GFP_KERNEL); - if (!reloc_buf) { - DRM_ERROR("Out of memory for reloc buffer\n"); - ret = -ENOMEM; - goto out; - } - - if (copy_from_user(reloc_buf, *reloc_user_ptr, reloc_buf_size)) { - ret = -EFAULT; - goto out; - } - - /* get next relocate buffer handle */ - *reloc_user_ptr = (uint32_t *) * (unsigned long *)&reloc_buf[2]; - - reloc_stride = I915_RELOC0_STRIDE * sizeof(uint32_t); /* may be different for other types of relocs */ - - DRM_DEBUG("num relocs is %d, next is %p\n", reloc_count, - *reloc_user_ptr); - - for (i = 0; i < reloc_count; i++) { - cur_offset = I915_RELOC_HEADER + (i * I915_RELOC0_STRIDE); - - ret = i915_apply_reloc(file_priv, num_buffers, buffers, - relocatee, reloc_buf + cur_offset); - if (ret) - goto out; - } - - out: - if (reloc_buf) - kfree(reloc_buf); - - if (relocatee->data_page) { - drm_bo_kunmap(&relocatee->kmap); - relocatee->data_page = NULL; - } - - return ret; -} - -static int i915_exec_reloc(struct drm_file *file_priv, drm_handle_t buf_handle, - uint32_t __user * reloc_user_ptr, - struct drm_i915_validate_buffer *buffers, - uint32_t buf_count) -{ - struct drm_device *dev = file_priv->minor->dev; - struct i915_relocatee_info relocatee; - int ret = 0; - int b; - - /* - * Short circuit relocations when all previous - * buffers offsets were correctly guessed by - * the client - */ - if (!DRM_DEBUG_RELOCATION) { - for (b = 0; b < buf_count; b++) - if (!buffers[b].presumed_offset_correct) - break; - - if (b == buf_count) - return 0; - } - - memset(&relocatee, 0, sizeof(relocatee)); - relocatee.idle = I915_RELOC_UNCHECKED; - - mutex_lock(&dev->struct_mutex); - relocatee.buf = drm_lookup_buffer_object(file_priv, buf_handle, 1); - mutex_unlock(&dev->struct_mutex); - if (!relocatee.buf) { - DRM_DEBUG("relocatee buffer invalid %08x\n", buf_handle); - ret = -EINVAL; - goto out_err; - } - - mutex_lock(&relocatee.buf->mutex); - while (reloc_user_ptr) { - ret = - i915_process_relocs(file_priv, buf_handle, &reloc_user_ptr, - &relocatee, buffers, buf_count); - if (ret) { - DRM_ERROR("process relocs failed\n"); - goto out_err1; - } - } - - out_err1: - mutex_unlock(&relocatee.buf->mutex); - drm_bo_usage_deref_unlocked(&relocatee.buf); - out_err: - return ret; -} - -static void i915_clear_relocatee(struct i915_relocatee_info *relocatee) -{ - if (relocatee->data_page) { -#ifndef DRM_KMAP_ATOMIC_PROT_PFN - drm_bo_kunmap(&relocatee->kmap); -#else - kunmap_atomic(relocatee->data_page, KM_USER0); -#endif - relocatee->data_page = NULL; - } - relocatee->buf = NULL; - relocatee->dst = ~0; -} - -static int i915_update_relocatee(struct i915_relocatee_info *relocatee, - struct drm_i915_validate_buffer *buffers, - unsigned int dst, unsigned long dst_offset) -{ - int ret; - - if (unlikely(dst != relocatee->dst || NULL == relocatee->buf)) { - i915_clear_relocatee(relocatee); - relocatee->dst = dst; - relocatee->buf = buffers[dst].buffer; - relocatee->idle = buffers[dst].idle; - - /* - * Check for buffer idle. If the buffer is busy, revert to - * ring relocations. - */ - - if (relocatee->idle == I915_RELOC_UNCHECKED) { - preempt_enable(); - mutex_lock(&relocatee->buf->mutex); - - ret = drm_bo_wait(relocatee->buf, 0, 1, 1, 0); - if (ret == 0) - relocatee->idle = I915_RELOC_IDLE; - else { - relocatee->idle = I915_RELOC_BUSY; - relocatee->performed_ring_relocs = 1; - } - mutex_unlock(&relocatee->buf->mutex); - preempt_disable(); - buffers[dst].idle = relocatee->idle; - } - } - - if (relocatee->idle == I915_RELOC_BUSY) - return 0; - - if (unlikely(dst_offset > relocatee->buf->num_pages * PAGE_SIZE)) { - DRM_ERROR("Relocation destination out of bounds.\n"); - return -EINVAL; - } - if (unlikely(!drm_bo_same_page(relocatee->page_offset, dst_offset) || - NULL == relocatee->data_page)) { -#ifdef DRM_KMAP_ATOMIC_PROT_PFN - if (NULL != relocatee->data_page) { - kunmap_atomic(relocatee->data_page, KM_USER0); - relocatee->data_page = NULL; - } - ret = drm_bo_pfn_prot(relocatee->buf, dst_offset, - &relocatee->pfn, &relocatee->pg_prot); - if (ret) { - DRM_ERROR("Can't map relocation destination.\n"); - return -EINVAL; - } - relocatee->data_page = - kmap_atomic_prot_pfn(relocatee->pfn, KM_USER0, - relocatee->pg_prot); -#else - if (NULL != relocatee->data_page) { - drm_bo_kunmap(&relocatee->kmap); - relocatee->data_page = NULL; - } - - ret = drm_bo_kmap(relocatee->buf, dst_offset >> PAGE_SHIFT, - 1, &relocatee->kmap); - if (ret) { - DRM_ERROR("Can't map relocation destination.\n"); - return ret; - } - - relocatee->data_page = drm_bmo_virtual(&relocatee->kmap, - &relocatee->is_iomem); -#endif - relocatee->page_offset = dst_offset & PAGE_MASK; - } - return 0; -} - -static int i915_apply_post_reloc(uint32_t reloc[], - struct drm_i915_validate_buffer *buffers, - uint32_t num_buffers, - struct i915_relocatee_info *relocatee) -{ - uint32_t reloc_buffer = reloc[2]; - uint32_t dst_buffer = reloc[3]; - uint32_t val; - uint32_t index; - int ret; - - if (likely(buffers[reloc_buffer].presumed_offset_correct)) - return 0; - if (unlikely(reloc_buffer >= num_buffers)) { - DRM_ERROR("Invalid reloc buffer index.\n"); - return -EINVAL; - } - if (unlikely(dst_buffer >= num_buffers)) { - DRM_ERROR("Invalid dest buffer index.\n"); - return -EINVAL; - } - - ret = i915_update_relocatee(relocatee, buffers, dst_buffer, reloc[0]); - if (unlikely(ret)) - return ret; - - val = buffers[reloc_buffer].buffer->offset; - index = (reloc[0] - relocatee->page_offset) >> 2; - val = val + reloc[1]; - - if (relocatee->idle == I915_RELOC_BUSY) { - i915_emit_ring_reloc(relocatee->buf->dev, - relocatee->buf->offset + reloc[0], val); - return 0; - } -#ifdef DRM_KMAP_ATOMIC_PROT_PFN - relocatee->data_page[index] = val; -#else - if (likely(relocatee->is_iomem)) - iowrite32(val, relocatee->data_page + index); - else - relocatee->data_page[index] = val; -#endif - - return 0; -} - -static int i915_post_relocs(struct drm_file *file_priv, - uint32_t __user * new_reloc_ptr, - struct drm_i915_validate_buffer *buffers, - unsigned int num_buffers) -{ - uint32_t *reloc; - uint32_t reloc_stride = I915_RELOC0_STRIDE * sizeof(uint32_t); - uint32_t header_size = I915_RELOC_HEADER * sizeof(uint32_t); - struct i915_relocatee_info relocatee; - uint32_t reloc_type; - uint32_t num_relocs; - uint32_t count; - int ret = 0; - int i; - int short_circuit = 1; - uint32_t __user *reloc_ptr; - uint64_t new_reloc_data; - uint32_t reloc_buf_size; - uint32_t *reloc_buf; - - for (i = 0; i < num_buffers; ++i) { - if (unlikely(!buffers[i].presumed_offset_correct)) { - short_circuit = 0; - break; - } - } - - if (likely(short_circuit)) - return 0; - - memset(&relocatee, 0, sizeof(relocatee)); - - while (new_reloc_ptr) { - reloc_ptr = new_reloc_ptr; - - ret = get_user(num_relocs, reloc_ptr); - if (unlikely(ret)) - goto out; - if (unlikely(!access_ok(VERIFY_READ, reloc_ptr, - header_size + - num_relocs * reloc_stride))) - return -EFAULT; - - ret = __get_user(reloc_type, reloc_ptr + 1); - if (unlikely(ret)) - goto out; - - if (unlikely(reloc_type != 1)) { - DRM_ERROR("Unsupported relocation type requested.\n"); - ret = -EINVAL; - goto out; - } - - ret = __get_user(new_reloc_data, reloc_ptr + 2); - new_reloc_ptr = (uint32_t __user *) (unsigned long) - new_reloc_data; - - reloc_ptr += I915_RELOC_HEADER; - - if (num_relocs == 0) - goto out; - - reloc_buf_size = - (num_relocs * I915_RELOC0_STRIDE) * sizeof(uint32_t); - reloc_buf = kmalloc(reloc_buf_size, GFP_KERNEL); - if (!reloc_buf) { - DRM_ERROR("Out of memory for reloc buffer\n"); - ret = -ENOMEM; - goto out; - } - - if (__copy_from_user(reloc_buf, reloc_ptr, reloc_buf_size)) { - ret = -EFAULT; - goto out; - } - reloc = reloc_buf; - preempt_disable(); - for (count = 0; count < num_relocs; ++count) { - ret = i915_apply_post_reloc(reloc, buffers, - num_buffers, &relocatee); - if (unlikely(ret)) { - preempt_enable(); - goto out; - } - reloc += I915_RELOC0_STRIDE; - } - preempt_enable(); - - if (reloc_buf) { - kfree(reloc_buf); - reloc_buf = NULL; - } - i915_clear_relocatee(&relocatee); - } - - out: - /* - * Flush ring relocs so the command parser will pick them up. - */ - - if (relocatee.performed_ring_relocs) - (void)i915_emit_mi_flush(file_priv->minor->dev, 0); - - i915_clear_relocatee(&relocatee); - if (reloc_buf) { - kfree(reloc_buf); - reloc_buf = NULL; - } - - return ret; -} - -static int i915_check_presumed(struct drm_i915_op_arg *arg, - struct drm_buffer_object *bo, - uint32_t __user * data, int *presumed_ok) -{ - struct drm_bo_op_req *req = &arg->d.req; - uint32_t hint_offset; - uint32_t hint = req->bo_req.hint; - - *presumed_ok = 0; - - if (!(hint & DRM_BO_HINT_PRESUMED_OFFSET)) - return 0; - if (bo->offset == req->bo_req.presumed_offset) { - *presumed_ok = 1; - return 0; - } - - /* - * We need to turn off the HINT_PRESUMED_OFFSET for this buffer in - * the user-space IOCTL argument list, since the buffer has moved, - * we're about to apply relocations and we might subsequently - * hit an -EAGAIN. In that case the argument list will be reused by - * user-space, but the presumed offset is no longer valid. - * - * Needless to say, this is a bit ugly. - */ - - hint_offset = (uint32_t *) & req->bo_req.hint - (uint32_t *) arg; - hint &= ~DRM_BO_HINT_PRESUMED_OFFSET; - return __put_user(hint, data + hint_offset); -} - -/* - * Validate, add fence and relocate a block of bos from a userspace list - */ -int i915_validate_buffer_list(struct drm_file *file_priv, - unsigned int fence_class, uint64_t data, - struct drm_i915_validate_buffer *buffers, - uint32_t * num_buffers, - uint32_t __user ** post_relocs) -{ - struct drm_i915_op_arg arg; - struct drm_bo_op_req *req = &arg.d.req; - int ret = 0; - unsigned buf_count = 0; - uint32_t buf_handle; - uint32_t __user *reloc_user_ptr; - struct drm_i915_validate_buffer *item = buffers; - *post_relocs = NULL; - - do { - if (buf_count >= *num_buffers) { - DRM_ERROR("Buffer count exceeded %d\n.", *num_buffers); - ret = -EINVAL; - goto out_err; - } - item = buffers + buf_count; - item->buffer = NULL; - item->presumed_offset_correct = 0; - item->idle = I915_RELOC_UNCHECKED; - - if (copy_from_user - (&arg, (void __user *)(unsigned long)data, sizeof(arg))) { - ret = -EFAULT; - goto out_err; - } - - ret = 0; - if (req->op != drm_bo_validate) { - DRM_ERROR - ("Buffer object operation wasn't \"validate\".\n"); - ret = -EINVAL; - goto out_err; - } - item->ret = 0; - item->data = (void __user *)(unsigned long)data; - - buf_handle = req->bo_req.handle; - reloc_user_ptr = (uint32_t *) (unsigned long)arg.reloc_ptr; - - /* - * Switch mode to post-validation relocations? - */ - - if (unlikely((buf_count == 0) && (*post_relocs == NULL) && - (reloc_user_ptr != NULL))) { - uint32_t reloc_type; - - ret = get_user(reloc_type, reloc_user_ptr + 1); - if (ret) - goto out_err; - - if (reloc_type == 1) - *post_relocs = reloc_user_ptr; - - } - - if ((*post_relocs == NULL) && (reloc_user_ptr != NULL)) { - ret = - i915_exec_reloc(file_priv, buf_handle, - reloc_user_ptr, buffers, buf_count); - if (ret) - goto out_err; - DRM_MEMORYBARRIER(); - } - - ret = drm_bo_handle_validate(file_priv, req->bo_req.handle, - req->bo_req.flags, - req->bo_req.mask, req->bo_req.hint, - req->bo_req.fence_class, - NULL, &item->buffer); - if (ret) { - DRM_ERROR("error on handle validate %d\n", ret); - goto out_err; - } - - buf_count++; - - ret = i915_check_presumed(&arg, item->buffer, - (uint32_t __user *) - (unsigned long)data, - &item->presumed_offset_correct); - if (ret) - goto out_err; - - data = arg.next; - } while (data != 0); - out_err: - *num_buffers = buf_count; - item->ret = (ret != -EAGAIN) ? ret : 0; - return ret; -} - -/* - * Remove all buffers from the unfenced list. - * If the execbuffer operation was aborted, for example due to a signal, - * this also make sure that buffers retain their original state and - * fence pointers. - * Copy back buffer information to user-space unless we were interrupted - * by a signal. In which case the IOCTL must be rerun. - */ - -static int i915_handle_copyback(struct drm_device *dev, - struct drm_i915_validate_buffer *buffers, - unsigned int num_buffers, int ret) -{ - int err = ret; - int i; - struct drm_i915_op_arg arg; - struct drm_buffer_object *bo; - - if (ret) - drm_putback_buffer_objects(dev); - - if (ret != -EAGAIN) { - for (i = 0; i < num_buffers; ++i) { - arg.handled = 1; - arg.d.rep.ret = buffers->ret; - bo = buffers->buffer; - mutex_lock(&bo->mutex); - drm_bo_fill_rep_arg(bo, &arg.d.rep.bo_info); - mutex_unlock(&bo->mutex); - if (__copy_to_user(buffers->data, &arg, sizeof(arg))) - err = -EFAULT; - buffers++; - } - } - - return err; -} - -/* - * Create a fence object, and if that fails, pretend that everything is - * OK and just idle the GPU. - */ - -void i915_fence_or_sync(struct drm_file *file_priv, - uint32_t fence_flags, - struct drm_fence_arg *fence_arg, - struct drm_fence_object **fence_p) -{ - struct drm_device *dev = file_priv->minor->dev; - int ret; - struct drm_fence_object *fence; - - ret = drm_fence_buffer_objects(dev, NULL, fence_flags, NULL, &fence); - - if (ret) { - - /* - * Fence creation failed. - * Fall back to synchronous operation and idle the engine. - */ - - (void)i915_emit_mi_flush(dev, MI_READ_FLUSH); - (void)i915_quiescent(dev); - - if (!(fence_flags & DRM_FENCE_FLAG_NO_USER)) { - - /* - * Communicate to user-space that - * fence creation has failed and that - * the engine is idle. - */ - - fence_arg->handle = ~0; - fence_arg->error = ret; - } - drm_putback_buffer_objects(dev); - if (fence_p) - *fence_p = NULL; - return; - } - - if (!(fence_flags & DRM_FENCE_FLAG_NO_USER)) { - - ret = drm_fence_add_user_object(file_priv, fence, - fence_flags & - DRM_FENCE_FLAG_SHAREABLE); - if (!ret) - drm_fence_fill_arg(fence, fence_arg); - else { - /* - * Fence user object creation failed. - * We must idle the engine here as well, as user- - * space expects a fence object to wait on. Since we - * have a fence object we wait for it to signal - * to indicate engine "sufficiently" idle. - */ - - (void)drm_fence_object_wait(fence, 0, 1, fence->type); - drm_fence_usage_deref_unlocked(&fence); - fence_arg->handle = ~0; - fence_arg->error = ret; - } - } - - if (fence_p) - *fence_p = fence; - else if (fence) - drm_fence_usage_deref_unlocked(&fence); -} - -int i915_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_i915_private *dev_priv = (struct drm_i915_private *) - dev->dev_private; - struct drm_i915_master_private *master_priv = - (struct drm_i915_master_private *) - dev->primary->master->driver_priv; - struct drm_i915_sarea *sarea_priv = (struct drm_i915_sarea *) - master_priv->sarea_priv; - struct drm_i915_execbuffer *exec_buf = data; - struct drm_i915_batchbuffer *batch = &exec_buf->batch; - struct drm_fence_arg *fence_arg = &exec_buf->fence_arg; - int num_buffers; - int ret; - uint32_t __user *post_relocs; - - if (!dev_priv->allow_batchbuffer) { - DRM_ERROR("Batchbuffer ioctl disabled\n"); - return -EINVAL; - } - - if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects, - batch->num_cliprects * - sizeof(struct - drm_clip_rect))) - return -EFAULT; - - if (exec_buf->num_buffers > dev_priv->max_validate_buffers) - return -EINVAL; - - ret = drm_bo_read_lock(&dev->bm.bm_lock, 1); - if (ret) - return ret; - - /* - * The cmdbuf_mutex makes sure the validate-submit-fence - * operation is atomic. - */ - - ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex); - if (ret) { - drm_bo_read_unlock(&dev->bm.bm_lock); - return -EAGAIN; - } - - num_buffers = exec_buf->num_buffers; - - if (!dev_priv->val_bufs) { - dev_priv->val_bufs = - vmalloc(sizeof(struct drm_i915_validate_buffer) * - dev_priv->max_validate_buffers); - } - if (!dev_priv->val_bufs) { - drm_bo_read_unlock(&dev->bm.bm_lock); - mutex_unlock(&dev_priv->cmdbuf_mutex); - return -ENOMEM; - } - - /* validate buffer list + fixup relocations */ - ret = i915_validate_buffer_list(file_priv, 0, exec_buf->ops_list, - dev_priv->val_bufs, &num_buffers, - &post_relocs); - if (ret) - goto out_err0; - - if (post_relocs) { - ret = i915_post_relocs(file_priv, post_relocs, - dev_priv->val_bufs, num_buffers); - if (ret) - goto out_err0; - } - - /* make sure all previous memory operations have passed */ - DRM_MEMORYBARRIER(); - - if (!post_relocs) { - drm_agp_chipset_flush(dev); - batch->start = - dev_priv->val_bufs[num_buffers - 1].buffer->offset; - } else { - batch->start += dev_priv->val_bufs[0].buffer->offset; - } - - DRM_DEBUG("i915 exec batchbuffer, start %x used %d cliprects %d\n", - batch->start, batch->used, batch->num_cliprects); - - ret = i915_dispatch_batchbuffer(dev, batch); - if (ret) - goto out_err0; - if (sarea_priv) - sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - i915_fence_or_sync(file_priv, fence_arg->flags, fence_arg, NULL); - - out_err0: - ret = i915_handle_copyback(dev, dev_priv->val_bufs, num_buffers, ret); - mutex_lock(&dev->struct_mutex); - i915_dereference_buffers_locked(dev_priv->val_bufs, num_buffers); - mutex_unlock(&dev->struct_mutex); - mutex_unlock(&dev_priv->cmdbuf_mutex); - drm_bo_read_unlock(&dev->bm.bm_lock); - return ret; -} diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c deleted file mode 100644 index 436b7e1f..00000000 --- a/linux-core/i915_fence.c +++ /dev/null @@ -1,273 +0,0 @@ -/************************************************************************** - * - * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * - **************************************************************************/ -/* - * Authors: Thomas Hellström - */ - -#include "drmP.h" -#include "drm.h" -#include "i915_drm.h" -#include "i915_drv.h" - -/* - * Initiate a sync flush if it's not already pending. - */ - -static inline void i915_initiate_rwflush(struct drm_i915_private *dev_priv, - struct drm_fence_class_manager *fc) -{ - if ((fc->pending_flush & DRM_I915_FENCE_TYPE_RW) && - !dev_priv->flush_pending) { - dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); - dev_priv->flush_flags = fc->pending_flush; - dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); - I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); - dev_priv->flush_pending = 1; - fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW; - } -} - -static inline void i915_report_rwflush(struct drm_device *dev, - struct drm_i915_private *dev_priv) -{ - if (unlikely(dev_priv->flush_pending)) { - - uint32_t flush_flags; - uint32_t i_status; - uint32_t flush_sequence; - - i_status = READ_HWSP(dev_priv, 0); - if ((i_status & (1 << 12)) != - (dev_priv->saved_flush_status & (1 << 12))) { - flush_flags = dev_priv->flush_flags; - flush_sequence = dev_priv->flush_sequence; - dev_priv->flush_pending = 0; - drm_fence_handler(dev, 0, flush_sequence, - flush_flags, 0); - } - } -} - -static void i915_fence_flush(struct drm_device *dev, - uint32_t fence_class) -{ - struct drm_i915_private *dev_priv = - (struct drm_i915_private *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_class_manager *fc = &fm->fence_class[0]; - unsigned long irq_flags; - - if (unlikely(!dev_priv)) - return; - - write_lock_irqsave(&fm->lock, irq_flags); - i915_initiate_rwflush(dev_priv, fc); - write_unlock_irqrestore(&fm->lock, irq_flags); -} - - -static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class, - uint32_t waiting_types) -{ - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_class_manager *fc = &fm->fence_class[0]; - uint32_t sequence; - - if (unlikely(!dev_priv)) - return; - - /* - * First, report any executed sync flush: - */ - - i915_report_rwflush(dev, dev_priv); - - /* - * Report A new breadcrumb, and adjust IRQs. - */ - - if (waiting_types & DRM_FENCE_TYPE_EXE) { - - sequence = READ_BREADCRUMB(dev_priv); - drm_fence_handler(dev, 0, sequence, - DRM_FENCE_TYPE_EXE, 0); - - if (dev_priv->fence_irq_on && - !(fc->waiting_types & DRM_FENCE_TYPE_EXE)) { - i915_user_irq_off(dev); - dev_priv->fence_irq_on = 0; - } else if (!dev_priv->fence_irq_on && - (fc->waiting_types & DRM_FENCE_TYPE_EXE)) { - i915_user_irq_on(dev); - dev_priv->fence_irq_on = 1; - } - } - - /* - * There may be new RW flushes pending. Start them. - */ - - i915_initiate_rwflush(dev_priv, fc); - - /* - * And possibly, but unlikely, they finish immediately. - */ - - i915_report_rwflush(dev, dev_priv); - -} - -static int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class, - uint32_t flags, uint32_t *sequence, - uint32_t *native_type) -{ - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - if (unlikely(!dev_priv)) - return -EINVAL; - - i915_emit_irq(dev); - *sequence = (uint32_t) dev_priv->counter; - *native_type = DRM_FENCE_TYPE_EXE; - if (flags & DRM_I915_FENCE_FLAG_FLUSHED) - *native_type |= DRM_I915_FENCE_TYPE_RW; - - return 0; -} - -void i915_fence_handler(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_class_manager *fc = &fm->fence_class[0]; - - write_lock(&fm->lock); - if (likely(dev_priv->fence_irq_on)) - i915_fence_poll(dev, 0, fc->waiting_types); - write_unlock(&fm->lock); -} - -/* - * We need a separate wait function since we need to poll for - * sync flushes. - */ - -static int i915_fence_wait(struct drm_fence_object *fence, - int lazy, int interruptible, uint32_t mask) -{ - struct drm_device *dev = fence->dev; - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - struct drm_fence_manager *fm = &dev->fm; - struct drm_fence_class_manager *fc = &fm->fence_class[0]; - int ret; - unsigned long _end = jiffies + 3 * DRM_HZ; - - drm_fence_object_flush(fence, mask); - if (likely(interruptible)) - ret = wait_event_interruptible_timeout - (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), - 3 * DRM_HZ); - else - ret = wait_event_timeout - (fc->fence_queue, drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), - 3 * DRM_HZ); - - if (unlikely(ret == -ERESTARTSYS)) - return -EAGAIN; - - if (unlikely(ret == 0)) - return -EBUSY; - - if (likely(mask == DRM_FENCE_TYPE_EXE || - drm_fence_object_signaled(fence, mask))) - return 0; - - /* - * Remove this code snippet when fixed. HWSTAM doesn't let - * flush info through... - */ - - if (unlikely(dev_priv && !dev_priv->irq_enabled)) { - unsigned long irq_flags; - - DRM_ERROR("X server disabled IRQs before releasing frame buffer.\n"); - msleep(100); - dev_priv->flush_pending = 0; - write_lock_irqsave(&fm->lock, irq_flags); - drm_fence_handler(dev, fence->fence_class, - fence->sequence, fence->type, 0); - write_unlock_irqrestore(&fm->lock, irq_flags); - } - - /* - * Poll for sync flush completion. - */ - - return drm_fence_wait_polling(fence, lazy, interruptible, mask, _end); -} - -static uint32_t i915_fence_needed_flush(struct drm_fence_object *fence) -{ - uint32_t flush_flags = fence->waiting_types & - ~(DRM_FENCE_TYPE_EXE | fence->signaled_types); - - if (likely(flush_flags == 0 || - ((flush_flags & ~fence->native_types) == 0) || - (fence->signaled_types != DRM_FENCE_TYPE_EXE))) - return 0; - else { - struct drm_device *dev = fence->dev; - struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - struct drm_fence_driver *driver = dev->driver->fence_driver; - - if (unlikely(!dev_priv)) - return 0; - - if (dev_priv->flush_pending) { - uint32_t diff = (dev_priv->flush_sequence - fence->sequence) & - driver->sequence_mask; - - if (diff < driver->wrap_diff) - return 0; - } - } - return flush_flags; -} - -struct drm_fence_driver i915_fence_driver = { - .num_classes = 1, - .wrap_diff = (1U << (BREADCRUMB_BITS - 1)), - .flush_diff = (1U << (BREADCRUMB_BITS - 2)), - .sequence_mask = BREADCRUMB_MASK, - .has_irq = NULL, - .emit = i915_fence_emit_sequence, - .flush = i915_fence_flush, - .poll = i915_fence_poll, - .needed_flush = i915_fence_needed_flush, - .wait = i915_fence_wait, -}; diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index e06cba5b..1aa3afbf 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -245,8 +245,7 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, if (!(obj_priv->bo->type != drm_bo_type_kernel && !DRM_SUSER(DRM_CURPROC))) { ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, - 0, NULL); + DRM_BO_HINT_DONT_FENCE, 0); } else ret = 0; @@ -276,8 +275,7 @@ int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, /* validate into a pin with no fence */ ret = drm_bo_do_validate(obj_priv->bo, DRM_BO_FLAG_NO_EVICT, DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, - 0, NULL); + DRM_BO_HINT_DONT_FENCE, 0); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); @@ -321,7 +319,7 @@ int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, //VB_AGE_TEST_WITH_RETURN(dev_priv); ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, - 0 , 0, NULL); + 0 , 0); if (ret) return ret; @@ -693,7 +691,7 @@ int radeon_gem_object_pin(struct drm_gem_object *obj, obj_priv = obj->driver_private; ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0, NULL); + DRM_BO_HINT_DONT_FENCE, 0); return ret; } @@ -743,7 +741,7 @@ int radeon_gem_ib_get(struct drm_device *dev, void **ib, uint32_t dwords, uint32 ret = drm_bo_do_validate(dev_priv->ib_objs[index]->bo, 0, DRM_BO_FLAG_NO_EVICT, - 0, 0, NULL); + 0, 0); if (ret) { DRM_ERROR("Failed to validate IB %d\n", index); return -EINVAL; @@ -761,7 +759,6 @@ static void radeon_gem_ib_free(struct drm_device *dev, void *ib, uint32_t dwords struct drm_fence_object *fence; int ret; int i; - RING_LOCALS; for (i = 0; i < RADEON_NUM_IB; i++) { @@ -821,7 +818,7 @@ static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_pri flags = DRM_BO_FLAG_MEM_TT; } - ret = drm_bo_do_validate(obj_priv->bo, flags, DRM_BO_MASK_MEM, 0, 0, NULL); + ret = drm_bo_do_validate(obj_priv->bo, flags, DRM_BO_MASK_MEM, 0, 0); if (ret) return ret; diff --git a/shared-core/drm.h b/shared-core/drm.h index 7aba2939..76d2c4c5 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -675,324 +675,6 @@ struct drm_set_version { int drm_dd_minor; }; - -#define DRM_FENCE_FLAG_EMIT 0x00000001 -#define DRM_FENCE_FLAG_SHAREABLE 0x00000002 -/** - * On hardware with no interrupt events for operation completion, - * indicates that the kernel should sleep while waiting for any blocking - * operation to complete rather than spinning. - * - * Has no effect otherwise. - */ -#define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 -#define DRM_FENCE_FLAG_NO_USER 0x00000010 - -/* Reserved for driver use */ -#define DRM_FENCE_MASK_DRIVER 0xFF000000 - -#define DRM_FENCE_TYPE_EXE 0x00000001 - -struct drm_fence_arg { - unsigned int handle; - unsigned int fence_class; - unsigned int type; - unsigned int flags; - unsigned int signaled; - unsigned int error; - unsigned int sequence; - unsigned int pad64; - uint64_t expand_pad[2]; /*Future expansion */ -}; - -/* Buffer permissions, referring to how the GPU uses the buffers. - * these translate to fence types used for the buffers. - * Typically a texture buffer is read, A destination buffer is write and - * a command (batch-) buffer is exe. Can be or-ed together. - */ - -#define DRM_BO_FLAG_READ (1ULL << 0) -#define DRM_BO_FLAG_WRITE (1ULL << 1) -#define DRM_BO_FLAG_EXE (1ULL << 2) - -/* - * All of the bits related to access mode - */ -#define DRM_BO_MASK_ACCESS (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE) -/* - * Status flags. Can be read to determine the actual state of a buffer. - * Can also be set in the buffer mask before validation. - */ - -/* - * Mask: Never evict this buffer. Not even with force. This type of buffer is only - * available to root and must be manually removed before buffer manager shutdown - * or lock. - * Flags: Acknowledge - */ -#define DRM_BO_FLAG_NO_EVICT (1ULL << 4) - -/* - * Mask: Require that the buffer is placed in mappable memory when validated. - * If not set the buffer may or may not be in mappable memory when validated. - * Flags: If set, the buffer is in mappable memory. - */ -#define DRM_BO_FLAG_MAPPABLE (1ULL << 5) - -/* Mask: The buffer should be shareable with other processes. - * Flags: The buffer is shareable with other processes. - */ -#define DRM_BO_FLAG_SHAREABLE (1ULL << 6) - -/* Mask: If set, place the buffer in cache-coherent memory if available. - * If clear, never place the buffer in cache coherent memory if validated. - * Flags: The buffer is currently in cache-coherent memory. - */ -#define DRM_BO_FLAG_CACHED (1ULL << 7) - -/* Mask: Make sure that every time this buffer is validated, - * it ends up on the same location provided that the memory mask is the same. - * The buffer will also not be evicted when claiming space for - * other buffers. Basically a pinned buffer but it may be thrown out as - * part of buffer manager shutdown or locking. - * Flags: Acknowledge. - */ -#define DRM_BO_FLAG_NO_MOVE (1ULL << 8) - -/* Mask: Make sure the buffer is in cached memory when mapped. In conjunction - * with DRM_BO_FLAG_CACHED it also allows the buffer to be bound into the GART - * with unsnooped PTEs instead of snooped, by using chipset-specific cache - * flushing at bind time. A better name might be DRM_BO_FLAG_TT_UNSNOOPED, - * as the eviction to local memory (TTM unbind) on map is just a side effect - * to prevent aggressive cache prefetch from the GPU disturbing the cache - * management that the DRM is doing. - * - * Flags: Acknowledge. - * Buffers allocated with this flag should not be used for suballocators - * This type may have issues on CPUs with over-aggressive caching - * http://marc.info/?l=linux-kernel&m=102376926732464&w=2 - */ -#define DRM_BO_FLAG_CACHED_MAPPED (1ULL << 19) - - -/* Mask: Force DRM_BO_FLAG_CACHED flag strictly also if it is set. - * Flags: Acknowledge. - */ -#define DRM_BO_FLAG_FORCE_CACHING (1ULL << 13) - -/* - * Mask: Force DRM_BO_FLAG_MAPPABLE flag strictly also if it is clear. - * Flags: Acknowledge. - */ -#define DRM_BO_FLAG_FORCE_MAPPABLE (1ULL << 14) -#define DRM_BO_FLAG_TILE (1ULL << 15) - -/* - * Memory type flags that can be or'ed together in the mask, but only - * one appears in flags. - */ - -/* System memory */ -#define DRM_BO_FLAG_MEM_LOCAL (1ULL << 24) -/* Translation table memory */ -#define DRM_BO_FLAG_MEM_TT (1ULL << 25) -/* Vram memory */ -#define DRM_BO_FLAG_MEM_VRAM (1ULL << 26) -/* Up to the driver to define. */ -#define DRM_BO_FLAG_MEM_PRIV0 (1ULL << 27) -#define DRM_BO_FLAG_MEM_PRIV1 (1ULL << 28) -#define DRM_BO_FLAG_MEM_PRIV2 (1ULL << 29) -#define DRM_BO_FLAG_MEM_PRIV3 (1ULL << 30) -#define DRM_BO_FLAG_MEM_PRIV4 (1ULL << 31) -/* We can add more of these now with a 64-bit flag type */ - -/* - * This is a mask covering all of the memory type flags; easier to just - * use a single constant than a bunch of | values. It covers - * DRM_BO_FLAG_MEM_LOCAL through DRM_BO_FLAG_MEM_PRIV4 - */ -#define DRM_BO_MASK_MEM 0x00000000FF000000ULL -/* - * This adds all of the CPU-mapping options in with the memory - * type to label all bits which change how the page gets mapped - */ -#define DRM_BO_MASK_MEMTYPE (DRM_BO_MASK_MEM | \ - DRM_BO_FLAG_CACHED_MAPPED | \ - DRM_BO_FLAG_CACHED | \ - DRM_BO_FLAG_MAPPABLE) - -/* Driver-private flags */ -#define DRM_BO_MASK_DRIVER 0xFFFF000000000000ULL - -/* - * Don't block on validate and map. Instead, return EBUSY. - */ -#define DRM_BO_HINT_DONT_BLOCK 0x00000002 -/* - * Don't place this buffer on the unfenced list. This means - * that the buffer will not end up having a fence associated - * with it as a result of this operation - */ -#define DRM_BO_HINT_DONT_FENCE 0x00000004 -/** - * On hardware with no interrupt events for operation completion, - * indicates that the kernel should sleep while waiting for any blocking - * operation to complete rather than spinning. - * - * Has no effect otherwise. - */ -#define DRM_BO_HINT_WAIT_LAZY 0x00000008 -/* - * The client has compute relocations refering to this buffer using the - * offset in the presumed_offset field. If that offset ends up matching - * where this buffer lands, the kernel is free to skip executing those - * relocations - */ -#define DRM_BO_HINT_PRESUMED_OFFSET 0x00000010 - -#define DRM_BO_INIT_MAGIC 0xfe769812 -#define DRM_BO_INIT_MAJOR 1 -#define DRM_BO_INIT_MINOR 0 -#define DRM_BO_INIT_PATCH 0 - - -struct drm_bo_info_req { - uint64_t mask; - uint64_t flags; - unsigned int handle; - unsigned int hint; - unsigned int fence_class; - unsigned int desired_tile_stride; - unsigned int tile_info; - unsigned int pad64; - uint64_t presumed_offset; -}; - -struct drm_bo_create_req { - uint64_t flags; - uint64_t size; - uint64_t buffer_start; - unsigned int hint; - unsigned int page_alignment; -}; - - -/* - * Reply flags - */ - -#define DRM_BO_REP_BUSY 0x00000001 - -struct drm_bo_info_rep { - uint64_t flags; - uint64_t proposed_flags; - uint64_t size; - uint64_t offset; - uint64_t arg_handle; - uint64_t buffer_start; - unsigned int handle; - unsigned int fence_flags; - unsigned int rep_flags; - unsigned int page_alignment; - unsigned int desired_tile_stride; - unsigned int hw_tile_stride; - unsigned int tile_info; - unsigned int pad64; - uint64_t expand_pad[4]; /*Future expansion */ -}; - -struct drm_bo_arg_rep { - struct drm_bo_info_rep bo_info; - int ret; - unsigned int pad64; -}; - -struct drm_bo_create_arg { - union { - struct drm_bo_create_req req; - struct drm_bo_info_rep rep; - } d; -}; - -struct drm_bo_handle_arg { - unsigned int handle; -}; - -struct drm_bo_reference_info_arg { - union { - struct drm_bo_handle_arg req; - struct drm_bo_info_rep rep; - } d; -}; - -struct drm_bo_map_wait_idle_arg { - union { - struct drm_bo_info_req req; - struct drm_bo_info_rep rep; - } d; -}; - -struct drm_bo_op_req { - enum { - drm_bo_validate, - drm_bo_fence, - drm_bo_ref_fence, - } op; - unsigned int arg_handle; - struct drm_bo_info_req bo_req; -}; - - -struct drm_bo_op_arg { - uint64_t next; - union { - struct drm_bo_op_req req; - struct drm_bo_arg_rep rep; - } d; - int handled; - unsigned int pad64; -}; - - -#define DRM_BO_MEM_LOCAL 0 -#define DRM_BO_MEM_TT 1 -#define DRM_BO_MEM_VRAM 2 -#define DRM_BO_MEM_PRIV0 3 -#define DRM_BO_MEM_PRIV1 4 -#define DRM_BO_MEM_PRIV2 5 -#define DRM_BO_MEM_PRIV3 6 -#define DRM_BO_MEM_PRIV4 7 - -#define DRM_BO_MEM_TYPES 8 /* For now. */ - -#define DRM_BO_LOCK_UNLOCK_BM (1 << 0) -#define DRM_BO_LOCK_IGNORE_NO_EVICT (1 << 1) - -struct drm_bo_version_arg { - uint32_t major; - uint32_t minor; - uint32_t patchlevel; -}; - -struct drm_mm_type_arg { - unsigned int mem_type; - unsigned int lock_flags; -}; - -struct drm_mm_init_arg { - unsigned int magic; - unsigned int major; - unsigned int minor; - unsigned int mem_type; - uint64_t p_offset; - uint64_t p_size; -}; - -struct drm_mm_info_arg { - unsigned int mem_type; - uint64_t p_size; -}; - struct drm_gem_close { /** Handle of the object to be closed. */ uint32_t handle; @@ -1337,31 +1019,6 @@ struct drm_mode_crtc_lut { #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) -#define DRM_IOCTL_MM_INIT DRM_IOWR(0xc0, struct drm_mm_init_arg) -#define DRM_IOCTL_MM_TAKEDOWN DRM_IOWR(0xc1, struct drm_mm_type_arg) -#define DRM_IOCTL_MM_LOCK DRM_IOWR(0xc2, struct drm_mm_type_arg) -#define DRM_IOCTL_MM_UNLOCK DRM_IOWR(0xc3, struct drm_mm_type_arg) - -#define DRM_IOCTL_FENCE_CREATE DRM_IOWR(0xc4, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_REFERENCE DRM_IOWR(0xc6, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_UNREFERENCE DRM_IOWR(0xc7, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_SIGNALED DRM_IOWR(0xc8, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_FLUSH DRM_IOWR(0xc9, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_WAIT DRM_IOWR(0xca, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_EMIT DRM_IOWR(0xcb, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_BUFFERS DRM_IOWR(0xcc, struct drm_fence_arg) - -#define DRM_IOCTL_BO_CREATE DRM_IOWR(0xcd, struct drm_bo_create_arg) -#define DRM_IOCTL_BO_MAP DRM_IOWR(0xcf, struct drm_bo_map_wait_idle_arg) -#define DRM_IOCTL_BO_UNMAP DRM_IOWR(0xd0, struct drm_bo_handle_arg) -#define DRM_IOCTL_BO_REFERENCE DRM_IOWR(0xd1, struct drm_bo_reference_info_arg) -#define DRM_IOCTL_BO_UNREFERENCE DRM_IOWR(0xd2, struct drm_bo_handle_arg) -#define DRM_IOCTL_BO_SETSTATUS DRM_IOWR(0xd3, struct drm_bo_map_wait_idle_arg) -#define DRM_IOCTL_BO_INFO DRM_IOWR(0xd4, struct drm_bo_reference_info_arg) -#define DRM_IOCTL_BO_WAIT_IDLE DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg) -#define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_arg) -#define DRM_IOCTL_MM_INFO DRM_IOWR(0xd7, struct drm_mm_info_arg) - #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) #define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA2, struct drm_mode_get_connector) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 09c53676..3e6a6626 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -148,7 +148,7 @@ int i915_dma_cleanup(struct drm_device * dev) return 0; } -#if defined(I915_HAVE_BUFFER) && defined(DRI2) +#if defined(DRI2) #define DRI2_SAREA_BLOCK_TYPE(b) ((b) >> 16) #define DRI2_SAREA_BLOCK_SIZE(b) ((b) & 0xffff) #define DRI2_SAREA_BLOCK_NEXT(p) \ @@ -226,12 +226,7 @@ static int i915_initialize(struct drm_device * dev, } } -#ifdef I915_HAVE_BUFFER - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS; - } -#endif - + if (init->ring_size != 0) { dev_priv->ring.Size = init->ring_size; dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; @@ -285,10 +280,6 @@ static int i915_initialize(struct drm_device * dev, } DRM_DEBUG("Enabled hardware status page\n"); -#ifdef I915_HAVE_BUFFER - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - mutex_init(&dev_priv->cmdbuf_mutex); - } #ifdef DRI2 if (init->func == I915_INIT_DMA2) { int ret = setup_dri2_sarea(dev, file_priv, init); @@ -299,7 +290,6 @@ static int i915_initialize(struct drm_device * dev, } } #endif /* DRI2 */ -#endif /* I915_HAVE_BUFFER */ return 0; } @@ -565,9 +555,6 @@ int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) static int i915_dispatch_cmdbuffer(struct drm_device * dev, struct drm_i915_cmdbuffer * cmd) { -#ifdef I915_HAVE_FENCE - struct drm_i915_private *dev_priv = dev->dev_private; -#endif int nbox = cmd->num_cliprects; int i = 0, count, ret; @@ -594,10 +581,6 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev, } i915_emit_breadcrumb(dev); -#ifdef I915_HAVE_FENCE - if (unlikely((dev_priv->counter & 0xFF) == 0)) - drm_fence_flush_old(dev, 0, dev_priv->counter); -#endif return 0; } @@ -648,10 +631,6 @@ int i915_dispatch_batchbuffer(struct drm_device * dev, } i915_emit_breadcrumb(dev); -#ifdef I915_HAVE_FENCE - if (unlikely((dev_priv->counter & 0xFF) == 0)) - drm_fence_flush_old(dev, 0, dev_priv->counter); -#endif return 0; } @@ -724,10 +703,6 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) i915_do_dispatch_flip(dev, i, sync); i915_emit_breadcrumb(dev); -#ifdef I915_HAVE_FENCE - if (unlikely(!sync && ((dev_priv->counter & 0xFF) == 0))) - drm_fence_flush_old(dev, 0, dev_priv->counter); -#endif } int i915_quiescent(struct drm_device *dev) @@ -1077,9 +1052,6 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_MMIO, i915_mmio, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH), -#ifdef I915_HAVE_BUFFER - DRM_IOCTL_DEF(DRM_I915_EXECBUFFER, i915_execbuffer, DRM_AUTH), -#endif DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 8ba71687..611f943a 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -375,58 +375,6 @@ typedef struct drm_i915_hws_addr { uint64_t addr; } drm_i915_hws_addr_t; -/* - * Relocation header is 4 uint32_ts - * 0 - 32 bit reloc count - * 1 - 32-bit relocation type - * 2-3 - 64-bit user buffer handle ptr for another list of relocs. - */ -#define I915_RELOC_HEADER 4 - -/* - * type 0 relocation has 4-uint32_t stride - * 0 - offset into buffer - * 1 - delta to add in - * 2 - buffer handle - * 3 - reserved (for optimisations later). - */ -/* - * type 1 relocation has 4-uint32_t stride. - * Hangs off the first item in the op list. - * Performed after all valiations are done. - * Try to group relocs into the same relocatee together for - * performance reasons. - * 0 - offset into buffer - * 1 - delta to add in - * 2 - buffer index in op list. - * 3 - relocatee index in op list. - */ -#define I915_RELOC_TYPE_0 0 -#define I915_RELOC0_STRIDE 4 -#define I915_RELOC_TYPE_1 1 -#define I915_RELOC1_STRIDE 4 - - -struct drm_i915_op_arg { - uint64_t next; - uint64_t reloc_ptr; - int handled; - unsigned int pad64; - union { - struct drm_bo_op_req req; - struct drm_bo_arg_rep rep; - } d; - -}; - -struct drm_i915_execbuffer { - uint64_t ops_list; - uint32_t num_buffers; - struct drm_i915_batchbuffer batch; - drm_context_t context; /* for lockless use in the future */ - struct drm_fence_arg fence_arg; -}; - struct drm_i915_gem_init { /** * Beginning offset in the GTT to be managed by the DRM memory -- cgit v1.2.3 From 55761b2fe706f8f68ca3a8827b950fd01af1650b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 31 Jul 2008 13:12:36 +1000 Subject: drm: add fault handler support so as to be more like possible upstream (cherry picked from commit 10d5b037b85706037df89bf0275436797e4eb559) --- linux-core/drm_compat.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_compat.h | 3 ++ linux-core/drm_vm.c | 35 ++++++++--------- 3 files changed, 120 insertions(+), 17 deletions(-) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index aa825f32..d06b9d24 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -806,3 +806,102 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, EXPORT_SYMBOL(kmap_atomic_prot_pfn); #endif +#ifdef DRM_FULL_MM_COMPAT +#ifdef DRM_NO_FAULT +unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, + unsigned long address) +{ + struct drm_buffer_object *bo = (struct drm_buffer_object *) vma->vm_private_data; + unsigned long page_offset; + struct page *page = NULL; + struct drm_ttm *ttm; + struct drm_device *dev; + unsigned long pfn; + int err; + unsigned long bus_base; + unsigned long bus_offset; + unsigned long bus_size; + unsigned long ret = NOPFN_REFAULT; + + if (address > vma->vm_end) + return NOPFN_SIGBUS; + + dev = bo->dev; + err = drm_bo_read_lock(&dev->bm.bm_lock, 1); + if (err) + return NOPFN_REFAULT; + + err = mutex_lock_interruptible(&bo->mutex); + if (err) { + drm_bo_read_unlock(&dev->bm.bm_lock); + return NOPFN_REFAULT; + } + + err = drm_bo_wait(bo, 0, 1, 0, 1); + if (err) { + ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT; + bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; + goto out_unlock; + } + + bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; + + /* + * If buffer happens to be in a non-mappable location, + * move it to a mappable. + */ + + if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) { + uint32_t new_flags = bo->mem.proposed_flags | + DRM_BO_FLAG_MAPPABLE | + DRM_BO_FLAG_FORCE_MAPPABLE; + err = drm_bo_move_buffer(bo, new_flags, 0, 0); + if (err) { + ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT; + goto out_unlock; + } + } + + err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset, + &bus_size); + + if (err) { + ret = NOPFN_SIGBUS; + goto out_unlock; + } + + page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + + if (bus_size) { + struct drm_mem_type_manager *man = &dev->bm.man[bo->mem.mem_type]; + + pfn = ((bus_base + bus_offset) >> PAGE_SHIFT) + page_offset; + vma->vm_page_prot = drm_io_prot(man->drm_bus_maptype, vma); + } else { + ttm = bo->ttm; + + drm_ttm_fixup_caching(ttm); + page = drm_ttm_get_page(ttm, page_offset); + if (!page) { + ret = NOPFN_OOM; + goto out_unlock; + } + pfn = page_to_pfn(page); + vma->vm_page_prot = (bo->mem.flags & DRM_BO_FLAG_CACHED) ? + vm_get_page_prot(vma->vm_flags) : + drm_io_prot(_DRM_TTM, vma); + } + + err = vm_insert_pfn(vma, address, pfn); + if (err) { + ret = (err != -EAGAIN) ? NOPFN_OOM : NOPFN_REFAULT; + goto out_unlock; + } +out_unlock: + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); + mutex_unlock(&bo->mutex); + drm_bo_read_unlock(&dev->bm.bm_lock); + return ret; +} +#endif +#endif diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index cfa4fc6d..19dc1f67 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -319,6 +319,9 @@ extern int drm_bo_map_bound(struct vm_area_struct *vma); /* fixme when functions are upstreamed - upstreamed for 2.6.23 */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) #define DRM_IDR_COMPAT_FN +#define DRM_NO_FAULT +extern unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, + unsigned long address); #endif #ifdef DRM_IDR_COMPAT_FN int idr_for_each(struct idr *idp, diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 6618c0ae..0d5242d3 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -685,8 +685,8 @@ EXPORT_SYMBOL(drm_mmap); * \c Pagefault method for buffer objects. * * \param vma Virtual memory area. - * \param address File offset. - * \return Error or refault. The pfn is manually inserted. + * \param vmf vm fault data + * \return Error or VM_FAULT_NOPAGE:. The pfn is manually inserted. * * It's important that pfns are inserted while holding the bo->mutex lock. * otherwise we might race with unmap_mapping_range() which is always @@ -699,8 +699,8 @@ EXPORT_SYMBOL(drm_mmap); */ #ifdef DRM_FULL_MM_COMPAT -static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, - unsigned long address) +static int drm_bo_vm_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) { struct drm_buffer_object *bo = (struct drm_buffer_object *) vma->vm_private_data; unsigned long page_offset; @@ -712,25 +712,22 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, unsigned long bus_base; unsigned long bus_offset; unsigned long bus_size; - unsigned long ret = NOPFN_REFAULT; - - if (address > vma->vm_end) - return NOPFN_SIGBUS; + unsigned long ret = VM_FAULT_NOPAGE; dev = bo->dev; err = drm_bo_read_lock(&dev->bm.bm_lock, 1); if (err) - return NOPFN_REFAULT; + return VM_FAULT_NOPAGE; err = mutex_lock_interruptible(&bo->mutex); if (err) { drm_bo_read_unlock(&dev->bm.bm_lock); - return NOPFN_REFAULT; + return VM_FAULT_NOPAGE; } err = drm_bo_wait(bo, 0, 1, 0, 1); if (err) { - ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT; + ret = (err != -EAGAIN) ? VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; goto out_unlock; } @@ -748,7 +745,7 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, DRM_BO_FLAG_FORCE_MAPPABLE; err = drm_bo_move_buffer(bo, new_flags, 0, 0); if (err) { - ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT; + ret = (err != -EAGAIN) ? VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; goto out_unlock; } } @@ -757,11 +754,11 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, &bus_size); if (err) { - ret = NOPFN_SIGBUS; + ret = VM_FAULT_SIGBUS; goto out_unlock; } - page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; if (bus_size) { struct drm_mem_type_manager *man = &dev->bm.man[bo->mem.mem_type]; @@ -774,7 +771,7 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, drm_ttm_fixup_caching(ttm); page = drm_ttm_get_page(ttm, page_offset); if (!page) { - ret = NOPFN_OOM; + ret = VM_FAULT_OOM; goto out_unlock; } pfn = page_to_pfn(page); @@ -783,9 +780,9 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, drm_io_prot(_DRM_TTM, vma); } - err = vm_insert_pfn(vma, address, pfn); + err = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); if (err) { - ret = (err != -EAGAIN) ? NOPFN_OOM : NOPFN_REFAULT; + ret = (err != -EAGAIN) ? VM_FAULT_OOM : VM_FAULT_NOPAGE; goto out_unlock; } out_unlock: @@ -849,7 +846,11 @@ static void drm_bo_vm_close(struct vm_area_struct *vma) static struct vm_operations_struct drm_bo_vm_ops = { #ifdef DRM_FULL_MM_COMPAT +#ifdef DRM_NO_FAULT .nopfn = drm_bo_vm_nopfn, +#else + .fault = drm_bo_vm_fault, +#endif #else #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) .nopfn = drm_bo_vm_nopfn, -- cgit v1.2.3 From d2d7f3069dac4bc5ddd3c8da4d3955f690274276 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 31 Jul 2008 13:13:21 +1000 Subject: drm: userspace rip out TTM API --- libdrm/intel/intel_bufmgr_fake.c | 2 +- libdrm/xf86drm.c | 530 --------------------------------------- linux-core/drm_bo.c | 5 +- linux-core/drm_objects.h | 17 -- linux-core/drm_vm.c | 6 - shared-core/i915_dma.c | 1 - 6 files changed, 3 insertions(+), 558 deletions(-) diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index e988eb58..e7ed893f 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -649,7 +649,7 @@ intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name, bo_fake->refcount = 1; bo_fake->id = ++bufmgr_fake->buf_nr; bo_fake->name = name; - bo_fake->flags = BM_PINNED | DRM_BO_FLAG_NO_MOVE; + bo_fake->flags = BM_PINNED; bo_fake->is_static = 1; DBG("drm_bo_alloc_static: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 4b4d009b..1fd3a697 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2357,165 +2357,6 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, } -/* - * Valid flags are - * DRM_FENCE_FLAG_EMIT - * DRM_FENCE_FLAG_SHAREABLE - * DRM_FENCE_MASK_DRIVER - */ - -int drmFenceCreate(int fd, unsigned flags, int fence_class, unsigned type, - drmFence *fence) -{ - drm_fence_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.flags = flags; - arg.type = type; - arg.fence_class = fence_class; - - if (drmIoctl(fd, DRM_IOCTL_FENCE_CREATE, &arg)) - return -errno; - fence->handle = arg.handle; - fence->fence_class = arg.fence_class; - fence->type = arg.type; - fence->flags = arg.flags; - fence->signaled = 0; - return 0; -} - -/* - * Valid flags are - * DRM_FENCE_FLAG_SHAREABLE - * DRM_FENCE_MASK_DRIVER - */ - -int drmFenceBuffers(int fd, unsigned flags, uint32_t fence_class, drmFence *fence) -{ - drm_fence_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.flags = flags; - arg.fence_class = fence_class; - - if (drmIoctl(fd, DRM_IOCTL_FENCE_BUFFERS, &arg)) - return -errno; - fence->handle = arg.handle; - fence->fence_class = arg.fence_class; - fence->type = arg.type; - fence->flags = arg.flags; - fence->sequence = arg.sequence; - fence->signaled = 0; - return 0; -} - -int drmFenceReference(int fd, unsigned handle, drmFence *fence) -{ - drm_fence_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.handle = handle; - - if (drmIoctl(fd, DRM_IOCTL_FENCE_REFERENCE, &arg)) - return -errno; - fence->handle = arg.handle; - fence->fence_class = arg.fence_class; - fence->type = arg.type; - fence->flags = arg.flags; - fence->signaled = arg.signaled; - return 0; -} - -int drmFenceUnreference(int fd, const drmFence *fence) -{ - drm_fence_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.handle = fence->handle; - - if (drmIoctl(fd, DRM_IOCTL_FENCE_UNREFERENCE, &arg)) - return -errno; - return 0; -} - -int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type) -{ - drm_fence_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.handle = fence->handle; - arg.type = flush_type; - - if (drmIoctl(fd, DRM_IOCTL_FENCE_FLUSH, &arg)) - return -errno; - fence->fence_class = arg.fence_class; - fence->type = arg.type; - fence->signaled = arg.signaled; - return arg.error; -} - -int drmFenceUpdate(int fd, drmFence *fence) -{ - drm_fence_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.handle = fence->handle; - - if (drmIoctl(fd, DRM_IOCTL_FENCE_SIGNALED, &arg)) - return -errno; - fence->fence_class = arg.fence_class; - fence->type = arg.type; - fence->signaled = arg.signaled; - return 0; -} - -int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType, - int *signaled) -{ - if ((fence->flags & DRM_FENCE_FLAG_SHAREABLE) || - ((fenceType & fence->signaled) != fenceType)) { - int ret = drmFenceFlush(fd, fence, fenceType); - if (ret) - return ret; - } - - *signaled = ((fenceType & fence->signaled) == fenceType); - - return 0; -} - -/* - * Valid flags are - * DRM_FENCE_FLAG_SHAREABLE - * DRM_FENCE_MASK_DRIVER - */ - - -int drmFenceEmit(int fd, unsigned flags, drmFence *fence, unsigned emit_type) -{ - drm_fence_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.fence_class = fence->fence_class; - arg.flags = flags; - arg.handle = fence->handle; - arg.type = emit_type; - - if (drmIoctl(fd, DRM_IOCTL_FENCE_EMIT, &arg)) - return -errno; - fence->fence_class = arg.fence_class; - fence->type = arg.type; - fence->signaled = arg.signaled; - fence->sequence = arg.sequence; - return 0; -} - -/* - * Valid flags are - * DRM_FENCE_FLAG_WAIT_LAZY - * DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS - */ - #define DRM_IOCTL_TIMEOUT_USEC 3000000UL static unsigned long @@ -2558,377 +2399,6 @@ drmIoctlTimeout(int fd, unsigned long request, void *argp) - -int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) -{ - drm_fence_arg_t arg; - int ret; - - if (flush_type == 0) { - flush_type = fence->type; - } - - if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) { - if ((flush_type & fence->signaled) == flush_type) { - return 0; - } - } - - memset(&arg, 0, sizeof(arg)); - arg.handle = fence->handle; - arg.type = flush_type; - arg.flags = flags; - - - ret = drmIoctlTimeout(fd, DRM_IOCTL_FENCE_WAIT, &arg); - if (ret) - return ret; - - fence->fence_class = arg.fence_class; - fence->type = arg.type; - fence->signaled = arg.signaled; - return arg.error; -} - -static void drmBOCopyReply(const struct drm_bo_info_rep *rep, drmBO *buf) -{ - buf->handle = rep->handle; - buf->flags = rep->flags; - buf->size = rep->size; - buf->offset = rep->offset; - buf->mapHandle = rep->arg_handle; - buf->proposedFlags = rep->proposed_flags; - buf->start = rep->buffer_start; - buf->fenceFlags = rep->fence_flags; - buf->replyFlags = rep->rep_flags; - buf->pageAlignment = rep->page_alignment; - buf->tileInfo = rep->tile_info; - buf->hwTileStride = rep->hw_tile_stride; - buf->desiredTileStride = rep->desired_tile_stride; -} - - - -int drmBOCreate(int fd, unsigned long size, - unsigned pageAlignment, void *user_buffer, - uint64_t flags, - unsigned hint, drmBO *buf) -{ - struct drm_bo_create_arg arg; - struct drm_bo_create_req *req = &arg.d.req; - struct drm_bo_info_rep *rep = &arg.d.rep; - int ret; - - memset(buf, 0, sizeof(*buf)); - memset(&arg, 0, sizeof(arg)); - req->flags = flags; - req->hint = hint; - req->size = size; - req->page_alignment = pageAlignment; - req->buffer_start = (unsigned long) user_buffer; - - buf->virtual = NULL; - - ret = drmIoctlTimeout(fd, DRM_IOCTL_BO_CREATE, &arg); - if (ret) - return ret; - - drmBOCopyReply(rep, buf); - buf->virtual = user_buffer; - buf->mapCount = 0; - - return 0; -} - -int drmBOReference(int fd, unsigned handle, drmBO *buf) -{ - struct drm_bo_reference_info_arg arg; - struct drm_bo_handle_arg *req = &arg.d.req; - struct drm_bo_info_rep *rep = &arg.d.rep; - - memset(&arg, 0, sizeof(arg)); - req->handle = handle; - - if (drmIoctl(fd, DRM_IOCTL_BO_REFERENCE, &arg)) - return -errno; - - drmBOCopyReply(rep, buf); - buf->mapVirtual = NULL; - buf->mapCount = 0; - buf->virtual = NULL; - - return 0; -} - -int drmBOUnreference(int fd, drmBO *buf) -{ - struct drm_bo_handle_arg arg; - - if (buf->mapVirtual && buf->mapHandle) { - (void) munmap(buf->mapVirtual, buf->start + buf->size); - buf->mapVirtual = NULL; - buf->virtual = NULL; - } - - memset(&arg, 0, sizeof(arg)); - arg.handle = buf->handle; - - if (drmIoctl(fd, DRM_IOCTL_BO_UNREFERENCE, &arg)) - return -errno; - - buf->handle = 0; - return 0; -} - - -/* - * Flags can be DRM_BO_FLAG_READ, DRM_BO_FLAG_WRITE or'ed together - * Hint currently be DRM_BO_HINT_DONT_BLOCK, which makes the - * call return an -EBUSY if it can' immediately honor the mapping request. - */ - -int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, - void **address) -{ - struct drm_bo_map_wait_idle_arg arg; - struct drm_bo_info_req *req = &arg.d.req; - struct drm_bo_info_rep *rep = &arg.d.rep; - int ret = 0; - - /* - * Make sure we have a virtual address of the buffer. - */ - - if (!buf->virtual) { - drmAddress virtual; - virtual = mmap(0, buf->size + buf->start, - PROT_READ | PROT_WRITE, MAP_SHARED, - fd, buf->mapHandle); - if (virtual == MAP_FAILED) { - ret = -errno; - } - if (ret) - return ret; - buf->mapVirtual = virtual; - buf->virtual = ((char *) virtual) + buf->start; - } - - memset(&arg, 0, sizeof(arg)); - req->handle = buf->handle; - req->mask = mapFlags; - req->hint = mapHint; - - /* - * May hang if the buffer object is busy. - * This IOCTL synchronizes the buffer. - */ - - ret = drmIoctlTimeout(fd, DRM_IOCTL_BO_MAP, &arg); - if (ret) - return ret; - - drmBOCopyReply(rep, buf); - buf->mapFlags = mapFlags; - ++buf->mapCount; - *address = buf->virtual; - - return 0; -} - - -int drmBOUnmap(int fd, drmBO *buf) -{ - struct drm_bo_handle_arg arg; - - memset(&arg, 0, sizeof(arg)); - arg.handle = buf->handle; - - if (drmIoctl(fd, DRM_IOCTL_BO_UNMAP, &arg)) { - return -errno; - } - buf->mapCount--; - return 0; -} - -int drmBOSetStatus(int fd, drmBO *buf, - uint64_t flags, uint64_t mask, - unsigned int hint, - unsigned int desired_tile_stride, - unsigned int tile_info) -{ - - struct drm_bo_map_wait_idle_arg arg; - struct drm_bo_info_req *req = &arg.d.req; - struct drm_bo_info_rep *rep = &arg.d.rep; - int ret = 0; - - memset(&arg, 0, sizeof(arg)); - req->mask = mask; - req->flags = flags; - req->handle = buf->handle; - req->hint = hint; - req->desired_tile_stride = desired_tile_stride; - req->tile_info = tile_info; - - ret = drmIoctlTimeout(fd, DRM_IOCTL_BO_SETSTATUS, &arg); - if (ret) - return ret; - - drmBOCopyReply(rep, buf); - return 0; -} - - -int drmBOInfo(int fd, drmBO *buf) -{ - struct drm_bo_reference_info_arg arg; - struct drm_bo_handle_arg *req = &arg.d.req; - struct drm_bo_info_rep *rep = &arg.d.rep; - int ret = 0; - - memset(&arg, 0, sizeof(arg)); - req->handle = buf->handle; - - ret = drmIoctl(fd, DRM_IOCTL_BO_INFO, &arg); - if (ret) - return -errno; - - drmBOCopyReply(rep, buf); - return 0; -} - -int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint) -{ - struct drm_bo_map_wait_idle_arg arg; - struct drm_bo_info_req *req = &arg.d.req; - struct drm_bo_info_rep *rep = &arg.d.rep; - int ret = 0; - - if ((buf->flags & DRM_BO_FLAG_SHAREABLE) || - (buf->replyFlags & DRM_BO_REP_BUSY)) { - memset(&arg, 0, sizeof(arg)); - req->handle = buf->handle; - req->hint = hint; - - ret = drmIoctlTimeout(fd, DRM_IOCTL_BO_WAIT_IDLE, &arg); - if (ret) - return ret; - - drmBOCopyReply(rep, buf); - } - return 0; -} - -int drmBOBusy(int fd, drmBO *buf, int *busy) -{ - int ret = drmBOInfo(fd, buf); - - if (ret) - return ret; - - *busy = (buf->replyFlags & DRM_BO_REP_BUSY); - return 0; -} - -int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, - unsigned memType) -{ - struct drm_mm_init_arg arg; - - memset(&arg, 0, sizeof(arg)); - - arg.magic = DRM_BO_INIT_MAGIC; - arg.major = DRM_BO_INIT_MAJOR; - arg.minor = DRM_BO_INIT_MINOR; - arg.p_offset = pOffset; - arg.p_size = pSize; - arg.mem_type = memType; - - if (drmIoctl(fd, DRM_IOCTL_MM_INIT, &arg)) - return -errno; - return 0; -} - -int drmMMTakedown(int fd, unsigned memType) -{ - struct drm_mm_type_arg arg; - - memset(&arg, 0, sizeof(arg)); - arg.mem_type = memType; - - if (drmIoctl(fd, DRM_IOCTL_MM_TAKEDOWN, &arg)) - return -errno; - return 0; -} - -/* - * If this function returns an error, and lockBM was set to 1, - * the buffer manager is NOT locked. - */ - -int drmMMLock(int fd, unsigned memType, int lockBM, int ignoreNoEvict) -{ - struct drm_mm_type_arg arg; - - memset(&arg, 0, sizeof(arg)); - arg.mem_type = memType; - arg.lock_flags |= (lockBM) ? DRM_BO_LOCK_UNLOCK_BM : 0; - arg.lock_flags |= (ignoreNoEvict) ? DRM_BO_LOCK_IGNORE_NO_EVICT : 0; - - return drmIoctlTimeout(fd, DRM_IOCTL_MM_LOCK, &arg); -} - -int drmMMUnlock(int fd, unsigned memType, int unlockBM) -{ - struct drm_mm_type_arg arg; - - memset(&arg, 0, sizeof(arg)); - - arg.mem_type = memType; - arg.lock_flags |= (unlockBM) ? DRM_BO_LOCK_UNLOCK_BM : 0; - - return drmIoctlTimeout(fd, DRM_IOCTL_MM_UNLOCK, &arg); -} - -int drmMMInfo(int fd, unsigned memType, uint64_t *size) -{ - struct drm_mm_info_arg arg; - - memset(&arg, 0, sizeof(arg)); - - arg.mem_type = memType; - - if (drmIoctl(fd, DRM_IOCTL_MM_INFO, &arg)) - return -errno; - - *size = arg.p_size; - return 0; -} - -int drmBOVersion(int fd, unsigned int *major, - unsigned int *minor, - unsigned int *patchlevel) -{ - struct drm_bo_version_arg arg; - int ret; - - memset(&arg, 0, sizeof(arg)); - ret = drmIoctl(fd, DRM_IOCTL_BO_VERSION, &arg); - if (ret) - return -errno; - - if (major) - *major = arg.major; - if (minor) - *minor = arg.minor; - if (patchlevel) - *patchlevel = arg.patchlevel; - - return 0; -} - - - #define DRM_MAX_FDS 16 static struct { char *BusID; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 84cf69bd..a1c1be89 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1061,7 +1061,7 @@ static int drm_bo_modify_proposed_flags (struct drm_buffer_object *bo, * Doesn't do any fence flushing as opposed to the drm_bo_busy function. */ -static int drm_bo_quick_busy(struct drm_buffer_object *bo, int check_unfenced) +int drm_bo_quick_busy(struct drm_buffer_object *bo, int check_unfenced) { struct drm_fence_object *fence = bo->fence; @@ -1712,7 +1712,7 @@ EXPORT_SYMBOL(drm_bo_clean_mm); *point since we have the hardware lock. */ -static int drm_bo_lock_mm(struct drm_device *dev, unsigned mem_type) +int drm_bo_lock_mm(struct drm_device *dev, unsigned mem_type) { int ret; struct drm_buffer_manager *bm = &dev->bm; @@ -1861,7 +1861,6 @@ int drm_bo_driver_init(struct drm_device *dev) int ret = -EINVAL; bm->dummy_read_page = NULL; - drm_bo_init_lock(&bm->bm_lock); mutex_lock(&dev->struct_mutex); if (!driver) goto out_unlock; diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 032687f7..a8aa84db 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -879,23 +879,6 @@ extern int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg * m void **virtual); extern void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg * mem, void *virtual); -/* - * drm_bo_lock.c - * Simple replacement for the hardware lock on buffer manager init and clean. - */ - - -extern void drm_bo_init_lock(struct drm_bo_lock *lock); -extern void drm_bo_read_unlock(struct drm_bo_lock *lock); -extern int drm_bo_read_lock(struct drm_bo_lock *lock, - int interruptible); -extern int drm_bo_write_lock(struct drm_bo_lock *lock, - int interruptible, - struct drm_file *file_priv); - -extern int drm_bo_write_unlock(struct drm_bo_lock *lock, - struct drm_file *file_priv); - #ifdef CONFIG_DEBUG_MUTEXES #define DRM_ASSERT_LOCKED(_mutex) \ BUG_ON(!mutex_is_locked(_mutex) || \ diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 0d5242d3..9a215161 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -715,13 +715,8 @@ static int drm_bo_vm_fault(struct vm_area_struct *vma, unsigned long ret = VM_FAULT_NOPAGE; dev = bo->dev; - err = drm_bo_read_lock(&dev->bm.bm_lock, 1); - if (err) - return VM_FAULT_NOPAGE; - err = mutex_lock_interruptible(&bo->mutex); if (err) { - drm_bo_read_unlock(&dev->bm.bm_lock); return VM_FAULT_NOPAGE; } @@ -788,7 +783,6 @@ static int drm_bo_vm_fault(struct vm_area_struct *vma, out_unlock: BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); mutex_unlock(&bo->mutex); - drm_bo_read_unlock(&dev->bm.bm_lock); return ret; } #endif diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 3e6a6626..bd52a057 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -689,7 +689,6 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync) void i915_dispatch_flip(struct drm_device * dev, int planes, int sync) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int i; -- cgit v1.2.3 From 296073dc5f0bf3f8b74a7d6db48b05c09a1b9242 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 31 Jul 2008 14:39:25 +1000 Subject: drm: remove object hash --- linux-core/drmP.h | 2 -- linux-core/drm_drv.c | 1 - linux-core/drm_stub.c | 6 ------ 3 files changed, 9 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4938881f..59d44ac2 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -166,7 +166,6 @@ typedef unsigned long uintptr_t; #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) #define DRM_MAP_HASH_OFFSET 0x10000000 #define DRM_MAP_HASH_ORDER 12 -#define DRM_OBJECT_HASH_ORDER 12 #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) /* @@ -888,7 +887,6 @@ struct drm_device { int map_count; /**< Number of mappable regions */ struct drm_open_hash map_hash; /**< User token hash table for maps */ struct drm_memrange offset_manager; /**< User token manager */ - struct drm_open_hash object_hash; /**< User token hash table for objects */ struct address_space *dev_mapping; /**< For unmap_mapping_range() */ struct page *ttm_dummy_page; diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 2c3e29f0..c3cc620a 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -399,7 +399,6 @@ static void drm_cleanup(struct drm_device * dev) drm_ctxbitmap_cleanup(dev); drm_ht_remove(&dev->map_hash); drm_memrange_takedown(&dev->offset_manager); - drm_ht_remove(&dev->object_hash); drm_put_minor(dev, &dev->primary); if (drm_core_check_feature(dev, DRIVER_MODESET)) diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index c62b901d..97533d72 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -207,12 +207,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, return -ENOMEM; } - if (drm_ht_create(&dev->object_hash, DRM_OBJECT_HASH_ORDER)) { - drm_ht_remove(&dev->map_hash); - drm_memrange_takedown(&dev->offset_manager); - return -ENOMEM; - } - /* the DRM has 6 counters */ dev->counters = 6; dev->types[0] = _DRM_STAT_LOCK; -- cgit v1.2.3 From 922f74f3c95fae39ffe8cf0659fa47e0bc354076 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:52:58 +1000 Subject: drm: remove unneeded debugging --- linux-core/ati_pcigart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 3aa445e8..48c7988f 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -111,7 +111,6 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info /* we need to support large memory configurations */ if (!entry) { - DRM_ERROR("no scatter/gather memory!\n"); return 0; } -- cgit v1.2.3 From 129c8a11814741a997e3d039ab4be542d38e5ed8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:53:14 +1000 Subject: modesetting: pick_crtcs can't be static --- linux-core/drm_crtc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index ee1dc258..dc18dbb4 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -203,7 +203,7 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions); * LOCKING: * Caller must hold mode config lock. */ -static void drm_pick_crtcs (struct drm_device *dev) +void drm_pick_crtcs (struct drm_device *dev) { int c, o, assigned; struct drm_connector *connector, *connector_equal; -- cgit v1.2.3 From af6efc3d778b96164849f822331938c4cdf8f4b2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:53:45 +1000 Subject: i915/radeon: use rmmap locked --- shared-core/i915_init.c | 2 +- shared-core/radeon_cp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 3a652e8d..dc218688 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -443,7 +443,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) return; if (master_priv->sarea) - drm_rmmap(dev, master_priv->sarea); + drm_rmmap_locked(dev, master_priv->sarea); drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 48f72ab0..b69fadbb 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2535,7 +2535,7 @@ void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) master_priv->sarea_priv = NULL; if (master_priv->sarea) - drm_rmmap(dev, master_priv->sarea); + drm_rmmap_locked(dev, master_priv->sarea); drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); -- cgit v1.2.3 From 717dd804d0d1d9984345a998b28ee47079c70639 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:54:32 +1000 Subject: drm: fixup master code to use krefs --- linux-core/drmP.h | 13 +++++--- linux-core/drm_drv.c | 10 ++---- linux-core/drm_fops.c | 31 +++++++++++-------- linux-core/drm_stub.c | 85 +++++++++++++++++++++++++++++++-------------------- 4 files changed, 82 insertions(+), 57 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 59d44ac2..848fa885 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -670,7 +670,9 @@ struct drm_gem_object { /* per-master structure */ struct drm_master { - + + struct kref refcount; /* refcount for this master */ + struct list_head head; /**< each minor contains a list of masters */ struct drm_minor *minor; /**< link back to minor we are a master for */ @@ -1345,12 +1347,13 @@ extern int drm_setmaster_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern struct drm_master *drm_get_master(struct drm_minor *minor); -extern void drm_put_master(struct drm_master *master); +struct drm_master *drm_master_create(struct drm_minor *minor); +extern struct drm_master *drm_master_get(struct drm_master *master); +extern void drm_master_put(struct drm_master **master); extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, - struct drm_driver *driver); + struct drm_driver *driver); extern int drm_put_dev(struct drm_device *dev); -extern int drm_put_minor(struct drm_device *dev, struct drm_minor **p); +extern int drm_put_minor(struct drm_minor **minor_p); extern unsigned int drm_debug; /* 1 to enable debug output */ extern struct class *drm_class; diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index c3cc620a..751322db 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -191,11 +191,6 @@ int drm_lastclose(struct drm_device * dev) drm_drawable_free_all(dev); del_timer(&dev->timer); - if (dev->primary->master) { - drm_put_master(dev->primary->master); - dev->primary->master = NULL; - } - /* Clear AGP information */ if (drm_core_has_AGP(dev) && dev->agp) { struct drm_agp_mem *entry, *tempe; @@ -400,9 +395,10 @@ static void drm_cleanup(struct drm_device * dev) drm_ht_remove(&dev->map_hash); drm_memrange_takedown(&dev->offset_manager); - drm_put_minor(dev, &dev->primary); if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_put_minor(dev, &dev->control); + drm_put_minor(&dev->control); + + drm_put_minor(&dev->primary); if (drm_put_dev(dev)) DRM_ERROR("Cannot unload module\n"); diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 8eb20b47..f45d5e46 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -260,28 +260,34 @@ static int drm_open_helper(struct inode *inode, struct file *filp, /* if there is no current master make this fd it */ mutex_lock(&dev->struct_mutex); if (!priv->minor->master) { - priv->minor->master = drm_get_master(priv->minor); + /* create a new master */ + priv->minor->master = drm_master_create(priv->minor); if (!priv->minor->master) { ret = -ENOMEM; goto out_free; } priv->is_master = 1; - priv->master = priv->minor->master; + /* take another reference for the copy in the local file priv */ + priv->master = drm_master_get(priv->minor->master); priv->authenticated = 1; + mutex_unlock(&dev->struct_mutex); if (dev->driver->master_create) { ret = dev->driver->master_create(dev, priv->master); if (ret) { - drm_put_master(priv->minor->master); - priv->minor->master = priv->master = NULL; + mutex_lock(&dev->struct_mutex); + /* drop both references if this fails */ + drm_master_put(&priv->minor->master); + drm_master_put(&priv->master); mutex_unlock(&dev->struct_mutex); goto out_free; } } } else { - priv->master = priv->minor->master; + /* get a reference to the master */ + priv->master = drm_master_get(priv->minor->master); mutex_unlock(&dev->struct_mutex); } @@ -453,6 +459,8 @@ int drm_release(struct inode *inode, struct file *filp) if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_fb_release(filp); + mutex_lock(&dev->struct_mutex); + if (file_priv->is_master) { struct drm_file *temp; list_for_each_entry(temp, &dev->filelist, lhead) { @@ -461,18 +469,17 @@ int drm_release(struct inode *inode, struct file *filp) temp->authenticated = 0; } - if (file_priv->minor->master == file_priv->master) - file_priv->minor->master = NULL; - drm_put_master(file_priv->master); + if (file_priv->minor->master == file_priv->master) { + /* drop the reference held my the minor */ + drm_master_put(&file_priv->minor->master); + } } - file_priv->master = NULL; + /* drop the reference held my the file priv */ + drm_master_put(&file_priv->master); file_priv->is_master = 0; - mutex_lock(&dev->struct_mutex); - list_del(&file_priv->lhead); - mutex_unlock(&dev->struct_mutex); if (dev->driver->postclose) diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 97533d72..4654dca1 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -88,30 +88,7 @@ again: return new_id; } -int drm_setmaster_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - if (file_priv->minor->master && file_priv->minor->master != file_priv->master) - return -EINVAL; - - if (!file_priv->master) - return -EINVAL; - - if (!file_priv->minor->master && file_priv->minor->master != file_priv->master) - file_priv->minor->master = file_priv->master; - return 0; -} - -int drm_dropmaster_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - if (!file_priv->master) - return -EINVAL; - file_priv->minor->master = NULL; - return 0; -} - -struct drm_master *drm_get_master(struct drm_minor *minor) +struct drm_master *drm_master_create(struct drm_minor *minor) { struct drm_master *master; @@ -119,7 +96,7 @@ struct drm_master *drm_get_master(struct drm_minor *minor) if (!master) return NULL; -// INIT_LIST_HEAD(&master->filelist); + kref_init(&master->refcount); spin_lock_init(&master->lock.spinlock); init_waitqueue_head(&master->lock.lock_queue); drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); @@ -131,8 +108,15 @@ struct drm_master *drm_get_master(struct drm_minor *minor) return master; } -void drm_put_master(struct drm_master *master) +struct drm_master *drm_master_get(struct drm_master *master) +{ + kref_get(&master->refcount); + return master; +} + +static void drm_master_destroy(struct kref *kref) { + struct drm_master *master = container_of(kref, struct drm_master, refcount); struct drm_magic_entry *pt, *next; struct drm_device *dev = master->minor->dev; @@ -166,21 +150,56 @@ void drm_put_master(struct drm_master *master) drm_free(master, sizeof(*master), DRM_MEM_DRIVER); } +void drm_master_put(struct drm_master **master) +{ + kref_put(&(*master)->refcount, drm_master_destroy); + *master = NULL; +} + +int drm_setmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + if (file_priv->minor->master && file_priv->minor->master != file_priv->master) + return -EINVAL; + + if (!file_priv->master) + return -EINVAL; + + if (!file_priv->minor->master && file_priv->minor->master != file_priv->master) { + mutex_lock(&dev->struct_mutex); + file_priv->minor->master = drm_master_get(file_priv->master); + mutex_unlock(&dev->struct_mutex); + } + + return 0; +} + +int drm_dropmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + if (!file_priv->master) + return -EINVAL; + mutex_lock(&dev->struct_mutex); + drm_master_put(&file_priv->minor->master); + mutex_unlock(&dev->struct_mutex); + return 0; +} + static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) { int retcode; + INIT_LIST_HEAD(&dev->filelist); INIT_LIST_HEAD(&dev->ctxlist); INIT_LIST_HEAD(&dev->vmalist); INIT_LIST_HEAD(&dev->maplist); - INIT_LIST_HEAD(&dev->filelist); spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); spin_lock_init(&dev->tasklet_lock); -// spin_lock_init(&dev->lock.spinlock); + init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); @@ -402,10 +421,10 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, return 0; err_g5: - drm_put_minor(dev, &dev->primary); + drm_put_minor(&dev->primary); err_g4: if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_put_minor(dev, &dev->control); + drm_put_minor(&dev->control); err_g3: if (!drm_fb_loaded) pci_disable_device(pdev); @@ -456,14 +475,14 @@ int drm_put_dev(struct drm_device * dev) * last minor released. * */ -int drm_put_minor(struct drm_device *dev, struct drm_minor **minor_p) +int drm_put_minor(struct drm_minor **minor_p) { struct drm_minor *minor = *minor_p; DRM_DEBUG("release secondary minor %d\n", minor->index); if (minor->type == DRM_MINOR_LEGACY) { - if (dev->driver->proc_cleanup) - dev->driver->proc_cleanup(minor); + if (minor->dev->driver->proc_cleanup) + minor->dev->driver->proc_cleanup(minor); drm_proc_cleanup(minor, drm_proc_root); } drm_sysfs_device_remove(minor); -- cgit v1.2.3 From dff84851516a71639d734e134c584f6ed4d3ee07 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:55:12 +1000 Subject: drm: remove unused types --- shared-core/drm.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index 76d2c4c5..ed390885 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1096,11 +1096,6 @@ typedef struct drm_agp_binding drm_agp_binding_t; typedef struct drm_agp_info drm_agp_info_t; typedef struct drm_scatter_gather drm_scatter_gather_t; typedef struct drm_set_version drm_set_version_t; - -typedef struct drm_fence_arg drm_fence_arg_t; -typedef struct drm_mm_type_arg drm_mm_type_arg_t; -typedef struct drm_mm_init_arg drm_mm_init_arg_t; -typedef enum drm_bo_type drm_bo_type_t; #endif #endif -- cgit v1.2.3 From 29649ddedee6b07b922c99233b8afc7c3a1db66f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:56:08 +1000 Subject: radeon: don't use ring if cp not going --- linux-core/radeon_buffer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index e9ba11d4..a4ac38c1 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -55,10 +55,14 @@ int radeon_invalidate_caches(struct drm_device * dev, uint64_t flags) drm_radeon_private_t *dev_priv = dev->dev_private; RING_LOCALS; + if (!dev_priv->cp_running) + return 0; + BEGIN_RING(4); RADEON_FLUSH_CACHE(); RADEON_FLUSH_ZCACHE(); ADVANCE_RING(); + COMMIT_RING(); return 0; } -- cgit v1.2.3 From aa8e15f8b51e555e78cb93e279bad5843eea5391 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:59:17 +1000 Subject: radeon: add userspace mm enable switch --- shared-core/radeon_cp.c | 10 ++++++---- shared-core/radeon_drm.h | 1 + shared-core/radeon_drv.h | 2 ++ shared-core/radeon_state.c | 3 +++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index b69fadbb..430f5493 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1364,8 +1364,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev) if (dev_priv->gart_info.bus_addr) { /* Turn off PCI GART */ radeon_set_pcigart(dev_priv, 0); - if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info)) - DRM_ERROR("failed to cleanup PCI GART!\n"); + drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info); } if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) @@ -1373,6 +1372,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev) if (dev_priv->pcigart_offset_set == 1) { drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = NULL; + dev_priv->pcigart_offset_set = 0; } } } @@ -1563,8 +1563,10 @@ void radeon_do_release(struct drm_device * dev) radeon_mem_takedown(&(dev_priv->gart_heap)); radeon_mem_takedown(&(dev_priv->fb_heap)); - - radeon_gem_mm_fini(dev); + if (dev_priv->user_mm_enable) { + radeon_gem_mm_fini(dev); + dev_priv->user_mm_enable = false; + } /* deallocate kernel resources */ radeon_do_cleanup_cp(dev); diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index 8ee1baa7..8bb5d87c 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -768,6 +768,7 @@ typedef struct drm_radeon_setparam { #define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ #define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */ #define RADEON_SETPARAM_VBLANK_CRTC 6 /* VBLANK CRTC */ +#define RADEON_SETPARAM_MM_INIT 7 /* Initialise the mm */ /* 1.14: Clients can allocate/free a surface */ typedef struct drm_radeon_surface_alloc { diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index e55a9697..0363dfd4 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -314,6 +314,8 @@ typedef struct drm_radeon_private { int new_memmap; + bool user_mm_enable; + int gart_size; u32 gart_vm_start; unsigned long gart_buffers_offset; diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 00160fbf..ca10db4b 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3182,6 +3182,9 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil case RADEON_SETPARAM_VBLANK_CRTC: return radeon_vblank_crtc_set(dev, sp->value); break; + case RADEON_SETPARAM_MM_INIT: + dev_priv->user_mm_enable = true; + return radeon_gem_mm_init(dev); default: DRM_DEBUG("Invalid parameter %d\n", sp->param); return -EINVAL; -- cgit v1.2.3 From fd75c02ddd380c102ca089f015f14dfe964910b1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:59:49 +1000 Subject: drm: finish bo after lastclose --- linux-core/drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 751322db..c503d484 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -170,8 +170,6 @@ int drm_lastclose(struct drm_device * dev) DRM_DEBUG("\n"); - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - drm_bo_driver_finish(dev); /* * We can't do much about this function failing. @@ -181,6 +179,8 @@ int drm_lastclose(struct drm_device * dev) dev->driver->lastclose(dev); DRM_DEBUG("driver lastclose completed\n"); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + drm_bo_driver_finish(dev); /* if (dev->irq_enabled) drm_irq_uninstall(dev); */ -- cgit v1.2.3 From 4748fbcbd7b0337448ce88c2cdbbc500ff959e42 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Aug 2008 11:36:20 +1000 Subject: radeon: fix blit due to registers wrong --- linux-core/radeon_reg.h | 23 +++++++++++++---------- shared-core/r300_reg.h | 14 +------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index 784b3b50..0f2d239c 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -2095,16 +2095,19 @@ # define RADEON_STENCIL_ENABLE (1 << 7) # define RADEON_Z_ENABLE (1 << 8) # define RADEON_DEPTH_XZ_OFFEST_ENABLE (1 << 9) -# define RADEON_COLOR_FORMAT_ARGB1555 (3 << 10) -# define RADEON_COLOR_FORMAT_RGB565 (4 << 10) -# define RADEON_COLOR_FORMAT_ARGB8888 (6 << 10) -# define RADEON_COLOR_FORMAT_RGB332 (7 << 10) -# define RADEON_COLOR_FORMAT_Y8 (8 << 10) -# define RADEON_COLOR_FORMAT_RGB8 (9 << 10) -# define RADEON_COLOR_FORMAT_YUV422_VYUY (11 << 10) -# define RADEON_COLOR_FORMAT_YUV422_YVYU (12 << 10) -# define RADEON_COLOR_FORMAT_aYUV444 (14 << 10) -# define RADEON_COLOR_FORMAT_ARGB4444 (15 << 10) +# define RADEON_RB3D_COLOR_FORMAT_SHIFT 10 + +# define RADEON_COLOR_FORMAT_ARGB1555 3 +# define RADEON_COLOR_FORMAT_RGB565 4 +# define RADEON_COLOR_FORMAT_ARGB8888 6 +# define RADEON_COLOR_FORMAT_RGB332 7 +# define RADEON_COLOR_FORMAT_Y8 8 +# define RADEON_COLOR_FORMAT_RGB8 9 +# define RADEON_COLOR_FORMAT_YUV422_VYUY 11 +# define RADEON_COLOR_FORMAT_YUV422_YVYU 12 +# define RADEON_COLOR_FORMAT_aYUV444 14 +# define RADEON_COLOR_FORMAT_ARGB4444 15 + # define RADEON_CLRCMP_FLIP_ENABLE (1 << 14) #define RADEON_RB3D_COLOROFFSET 0x1c40 # define RADEON_COLOROFFSET_MASK 0xfffffff0 diff --git a/shared-core/r300_reg.h b/shared-core/r300_reg.h index 0be01fc7..65c5606a 100644 --- a/shared-core/r300_reg.h +++ b/shared-core/r300_reg.h @@ -129,15 +129,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* END: Wild guesses */ #define R300_SE_VTE_CNTL 0x20b0 -# define R300_VPORT_X_SCALE_ENA 0x00000001 -# define R300_VPORT_X_OFFSET_ENA 0x00000002 -# define R300_VPORT_Y_SCALE_ENA 0x00000004 -# define R300_VPORT_Y_OFFSET_ENA 0x00000008 -# define R300_VPORT_Z_SCALE_ENA 0x00000010 -# define R300_VPORT_Z_OFFSET_ENA 0x00000020 -# define R300_VTX_XY_FMT 0x00000100 -# define R300_VTX_Z_FMT 0x00000200 -# define R300_VTX_W0_FMT 0x00000400 # define R300_VTX_W0_NORMALIZE 0x00000800 # define R300_VTX_ST_DENORMALIZED 0x00001000 @@ -493,7 +484,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. # define R300_OFIFO_HIGHWATER_SHIFT 22 /* two bits only */ # define R300_CUBE_FIFO_HIGHWATER_COL_SHIFT 24 -#define R300_GB_SELECT 0x401C + # define R300_GB_FOG_SELECT_C0A 0 # define R300_GB_FOG_SELECT_C1A 1 # define R300_GB_FOG_SELECT_C2A 2 @@ -934,7 +925,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* 32 bit chroma key */ #define R300_TX_CHROMA_KEY_0 0x4580 /* ff00ff00 == { 0, 1.0, 0, 1.0 } */ -#define R300_TX_BORDER_COLOR_0 0x45C0 /* END: Texture specification */ @@ -1319,7 +1309,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* gap */ -#define R300_RB3D_COLOROFFSET0 0x4E28 # define R300_COLOROFFSET_MASK 0xFFFFFFF0 /* GUESS */ #define R300_RB3D_COLOROFFSET1 0x4E2C /* GUESS */ #define R300_RB3D_COLOROFFSET2 0x4E30 /* GUESS */ @@ -1331,7 +1320,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. * Bit 17: 4x2 tiles * Bit 18: Extremely weird tile like, but some pixels duplicated? */ -#define R300_RB3D_COLORPITCH0 0x4E38 # define R300_COLORPITCH_MASK 0x00001FF8 /* GUESS */ # define R300_COLOR_TILE_ENABLE (1 << 16) /* GUESS */ # define R300_COLOR_MICROTILE_ENABLE (1 << 17) /* GUESS */ -- cgit v1.2.3 From 513d4c3ff1937159e0d32047376415df09031ce6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 6 Aug 2008 10:21:20 +1000 Subject: radeon: fix setting new memmap in right place --- shared-core/radeon_cp.c | 2 +- shared-core/radeon_drv.h | 2 +- shared-core/radeon_state.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 430f5493..4c03f739 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2301,7 +2301,7 @@ int radeon_modeset_cp_init(struct drm_device *dev) dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; - dev_priv->new_memmap = 1; + dev_priv->new_memmap = true; r300_init_reg_flags(dev); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 0363dfd4..94975e4d 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -312,7 +312,7 @@ typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; - int new_memmap; + bool new_memmap; bool user_mm_enable; diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index ca10db4b..e168ea02 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3184,6 +3184,7 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil break; case RADEON_SETPARAM_MM_INIT: dev_priv->user_mm_enable = true; + dev_priv->new_memmap = true; return radeon_gem_mm_init(dev); default: DRM_DEBUG("Invalid parameter %d\n", sp->param); -- cgit v1.2.3 From 04b5584c62fa3311e717692e261870276cbd6350 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 6 Aug 2008 15:56:08 +1000 Subject: pcigart: fixup memset + remove wbinvd --- linux-core/ati_pcigart.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 48c7988f..9b954291 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -90,7 +90,7 @@ int drm_ati_alloc_pcigart_table(struct drm_device *dev, if (gart_info->table_handle == NULL) return -ENOMEM; - memset(gart_info->table_handle, 0, gart_info->table_size); + memset(gart_info->table_handle->vaddr, 0, gart_info->table_size); return 0; } EXPORT_SYMBOL(drm_ati_alloc_pcigart_table); @@ -205,11 +205,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga ret = 1; -#if defined(__i386__) || defined(__x86_64__) - wbinvd(); -#else mb(); -#endif done: gart_info->addr = address; @@ -265,11 +261,7 @@ static int ati_pcigart_bind_ttm(struct drm_ttm_backend *backend, gart_insert_page_into_table(info, page_base, pci_gart + j); } -#if defined(__i386__) || defined(__x86_64__) - wbinvd(); -#else mb(); -#endif atipci_be->gart_flush_fn(atipci_be->dev); -- cgit v1.2.3 From a6c075fca6faf83ccbfa38fb27dc4f743b6cdd61 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 6 Aug 2008 15:57:38 +1000 Subject: drm: don't teardown things in modeset paths --- linux-core/drm_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index c503d484..2a6bebd7 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -182,8 +182,8 @@ int drm_lastclose(struct drm_device * dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) drm_bo_driver_finish(dev); -/* if (dev->irq_enabled) - drm_irq_uninstall(dev); */ + if (dev->irq_enabled && !drm_core_check_feature(dev, DRIVER_MODESET)) + drm_irq_uninstall(dev); /* Free drawable information memory */ mutex_lock(&dev->struct_mutex); @@ -192,7 +192,7 @@ int drm_lastclose(struct drm_device * dev) del_timer(&dev->timer); /* Clear AGP information */ - if (drm_core_has_AGP(dev) && dev->agp) { + if (drm_core_has_AGP(dev) && dev->agp && !drm_core_check_feature(dev, DRIVER_MODESET)) { struct drm_agp_mem *entry, *tempe; /* Remove AGP resources, but leave dev->agp -- cgit v1.2.3 From 64359586730268fc83ccc0db0487e217a894335b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 6 Aug 2008 15:58:09 +1000 Subject: radeon: just evict to TT not cached --- linux-core/radeon_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index a4ac38c1..5fdd9c35 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -265,6 +265,6 @@ uint64_t radeon_evict_flags(struct drm_buffer_object *bo) case DRM_BO_MEM_TT: return DRM_BO_FLAG_MEM_LOCAL; default: - return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED; + return DRM_BO_FLAG_MEM_TT; } } -- cgit v1.2.3 From 8c042a0b0531117f2663ae6932d299cb47941607 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 6 Aug 2008 15:59:31 +1000 Subject: radeon: fixup PCI GART table with GEM enabled --- linux-core/radeon_gem.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 1aa3afbf..1ee48514 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -485,6 +485,7 @@ static int radeon_gart_init(struct drm_device *dev) /* setup a 32MB GART */ dev_priv->gart_size = dev_priv->mm.gart_size; + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; #if __OS_HAS_AGP /* setup VRAM vs GART here */ @@ -547,8 +548,8 @@ static int radeon_gart_init(struct drm_device *dev) dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; else dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; - dev_priv->gart_info.addr = NULL; - dev_priv->gart_info.bus_addr = 0; + dev_priv->gart_info.addr = dev_priv->gart_info.table_handle->vaddr; + dev_priv->gart_info.bus_addr = dev_priv->gart_info.table_handle->busaddr; } /* gart values setup - start the GART */ @@ -843,7 +844,7 @@ static int radeon_gem_ib_init(struct drm_device *dev) if (!dev_priv->ib_objs) goto free_all; - for (i = 0; i < RADEON_NUM_IB; i++) { + for (i = 0; i < RADEON_NUM_IB; i++) { dev_priv->ib_objs[i] = drm_calloc(1, sizeof(struct radeon_mm_obj), DRM_MEM_DRIVER); if (!dev_priv->ib_objs[i]) goto free_all; -- cgit v1.2.3 From c2184e450e4c5613c1f1a004d183ad478358013e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 8 Aug 2008 16:04:45 +1000 Subject: radeon: add initial support for legacy crtc/encoders. not all there yet --- linux-core/Makefile.kernel | 2 +- linux-core/radeon_combios.c | 39 ++ linux-core/radeon_display.c | 54 +-- linux-core/radeon_encoders.c | 73 +--- linux-core/radeon_legacy_crtc.c | 748 ++++++++++++++++++++++++++++++++++++ linux-core/radeon_legacy_encoders.c | 391 +++++++++++++++++++ linux-core/radeon_mode.h | 196 +++++++++- shared-core/radeon_cp.c | 8 +- shared-core/radeon_drv.h | 106 +++-- 9 files changed, 1454 insertions(+), 163 deletions(-) create mode 100644 linux-core/radeon_legacy_crtc.c create mode 100644 linux-core/radeon_legacy_encoders.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index b15a12ab..576de5b2 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -41,7 +41,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv50_fbcon.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_gem.o \ radeon_buffer.o radeon_fence.o atom.o radeon_display.o radeon_atombios.o radeon_i2c.o radeon_connectors.o radeon_cs.o \ - atombios_crtc.o radeon_encoders.o radeon_fb.o radeon_combios.o + atombios_crtc.o radeon_encoders.o radeon_fb.o radeon_combios.o radeon_legacy_crtc.o radeon_legacy_encoders.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index e2b768ca..8a1dd8b3 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -175,6 +175,45 @@ bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder) return true; } +bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint16_t tmp; + int i, n; + uint8_t ver; + + tmp = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x34); + if (!tmp) { + DRM_INFO("No TMDS info found in BIOS\n"); + return false; + } + + ver = radeon_bios8(dev_priv, tmp); + DRM_INFO("DFP table revision: %d\n", ver); + if (ver == 3) { + n = radeon_bios8(dev_priv, tmp + 5) + 1; + if (n > 4) n = 4; + for (i = 0; i < n; i++) { + encoder->tmds_pll[i].value = radeon_bios32(dev_priv, tmp+i*10+0x08); + encoder->tmds_pll[i].freq = radeon_bios16(dev_priv, tmp+i*10+0x10); + } + return true; + } else if (ver == 4) { + int stride = 0; + n = radeon_bios8(dev_priv, tmp + 5) + 1; + if (n > 4) n = 4; + for (i = 0; i < n; i++) { + encoder->tmds_pll[i].value = radeon_bios32(dev_priv, tmp+stride+0x08); + encoder->tmds_pll[i].freq = radeon_bios16(dev_priv, tmp+stride+0x10); + if (i == 0) stride += 10; + else stride += 6; + } + return true; + } + return false; +} + static void radeon_apply_legacy_quirks(struct drm_device *dev, int bios_index) { struct drm_radeon_private *dev_priv = dev->dev_private; diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 7a7b5856..1e5233d2 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -116,38 +116,7 @@ void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, radeon_crtc->lut_b[regno] = blue >> 8; } -void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) -{ -} - - -static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - -static void radeon_crtc_mode_set(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, - int x, int y) -{ - -} - -void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y) -{ -} - -static void radeon_crtc_prepare(struct drm_crtc *crtc) -{ -} - -static void radeon_crtc_commit(struct drm_crtc *crtc) -{ -} static void avivo_lock_cursor(struct drm_crtc *crtc, bool lock) { @@ -263,15 +232,6 @@ static void radeon_crtc_destroy(struct drm_crtc *crtc) kfree(radeon_crtc); } -static const struct drm_crtc_helper_funcs radeon_helper_funcs = { - .dpms = radeon_crtc_dpms, - .mode_fixup = radeon_crtc_mode_fixup, - .mode_set = radeon_crtc_mode_set, - .mode_set_base = radeon_crtc_set_base, - .prepare = radeon_crtc_prepare, - .commit = radeon_crtc_commit, -}; - static const struct drm_crtc_funcs radeon_crtc_funcs = { .cursor_set = radeon_crtc_cursor_set, .cursor_move = radeon_crtc_cursor_move, @@ -309,7 +269,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index) if (dev_priv->is_atom_bios && dev_priv->chip_family > CHIP_RS690) radeon_atombios_init_crtc(dev, radeon_crtc); else - drm_crtc_helper_add(&radeon_crtc->base, &radeon_helper_funcs); + radeon_legacy_init_crtc(dev, radeon_crtc); } bool radeon_legacy_setup_enc_conn(struct drm_device *dev) @@ -360,8 +320,14 @@ bool radeon_setup_enc_conn(struct drm_device *dev) if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_A) || (mode_info->bios_connector[i].connector_type == CONNECTOR_VGA)) { - if (radeon_is_avivo(dev_priv)) + if (radeon_is_avivo(dev_priv)) { encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 0); + } else { + if (mode_info->bios_connector[i].dac_type == DAC_PRIMARY) + encoder = radeon_encoder_legacy_primary_dac_add(dev, i, 0); +// else if (mode_info->bios_connector[i].dac_type == DAC_TVDAC) +// encoder radeon_encoder_legacy_secondary_dac_add(dev, i, 0); + } if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } @@ -371,6 +337,10 @@ bool radeon_setup_enc_conn(struct drm_device *dev) (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D)) { if (radeon_is_avivo(dev_priv)) encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].dac_type); + else { + if (mode_info->bios_connector[i].tmds_type == TMDS_INT) + encoder = radeon_encoder_legacy_tmds_int_add(dev, i); + } if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 1b75bd6a..9a2d63ea 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -30,9 +30,9 @@ extern int atom_debug; -static void radeon_rmx_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +void radeon_rmx_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); if (mode->hdisplay < radeon_encoder->panel_xres || @@ -319,7 +319,7 @@ static const struct drm_encoder_helper_funcs radeon_atom_lvtma_helper_funcs = { .commit = radeon_lvtma_commit, }; -static void radeon_enc_destroy(struct drm_encoder *encoder) +void radeon_enc_destroy(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); drm_encoder_cleanup(encoder); @@ -895,68 +895,3 @@ struct drm_encoder *radeon_encoder_atom_tmds_add(struct drm_device *dev, int bio return encoder; } -static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) -{ - struct drm_device *dev = encoder->dev; -} - -static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) -{ - radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); -} - -static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) -{ - radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); -} - -static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - - -} - -static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { - .dpms = radeon_legacy_lvds_dpms, - .mode_fixup = radeon_lvtma_mode_fixup, - .prepare = radeon_legacy_lvds_prepare, - .mode_set = radeon_legacy_lvds_mode_set, - .commit = radeon_legacy_lvds_commit, -}; - - -static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { - .destroy = radeon_enc_destroy, -}; - -struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_mode_info *mode_info = &dev_priv->mode_info; - struct radeon_encoder *radeon_encoder; - struct drm_encoder *encoder; - radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); - if (!radeon_encoder) { - return NULL; - } - - encoder = &radeon_encoder->base; - - encoder->possible_crtcs = 0x3; - encoder->possible_clones = 0; - drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, - DRM_MODE_ENCODER_LVDS); - - drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); - - /* TODO get the LVDS info from the BIOS for panel size etc. */ - /* get the lvds info from the bios */ - radeon_combios_get_lvds_info(radeon_encoder); - - /* LVDS gets default RMX full scaling */ - radeon_encoder->rmx_type = RMX_FULL; - - return encoder; -} diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c new file mode 100644 index 00000000..eb005a07 --- /dev/null +++ b/linux-core/radeon_legacy_crtc.c @@ -0,0 +1,748 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#include "drm_crtc_helper.h" + +void radeon_restore_common_regs(struct drm_device *dev, struct radeon_legacy_state *state) +{ + /* don't need this yet */ +} + +void radeon_restore_crtc_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + RADEON_WRITE(RADEON_CRTC_GEN_CNTL, state->crtc_gen_cntl | + RADEON_CRTC_DISP_REQ_EN_B); + + RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, state->crtc_ext_cntl, + RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_DISPLAY_DIS); + + RADEON_WRITE(RADEON_CRTC_H_TOTAL_DISP, state->crtc_h_total_disp); + RADEON_WRITE(RADEON_CRTC_H_SYNC_STRT_WID, state->crtc_h_sync_strt_wid); + RADEON_WRITE(RADEON_CRTC_V_TOTAL_DISP, state->crtc_v_total_disp); + RADEON_WRITE(RADEON_CRTC_V_SYNC_STRT_WID, state->crtc_v_sync_strt_wid); + + if (radeon_is_r300(dev_priv)) + RADEON_WRITE(R300_CRTC_TILE_X0_Y0, state->crtc_tile_x0_y0); + + RADEON_WRITE(RADEON_CRTC_OFFSET_CNTL, state->crtc_offset_cntl); + RADEON_WRITE(RADEON_CRTC_OFFSET, state->crtc_offset); + + RADEON_WRITE(RADEON_CRTC_PITCH, state->crtc_pitch); + RADEON_WRITE(RADEON_DISP_MERGE_CNTL, state->disp_merge_cntl); + + /* if dell server */ + if (0) + { + RADEON_WRITE(RADEON_TV_DAC_CNTL, state->tv_dac_cntl); + RADEON_WRITE(RADEON_DISP_HW_DEBUG, state->disp_hw_debug); + RADEON_WRITE(RADEON_DAC_CNTL2, state->dac2_cntl); + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, state->crtc2_gen_cntl); + } + + RADEON_WRITE(RADEON_CRTC_GEN_CNTL, state->crtc_gen_cntl); +} + +void radeon_restore_crtc2_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + /* We prevent the CRTC from hitting th + e memory controller until + * fully programmed + */ + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, + state->crtc2_gen_cntl | RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS | + RADEON_CRTC2_DISP_REQ_EN_B); + + RADEON_WRITE(RADEON_CRTC2_H_TOTAL_DISP, state->crtc2_h_total_disp); + RADEON_WRITE(RADEON_CRTC2_H_SYNC_STRT_WID, state->crtc2_h_sync_strt_wid); + RADEON_WRITE(RADEON_CRTC2_V_TOTAL_DISP, state->crtc2_v_total_disp); + RADEON_WRITE(RADEON_CRTC2_V_SYNC_STRT_WID, state->crtc2_v_sync_strt_wid); + + RADEON_WRITE(RADEON_FP_H2_SYNC_STRT_WID, state->fp_h2_sync_strt_wid); + RADEON_WRITE(RADEON_FP_V2_SYNC_STRT_WID, state->fp_v2_sync_strt_wid); + + if (radeon_is_r300(dev_priv)) + RADEON_WRITE(R300_CRTC2_TILE_X0_Y0, state->crtc2_tile_x0_y0); + RADEON_WRITE(RADEON_CRTC2_OFFSET_CNTL, state->crtc2_offset_cntl); + RADEON_WRITE(RADEON_CRTC2_OFFSET, state->crtc2_offset); + + RADEON_WRITE(RADEON_CRTC2_PITCH, state->crtc2_pitch); + RADEON_WRITE(RADEON_DISP2_MERGE_CNTL, state->disp2_merge_cntl); + + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, state->crtc2_gen_cntl); +} + +static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i = 0; + + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; + (i < 10000 && + RADEON_READ_PLL(dev_priv, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); + i++); +} + +static void radeon_pll_write_update(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + while (RADEON_READ_PLL(dev_priv, RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, + RADEON_PPLL_ATOMIC_UPDATE_W, + ~(RADEON_PPLL_ATOMIC_UPDATE_W)); +} + +static void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int i = 0; + + + /* FIXME: Certain revisions of R300 can't recover here. Not sure of + the cause yet, but this workaround will mask the problem for now. + Other chips usually will pass at the very first test, so the + workaround shouldn't have any effect on them. */ + for (i = 0; + (i < 10000 && + RADEON_READ_PLL(dev_priv, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); + i++); +} + +static void radeon_pll2_write_update(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + while (RADEON_READ_PLL(dev_priv, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_REF_DIV, + RADEON_P2PLL_ATOMIC_UPDATE_W, + ~(RADEON_P2PLL_ATOMIC_UPDATE_W)); +} + +static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div, + uint16_t fb_div) +{ + unsigned int vcoFreq; + + if (!ref_div) + return 1; + + vcoFreq = ((unsigned)ref_freq & fb_div) / ref_div; + + /* + * This is horribly crude: the VCO frequency range is divided into + * 3 parts, each part having a fixed PLL gain value. + */ + if (vcoFreq >= 30000) + /* + * [300..max] MHz : 7 + */ + return 7; + else if (vcoFreq >= 18000) + /* + * [180..300) MHz : 4 + */ + return 4; + else + /* + * [0..180) MHz : 1 + */ + return 1; +} + +void radeon_restore_pll_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint8_t pll_gain; + + pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.pll.reference_freq, + state->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + state->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK); + + if (dev_priv->flags & RADEON_IS_MOBILITY) { + /* A temporal workaround for the occational blanking on certain laptop panels. + This appears to related to the PLL divider registers (fail to lock?). + It occurs even when all dividers are the same with their old settings. + In this case we really don't need to fiddle with PLL registers. + By doing this we can avoid the blanking problem with some panels. + */ + if ((state->ppll_ref_div == (RADEON_READ_PLL(dev_priv, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && + (state->ppll_div_3 == (RADEON_READ_PLL(dev_priv, RADEON_PPLL_DIV_3) & + (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) { + RADEON_WRITE_P(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + radeon_pll_errata_after_index(dev_priv); + return; + } + } + + RADEON_WRITE_PLL_P(dev_priv, RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_CPUCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + + RADEON_WRITE_PLL_P(dev_priv, + RADEON_PPLL_CNTL, + RADEON_PPLL_RESET + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN + | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT), + ~(RADEON_PPLL_RESET + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN + | RADEON_PPLL_PVG_MASK)); + + RADEON_WRITE_P(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + radeon_pll_errata_after_index(dev_priv); + + if (radeon_is_r300(dev_priv) || + (dev_priv->chip_family == CHIP_RS300) || + (dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) { + if (state->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { + /* When restoring console mode, use saved PPLL_REF_DIV + * setting. + */ + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, + state->ppll_ref_div, + 0); + } else { + /* R300 uses ref_div_acc field as real ref divider */ + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, + (state->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), + ~R300_PPLL_REF_DIV_ACC_MASK); + } + } else { + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, + state->ppll_ref_div, + ~RADEON_PPLL_REF_DIV_MASK); + } + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_DIV_3, + state->ppll_div_3, + ~RADEON_PPLL_FB3_DIV_MASK); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_DIV_3, + state->ppll_div_3, + ~RADEON_PPLL_POST3_DIV_MASK); + + radeon_pll_write_update(dev); + radeon_pll_wait_for_read_update_complete(dev); + + RADEON_WRITE_PLL(dev_priv, RADEON_HTOTAL_CNTL, state->htotal_cntl); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_CNTL, + 0, + ~(RADEON_PPLL_RESET + | RADEON_PPLL_SLEEP + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); + + DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + state->ppll_ref_div, + state->ppll_div_3, + (unsigned)state->htotal_cntl, + RADEON_READ_PLL(dev_priv, RADEON_PPLL_CNTL)); + DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n", + state->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + state->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, + (state->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); + + mdelay(50); /* Let the clock to lock */ + + RADEON_WRITE_PLL_P(dev_priv, RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_PPLLCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + + /*RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, state->vclk_ecp_cntl);*/ + +} + +void radeon_restore_pll2_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint8_t pll_gain; + + pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.pll.reference_freq, + state->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + state->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK); + + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_CPUCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + + RADEON_WRITE_PLL_P(dev_priv, + RADEON_P2PLL_CNTL, + RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT), + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | RADEON_P2PLL_PVG_MASK)); + + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_REF_DIV, + state->p2pll_ref_div, + ~RADEON_P2PLL_REF_DIV_MASK); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_DIV_0, + state->p2pll_div_0, + ~RADEON_P2PLL_FB0_DIV_MASK); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_DIV_0, + state->p2pll_div_0, + ~RADEON_P2PLL_POST0_DIV_MASK); + + radeon_pll2_write_update(dev); + radeon_pll2_wait_for_read_update_complete(dev); + + RADEON_WRITE_PLL(dev_priv, RADEON_HTOTAL2_CNTL, state->htotal_cntl2); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_CNTL, + 0, + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_SLEEP + | RADEON_P2PLL_ATOMIC_UPDATE_EN)); + + DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + (unsigned)state->p2pll_ref_div, + (unsigned)state->p2pll_div_0, + (unsigned)state->htotal_cntl2, + RADEON_READ_PLL(dev_priv, RADEON_P2PLL_CNTL)); + DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n", + (unsigned)state->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + (unsigned)state->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK, + (unsigned)((state->p2pll_div_0 & + RADEON_P2PLL_POST0_DIV_MASK) >>16)); + + mdelay(50); /* Let the clock to lock */ + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, state->pixclks_cntl); + + +} + + +void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + + uint32_t mask; + + mask = radeon_crtc->crtc_id ? + (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_REQ_EN_B) : + (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS); + + switch(mode) { + case DRM_MODE_DPMS_ON: + if (radeon_crtc->crtc_id) { + RADEON_WRITE_P(RADEON_CRTC2_GEN_CNTL, 0, ~mask); + } else { + RADEON_WRITE_P(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); + RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, 0, ~mask); + } + break; + case DRM_MODE_DPMS_STANDBY: + if (radeon_crtc->crtc_id) { + RADEON_WRITE_P(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS), ~mask); + } else { + RADEON_WRITE_P(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); + RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS), ~mask); + } + break; + case DRM_MODE_DPMS_SUSPEND: + if (radeon_crtc->crtc_id) { + RADEON_WRITE_P(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS), ~mask); + } else { + RADEON_WRITE_P(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); + RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS), ~mask); + } + break; + case DRM_MODE_DPMS_OFF: + if (radeon_crtc->crtc_id) { + RADEON_WRITE_P(RADEON_CRTC2_GEN_CNTL, mask, ~mask); + } else { + RADEON_WRITE_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~RADEON_CRTC_DISP_REQ_EN_B); + RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); + } + break; + } + + if (mode != DRM_MODE_DPMS_OFF) { + radeon_crtc_load_lut(crtc); + } +} + +static bool radeon_init_crtc_base(struct drm_crtc *crtc, struct radeon_legacy_state *state, int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_framebuffer *radeon_fb; + struct drm_radeon_gem_object *obj_priv; + uint32_t base; + + radeon_fb = to_radeon_framebuffer(crtc->fb); + + obj_priv = radeon_fb->obj->driver_private; + + state->crtc_offset = obj_priv->bo->offset + dev_priv->fb_location; + + state->crtc_offset_cntl = 0; + + /* TODO tiling */ + if (0) { + if (radeon_is_r300(dev_priv)) { + state->crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + } else { + state->crtc_offset_cntl |= RADEON_CRTC_TILE_EN; + } + } else { + if (radeon_is_r300(dev_priv)) { + state->crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + } else { + state->crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; + } + } + + base = obj_priv->bo->offset; + + /* TODO more tiling */ + if (0) { + if (radeon_is_r300(dev_priv)) { + state->crtc_tile_x0_y0 = x | (y << 16); + base &= ~0x7ff; + } else { + int byteshift = crtc->fb->bits_per_pixel >> 4; + int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11; + base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); + state->crtc_offset_cntl |= (y % 16); + } + } else { + int offset = y * crtc->fb->pitch + x; + switch (crtc->fb->bits_per_pixel) { + } + base += offset; + } + + base &= ~7; + + /* update sarea TODO */ + + state->crtc_offset = base; + return true; +} + +static bool radeon_init_crtc_registers(struct drm_crtc *crtc, struct radeon_legacy_state *state, + struct drm_display_mode *mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + int format; + int hsync_start; + int hsync_wid; + int vsync_wid; + + switch (crtc->fb->depth) { + + case 15: format = 3; break; /* 555 */ + case 16: format = 4; break; /* 565 */ + case 24: format = 5; break; /* RGB */ + case 32: format = 6; break; /* xRGB */ + default: + return false; + } + + state->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN + | RADEON_CRTC_EN + | (format << 8) + | ((mode->flags & DRM_MODE_FLAG_DBLSCAN) + ? RADEON_CRTC_DBL_SCAN_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_CSYNC) + ? RADEON_CRTC_CSYNC_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_INTERLACE) + ? RADEON_CRTC_INTERLACE_EN + : 0)); + + state->crtc_ext_cntl |= (RADEON_XCRT_CNT_EN| + RADEON_CRTC_VSYNC_DIS | + RADEON_CRTC_HSYNC_DIS | + RADEON_CRTC_DISPLAY_DIS); + + state->disp_merge_cntl = RADEON_READ(RADEON_DISP_MERGE_CNTL); + state->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + + state->crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) + | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) + << 16)); + + hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; + if (!hsync_wid) hsync_wid = 1; + hsync_start = mode->crtc_hsync_start - 8; + + state->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + /* This works for double scan mode. */ + state->crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) + | ((mode->crtc_vdisplay - 1) << 16)); + + vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; + if (!vsync_wid) vsync_wid = 1; + + state->crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0)); + + state->crtc_pitch = (((crtc->fb->pitch * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) -1)) / + (crtc->fb->bits_per_pixel * 8)); + state->crtc_pitch |= state->crtc_pitch << 16; + + /* TODO -> Dell Server */ + if (0) { +// state->dac2_cntl = info->StatedReg->dac2_cntl; +// state->tv_dac_cntl = info->StatedReg->tv_dac_cntl; +// state->crtc2_gen_cntl = info->StatedReg->crtc2_gen_cntl; +// state->disp_hw_debug = info->StatedReg->disp_hw_debug; + +// state->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; +// state->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; + + /* For CRT on DAC2, don't turn it on if BIOS didn't + enable it, even it's detected. + */ + state->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + state->tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16)); + state->tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16)); + } + + return true; +} + +static void radeon_init_pll_registers(struct drm_crtc *crtc, struct radeon_legacy_state *state, + struct drm_display_mode *mode, int flags) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t feedback_div = 0; + uint32_t reference_div = 0; + uint32_t post_divider = 0; + uint32_t freq = 0; + struct radeon_pll *pll = &dev_priv->mode_info.pll; + struct { + int divider; + int bitvalue; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 16, 5 }, /* VCLK_SRC/16 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + +#if 0 // TODO + if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) { + state->ppll_ref_div = info->RefDivider; + state->ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16); + state->htotal_cntl = 0; + return; + } +#endif + + DRM_DEBUG("\n"); + radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &reference_div, &post_divider, flags); + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + if (post_div->divider == post_divider) + break; + } + + if (!post_div->divider) { + state->pll_output_freq = freq; + post_div = &post_divs[0]; + } + + state->dot_clock_freq = freq; + state->feedback_div = feedback_div; + state->reference_div = reference_div; + state->post_div = post_divider; + + DRM_DEBUG("dc=%u, of=%u, fd=%d, rd=%d, pd=%d\n", + (unsigned)state->dot_clock_freq, + (unsigned)state->pll_output_freq, + state->feedback_div, + state->reference_div, + state->post_div); + + state->ppll_ref_div = state->reference_div; + +#if defined(__powerpc__) && (0) /* TODO */ + /* apparently programming this otherwise causes a hang??? */ + if (info->MacModel == RADEON_MAC_IBOOK) + state->ppll_div_3 = 0x000600ad; + else +#endif + state->ppll_div_3 = (state->feedback_div | (post_div->bitvalue << 16)); + + state->htotal_cntl = mode->htotal & 0x7; + + state->vclk_ecp_cntl = (RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL) & + ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK; + +} + +static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder; + int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV; + int i; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (encoder->crtc == crtc) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) + pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) + pll_flags |= RADEON_PLL_USE_BIOS_DIVS | RADEON_PLL_USE_REF_DIV; + } + } + + switch(radeon_crtc->crtc_id) { + case 0: + radeon_init_crtc_registers(crtc, &dev_priv->mode_info.legacy_state, adjusted_mode); + radeon_init_crtc_base(crtc, &dev_priv->mode_info.legacy_state, crtc->x, crtc->y); +// dot_clock = adjusted_mode->clock / 1000; + + // if (dot_clock) + radeon_init_pll_registers(crtc, &dev_priv->mode_info.legacy_state, adjusted_mode, + pll_flags); + break; + case 1: + break; + + } + + /* TODO TV */ + + switch (radeon_crtc->crtc_id) { + case 0: + radeon_restore_crtc_registers(dev, &dev_priv->mode_info.legacy_state); + radeon_restore_pll_registers(dev, &dev_priv->mode_info.legacy_state); + break; + case 1: + radeon_restore_crtc2_registers(dev, &dev_priv->mode_info.legacy_state); + radeon_restore_pll2_registers(dev, &dev_priv->mode_info.legacy_state); + break; + } + +} + +void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y) +{ +} + +static void radeon_crtc_prepare(struct drm_crtc *crtc) +{ +} + +static void radeon_crtc_commit(struct drm_crtc *crtc) +{ +} + +static const struct drm_crtc_helper_funcs legacy_helper_funcs = { + .dpms = radeon_crtc_dpms, + .mode_fixup = radeon_crtc_mode_fixup, + .mode_set = radeon_crtc_mode_set, + .mode_set_base = radeon_crtc_set_base, + .prepare = radeon_crtc_prepare, + .commit = radeon_crtc_commit, +}; + + +void radeon_legacy_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc) +{ + drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs); +} diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c new file mode 100644 index 00000000..8846653d --- /dev/null +++ b/linux-core/radeon_legacy_encoders.c @@ -0,0 +1,391 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + + +void radeon_restore_dac_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (radeon_is_r300(dev_priv)) + RADEON_WRITE_P(RADEON_GPIOPAD_A, state->gpiopad_a, ~1); + + RADEON_WRITE_P(RADEON_DAC_CNTL, + state->dac_cntl, + RADEON_DAC_RANGE_CNTL | + RADEON_DAC_BLANKING); + + RADEON_WRITE(RADEON_DAC_CNTL2, state->dac2_cntl); + + if ((dev_priv->chip_family != CHIP_R100) && + (dev_priv->chip_family != CHIP_R200)) + RADEON_WRITE (RADEON_TV_DAC_CNTL, state->tv_dac_cntl); + + RADEON_WRITE(RADEON_DISP_OUTPUT_CNTL, state->disp_output_cntl); + + if ((dev_priv->chip_family == CHIP_R200) || + radeon_is_r300(dev_priv)) { + RADEON_WRITE(RADEON_DISP_TV_OUT_CNTL, state->disp_tv_out_cntl); + } else { + RADEON_WRITE(RADEON_DISP_HW_DEBUG, state->disp_hw_debug); + } + + RADEON_WRITE(RADEON_DAC_MACRO_CNTL, state->dac_macro_cntl); + + /* R200 DAC connected via DVO */ + if (dev_priv->chip_family == CHIP_R200) + RADEON_WRITE(RADEON_FP2_GEN_CNTL, state->fp2_gen_cntl); +} + + +/* Write TMDS registers */ +void radeon_restore_fp_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + RADEON_WRITE(RADEON_TMDS_PLL_CNTL, state->tmds_pll_cntl); + RADEON_WRITE(RADEON_TMDS_TRANSMITTER_CNTL,state->tmds_transmitter_cntl); + RADEON_WRITE(RADEON_FP_GEN_CNTL, state->fp_gen_cntl); + + if ((dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) { + RADEON_WRITE(RS400_FP_2ND_GEN_CNTL, state->fp_2nd_gen_cntl); + /*RADEON_WRITE(RS400_TMDS2_CNTL, state->tmds2_cntl);*/ + RADEON_WRITE(RS400_TMDS2_TRANSMITTER_CNTL, state->tmds2_transmitter_cntl); + } + + /* old AIW Radeon has some BIOS initialization problem + * with display buffer underflow, only occurs to DFP + */ + if (dev_priv->flags & RADEON_SINGLE_CRTC) + RADEON_WRITE(RADEON_GRPH_BUFFER_CNTL, + RADEON_READ(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); + +} + +/* Write FP2 registers */ +void radeon_restore_fp2_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + RADEON_WRITE(RADEON_FP2_GEN_CNTL, state->fp2_gen_cntl); + + if ((dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) + RADEON_WRITE(RS400_FP2_2_GEN_CNTL, state->fp2_2_gen_cntl); +} + +/* Write RMX registers */ +void radeon_state_rmx_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + RADEON_WRITE(RADEON_FP_HORZ_STRETCH, state->fp_horz_stretch); + RADEON_WRITE(RADEON_FP_VERT_STRETCH, state->fp_vert_stretch); + RADEON_WRITE(RADEON_CRTC_MORE_CNTL, state->crtc_more_cntl); + RADEON_WRITE(RADEON_FP_HORZ_VERT_ACTIVE, state->fp_horz_vert_active); + RADEON_WRITE(RADEON_FP_H_SYNC_STRT_WID, state->fp_h_sync_strt_wid); + RADEON_WRITE(RADEON_FP_V_SYNC_STRT_WID, state->fp_v_sync_strt_wid); + RADEON_WRITE(RADEON_FP_CRTC_H_TOTAL_DISP, state->fp_crtc_h_total_disp); + RADEON_WRITE(RADEON_FP_CRTC_V_TOTAL_DISP, state->fp_crtc_v_total_disp); + +} + +/* Write LVDS registers */ +void radeon_restore_lvds_registers(struct drm_device *dev, struct radeon_legacy_state *state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (dev_priv->flags & RADEON_IS_MOBILITY) { + RADEON_WRITE(RADEON_LVDS_GEN_CNTL, state->lvds_gen_cntl); + /*RADEON_WRITE(RADEON_LVDS_PLL_CNTL, state->lvds_pll_cntl);*/ + + if (dev_priv->chip_family == CHIP_RV410) { + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, 0); + } + } + +} + +static void radeon_init_fp_registers(struct drm_encoder *encoder, struct drm_display_mode *mode, + bool is_primary) +{ + + +} + +static void radeon_init_dac_registers(struct drm_encoder *encoder, struct radeon_legacy_state *state, + struct drm_display_mode *mode, bool is_primary) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (is_primary) { + if (dev_priv->chip_family == CHIP_R200 || radeon_is_r300(dev_priv)) { + state->disp_output_cntl = RADEON_READ(RADEON_DISP_OUTPUT_CNTL & + ~RADEON_DISP_DAC_SOURCE_MASK); + } else { + state->dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2) & ~(RADEON_DAC2_DAC_CLK_SEL); + } + } else { + if (dev_priv->chip_family == CHIP_R200 || radeon_is_r300(dev_priv)) { + state->disp_output_cntl = RADEON_READ(RADEON_DISP_OUTPUT_CNTL & + ~RADEON_DISP_DAC_SOURCE_MASK); + state->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; + } else { + state->dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL; + } + } + + state->dac_cntl = (RADEON_DAC_MASK_ALL | + RADEON_DAC_VGA_ADR_EN | + /* TODO 6-bits */ + RADEON_DAC_8BIT_EN); + state->dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); +} + +static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; +} + +static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) +{ + radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) +{ + radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + +} + +static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + radeon_encoder->flags &= ~RADEON_USE_RMX; + + if (radeon_encoder->rmx_type != RMX_OFF) + radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); + + return true; +} + +static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { + .dpms = radeon_legacy_lvds_dpms, + .mode_fixup = radeon_legacy_lvds_mode_fixup, + .prepare = radeon_legacy_lvds_prepare, + .mode_set = radeon_legacy_lvds_mode_set, + .commit = radeon_legacy_lvds_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + + +struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder; + struct drm_encoder *encoder; + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, + DRM_MODE_ENCODER_LVDS); + + drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); + + /* TODO get the LVDS info from the BIOS for panel size etc. */ + /* get the lvds info from the bios */ + radeon_combios_get_lvds_info(radeon_encoder); + + /* LVDS gets default RMX full scaling */ + radeon_encoder->rmx_type = RMX_FULL; + + return encoder; +} + +static bool radeon_legacy_primary_dac_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode) +{ + + +} + +static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) +{ + radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) +{ + radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + radeon_init_dac_registers(encoder, &dev_priv->mode_info.legacy_state, adjusted_mode, + (radeon_crtc->crtc_id == 1)); + + radeon_restore_dac_registers(dev, &dev_priv->mode_info.legacy_state); +} + +static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = { + .dpms = radeon_legacy_primary_dac_dpms, + .mode_fixup = radeon_legacy_primary_dac_mode_fixup, + .prepare = radeon_legacy_primary_dac_prepare, + .mode_set = radeon_legacy_primary_dac_mode_set, + .commit = radeon_legacy_primary_dac_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev, int bios_index, int has_tv) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder; + struct drm_encoder *encoder; + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs, + DRM_MODE_ENCODER_DAC); + + drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs); + + return encoder; +} + + +static bool radeon_legacy_tmds_int_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + +} + +static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) +{ + /* dfp1 */ + +} + +static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) +{ + radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) +{ + radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + +} + +static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs = { + .dpms = radeon_legacy_tmds_int_dpms, + .mode_fixup = radeon_legacy_tmds_int_mode_fixup, + .prepare = radeon_legacy_tmds_int_prepare, + .mode_set = radeon_legacy_tmds_int_mode_set, + .commit = radeon_legacy_tmds_int_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder; + struct drm_encoder *encoder; + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, + DRM_MODE_ENCODER_TMDS); + + drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs); + + radeon_combios_get_tmds_info(radeon_encoder); + return encoder; +} diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index f75e8272..91c6f48d 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -115,6 +115,11 @@ struct radeon_bios_connector { int igp_lane_info; }; +struct radeon_tmds_pll { + uint32_t freq; + uint32_t value; +}; + #define RADEON_MAX_BIOS_CONNECTOR 16 #define RADEON_PLL_USE_BIOS_DIVS (1 << 0) @@ -124,27 +129,177 @@ struct radeon_bios_connector { #define RADEON_PLL_PREFER_LOW_REF_DIV (1 << 4) struct radeon_pll { - uint16_t reference_freq; - uint16_t reference_div; - uint32_t pll_in_min; - uint32_t pll_in_max; - uint32_t pll_out_min; - uint32_t pll_out_max; - uint16_t xclk; - - uint32_t min_ref_div; - uint32_t max_ref_div; - uint32_t min_post_div; - uint32_t max_post_div; - uint32_t min_feedback_div; - uint32_t max_feedback_div; - uint32_t best_vco; + uint16_t reference_freq; + uint16_t reference_div; + uint32_t pll_in_min; + uint32_t pll_in_max; + uint32_t pll_out_min; + uint32_t pll_out_max; + uint16_t xclk; + + uint32_t min_ref_div; + uint32_t max_ref_div; + uint32_t min_post_div; + uint32_t max_post_div; + uint32_t min_feedback_div; + uint32_t max_feedback_div; + uint32_t best_vco; +}; + +#define MAX_H_CODE_TIMING_LEN 32 +#define MAX_V_CODE_TIMING_LEN 32 + +struct radeon_legacy_state { + + uint32_t bus_cntl; + + /* DAC */ + uint32_t dac_cntl; + uint32_t dac2_cntl; + uint32_t dac_macro_cntl; + + /* CRTC 1 */ + uint32_t crtc_gen_cntl; + uint32_t crtc_ext_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_h_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_offset; + uint32_t crtc_offset_cntl; + uint32_t crtc_pitch; + uint32_t disp_merge_cntl; + uint32_t grph_buffer_cntl; + uint32_t crtc_more_cntl; + uint32_t crtc_tile_x0_y0; + + /* CRTC 2 */ + uint32_t crtc2_gen_cntl; + uint32_t crtc2_h_total_disp; + uint32_t crtc2_h_sync_strt_wid; + uint32_t crtc2_v_total_disp; + uint32_t crtc2_v_sync_strt_wid; + uint32_t crtc2_offset; + uint32_t crtc2_offset_cntl; + uint32_t crtc2_pitch; + uint32_t crtc2_tile_x0_y0; + + uint32_t disp_output_cntl; + uint32_t disp_tv_out_cntl; + uint32_t disp_hw_debug; + uint32_t disp2_merge_cntl; + uint32_t grph2_buffer_cntl; + + /* FP regs */ + uint32_t fp_crtc_h_total_disp; + uint32_t fp_crtc_v_total_disp; + uint32_t fp_gen_cntl; + uint32_t fp2_gen_cntl; + uint32_t fp_h_sync_strt_wid; + uint32_t fp_h2_sync_strt_wid; + uint32_t fp_horz_stretch; + uint32_t fp_horz_vert_active; + uint32_t fp_panel_cntl; + uint32_t fp_v_sync_strt_wid; + uint32_t fp_v2_sync_strt_wid; + uint32_t fp_vert_stretch; + uint32_t lvds_gen_cntl; + uint32_t lvds_pll_cntl; + uint32_t tmds_pll_cntl; + uint32_t tmds_transmitter_cntl; + + /* Computed values for PLL */ + uint32_t dot_clock_freq; + uint32_t pll_output_freq; + int feedback_div; + int reference_div; + int post_div; + + /* PLL registers */ + uint32_t ppll_ref_div; + uint32_t ppll_div_3; + uint32_t htotal_cntl; + uint32_t vclk_ecp_cntl; + + /* Computed values for PLL2 */ + uint32_t dot_clock_freq_2; + uint32_t pll_output_freq_2; + int feedback_div_2; + int reference_div_2; + int post_div_2; + + /* PLL2 registers */ + uint32_t p2pll_ref_div; + uint32_t p2pll_div_0; + uint32_t htotal_cntl2; + uint32_t pixclks_cntl; + + bool palette_valid; + uint32_t palette[256]; + uint32_t palette2[256]; + + uint32_t disp2_req_cntl1; + uint32_t disp2_req_cntl2; + uint32_t dmif_mem_cntl1; + uint32_t disp1_req_cntl1; + + uint32_t fp_2nd_gen_cntl; + uint32_t fp2_2_gen_cntl; + uint32_t tmds2_cntl; + uint32_t tmds2_transmitter_cntl; + + /* TV out registers */ + uint32_t tv_master_cntl; + uint32_t tv_htotal; + uint32_t tv_hsize; + uint32_t tv_hdisp; + uint32_t tv_hstart; + uint32_t tv_vtotal; + uint32_t tv_vdisp; + uint32_t tv_timing_cntl; + uint32_t tv_vscaler_cntl1; + uint32_t tv_vscaler_cntl2; + uint32_t tv_sync_size; + uint32_t tv_vrestart; + uint32_t tv_hrestart; + uint32_t tv_frestart; + uint32_t tv_ftotal; + uint32_t tv_clock_sel_cntl; + uint32_t tv_clkout_cntl; + uint32_t tv_data_delay_a; + uint32_t tv_data_delay_b; + uint32_t tv_dac_cntl; + uint32_t tv_pll_cntl; + uint32_t tv_pll_cntl1; + uint32_t tv_pll_fine_cntl; + uint32_t tv_modulator_cntl1; + uint32_t tv_modulator_cntl2; + uint32_t tv_frame_lock_cntl; + uint32_t tv_pre_dac_mux_cntl; + uint32_t tv_rgb_cntl; + uint32_t tv_y_saw_tooth_cntl; + uint32_t tv_y_rise_cntl; + uint32_t tv_y_fall_cntl; + uint32_t tv_uv_adr; + uint32_t tv_upsamp_and_gain_cntl; + uint32_t tv_gain_limit_settings; + uint32_t tv_linear_gain_settings; + uint32_t tv_crc_cntl; + uint32_t tv_sync_cntl; + uint32_t gpiopad_a; + uint32_t pll_test_cntl; + + uint16_t h_code_timing[MAX_H_CODE_TIMING_LEN]; + uint16_t v_code_timing[MAX_V_CODE_TIMING_LEN]; + + }; struct radeon_mode_info { struct atom_context *atom_context; struct radeon_bios_connector bios_connector[RADEON_MAX_BIOS_CONNECTOR]; struct radeon_pll pll; + struct radeon_legacy_state legacy_state; }; struct radeon_crtc { @@ -185,6 +340,7 @@ struct radeon_encoder { uint32_t vblank; uint32_t panel_pwr_delay; uint32_t dotclock; + struct radeon_tmds_pll tmds_pll[4]; }; struct radeon_connector { @@ -221,6 +377,8 @@ struct drm_encoder *radeon_encoder_lvtma_add(struct drm_device *dev, int bios_in struct drm_encoder *radeon_encoder_atom_dac_add(struct drm_device *dev, int bios_index, int dac_id, int with_tv); struct drm_encoder *radeon_encoder_atom_tmds_add(struct drm_device *dev, int bios_index, int tmds_type); struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index); +struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev, int bios_index, int with_tv); +struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); extern void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y); @@ -233,6 +391,7 @@ extern bool radeon_atom_get_clock_info(struct drm_device *dev); extern bool radeon_combios_get_clock_info(struct drm_device *dev); extern void radeon_get_lvds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder); +extern bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder); extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, @@ -245,6 +404,8 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev); void radeon_atombios_init_crtc(struct drm_device *dev, struct radeon_crtc *radeon_crtc); +void radeon_legacy_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc); void avivo_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state); void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable); @@ -252,4 +413,9 @@ void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable); void radeon_get_clock_info(struct drm_device *dev); extern bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev); +void radeon_rmx_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +void radeon_enc_destroy(struct drm_encoder *encoder); + #endif diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 4c03f739..b751740c 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2282,6 +2282,7 @@ static void radeon_set_dynamic_clock(struct drm_device *dev, int mode) int radeon_modeset_cp_init(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t tmp; /* allocate a ring and ring rptr bits from GART space */ /* these are allocated in GEM files */ @@ -2311,6 +2312,11 @@ int radeon_modeset_cp_init(struct drm_device *dev) radeon_cp_init_ring_buffer(dev, dev_priv); + /* need to enable BUS mastering in Buscntl */ + tmp = RADEON_READ(RADEON_BUS_CNTL); + tmp &= ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); + radeon_do_engine_reset(dev); radeon_test_writeback(dev_priv); @@ -2381,8 +2387,8 @@ int radeon_modeset_preinit(struct drm_device *dev) if (dev_priv->is_atom_bios) { dev_priv->mode_info.atom_context = atom_parse(&card, dev_priv->bios); - radeon_get_clock_info(dev); } + radeon_get_clock_info(dev); return 0; } diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 94975e4d..51a5b00c 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1277,41 +1277,59 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, extern int RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr); extern void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data); -#define RADEON_WRITE_PCIE( addr, val ) \ +#define RADEON_WRITE_P(reg, val, mask) \ +do { \ + uint32_t tmp = RADEON_READ(reg); \ + tmp &= ~(mask); \ + tmp |= ((val) & ~(mask)); \ + RADEON_WRITE(reg, tmp); \ +} while(0) + +#define RADEON_WRITE_PLL_P(dev_priv, addr, val, mask) \ +do { \ + uint32_t tmp_ = RADEON_READ_PLL(dev_priv, addr); \ + tmp_ &= (mask); \ + tmp_ |= ((val) & ~(mask)); \ + RADEON_WRITE_PLL(dev_priv, addr, tmp_); \ +} while (0) + + + +#define RADEON_WRITE_PCIE(addr, val) \ do { \ - RADEON_WRITE8( RADEON_PCIE_INDEX, \ + RADEON_WRITE8(RADEON_PCIE_INDEX, \ ((addr) & 0xff)); \ - RADEON_WRITE( RADEON_PCIE_DATA, (val) ); \ + RADEON_WRITE(RADEON_PCIE_DATA, (val)); \ } while (0) -#define R500_WRITE_MCIND( addr, val ) \ +#define R500_WRITE_MCIND(addr, val) \ do { \ RADEON_WRITE(R520_MC_IND_INDEX, 0xff0000 | ((addr) & 0xff)); \ RADEON_WRITE(R520_MC_IND_DATA, (val)); \ RADEON_WRITE(R520_MC_IND_INDEX, 0); \ } while (0) -#define RS480_WRITE_MCIND( addr, val ) \ +#define RS480_WRITE_MCIND(addr, val) \ do { \ - RADEON_WRITE( RS480_NB_MC_INDEX, \ + RADEON_WRITE(RS480_NB_MC_INDEX, \ ((addr) & 0xff) | RS480_NB_MC_IND_WR_EN); \ - RADEON_WRITE( RS480_NB_MC_DATA, (val) ); \ - RADEON_WRITE( RS480_NB_MC_INDEX, 0xff ); \ + RADEON_WRITE(RS480_NB_MC_DATA, (val)); \ + RADEON_WRITE(RS480_NB_MC_INDEX, 0xff); \ } while (0) -#define RS690_WRITE_MCIND( addr, val ) \ +#define RS690_WRITE_MCIND(addr, val) \ do { \ RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_EN | ((addr) & RS690_MC_INDEX_MASK)); \ RADEON_WRITE(RS690_MC_DATA, val); \ RADEON_WRITE(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK); \ } while (0) -#define IGP_WRITE_MCIND( addr, val ) \ +#define IGP_WRITE_MCIND(addr, val) \ do { \ - if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) \ - RS690_WRITE_MCIND( addr, val ); \ - else \ - RS480_WRITE_MCIND( addr, val ); \ + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) \ + RS690_WRITE_MCIND(addr, val); \ + else \ + RS480_WRITE_MCIND(addr, val); \ } while (0) #define CP_PACKET0( reg, n ) \ @@ -1355,42 +1373,42 @@ do { \ #define RADEON_FLUSH_CACHE() do { \ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \ - OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_DC_FLUSH ); \ + OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_DC_FLUSH); \ } else { \ - OUT_RING( CP_PACKET0( R300_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_DC_FLUSH ); \ - } \ + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_DC_FLUSH); \ + } \ } while (0) #define RADEON_PURGE_CACHE() do { \ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \ - OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \ + OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_DC_FLUSH_ALL); \ } else { \ - OUT_RING( CP_PACKET0( R300_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \ - } \ + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_DC_FLUSH_ALL); \ + } \ } while (0) #define RADEON_FLUSH_ZCACHE() do { \ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \ - OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_ZC_FLUSH ); \ + OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_ZC_FLUSH); \ } else { \ - OUT_RING( CP_PACKET0( R300_ZB_ZCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( R300_ZC_FLUSH ); \ - } \ + OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); \ + OUT_RING(R300_ZC_FLUSH); \ + } \ } while (0) #define RADEON_PURGE_ZCACHE() do { \ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \ - OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_ZC_FLUSH_ALL ); \ + OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_ZC_FLUSH_ALL); \ } else { \ - OUT_RING( CP_PACKET0( R300_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( R300_ZC_FLUSH_ALL ); \ - } \ + OUT_RING(CP_PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); \ + OUT_RING(R300_ZC_FLUSH_ALL); \ + } \ } while (0) /* ================================================================ @@ -1411,7 +1429,7 @@ do { \ #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ do { \ struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \ - drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \ + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \ if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ int __ret = radeon_do_cp_idle( dev_priv ); \ if ( __ret ) return __ret; \ @@ -1587,6 +1605,23 @@ static inline int radeon_update_breadcrumb(struct drm_device *dev) #define radeon_is_dce3(dev_priv) ((dev_priv->chip_family >= CHIP_RV620)) +#define radeon_is_rv100(dev_priv) ((dev_priv->chip_family == CHIP_RV100) || \ + (dev_priv->chip_family == CHIP_RV200) || \ + (dev_priv->chip_family == CHIP_RS100) || \ + (dev_priv->chip_family == CHIP_RS200) || \ + (dev_priv->chip_family == CHIP_RV250) || \ + (dev_priv->chip_family == CHIP_RV280) || \ + (dev_priv->chip_family == CHIP_RS300)) + +#define radeon_is_r300(dev_priv) ((dev_priv->chip_family == CHIP_R300) || \ + (dev_priv->chip_family == CHIP_RV350) || \ + (dev_priv->chip_family == CHIP_R350) || \ + (dev_priv->chip_family == CHIP_RV380) || \ + (dev_priv->chip_family == CHIP_R420) || \ + (dev_priv->chip_family == CHIP_RV410) || \ + (dev_priv->chip_family == CHIP_RS400) || \ + (dev_priv->chip_family == CHIP_RS480)) + #define radeon_bios8(dev_priv, v) (dev_priv->bios[v]) #define radeon_bios16(dev_priv, v) (dev_priv->bios[v] | (dev_priv->bios[(v) + 1] << 8)) #define radeon_bios32(dev_priv, v) ((dev_priv->bios[v]) | \ @@ -1594,6 +1629,7 @@ static inline int radeon_update_breadcrumb(struct drm_device *dev) (dev_priv->bios[(v) + 2] << 16) | \ (dev_priv->bios[(v) + 3] << 24)) +extern void radeon_pll_errata_after_index(struct drm_radeon_private *dev_priv); extern int radeon_emit_irq(struct drm_device * dev); extern void radeon_gem_free_object(struct drm_gem_object *obj); -- cgit v1.2.3 From 2b7feebb8ad5f49391b4f6bd6fc548e4f93b94f3 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 9 Aug 2008 19:33:32 +0200 Subject: NV50: call drm_sysfs_hotplug_event when appropriate --- linux-core/drm_sysfs.c | 1 + linux-core/nv50_kms_wrapper.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 5c384a60..3b217342 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -450,6 +450,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); } +EXPORT_SYMBOL(drm_sysfs_hotplug_event); static struct device_attribute dri_attrs[] = { __ATTR(dri_library_name, S_IRUGO, show_dri, NULL), diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 77271c1b..bf747a4c 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -970,6 +970,9 @@ static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector /* notify fb of changes */ dev->mode_config.funcs->fb_changed(dev); + + /* sent a hotplug event when appropriate. */ + drm_sysfs_hotplug_event(dev); } return drm_connector->status; -- cgit v1.2.3 From f79ed5546229aa923f8dd54055bebeb56efaa76c Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 9 Aug 2008 19:47:06 +0200 Subject: NV50: enable hotplug irq --- linux-core/nv50_display.c | 6 ++++++ shared-core/nouveau_irq.c | 9 +++++++-- shared-core/nouveau_reg.h | 2 -- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index eeaa0e68..6665a32f 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -125,6 +125,9 @@ static int nv50_display_init(struct nv50_display *display) /* enable clock change interrupts. */ NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) | 0x70); + /* enable hotplug interrupts */ + NV_WRITE(NV50_PCONNECTOR_HOTPLUG_INTR, 0x7FFF7FFF); + display->init_done = true; return 0; @@ -171,6 +174,9 @@ static int nv50_display_disable(struct nv50_display *display) /* disable clock change interrupts. */ NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) & ~0x70); + /* disable hotplug interrupts */ + NV_WRITE(NV50_PCONNECTOR_HOTPLUG_INTR, 0); + display->init_done = false; return 0; diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 4c46da8d..5b700915 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -41,6 +41,8 @@ #include "nv50_display.h" #include "nv50_crtc.h" #include "nv50_output.h" +/* needed for hotplug irq */ +#include "nv50_kms_wrapper.h" void nouveau_irq_preinstall(struct drm_device *dev) @@ -591,10 +593,13 @@ nouveau_nv50_i2c_irq_handler(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - DRM_INFO("NV50_I2C_INTR - 0x%08X\n", NV_READ(NV50_I2C_CONTROLLER)); + DRM_INFO("NV50_I2C_INTR - 0x%08X\n", NV_READ(NV50_PCONNECTOR_HOTPLUG_CTRL)); /* This seems to be the way to acknowledge an interrupt. */ - NV_WRITE(NV50_I2C_CONTROLLER, 0x7FFF7FFF); + NV_WRITE(NV50_PCONNECTOR_HOTPLUG_CTRL, 0x7FFF7FFF); + + /* Do a "dumb" detect all */ + nv50_kms_connector_detect_all(dev); } irqreturn_t diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 6ed23e26..091c22c4 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -128,8 +128,6 @@ #define NV04_PTIMER_TIME_1 0x00009410 #define NV04_PTIMER_ALARM_0 0x00009420 -#define NV50_I2C_CONTROLLER 0x0000E054 - #define NV04_PFB_CFG0 0x00100200 #define NV04_PFB_CFG1 0x00100204 #define NV40_PFB_020C 0x0010020C -- cgit v1.2.3 From 9a2adc442af9d83b85e4d558cb5e4d33597b60b9 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 9 Aug 2008 19:50:00 +0200 Subject: NV50: minor changes --- shared-core/nouveau_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 5b700915..48872622 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -512,7 +512,7 @@ nouveau_nv50_display_irq_handler(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t val = NV_READ(NV50_PDISPLAY_SUPERVISOR); - DRM_INFO("NV50_DISPLAY_INTR - 0x%08X\n", val); + DRM_INFO("NV50_PDISPLAY_SUPERVISOR - 0x%08X\n", val); /* vblank interrupts */ if (val & NV50_PDISPLAY_SUPERVISOR_CRTCn) { @@ -593,7 +593,7 @@ nouveau_nv50_i2c_irq_handler(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - DRM_INFO("NV50_I2C_INTR - 0x%08X\n", NV_READ(NV50_PCONNECTOR_HOTPLUG_CTRL)); + DRM_INFO("NV50_PCONNECTOR_HOTPLUG_CTRL - 0x%08X\n", NV_READ(NV50_PCONNECTOR_HOTPLUG_CTRL)); /* This seems to be the way to acknowledge an interrupt. */ NV_WRITE(NV50_PCONNECTOR_HOTPLUG_CTRL, 0x7FFF7FFF); -- cgit v1.2.3 From e9648e9107e90c3ef38a9c9ebb95bac1297d0df5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 12 Aug 2008 18:22:34 -0700 Subject: Export a generic dri_bo handle for use by clients We'll need something like this (either a handle field or a dri_bo_get_handle function) for kernel mode setting to get at the handles. --- libdrm/dri_bufmgr.h | 4 ++++ libdrm/intel/intel_bufmgr_gem.c | 1 + 2 files changed, 5 insertions(+) diff --git a/libdrm/dri_bufmgr.h b/libdrm/dri_bufmgr.h index a5ae6c0f..7a7dd6e9 100644 --- a/libdrm/dri_bufmgr.h +++ b/libdrm/dri_bufmgr.h @@ -58,6 +58,10 @@ struct _dri_bo { void *virtual; /** Buffer manager context associated with this buffer object */ dri_bufmgr *bufmgr; + /** + * MM-specific handle for accessing object + */ + int handle; }; /** diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 22f8695d..02b1b252 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -311,6 +311,7 @@ dri_gem_bo_alloc(dri_bufmgr *bufmgr, const char *name, ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_CREATE, &create); bo_gem->gem_handle = create.handle; + bo_gem->bo.handle = bo_gem->gem_handle; if (ret != 0) { free(bo_gem); return NULL; -- cgit v1.2.3 From 085df6491e4975681a6e17ff9a67d01268aa7553 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 12 Aug 2008 18:23:58 -0700 Subject: Add error checking to framebuffer creation Make the Intel routine return an error if needed and make the core check for it. --- linux-core/drm_crtc.c | 4 +++- linux-core/intel_display.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 8375bf9a..aa6749d6 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -285,7 +285,9 @@ struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, struct drm_framebuffer *drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_framebuffer_funcs *funcs) { - drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); + if(drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB)) + return NULL; + fb->dev = dev; fb->funcs = funcs; dev->mode_config.num_fb++; diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 0236bbc9..fbe06f7c 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1506,7 +1506,9 @@ struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, if (!intel_fb) return NULL; - drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); + if (!drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs)) + return NULL; + drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); if (filp) { -- cgit v1.2.3 From 1c6abcefdc37f5cbb447e8fee1f3805fd7d19bea Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 13 Aug 2008 11:39:22 -0700 Subject: i915: setup hardware status page if physical addrs are required Needed for the modesetting case where we initialize the ring at load time. --- shared-core/i915_init.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 4f2d3a4f..b21351c0 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -100,6 +100,32 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, return 0; } +static int +i915_init_hws_phys(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret = 0; + + dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, + 0xffffffff); + + if (!dev_priv->status_page_dmah) { + DRM_ERROR("Can not allocate hardware status page\n"); + ret = -ENOMEM; + goto out; + } + dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr; + dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + + I915_WRITE(HWS_PGA, dev_priv->dma_status_page); + DRM_DEBUG("hws kernel virt: 0x%p\n", dev_priv->hw_status_page); + +out: + return ret; +} + static int i915_load_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -113,6 +139,9 @@ static int i915_load_modeset_init(struct drm_device *dev) /* Let GEM Manage from end of prealloc space to end of aperture */ i915_gem_do_init(dev, prealloc_size, agp_size); + if (!I915_NEED_GFX_HWS(dev)) + i915_init_hws_phys(dev); + ret = i915_gem_init_ringbuffer(dev); if (ret) goto out; @@ -354,6 +383,8 @@ int i915_driver_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); drm_mm_takedown(&dev_priv->vram); i915_gem_lastclose(dev); + if (!I915_NEED_GFX_HWS(dev)) + drm_pci_free(dev, dev_priv->status_page_dmah); } drm_rmmap(dev, dev_priv->mmio_map); -- cgit v1.2.3 From 957c71ff52e93bb2c1bc01b99d29d763d0ef3899 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 09:10:11 +1000 Subject: radeon: FEDORA: add old DMA buffers on top of GEM This really shouldn't go upstream, it just lets me run the old 3D driver on GEM setup system --- linux-core/drm_bufs.c | 4 + linux-core/drm_dma.c | 2 + linux-core/drm_drv.c | 2 +- linux-core/drm_fops.c | 7 +- linux-core/drm_memory.c | 1 + linux-core/radeon_gem.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_drv.h | 3 + 7 files changed, 263 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index e9052570..c966badc 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -1528,6 +1528,7 @@ int drm_mapbufs(struct drm_device *dev, void *data, dev->buf_use++; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); + DRM_DEBUG("dma buf count %d, req count %d\n", request->count, dma->buf_count); if (request->count >= dma->buf_count) { if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || (drm_core_check_feature(dev, DRIVER_SG) @@ -1538,10 +1539,12 @@ int drm_mapbufs(struct drm_device *dev, void *data, unsigned long token = dev->agp_buffer_token; if (!map) { + DRM_DEBUG("No map\n"); retcode = -EINVAL; goto done; } down_write(¤t->mm->mmap_sem); + DRM_DEBUG("%x %d\n", token, map->size); virtual = do_mmap(file_priv->filp, 0, map->size, PROT_READ | PROT_WRITE, MAP_SHARED, @@ -1555,6 +1558,7 @@ int drm_mapbufs(struct drm_device *dev, void *data, up_write(¤t->mm->mmap_sem); } if (virtual > -1024UL) { + DRM_DEBUG("mmap failed\n"); /* Real error */ retcode = (signed long)virtual; goto done; diff --git a/linux-core/drm_dma.c b/linux-core/drm_dma.c index f7bff0ac..1e6aeefd 100644 --- a/linux-core/drm_dma.c +++ b/linux-core/drm_dma.c @@ -58,6 +58,7 @@ int drm_dma_setup(struct drm_device *dev) return 0; } +EXPORT_SYMBOL(drm_dma_setup); /** * Cleanup the DMA resources. @@ -120,6 +121,7 @@ void drm_dma_takedown(struct drm_device *dev) drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); dev->dma = NULL; } +EXPORT_SYMBOL(drm_dma_takedown); /** * Free a buffer. diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 2a6bebd7..7c43fd00 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -250,7 +250,7 @@ int drm_lastclose(struct drm_device * dev) } dev->queue_count = 0; - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !drm_core_check_feature(dev, DRIVER_MODESET)) drm_dma_takedown(dev); dev->dev_mapping = NULL; diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index f45d5e46..7bc73d26 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -54,10 +54,11 @@ static int drm_setup(struct drm_device * dev) atomic_set(&dev->ioctl_count, 0); atomic_set(&dev->vma_count, 0); - dev->buf_use = 0; - atomic_set(&dev->buf_alloc, 0); - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) { + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !drm_core_check_feature(dev, DRIVER_MODESET)) { + dev->buf_use = 0; + atomic_set(&dev->buf_alloc, 0); + i = drm_dma_setup(dev); if (i < 0) return i; diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c index 4b494f9c..a663e965 100644 --- a/linux-core/drm_memory.c +++ b/linux-core/drm_memory.c @@ -188,6 +188,7 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) } return pt; } +EXPORT_SYMBOL(drm_realloc); /** * Allocate pages. diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 1ee48514..250e6852 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -29,6 +29,8 @@ static int radeon_gem_ib_init(struct drm_device *dev); static int radeon_gem_ib_destroy(struct drm_device *dev); +static int radeon_gem_dma_bufs_init(struct drm_device *dev); +static void radeon_gem_dma_bufs_destroy(struct drm_device *dev); int radeon_gem_init_object(struct drm_gem_object *obj) { @@ -608,6 +610,7 @@ int radeon_alloc_gart_objects(struct drm_device *dev) /* init the indirect buffers */ radeon_gem_ib_init(dev); + radeon_gem_dma_bufs_init(dev); return 0; } @@ -650,6 +653,7 @@ void radeon_gem_mm_fini(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; + radeon_gem_dma_bufs_destroy(dev); radeon_gem_ib_destroy(dev); mutex_lock(&dev->struct_mutex); @@ -878,3 +882,247 @@ free_all: return -ENOMEM; } +#define RADEON_DMA_BUFFER_SIZE (64 * 1024) +#define RADEON_DMA_BUFFER_COUNT (16) + + +/** + * Cleanup after an error on one of the addbufs() functions. + * + * \param dev DRM device. + * \param entry buffer entry where the error occurred. + * + * Frees any pages and buffers associated with the given entry. + */ +static void drm_cleanup_buf_error(struct drm_device * dev, + struct drm_buf_entry * entry) +{ + int i; + + if (entry->seg_count) { + for (i = 0; i < entry->seg_count; i++) { + if (entry->seglist[i]) { + drm_pci_free(dev, entry->seglist[i]); + } + } + drm_free(entry->seglist, + entry->seg_count * + sizeof(*entry->seglist), DRM_MEM_SEGS); + + entry->seg_count = 0; + } + + if (entry->buf_count) { + for (i = 0; i < entry->buf_count; i++) { + if (entry->buflist[i].dev_private) { + drm_free(entry->buflist[i].dev_private, + entry->buflist[i].dev_priv_size, + DRM_MEM_BUFS); + } + } + drm_free(entry->buflist, + entry->buf_count * + sizeof(*entry->buflist), DRM_MEM_BUFS); + + entry->buf_count = 0; + } +} + +static int radeon_gem_addbufs(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_device_dma *dma = dev->dma; + struct drm_buf_entry *entry; + struct drm_buf *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + struct drm_buf **temp_buflist; + + if (!dma) + return -EINVAL; + + count = RADEON_DMA_BUFFER_COUNT; + order = drm_order(RADEON_DMA_BUFFER_SIZE); + size = 1 << order; + + alignment = PAGE_ALIGN(size); + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + byte_count = 0; + agp_offset = dev_priv->mm.dma_bufs.bo->offset; + + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %lu\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) + return -EINVAL; + if (dev->queue_count) + return -EBUSY; /* Not while in use */ + + spin_lock(&dev->count_lock); + if (dev->buf_use) { + spin_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + spin_unlock(&dev->count_lock); + + mutex_lock(&dev->struct_mutex); + entry = &dma->bufs[order]; + if (entry->buf_count) { + mutex_unlock(&dev->struct_mutex); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + if (count < 0 || count > 4096) { + mutex_unlock(&dev->struct_mutex); + atomic_dec(&dev->buf_alloc); + return -EINVAL; + } + + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), + DRM_MEM_BUFS); + if (!entry->buflist) { + mutex_unlock(&dev->struct_mutex); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + memset(entry->buflist, 0, count * sizeof(*entry->buflist)); + + entry->buf_size = size; + entry->page_order = page_order; + + offset = 0; + + while (entry->buf_count < count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + + buf->offset = (dma->byte_count + offset); + buf->bus_address = dev_priv->gart_vm_start + agp_offset + offset; + buf->address = (void *)(agp_offset + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head(&buf->dma_wait); + buf->file_priv = NULL; + + buf->dev_priv_size = dev->driver->dev_priv_size; + buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); + if (!buf->dev_private) { + /* Set count correctly so we free the proper amount. */ + entry->buf_count = count; + drm_cleanup_buf_error(dev, entry); + mutex_unlock(&dev->struct_mutex); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + + memset(buf->dev_private, 0, buf->dev_priv_size); + + DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); + + offset += alignment; + entry->buf_count++; + byte_count += PAGE_SIZE << page_order; + } + + DRM_DEBUG("byte_count: %d\n", byte_count); + + temp_buflist = drm_realloc(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), DRM_MEM_BUFS); + if (!temp_buflist) { + /* Free the entry because it isn't valid */ + drm_cleanup_buf_error(dev, entry); + mutex_unlock(&dev->struct_mutex); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + dma->buflist = temp_buflist; + + for (i = 0; i < entry->buf_count; i++) { + dma->buflist[i + dma->buf_count] = &entry->buflist[i]; + } + + dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += byte_count >> PAGE_SHIFT; + dma->byte_count += byte_count; + + DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); + DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); + + mutex_unlock(&dev->struct_mutex); + + dma->flags = _DRM_DMA_USE_SG; + atomic_dec(&dev->buf_alloc); + return 0; +} + +static int radeon_gem_dma_bufs_init(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int size = RADEON_DMA_BUFFER_SIZE * RADEON_DMA_BUFFER_COUNT; + int ret; + + ret = drm_dma_setup(dev); + if (ret < 0) + return ret; + + ret = drm_buffer_object_create(dev, size, drm_bo_type_device, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_NO_EVICT | + DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MAPPABLE, 0, + 0, 0, &dev_priv->mm.dma_bufs.bo); + if (ret) { + DRM_ERROR("Failed to create DMA bufs\n"); + return -ENOMEM; + } + + ret = drm_bo_kmap(dev_priv->mm.dma_bufs.bo, 0, size >> PAGE_SHIFT, + &dev_priv->mm.dma_bufs.kmap); + if (ret) { + DRM_ERROR("Failed to mmap DMA buffers\n"); + return -ENOMEM; + } + DRM_DEBUG("\n"); + radeon_gem_addbufs(dev); + + DRM_DEBUG("%x %d\n", dev_priv->mm.dma_bufs.bo->map_list.hash.key, size); + dev->agp_buffer_token = dev_priv->mm.dma_bufs.bo->map_list.hash.key << PAGE_SHIFT; + dev_priv->mm.fake_agp_map.handle = dev_priv->mm.dma_bufs.kmap.virtual; + dev_priv->mm.fake_agp_map.size = size; + + dev->agp_buffer_map = &dev_priv->mm.fake_agp_map; + + return 0; +} + +static void radeon_gem_dma_bufs_destroy(struct drm_device *dev) +{ + + struct drm_radeon_private *dev_priv = dev->dev_private; + drm_dma_takedown(dev); + + drm_bo_kunmap(&dev_priv->mm.dma_bufs.kmap); + drm_bo_usage_deref_unlocked(&dev_priv->mm.dma_bufs.bo); +} diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 51a5b00c..138db794 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -277,6 +277,9 @@ struct radeon_mm_info { struct radeon_mm_obj pcie_table; struct radeon_mm_obj ring; struct radeon_mm_obj ring_read; + + struct radeon_mm_obj dma_bufs; + struct drm_map fake_agp_map; }; #include "radeon_mode.h" -- cgit v1.2.3 From d59f41b8cf0634a433be7d11f6b473035060c5e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 09:11:15 +1000 Subject: radeon: add userspace call for mm support check --- shared-core/radeon_state.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index e168ea02..01ee71f6 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3121,6 +3121,9 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil /* BSD TODO */ value = 1; break; + case RADEON_PARAM_KERNEL_MM: + value = !dev_priv->mm_disabled; + break; default: DRM_DEBUG( "Invalid parameter %d\n", param->param ); return -EINVAL; -- cgit v1.2.3 From 18020e5e9647e218caf8f1566cdc053aac126f23 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 09:12:36 +1000 Subject: radeon: make buffer swap for older drivers work again on GEM --- linux-core/radeon_gem.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_drv.h | 1 + shared-core/radeon_state.c | 3 +++ 3 files changed, 51 insertions(+) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 250e6852..058131e9 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1126,3 +1126,50 @@ static void radeon_gem_dma_bufs_destroy(struct drm_device *dev) drm_bo_kunmap(&dev_priv->mm.dma_bufs.kmap); drm_bo_usage_deref_unlocked(&dev_priv->mm.dma_bufs.bo); } + + +static struct drm_gem_object *gem_object_get(struct drm_device *dev, uint32_t name) +{ + struct drm_gem_object *obj; + + spin_lock(&dev->object_name_lock); + obj = idr_find(&dev->object_name_idr, name); + if (obj) + drm_gem_object_reference(obj); + spin_unlock(&dev->object_name_lock); + return obj; +} + +void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + + /* update front_pitch_offset and back_pitch_offset */ + DRM_ERROR("old front %x back %x\n", dev_priv->front_pitch_offset, dev_priv->back_pitch_offset); + obj = gem_object_get(dev, sarea_priv->front_handle); + if (obj) { + obj_priv = obj->driver_private; + + dev_priv->front_offset = obj_priv->bo->offset; + dev_priv->front_pitch_offset = (((sarea_priv->front_pitch / 64) << 22) | + ((obj_priv->bo->offset + + dev_priv->fb_location) >> 10)); + drm_gem_object_unreference(obj); + } + + obj = gem_object_get(dev, sarea_priv->back_handle); + if (obj) { + obj_priv = obj->driver_private; + dev_priv->back_offset = obj_priv->bo->offset; + dev_priv->back_pitch_offset = (((sarea_priv->back_pitch / 64) << 22) | + ((obj_priv->bo->offset + + dev_priv->fb_location) >> 10)); + drm_gem_object_unreference(obj); + } + dev_priv->color_fmt = RADEON_COLOR_FORMAT_ARGB8888; + +} diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 138db794..aa5b4ba8 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1664,6 +1664,7 @@ extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *mas extern void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master); extern int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv); extern int radeon_cs_init(struct drm_device *dev); +void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master); #define MARK_SAFE 1 #define MARK_CHECK_OFFSET 2 diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 01ee71f6..1a828be8 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -2223,6 +2223,9 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; + if (dev_priv->mm.vram_offset) + radeon_gem_update_offsets(dev, file_priv->master); + radeon_cp_dispatch_swap(dev, file_priv->master); sarea_priv->ctx_owner = 0; -- cgit v1.2.3 From b0ee12e6bb55655c92184483a065780529c8aa63 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 09:14:14 +1000 Subject: radeon: use mm_enabled variable to denote memory manager running --- linux-core/radeon_gem.c | 5 ++++- shared-core/radeon_drv.h | 2 +- shared-core/radeon_state.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 058131e9..ebba3cfe 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -645,7 +645,7 @@ int radeon_gem_mm_init(struct drm_device *dev) if (ret) return -EINVAL; - + dev_priv->mm_enabled = true; return 0; } @@ -685,6 +685,9 @@ void radeon_gem_mm_fini(struct drm_device *dev) } mutex_unlock(&dev->struct_mutex); + + drm_bo_driver_finish(dev); + dev_priv->mm_enabled = false; } int radeon_gem_object_pin(struct drm_gem_object *obj, diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index aa5b4ba8..df08b8d3 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -399,7 +399,7 @@ typedef struct drm_radeon_private { int num_gb_pipes; - int mm_disabled; /* on OSes with no MM this will be 1*/ + bool mm_enabled; struct radeon_mm_info mm; drm_local_map_t *mmio; diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 1a828be8..4520a35d 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3125,7 +3125,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil value = 1; break; case RADEON_PARAM_KERNEL_MM: - value = !dev_priv->mm_disabled; + value = dev_priv->mm_enabled; break; default: DRM_DEBUG( "Invalid parameter %d\n", param->param ); -- cgit v1.2.3 From 58df2fa0ecc7e4dac83b4e7a72d70c3ea41c7ed2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 09:14:56 +1000 Subject: radeon: remove debugging --- linux-core/radeon_gem.c | 1 - shared-core/radeon_cs.c | 5 ----- 2 files changed, 6 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index ebba3cfe..4b9b1d38 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1152,7 +1152,6 @@ void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master struct drm_radeon_gem_object *obj_priv; /* update front_pitch_offset and back_pitch_offset */ - DRM_ERROR("old front %x back %x\n", dev_priv->front_pitch_offset, dev_priv->back_pitch_offset); obj = gem_object_get(dev, sarea_priv->front_handle); if (obj) { obj_priv = obj->driver_private; diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 33a8ccd4..d961189e 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -154,10 +154,7 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct break; } - - DRM_ERROR("New offset %x %x %x\n", packets[offset_dw+1], val, offset); packets[offset_dw + 1] = val; - return 0; } @@ -185,7 +182,6 @@ static int radeon_cs_relocate_packet3(struct drm_device *dev, struct drm_file *f offset >>= 10; val |= offset; - DRM_ERROR("New offset %x %x %x\n", packets[offset_dw+2], val, offset); packets[offset_dw + 2] = val; } default: @@ -215,7 +211,6 @@ static __inline__ int radeon_cs_check_offset(struct drm_device *dev, break; } - DRM_ERROR("Offset check %x %x\n", reg, offset); return 0; } -- cgit v1.2.3 From 0580785030714f10f624ad329354dc7c688c32ad Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 09:15:28 +1000 Subject: radeon: FEDORA: patch to make 3D driver work set gart buffers start --- linux-core/radeon_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 4b9b1d38..df4ed4ce 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1116,7 +1116,7 @@ static int radeon_gem_dma_bufs_init(struct drm_device *dev) dev_priv->mm.fake_agp_map.size = size; dev->agp_buffer_map = &dev_priv->mm.fake_agp_map; - + dev_priv->gart_buffers_offset = dev_priv->mm.dma_bufs.bo->offset + dev_priv->gart_vm_start; return 0; } -- cgit v1.2.3 From b167ccf10fffb3e0ae0be14fc3b168fcacc373d8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 09:17:43 +1000 Subject: radeon: fix kernel_mm properly --- shared-core/radeon_state.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 4520a35d..7262b2aa 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3120,10 +3120,6 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil case RADEON_PARAM_NUM_GB_PIPES: value = dev_priv->num_gb_pipes; break; - case RADEON_PARAM_KERNEL_MM: - /* BSD TODO */ - value = 1; - break; case RADEON_PARAM_KERNEL_MM: value = dev_priv->mm_enabled; break; -- cgit v1.2.3 From 7677c2dba5d06e888c742a607bc7f42d934043c6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 8 Aug 2008 19:36:46 -0400 Subject: on_each_cpu() compat fixup from krh --- linux-core/drm_compat.h | 8 ++++++++ linux-core/drm_ttm.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 19dc1f67..f1efc1fe 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -389,4 +389,12 @@ extern struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, unsigned long address, int *type); #endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) +#define drm_on_each_cpu(handler, data, wait) \ + on_each_cpu(handler, data, wait) +#else +#define drm_on_each_cpu(handler, data, wait) \ + on_each_cpu(handler, data, wait, 1) +#endif + #endif diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index b58a1ada..aa137dda 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -72,7 +72,7 @@ void drm_ttm_cache_flush(struct page *pages[], unsigned long num_pages) return; } #endif - if (on_each_cpu(drm_ttm_ipi_handler, NULL,1) != 0) + if (drm_on_each_cpu(drm_ttm_ipi_handler, NULL, 1) != 0) DRM_ERROR("Timed out waiting for drm cache flush.\n"); } EXPORT_SYMBOL(drm_ttm_cache_flush); -- cgit v1.2.3 From 5f427e9aaed76ec827b9523b4022205f5bd09a4a Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Aug 2008 12:29:42 -0400 Subject: Brute force port of legacy crtc/encoder code - removed save/init/restore chain with set functions --- linux-core/radeon_atombios.c | 22 +- linux-core/radeon_display.c | 2 +- linux-core/radeon_encoders.c | 4 +- linux-core/radeon_legacy_crtc.c | 997 ++++++++++++++++++++++-------------- linux-core/radeon_legacy_encoders.c | 857 ++++++++++++++++++++++++++----- linux-core/radeon_reg.h | 18 + shared-core/radeon_cp.c | 2 +- shared-core/radeon_drv.h | 2 +- 8 files changed, 1380 insertions(+), 524 deletions(-) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index ee628732..cdb001c1 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -94,7 +94,7 @@ static void radeon_atom_apply_quirks(struct drm_device *dev, int index) mode_info->bios_connector[index].ddc_i2c.valid = false; } } -} +} bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev) { @@ -146,7 +146,7 @@ bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device } mode_info->bios_connector[i].dac_type = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC; - + if ((i == ATOM_DEVICE_TV1_INDEX) || (i == ATOM_DEVICE_TV2_INDEX) || (i == ATOM_DEVICE_TV1_INDEX)) @@ -161,7 +161,7 @@ bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device mode_info->bios_connector[i].ddc_i2c = radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux); } else - mode_info->bios_connector[i].ddc_i2c = + mode_info->bios_connector[i].ddc_i2c = radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux); if (i == ATOM_DEVICE_DFP1_INDEX) @@ -243,7 +243,7 @@ bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device } } - + DRM_DEBUG("BIOS Connector table\n"); for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { if (!mode_info->bios_connector[i].valid) @@ -265,7 +265,7 @@ union firmware_info { ATOM_FIRMWARE_INFO_V1_3 info_13; ATOM_FIRMWARE_INFO_V1_4 info_14; }; - + bool radeon_atom_get_clock_info(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; @@ -284,8 +284,8 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) pll->reference_div = 0; pll->pll_out_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); - pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); - + pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); + if (pll->pll_out_min == 0) { if (radeon_is_avivo(dev_priv)) pll->pll_out_min = 64800; @@ -298,7 +298,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) pll->xclk = le16_to_cpu(firmware_info->info.usMaxPixelClock); - return true; + return true; } union lvds_info { @@ -330,7 +330,7 @@ void radeon_get_lvds_info(struct radeon_encoder *encoder) encoder->vblank = le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); encoder->hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); - encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); + encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); } void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable) @@ -342,7 +342,7 @@ void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable) int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating); args.ucEnable = enable; - + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } @@ -355,7 +355,7 @@ void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable) int index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt); args.ucEnable = enable; - + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 1e5233d2..97e9da55 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -336,7 +336,7 @@ bool radeon_setup_enc_conn(struct drm_device *dev) if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D)) { if (radeon_is_avivo(dev_priv)) - encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].dac_type); + encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].tmds_type); else { if (mode_info->bios_connector[i].tmds_type == TMDS_INT) encoder = radeon_encoder_legacy_tmds_int_add(dev, i); diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 9a2d63ea..04c57092 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -279,7 +279,7 @@ static void radeon_lvtma_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_ON: atombios_display_device_control(encoder, index, ATOM_ENABLE); break; - case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: atombios_display_device_control(encoder, index, ATOM_DISABLE); @@ -792,7 +792,7 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_ON: atombios_display_device_control(encoder, index, ATOM_ENABLE); break; - case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: atombios_display_device_control(encoder, index, ATOM_DISABLE); diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index eb005a07..6446f8cb 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -34,74 +34,6 @@ void radeon_restore_common_regs(struct drm_device *dev, struct radeon_legacy_sta /* don't need this yet */ } -void radeon_restore_crtc_registers(struct drm_device *dev, struct radeon_legacy_state *state) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; - - RADEON_WRITE(RADEON_CRTC_GEN_CNTL, state->crtc_gen_cntl | - RADEON_CRTC_DISP_REQ_EN_B); - - RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, state->crtc_ext_cntl, - RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_DISPLAY_DIS); - - RADEON_WRITE(RADEON_CRTC_H_TOTAL_DISP, state->crtc_h_total_disp); - RADEON_WRITE(RADEON_CRTC_H_SYNC_STRT_WID, state->crtc_h_sync_strt_wid); - RADEON_WRITE(RADEON_CRTC_V_TOTAL_DISP, state->crtc_v_total_disp); - RADEON_WRITE(RADEON_CRTC_V_SYNC_STRT_WID, state->crtc_v_sync_strt_wid); - - if (radeon_is_r300(dev_priv)) - RADEON_WRITE(R300_CRTC_TILE_X0_Y0, state->crtc_tile_x0_y0); - - RADEON_WRITE(RADEON_CRTC_OFFSET_CNTL, state->crtc_offset_cntl); - RADEON_WRITE(RADEON_CRTC_OFFSET, state->crtc_offset); - - RADEON_WRITE(RADEON_CRTC_PITCH, state->crtc_pitch); - RADEON_WRITE(RADEON_DISP_MERGE_CNTL, state->disp_merge_cntl); - - /* if dell server */ - if (0) - { - RADEON_WRITE(RADEON_TV_DAC_CNTL, state->tv_dac_cntl); - RADEON_WRITE(RADEON_DISP_HW_DEBUG, state->disp_hw_debug); - RADEON_WRITE(RADEON_DAC_CNTL2, state->dac2_cntl); - RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, state->crtc2_gen_cntl); - } - - RADEON_WRITE(RADEON_CRTC_GEN_CNTL, state->crtc_gen_cntl); -} - -void radeon_restore_crtc2_registers(struct drm_device *dev, struct radeon_legacy_state *state) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; - - /* We prevent the CRTC from hitting th - e memory controller until - * fully programmed - */ - RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, - state->crtc2_gen_cntl | RADEON_CRTC2_VSYNC_DIS | - RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS | - RADEON_CRTC2_DISP_REQ_EN_B); - - RADEON_WRITE(RADEON_CRTC2_H_TOTAL_DISP, state->crtc2_h_total_disp); - RADEON_WRITE(RADEON_CRTC2_H_SYNC_STRT_WID, state->crtc2_h_sync_strt_wid); - RADEON_WRITE(RADEON_CRTC2_V_TOTAL_DISP, state->crtc2_v_total_disp); - RADEON_WRITE(RADEON_CRTC2_V_SYNC_STRT_WID, state->crtc2_v_sync_strt_wid); - - RADEON_WRITE(RADEON_FP_H2_SYNC_STRT_WID, state->fp_h2_sync_strt_wid); - RADEON_WRITE(RADEON_FP_V2_SYNC_STRT_WID, state->fp_v2_sync_strt_wid); - - if (radeon_is_r300(dev_priv)) - RADEON_WRITE(R300_CRTC2_TILE_X0_Y0, state->crtc2_tile_x0_y0); - RADEON_WRITE(RADEON_CRTC2_OFFSET_CNTL, state->crtc2_offset_cntl); - RADEON_WRITE(RADEON_CRTC2_OFFSET, state->crtc2_offset); - - RADEON_WRITE(RADEON_CRTC2_PITCH, state->crtc2_pitch); - RADEON_WRITE(RADEON_DISP2_MERGE_CNTL, state->disp2_merge_cntl); - - RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, state->crtc2_gen_cntl); -} - static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; @@ -149,7 +81,7 @@ static void radeon_pll2_write_update(struct drm_device *dev) struct drm_radeon_private *dev_priv = dev->dev_private; while (RADEON_READ_PLL(dev_priv, RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R); - + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_REF_DIV, RADEON_P2PLL_ATOMIC_UPDATE_W, ~(RADEON_P2PLL_ATOMIC_UPDATE_W)); @@ -186,186 +118,6 @@ static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div, return 1; } -void radeon_restore_pll_registers(struct drm_device *dev, struct radeon_legacy_state *state) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; - uint8_t pll_gain; - - pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.pll.reference_freq, - state->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, - state->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK); - - if (dev_priv->flags & RADEON_IS_MOBILITY) { - /* A temporal workaround for the occational blanking on certain laptop panels. - This appears to related to the PLL divider registers (fail to lock?). - It occurs even when all dividers are the same with their old settings. - In this case we really don't need to fiddle with PLL registers. - By doing this we can avoid the blanking problem with some panels. - */ - if ((state->ppll_ref_div == (RADEON_READ_PLL(dev_priv, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && - (state->ppll_div_3 == (RADEON_READ_PLL(dev_priv, RADEON_PPLL_DIV_3) & - (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) { - RADEON_WRITE_P(RADEON_CLOCK_CNTL_INDEX, - RADEON_PLL_DIV_SEL, - ~(RADEON_PLL_DIV_SEL)); - radeon_pll_errata_after_index(dev_priv); - return; - } - } - - RADEON_WRITE_PLL_P(dev_priv, RADEON_VCLK_ECP_CNTL, - RADEON_VCLK_SRC_SEL_CPUCLK, - ~(RADEON_VCLK_SRC_SEL_MASK)); - - RADEON_WRITE_PLL_P(dev_priv, - RADEON_PPLL_CNTL, - RADEON_PPLL_RESET - | RADEON_PPLL_ATOMIC_UPDATE_EN - | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN - | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT), - ~(RADEON_PPLL_RESET - | RADEON_PPLL_ATOMIC_UPDATE_EN - | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN - | RADEON_PPLL_PVG_MASK)); - - RADEON_WRITE_P(RADEON_CLOCK_CNTL_INDEX, - RADEON_PLL_DIV_SEL, - ~(RADEON_PLL_DIV_SEL)); - radeon_pll_errata_after_index(dev_priv); - - if (radeon_is_r300(dev_priv) || - (dev_priv->chip_family == CHIP_RS300) || - (dev_priv->chip_family == CHIP_RS400) || - (dev_priv->chip_family == CHIP_RS480)) { - if (state->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { - /* When restoring console mode, use saved PPLL_REF_DIV - * setting. - */ - RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, - state->ppll_ref_div, - 0); - } else { - /* R300 uses ref_div_acc field as real ref divider */ - RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, - (state->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), - ~R300_PPLL_REF_DIV_ACC_MASK); - } - } else { - RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, - state->ppll_ref_div, - ~RADEON_PPLL_REF_DIV_MASK); - } - - RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_DIV_3, - state->ppll_div_3, - ~RADEON_PPLL_FB3_DIV_MASK); - - RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_DIV_3, - state->ppll_div_3, - ~RADEON_PPLL_POST3_DIV_MASK); - - radeon_pll_write_update(dev); - radeon_pll_wait_for_read_update_complete(dev); - - RADEON_WRITE_PLL(dev_priv, RADEON_HTOTAL_CNTL, state->htotal_cntl); - - RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_CNTL, - 0, - ~(RADEON_PPLL_RESET - | RADEON_PPLL_SLEEP - | RADEON_PPLL_ATOMIC_UPDATE_EN - | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); - - DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", - state->ppll_ref_div, - state->ppll_div_3, - (unsigned)state->htotal_cntl, - RADEON_READ_PLL(dev_priv, RADEON_PPLL_CNTL)); - DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n", - state->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, - state->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, - (state->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); - - mdelay(50); /* Let the clock to lock */ - - RADEON_WRITE_PLL_P(dev_priv, RADEON_VCLK_ECP_CNTL, - RADEON_VCLK_SRC_SEL_PPLLCLK, - ~(RADEON_VCLK_SRC_SEL_MASK)); - - /*RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, state->vclk_ecp_cntl);*/ - -} - -void radeon_restore_pll2_registers(struct drm_device *dev, struct radeon_legacy_state *state) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; - uint8_t pll_gain; - - pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.pll.reference_freq, - state->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, - state->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK); - - - RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, - RADEON_PIX2CLK_SRC_SEL_CPUCLK, - ~(RADEON_PIX2CLK_SRC_SEL_MASK)); - - RADEON_WRITE_PLL_P(dev_priv, - RADEON_P2PLL_CNTL, - RADEON_P2PLL_RESET - | RADEON_P2PLL_ATOMIC_UPDATE_EN - | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT), - ~(RADEON_P2PLL_RESET - | RADEON_P2PLL_ATOMIC_UPDATE_EN - | RADEON_P2PLL_PVG_MASK)); - - - RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_REF_DIV, - state->p2pll_ref_div, - ~RADEON_P2PLL_REF_DIV_MASK); - - RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_DIV_0, - state->p2pll_div_0, - ~RADEON_P2PLL_FB0_DIV_MASK); - - RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_DIV_0, - state->p2pll_div_0, - ~RADEON_P2PLL_POST0_DIV_MASK); - - radeon_pll2_write_update(dev); - radeon_pll2_wait_for_read_update_complete(dev); - - RADEON_WRITE_PLL(dev_priv, RADEON_HTOTAL2_CNTL, state->htotal_cntl2); - - RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_CNTL, - 0, - ~(RADEON_P2PLL_RESET - | RADEON_P2PLL_SLEEP - | RADEON_P2PLL_ATOMIC_UPDATE_EN)); - - DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", - (unsigned)state->p2pll_ref_div, - (unsigned)state->p2pll_div_0, - (unsigned)state->htotal_cntl2, - RADEON_READ_PLL(dev_priv, RADEON_P2PLL_CNTL)); - DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n", - (unsigned)state->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, - (unsigned)state->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK, - (unsigned)((state->p2pll_div_0 & - RADEON_P2PLL_POST0_DIV_MASK) >>16)); - - mdelay(50); /* Let the clock to lock */ - - RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, - RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, - ~(RADEON_PIX2CLK_SRC_SEL_MASK)); - - RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, state->pixclks_cntl); - - -} - - void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -374,7 +126,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) uint32_t mask; - mask = radeon_crtc->crtc_id ? + mask = radeon_crtc->crtc_id ? (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_REQ_EN_B) : (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS); @@ -412,46 +164,45 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } break; } - + if (mode != DRM_MODE_DPMS_OFF) { radeon_crtc_load_lut(crtc); } } -static bool radeon_init_crtc_base(struct drm_crtc *crtc, struct radeon_legacy_state *state, int x, int y) +static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) { - 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_radeon_private *dev_priv = dev->dev_private; struct radeon_framebuffer *radeon_fb; struct drm_radeon_gem_object *obj_priv; uint32_t base; + uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0; radeon_fb = to_radeon_framebuffer(crtc->fb); obj_priv = radeon_fb->obj->driver_private; - state->crtc_offset = obj_priv->bo->offset + dev_priv->fb_location; + crtc_offset = obj_priv->bo->offset; - state->crtc_offset_cntl = 0; + crtc_offset_cntl = 0; /* TODO tiling */ if (0) { - if (radeon_is_r300(dev_priv)) { - state->crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | - R300_CRTC_MICRO_TILE_BUFFER_DIS | - R300_CRTC_MACRO_TILE_EN); - } else { - state->crtc_offset_cntl |= RADEON_CRTC_TILE_EN; - } + if (radeon_is_r300(dev_priv)) + crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + crtc_offset_cntl |= RADEON_CRTC_TILE_EN; } else { - if (radeon_is_r300(dev_priv)) { - state->crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | - R300_CRTC_MICRO_TILE_BUFFER_DIS | - R300_CRTC_MACRO_TILE_EN); - } else { - state->crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; - } + if (radeon_is_r300(dev_priv)) + crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; } base = obj_priv->bo->offset; @@ -459,17 +210,29 @@ static bool radeon_init_crtc_base(struct drm_crtc *crtc, struct radeon_legacy_st /* TODO more tiling */ if (0) { if (radeon_is_r300(dev_priv)) { - state->crtc_tile_x0_y0 = x | (y << 16); - base &= ~0x7ff; - } else { - int byteshift = crtc->fb->bits_per_pixel >> 4; - int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11; - base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); - state->crtc_offset_cntl |= (y % 16); - } + crtc_tile_x0_y0 = x | (y << 16); + base &= ~0x7ff; + } else { + int byteshift = crtc->fb->bits_per_pixel >> 4; + int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11; + base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); + crtc_offset_cntl |= (y % 16); + } } else { int offset = y * crtc->fb->pitch + x; switch (crtc->fb->bits_per_pixel) { + case 15: + case 16: + offset *= 2; + break; + case 24: + offset *= 3; + break; + case 32: + offset *= 4; + break; + default: + return false; } base += offset; } @@ -478,86 +241,114 @@ static bool radeon_init_crtc_base(struct drm_crtc *crtc, struct radeon_legacy_st /* update sarea TODO */ - state->crtc_offset = base; + crtc_offset = base; + + if (radeon_is_r300(dev_priv)) + RADEON_WRITE(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0); + + RADEON_WRITE(RADEON_CRTC_OFFSET_CNTL, crtc_offset_cntl); + RADEON_WRITE(RADEON_CRTC_OFFSET, crtc_offset); + return true; } -static bool radeon_init_crtc_registers(struct drm_crtc *crtc, struct radeon_legacy_state *state, - struct drm_display_mode *mode) +static bool radeon_set_crtc1_timing(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_radeon_private *dev_priv = dev->dev_private; int format; int hsync_start; int hsync_wid; int vsync_wid; + uint32_t crtc_gen_cntl; + uint32_t crtc_ext_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_h_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_pitch; + uint32_t disp_merge_cntl; switch (crtc->fb->depth) { - case 15: format = 3; break; /* 555 */ - case 16: format = 4; break; /* 565 */ - case 24: format = 5; break; /* RGB */ - case 32: format = 6; break; /* xRGB */ + case 15: /* 555 */ + format = 3; + break; + case 16: /* 565 */ + format = 4; + break; + case 24: /* RGB */ + format = 5; + break; + case 32: /* xRGB */ + format = 6; + break; default: return false; } - state->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN - | RADEON_CRTC_EN - | (format << 8) - | ((mode->flags & DRM_MODE_FLAG_DBLSCAN) - ? RADEON_CRTC_DBL_SCAN_EN - : 0) - | ((mode->flags & DRM_MODE_FLAG_CSYNC) - ? RADEON_CRTC_CSYNC_EN - : 0) - | ((mode->flags & DRM_MODE_FLAG_INTERLACE) - ? RADEON_CRTC_INTERLACE_EN - : 0)); - - state->crtc_ext_cntl |= (RADEON_XCRT_CNT_EN| - RADEON_CRTC_VSYNC_DIS | - RADEON_CRTC_HSYNC_DIS | - RADEON_CRTC_DISPLAY_DIS); - - state->disp_merge_cntl = RADEON_READ(RADEON_DISP_MERGE_CNTL); - state->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; - - state->crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) - | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) - << 16)); + crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN + | RADEON_CRTC_EN + | (format << 8) + | ((mode->flags & DRM_MODE_FLAG_DBLSCAN) + ? RADEON_CRTC_DBL_SCAN_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_CSYNC) + ? RADEON_CRTC_CSYNC_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_INTERLACE) + ? RADEON_CRTC_INTERLACE_EN + : 0)); + + crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); + crtc_ext_cntl |= (RADEON_XCRT_CNT_EN| + RADEON_CRTC_VSYNC_DIS | + RADEON_CRTC_HSYNC_DIS | + RADEON_CRTC_DISPLAY_DIS); + + disp_merge_cntl = RADEON_READ(RADEON_DISP_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + + crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) + | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; - if (!hsync_wid) hsync_wid = 1; + if (!hsync_wid) + hsync_wid = 1; hsync_start = mode->crtc_hsync_start - 8; - state->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) - | ((hsync_wid & 0x3f) << 16) - | ((mode->flags & DRM_MODE_FLAG_NHSYNC) - ? RADEON_CRTC_H_SYNC_POL - : 0)); + crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); /* This works for double scan mode. */ - state->crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) - | ((mode->crtc_vdisplay - 1) << 16)); + crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) + | ((mode->crtc_vdisplay - 1) << 16)); vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; - if (!vsync_wid) vsync_wid = 1; + if (!vsync_wid) + vsync_wid = 1; - state->crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) - | ((vsync_wid & 0x1f) << 16) - | ((mode->flags & DRM_MODE_FLAG_NVSYNC) - ? RADEON_CRTC_V_SYNC_POL - : 0)); + crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0)); - state->crtc_pitch = (((crtc->fb->pitch * crtc->fb->bits_per_pixel) + - ((crtc->fb->bits_per_pixel * 8) -1)) / - (crtc->fb->bits_per_pixel * 8)); - state->crtc_pitch |= state->crtc_pitch << 16; + crtc_pitch = (((crtc->fb->pitch * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) -1)) / + (crtc->fb->bits_per_pixel * 8)); + crtc_pitch |= crtc_pitch << 16; /* TODO -> Dell Server */ if (0) { + uint32_t disp_hw_debug = RADEON_READ(RADEON_DISP_HW_DEBUG); + uint32_t tv_dac_cntl = RADEON_READ(RADEON_TV_DAC_CNTL); + uint32_t dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2); + uint32_t crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); // state->dac2_cntl = info->StatedReg->dac2_cntl; // state->tv_dac_cntl = info->StatedReg->tv_dac_cntl; // state->crtc2_gen_cntl = info->StatedReg->crtc2_gen_cntl; @@ -569,25 +360,53 @@ static bool radeon_init_crtc_registers(struct drm_crtc *crtc, struct radeon_lega /* For CRT on DAC2, don't turn it on if BIOS didn't enable it, even it's detected. */ - state->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; - state->tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16)); - state->tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16)); + disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16)); + tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16)); + + RADEON_WRITE(RADEON_TV_DAC_CNTL, tv_dac_cntl); + RADEON_WRITE(RADEON_DISP_HW_DEBUG, disp_hw_debug); + RADEON_WRITE(RADEON_DAC_CNTL2, dac2_cntl); + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); } + RADEON_WRITE(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl | + RADEON_CRTC_DISP_REQ_EN_B); + + RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl, + RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_DISPLAY_DIS); + + RADEON_WRITE(RADEON_CRTC_H_TOTAL_DISP, crtc_h_total_disp); + RADEON_WRITE(RADEON_CRTC_H_SYNC_STRT_WID, crtc_h_sync_strt_wid); + RADEON_WRITE(RADEON_CRTC_V_TOTAL_DISP, crtc_v_total_disp); + RADEON_WRITE(RADEON_CRTC_V_SYNC_STRT_WID, crtc_v_sync_strt_wid); + + RADEON_WRITE(RADEON_CRTC_PITCH, crtc_pitch); + RADEON_WRITE(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); + + RADEON_WRITE(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); + return true; } -static void radeon_init_pll_registers(struct drm_crtc *crtc, struct radeon_legacy_state *state, - struct drm_display_mode *mode, int flags) +static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode, int flags) { - 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_radeon_private *dev_priv = dev->dev_private; uint32_t feedback_div = 0; uint32_t reference_div = 0; uint32_t post_divider = 0; uint32_t freq = 0; + uint8_t pll_gain; + /* PLL registers */ + uint32_t ppll_ref_div; + uint32_t ppll_div_3; + uint32_t htotal_cntl; + uint32_t vclk_ecp_cntl; + struct radeon_pll *pll = &dev_priv->mode_info.pll; + struct { int divider; int bitvalue; @@ -607,12 +426,12 @@ static void radeon_init_pll_registers(struct drm_crtc *crtc, struct radeon_legac { 12, 7 }, /* VCLK_SRC/12 */ { 0, 0 } }; - + #if 0 // TODO if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) { - state->ppll_ref_div = info->RefDivider; - state->ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16); - state->htotal_cntl = 0; + ppll_ref_div = info->RefDivider; + ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16); + htotal_cntl = 0; return; } #endif @@ -626,23 +445,16 @@ static void radeon_init_pll_registers(struct drm_crtc *crtc, struct radeon_legac } if (!post_div->divider) { - state->pll_output_freq = freq; post_div = &post_divs[0]; } - - state->dot_clock_freq = freq; - state->feedback_div = feedback_div; - state->reference_div = reference_div; - state->post_div = post_divider; - DRM_DEBUG("dc=%u, of=%u, fd=%d, rd=%d, pd=%d\n", - (unsigned)state->dot_clock_freq, - (unsigned)state->pll_output_freq, - state->feedback_div, - state->reference_div, - state->post_div); + DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", + (unsigned)freq, + feedback_div, + reference_div, + post_divider); - state->ppll_ref_div = state->reference_div; + ppll_ref_div = reference_div; #if defined(__powerpc__) && (0) /* TODO */ /* apparently programming this otherwise causes a hang??? */ @@ -650,12 +462,451 @@ static void radeon_init_pll_registers(struct drm_crtc *crtc, struct radeon_legac state->ppll_div_3 = 0x000600ad; else #endif - state->ppll_div_3 = (state->feedback_div | (post_div->bitvalue << 16)); - - state->htotal_cntl = mode->htotal & 0x7; + ppll_div_3 = (feedback_div | (post_div->bitvalue << 16)); + + htotal_cntl = mode->htotal & 0x7; + + vclk_ecp_cntl = (RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL) & + ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK; + + pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.pll.reference_freq, + ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK); + + if (dev_priv->flags & RADEON_IS_MOBILITY) { + /* A temporal workaround for the occational blanking on certain laptop panels. + This appears to related to the PLL divider registers (fail to lock?). + It occurs even when all dividers are the same with their old settings. + In this case we really don't need to fiddle with PLL registers. + By doing this we can avoid the blanking problem with some panels. + */ + if ((ppll_ref_div == (RADEON_READ_PLL(dev_priv, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && + (ppll_div_3 == (RADEON_READ_PLL(dev_priv, RADEON_PPLL_DIV_3) & + (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) { + RADEON_WRITE_P(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + radeon_pll_errata_after_index(dev_priv); + return; + } + } + + RADEON_WRITE_PLL_P(dev_priv, RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_CPUCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + RADEON_WRITE_PLL_P(dev_priv, + RADEON_PPLL_CNTL, + RADEON_PPLL_RESET + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN + | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT), + ~(RADEON_PPLL_RESET + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN + | RADEON_PPLL_PVG_MASK)); + + RADEON_WRITE_P(RADEON_CLOCK_CNTL_INDEX, + RADEON_PLL_DIV_SEL, + ~(RADEON_PLL_DIV_SEL)); + radeon_pll_errata_after_index(dev_priv); + + if (radeon_is_r300(dev_priv) || + (dev_priv->chip_family == CHIP_RS300) || + (dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) { + if (ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { + /* When restoring console mode, use saved PPLL_REF_DIV + * setting. + */ + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, + ppll_ref_div, + 0); + } else { + /* R300 uses ref_div_acc field as real ref divider */ + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, + (ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), + ~R300_PPLL_REF_DIV_ACC_MASK); + } + } else { + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_REF_DIV, + ppll_ref_div, + ~RADEON_PPLL_REF_DIV_MASK); + } + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_DIV_3, + ppll_div_3, + ~RADEON_PPLL_FB3_DIV_MASK); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_DIV_3, + ppll_div_3, + ~RADEON_PPLL_POST3_DIV_MASK); + + radeon_pll_write_update(dev); + radeon_pll_wait_for_read_update_complete(dev); + + RADEON_WRITE_PLL(dev_priv, RADEON_HTOTAL_CNTL, htotal_cntl); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PPLL_CNTL, + 0, + ~(RADEON_PPLL_RESET + | RADEON_PPLL_SLEEP + | RADEON_PPLL_ATOMIC_UPDATE_EN + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); + + DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + ppll_ref_div, + ppll_div_3, + (unsigned)htotal_cntl, + RADEON_READ_PLL(dev_priv, RADEON_PPLL_CNTL)); + DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n", + ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK, + (ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16); + + mdelay(50); /* Let the clock to lock */ + + RADEON_WRITE_PLL_P(dev_priv, RADEON_VCLK_ECP_CNTL, + RADEON_VCLK_SRC_SEL_PPLLCLK, + ~(RADEON_VCLK_SRC_SEL_MASK)); + + /*RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, state->vclk_ecp_cntl);*/ + +} + +static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_framebuffer *radeon_fb; + struct drm_radeon_gem_object *obj_priv; + uint32_t crtc2_offset, crtc2_offset_cntl, crtc2_tile_x0_y0 = 0; + uint32_t base; + + radeon_fb = to_radeon_framebuffer(crtc->fb); + + obj_priv = radeon_fb->obj->driver_private; + + crtc2_offset = obj_priv->bo->offset; + + crtc2_offset_cntl = 0; + + /* TODO tiling */ + if (0) { + if (radeon_is_r300(dev_priv)) + crtc2_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + crtc2_offset_cntl |= RADEON_CRTC_TILE_EN; + } else { + if (radeon_is_r300(dev_priv)) + crtc2_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + crtc2_offset_cntl &= ~RADEON_CRTC_TILE_EN; + } + + base = obj_priv->bo->offset; + + /* TODO more tiling */ + if (0) { + if (radeon_is_r300(dev_priv)) { + crtc2_tile_x0_y0 = x | (y << 16); + base &= ~0x7ff; + } else { + int byteshift = crtc->fb->bits_per_pixel >> 4; + int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11; + base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); + crtc2_offset_cntl |= (y % 16); + } + } else { + int offset = y * crtc->fb->pitch + x; + switch (crtc->fb->bits_per_pixel) { + case 15: + case 16: + offset *= 2; + break; + case 24: + offset *= 3; + break; + case 32: + offset *= 4; + break; + default: + return false; + } + base += offset; + } + + base &= ~7; + + /* update sarea TODO */ + + crtc2_offset = base; + + if (radeon_is_r300(dev_priv)) + RADEON_WRITE(R300_CRTC2_TILE_X0_Y0, crtc2_tile_x0_y0); + RADEON_WRITE(RADEON_CRTC2_OFFSET_CNTL, crtc2_offset_cntl); + RADEON_WRITE(RADEON_CRTC2_OFFSET, crtc2_offset); + + return true; +} + +static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + int format; + int hsync_start; + int hsync_wid; + int vsync_wid; + uint32_t crtc2_gen_cntl; + uint32_t crtc2_h_total_disp; + uint32_t crtc2_h_sync_strt_wid; + uint32_t crtc2_v_total_disp; + uint32_t crtc2_v_sync_strt_wid; + uint32_t crtc2_pitch; + uint32_t disp2_merge_cntl; + uint32_t fp_h2_sync_strt_wid; + uint32_t fp_v2_sync_strt_wid; + + switch (crtc->fb->depth) { + + case 15: /* 555 */ + format = 3; + break; + case 16: /* 565 */ + format = 4; + break; + case 24: /* RGB */ + format = 5; + break; + case 32: /* xRGB */ + format = 6; + break; + default: + return false; + } + + crtc2_h_total_disp = + ((((mode->crtc_htotal / 8) - 1) & 0x3ff) + | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); + + hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; + if (!hsync_wid) + hsync_wid = 1; + hsync_start = mode->crtc_hsync_start - 8; + + crtc2_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + /* This works for double scan mode. */ + crtc2_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) + | ((mode->crtc_vdisplay - 1) << 16)); + + vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; + if (!vsync_wid) + vsync_wid = 1; + + crtc2_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NVSYNC) + ? RADEON_CRTC2_V_SYNC_POL + : 0)); + + crtc2_pitch = (((crtc->fb->pitch * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) -1)) / + (crtc->fb->bits_per_pixel * 8)); + crtc2_pitch |= crtc2_pitch << 16; + + /* check to see if TV DAC is enabled for another crtc and keep it enabled */ + if (RADEON_READ(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_CRT2_ON) + crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON; + else + crtc2_gen_cntl = 0; + + crtc2_gen_cntl |= (RADEON_CRTC2_EN + | (format << 8) + | RADEON_CRTC2_VSYNC_DIS + | RADEON_CRTC2_HSYNC_DIS + | RADEON_CRTC2_DISP_DIS + | ((mode->flags & DRM_MODE_FLAG_DBLSCAN) + ? RADEON_CRTC2_DBL_SCAN_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_CSYNC) + ? RADEON_CRTC2_CSYNC_EN + : 0) + | ((mode->flags & DRM_MODE_FLAG_INTERLACE) + ? RADEON_CRTC2_INTERLACE_EN + : 0)); + + disp2_merge_cntl = RADEON_READ(RADEON_DISP2_MERGE_CNTL); + disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; + + fp_h2_sync_strt_wid = crtc2_h_sync_strt_wid; + fp_v2_sync_strt_wid = crtc2_v_sync_strt_wid; + + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, + crtc2_gen_cntl | RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS | + RADEON_CRTC2_DISP_REQ_EN_B); + + RADEON_WRITE(RADEON_CRTC2_H_TOTAL_DISP, crtc2_h_total_disp); + RADEON_WRITE(RADEON_CRTC2_H_SYNC_STRT_WID, crtc2_h_sync_strt_wid); + RADEON_WRITE(RADEON_CRTC2_V_TOTAL_DISP, crtc2_v_total_disp); + RADEON_WRITE(RADEON_CRTC2_V_SYNC_STRT_WID, crtc2_v_sync_strt_wid); + + RADEON_WRITE(RADEON_FP_H2_SYNC_STRT_WID, fp_h2_sync_strt_wid); + RADEON_WRITE(RADEON_FP_V2_SYNC_STRT_WID, fp_v2_sync_strt_wid); + + RADEON_WRITE(RADEON_CRTC2_PITCH, crtc2_pitch); + RADEON_WRITE(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); + + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + + return true; + +} + +static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode, int flags) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t feedback_div = 0; + uint32_t reference_div = 0; + uint32_t post_divider = 0; + uint32_t freq = 0; + uint8_t pll_gain; + /* PLL2 registers */ + uint32_t p2pll_ref_div; + uint32_t p2pll_div_0; + uint32_t htotal_cntl2; + uint32_t pixclks_cntl; + + struct radeon_pll *pll = &dev_priv->mode_info.pll; + + struct { + int divider; + int bitvalue; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + +#if 0 + if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) { + p2pll_ref_div = info->RefDivider; + p2pll_div_0 = info->FeedbackDivider | (info->PostDivider << 16); + htotal_cntl2 = 0; + return; + } +#endif - state->vclk_ecp_cntl = (RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL) & - ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK; + radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &reference_div, &post_divider, flags); + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + if (post_div->divider == post_divider) + break; + } + + if (!post_div->divider) { + post_div = &post_divs[0]; + } + + DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", + (unsigned)freq, + feedback_div, + reference_div, + post_divider); + + p2pll_ref_div = reference_div; + + p2pll_div_0 = (feedback_div | (post_div->bitvalue << 16)); + + htotal_cntl2 = mode->htotal & 0x7; + + pixclks_cntl = ((RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL) & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); + + pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.pll.reference_freq, + p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK); + + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_CPUCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + + RADEON_WRITE_PLL_P(dev_priv, + RADEON_P2PLL_CNTL, + RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT), + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | RADEON_P2PLL_PVG_MASK)); + + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_REF_DIV, + p2pll_ref_div, + ~RADEON_P2PLL_REF_DIV_MASK); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_DIV_0, + p2pll_div_0, + ~RADEON_P2PLL_FB0_DIV_MASK); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_DIV_0, + p2pll_div_0, + ~RADEON_P2PLL_POST0_DIV_MASK); + + radeon_pll2_write_update(dev); + radeon_pll2_wait_for_read_update_complete(dev); + + RADEON_WRITE_PLL(dev_priv, RADEON_HTOTAL2_CNTL, htotal_cntl2); + + RADEON_WRITE_PLL_P(dev_priv, RADEON_P2PLL_CNTL, + 0, + ~(RADEON_P2PLL_RESET + | RADEON_P2PLL_SLEEP + | RADEON_P2PLL_ATOMIC_UPDATE_EN)); + + DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + (unsigned)p2pll_ref_div, + (unsigned)p2pll_div_0, + (unsigned)htotal_cntl2, + RADEON_READ_PLL(dev_priv, RADEON_P2PLL_CNTL)); + DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n", + (unsigned)p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + (unsigned)p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK, + (unsigned)((p2pll_div_0 & + RADEON_P2PLL_POST0_DIV_MASK) >>16)); + + mdelay(50); /* Let the clock to lock */ + + RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, + ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, pixclks_cntl); } @@ -671,7 +922,7 @@ static void radeon_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, int x, int y) { - 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_radeon_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; @@ -689,46 +940,44 @@ static void radeon_crtc_mode_set(struct drm_crtc *crtc, } } + /* TODO TV */ + switch(radeon_crtc->crtc_id) { case 0: - radeon_init_crtc_registers(crtc, &dev_priv->mode_info.legacy_state, adjusted_mode); - radeon_init_crtc_base(crtc, &dev_priv->mode_info.legacy_state, crtc->x, crtc->y); -// dot_clock = adjusted_mode->clock / 1000; - - // if (dot_clock) - radeon_init_pll_registers(crtc, &dev_priv->mode_info.legacy_state, adjusted_mode, - pll_flags); + radeon_set_crtc1_timing(crtc, adjusted_mode); + radeon_set_pll1(crtc, adjusted_mode, pll_flags); break; case 1: + radeon_set_crtc2_timing(crtc, adjusted_mode); + radeon_set_pll2(crtc, adjusted_mode, pll_flags); break; } +} - /* TODO TV */ +void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - switch (radeon_crtc->crtc_id) { + switch(radeon_crtc->crtc_id) { case 0: - radeon_restore_crtc_registers(dev, &dev_priv->mode_info.legacy_state); - radeon_restore_pll_registers(dev, &dev_priv->mode_info.legacy_state); + radeon_set_crtc1_base(crtc, x, y); break; case 1: - radeon_restore_crtc2_registers(dev, &dev_priv->mode_info.legacy_state); - radeon_restore_pll2_registers(dev, &dev_priv->mode_info.legacy_state); + radeon_set_crtc2_base(crtc, x, y); break; - } - -} -void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y) -{ + } } static void radeon_crtc_prepare(struct drm_crtc *crtc) { + radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); } static void radeon_crtc_commit(struct drm_crtc *crtc) { + radeon_crtc_dpms(crtc, DRM_MODE_DPMS_ON); } static const struct drm_crtc_helper_funcs legacy_helper_funcs = { diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 8846653d..0ef7e113 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -29,148 +29,205 @@ #include "radeon_drv.h" -void radeon_restore_dac_registers(struct drm_device *dev, struct radeon_legacy_state *state) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; - - if (radeon_is_r300(dev_priv)) - RADEON_WRITE_P(RADEON_GPIOPAD_A, state->gpiopad_a, ~1); - - RADEON_WRITE_P(RADEON_DAC_CNTL, - state->dac_cntl, - RADEON_DAC_RANGE_CNTL | - RADEON_DAC_BLANKING); - - RADEON_WRITE(RADEON_DAC_CNTL2, state->dac2_cntl); - - if ((dev_priv->chip_family != CHIP_R100) && - (dev_priv->chip_family != CHIP_R200)) - RADEON_WRITE (RADEON_TV_DAC_CNTL, state->tv_dac_cntl); - - RADEON_WRITE(RADEON_DISP_OUTPUT_CNTL, state->disp_output_cntl); - - if ((dev_priv->chip_family == CHIP_R200) || - radeon_is_r300(dev_priv)) { - RADEON_WRITE(RADEON_DISP_TV_OUT_CNTL, state->disp_tv_out_cntl); - } else { - RADEON_WRITE(RADEON_DISP_HW_DEBUG, state->disp_hw_debug); - } - - RADEON_WRITE(RADEON_DAC_MACRO_CNTL, state->dac_macro_cntl); - - /* R200 DAC connected via DVO */ - if (dev_priv->chip_family == CHIP_R200) - RADEON_WRITE(RADEON_FP2_GEN_CNTL, state->fp2_gen_cntl); -} - - -/* Write TMDS registers */ -void radeon_restore_fp_registers(struct drm_device *dev, struct radeon_legacy_state *state) +static void radeon_legacy_rmx_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { + struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - - RADEON_WRITE(RADEON_TMDS_PLL_CNTL, state->tmds_pll_cntl); - RADEON_WRITE(RADEON_TMDS_TRANSMITTER_CNTL,state->tmds_transmitter_cntl); - RADEON_WRITE(RADEON_FP_GEN_CNTL, state->fp_gen_cntl); - - if ((dev_priv->chip_family == CHIP_RS400) || - (dev_priv->chip_family == CHIP_RS480)) { - RADEON_WRITE(RS400_FP_2ND_GEN_CNTL, state->fp_2nd_gen_cntl); - /*RADEON_WRITE(RS400_TMDS2_CNTL, state->tmds2_cntl);*/ - RADEON_WRITE(RS400_TMDS2_TRANSMITTER_CNTL, state->tmds2_transmitter_cntl); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + int xres = mode->hdisplay; + int yres = mode->vdisplay; + bool hscale = true, vscale = true; + int hsync_wid; + int vsync_wid; + int hsync_start; + uint32_t scale, inc; + uint32_t fp_horz_stretch, fp_vert_stretch, crtc_more_cntl, fp_horz_vert_active; + uint32_t fp_h_sync_strt_wid, fp_v_sync_strt_wid, fp_crtc_h_total_disp, fp_crtc_v_total_disp; + + + fp_vert_stretch = RADEON_READ(RADEON_FP_VERT_STRETCH) & + (RADEON_VERT_STRETCH_RESERVED | + RADEON_VERT_AUTO_RATIO_INC); + fp_horz_stretch = RADEON_READ(RADEON_FP_HORZ_STRETCH) & + (RADEON_HORZ_FP_LOOP_STRETCH | + RADEON_HORZ_AUTO_RATIO_INC); + + crtc_more_cntl = 0; + if ((dev_priv->chip_family == CHIP_RS100) || + (dev_priv->chip_family == CHIP_RS200)) { + /* This is to workaround the asic bug for RMX, some versions + of BIOS dosen't have this register initialized correctly. */ + crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN; } - /* old AIW Radeon has some BIOS initialization problem - * with display buffer underflow, only occurs to DFP - */ - if (dev_priv->flags & RADEON_SINGLE_CRTC) - RADEON_WRITE(RADEON_GRPH_BUFFER_CNTL, - RADEON_READ(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); -} + fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) + | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); -/* Write FP2 registers */ -void radeon_restore_fp2_registers(struct drm_device *dev, struct radeon_legacy_state *state) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; - RADEON_WRITE(RADEON_FP2_GEN_CNTL, state->fp2_gen_cntl); + hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; + if (!hsync_wid) + hsync_wid = 1; + hsync_start = mode->crtc_hsync_start - 8; - if ((dev_priv->chip_family == CHIP_RS400) || - (dev_priv->chip_family == CHIP_RS480)) - RADEON_WRITE(RS400_FP2_2_GEN_CNTL, state->fp2_2_gen_cntl); -} + fp_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); -/* Write RMX registers */ -void radeon_state_rmx_registers(struct drm_device *dev, struct radeon_legacy_state *state) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; - RADEON_WRITE(RADEON_FP_HORZ_STRETCH, state->fp_horz_stretch); - RADEON_WRITE(RADEON_FP_VERT_STRETCH, state->fp_vert_stretch); - RADEON_WRITE(RADEON_CRTC_MORE_CNTL, state->crtc_more_cntl); - RADEON_WRITE(RADEON_FP_HORZ_VERT_ACTIVE, state->fp_horz_vert_active); - RADEON_WRITE(RADEON_FP_H_SYNC_STRT_WID, state->fp_h_sync_strt_wid); - RADEON_WRITE(RADEON_FP_V_SYNC_STRT_WID, state->fp_v_sync_strt_wid); - RADEON_WRITE(RADEON_FP_CRTC_H_TOTAL_DISP, state->fp_crtc_h_total_disp); - RADEON_WRITE(RADEON_FP_CRTC_V_TOTAL_DISP, state->fp_crtc_v_total_disp); + fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff) + | ((mode->crtc_vdisplay - 1) << 16)); -} + vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; + if (!vsync_wid) + vsync_wid = 1; -/* Write LVDS registers */ -void radeon_restore_lvds_registers(struct drm_device *dev, struct radeon_legacy_state *state) -{ - struct drm_radeon_private *dev_priv = dev->dev_private; + fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0)); - if (dev_priv->flags & RADEON_IS_MOBILITY) { - RADEON_WRITE(RADEON_LVDS_GEN_CNTL, state->lvds_gen_cntl); - /*RADEON_WRITE(RADEON_LVDS_PLL_CNTL, state->lvds_pll_cntl);*/ + fp_horz_vert_active = 0; - if (dev_priv->chip_family == CHIP_RV410) { - RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, 0); - } + if (radeon_encoder->panel_xres == 0 || + radeon_encoder->panel_yres == 0) { + hscale = false; + vscale = false; + } else { + if (xres > radeon_encoder->panel_xres) + xres = radeon_encoder->panel_xres; + if (yres > radeon_encoder->panel_yres) + yres = radeon_encoder->panel_yres; + + if (xres == radeon_encoder->panel_xres) + hscale = false; + if (yres == radeon_encoder->panel_yres) + vscale = false; } -} - -static void radeon_init_fp_registers(struct drm_encoder *encoder, struct drm_display_mode *mode, - bool is_primary) -{ - - -} - -static void radeon_init_dac_registers(struct drm_encoder *encoder, struct radeon_legacy_state *state, - struct drm_display_mode *mode, bool is_primary) -{ - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - - if (is_primary) { - if (dev_priv->chip_family == CHIP_R200 || radeon_is_r300(dev_priv)) { - state->disp_output_cntl = RADEON_READ(RADEON_DISP_OUTPUT_CNTL & - ~RADEON_DISP_DAC_SOURCE_MASK); - } else { - state->dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2) & ~(RADEON_DAC2_DAC_CLK_SEL); + if (radeon_encoder->flags & RADEON_USE_RMX) { + if (radeon_encoder->rmx_type != RMX_CENTER) { + if (!hscale) + fp_horz_stretch |= ((xres/8-1) << 16); + else { + inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0; + scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX) + / radeon_encoder->panel_xres + 1; + fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) | + RADEON_HORZ_STRETCH_BLEND | + RADEON_HORZ_STRETCH_ENABLE | + ((radeon_encoder->panel_xres/8-1) << 16)); + } + + if (!vscale) + fp_vert_stretch |= ((yres-1) << 12); + else { + inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0; + scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX) + / radeon_encoder->panel_yres + 1; + fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) | + RADEON_VERT_STRETCH_ENABLE | + RADEON_VERT_STRETCH_BLEND | + ((radeon_encoder->panel_yres-1) << 12)); + } + } else if (radeon_encoder->rmx_type == RMX_CENTER) { + int blank_width; + + fp_horz_stretch |= ((xres/8-1) << 16); + fp_vert_stretch |= ((yres-1) << 12); + + crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN | + RADEON_CRTC_AUTO_VERT_CENTER_EN); + + blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8; + if (blank_width > 110) + blank_width = 110; + + fp_crtc_h_total_disp = (((blank_width) & 0x3ff) + | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); + + hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8; + if (!hsync_wid) + hsync_wid = 1; + + fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff) + | ((mode->crtc_vdisplay - 1) << 16)); + + vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start; + if (!vsync_wid) + vsync_wid = 1; + + fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff) + | ((vsync_wid & 0x1f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0))); + + fp_horz_vert_active = (((radeon_encoder->panel_yres) & 0xfff) | + (((radeon_encoder->panel_xres / 8) & 0x1ff) << 16)); } } else { - if (dev_priv->chip_family == CHIP_R200 || radeon_is_r300(dev_priv)) { - state->disp_output_cntl = RADEON_READ(RADEON_DISP_OUTPUT_CNTL & - ~RADEON_DISP_DAC_SOURCE_MASK); - state->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; - } else { - state->dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL; - } + fp_horz_stretch |= ((xres/8-1) << 16); + fp_vert_stretch |= ((yres-1) << 12); } - state->dac_cntl = (RADEON_DAC_MASK_ALL | - RADEON_DAC_VGA_ADR_EN | - /* TODO 6-bits */ - RADEON_DAC_8BIT_EN); - state->dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); + RADEON_WRITE(RADEON_FP_HORZ_STRETCH, fp_horz_stretch); + RADEON_WRITE(RADEON_FP_VERT_STRETCH, fp_vert_stretch); + RADEON_WRITE(RADEON_CRTC_MORE_CNTL, crtc_more_cntl); + RADEON_WRITE(RADEON_FP_HORZ_VERT_ACTIVE, fp_horz_vert_active); + RADEON_WRITE(RADEON_FP_H_SYNC_STRT_WID, fp_h_sync_strt_wid); + RADEON_WRITE(RADEON_FP_V_SYNC_STRT_WID, fp_v_sync_strt_wid); + RADEON_WRITE(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp); + RADEON_WRITE(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp); + } static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; + + switch(mode) { + case DRM_MODE_DPMS_ON: + disp_pwr_man = RADEON_READ(RADEON_DISP_PWR_MAN); + disp_pwr_man |= RADEON_AUTO_PWRUP_EN; + RADEON_WRITE(RADEON_DISP_PWR_MAN, disp_pwr_man); + lvds_pll_cntl |= RADEON_LVDS_PLL_EN; + RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); + udelay(1000); + lvds_pll_cntl = RADEON_READ(RADEON_LVDS_PLL_CNTL); + lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; + RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); + lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); + lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN); + lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); + udelay(radeon_encoder->panel_pwr_delay * 1000); + RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + pixclks_cntl = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); + lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); + lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; + lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN); + RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, pixclks_cntl); + break; + } } static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) @@ -184,16 +241,53 @@ static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) } static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t lvds_pll_cntl, lvds_gen_cntl; + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + lvds_pll_cntl = RADEON_READ(RADEON_LVDS_PLL_CNTL); + lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN; + lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); + lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; + lvds_gen_cntl &= ~(RADEON_LVDS_ON | + RADEON_LVDS_BLON | + RADEON_LVDS_EN | + RADEON_LVDS_RST_FM); + + if (radeon_is_r300(dev_priv)) + lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK); + + if (radeon_crtc->crtc_id == 0) { + if (radeon_is_r300(dev_priv)) { + if (radeon_encoder->flags & RADEON_USE_RMX) + lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX; + } else + lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2; + } else { + if (radeon_is_r300(dev_priv)) { + lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2; + } else + lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2; + } + RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); + if (dev_priv->chip_family == CHIP_RV410) + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, 0); } static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -201,7 +295,7 @@ static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder, if (radeon_encoder->rmx_type != RMX_OFF) radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); - + return true; } @@ -258,7 +352,34 @@ static bool radeon_legacy_primary_dac_mode_fixup(struct drm_encoder *encoder, static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode) { + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); + uint32_t dac_cntl = RADEON_READ(RADEON_DAC_CNTL); + uint32_t dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); + + switch(mode) { + case DRM_MODE_DPMS_ON: + crtc_ext_cntl |= RADEON_CRTC_CRT_ON; + dac_cntl &= ~RADEON_DAC_PDWN; + dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON; + dac_cntl |= RADEON_DAC_PDWN; + dac_macro_cntl |= (RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + break; + } + RADEON_WRITE(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + RADEON_WRITE(RADEON_DAC_CNTL, dac_cntl); + RADEON_WRITE(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); } @@ -273,16 +394,50 @@ static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) } static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - radeon_init_dac_registers(encoder, &dev_priv->mode_info.legacy_state, adjusted_mode, - (radeon_crtc->crtc_id == 1)); + uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl; + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + if (radeon_crtc->crtc_id == 0) { + if (dev_priv->chip_family == CHIP_R200 || radeon_is_r300(dev_priv)) { + disp_output_cntl = RADEON_READ(RADEON_DISP_OUTPUT_CNTL) & + ~(RADEON_DISP_DAC_SOURCE_MASK); + RADEON_WRITE(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + } else { + dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2) & ~(RADEON_DAC2_DAC_CLK_SEL); + RADEON_WRITE(RADEON_DAC_CNTL2, dac2_cntl); + } + } else { + if (dev_priv->chip_family == CHIP_R200 || radeon_is_r300(dev_priv)) { + disp_output_cntl = RADEON_READ(RADEON_DISP_OUTPUT_CNTL) & + ~(RADEON_DISP_DAC_SOURCE_MASK); + disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; + RADEON_WRITE(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + } else { + dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL; + RADEON_WRITE(RADEON_DAC_CNTL2, dac2_cntl); + } + } + + dac_cntl = (RADEON_DAC_MASK_ALL | + RADEON_DAC_VGA_ADR_EN | + /* TODO 6-bits */ + RADEON_DAC_8BIT_EN); - radeon_restore_dac_registers(dev, &dev_priv->mode_info.legacy_state); + RADEON_WRITE_P(RADEON_DAC_CNTL, + dac_cntl, + RADEON_DAC_RANGE_CNTL | + RADEON_DAC_BLANKING); + + dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); + RADEON_WRITE(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); } static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = { @@ -318,6 +473,9 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs); + /* TODO get the primary dac vals from bios tables */ + //radeon_combios_get_lvds_info(radeon_encoder); + return encoder; } @@ -326,13 +484,27 @@ static bool radeon_legacy_tmds_int_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - + return true; } static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) { - /* dfp1 */ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t fp_gen_cntl = RADEON_READ(RADEON_FP_GEN_CNTL); + + switch(mode) { + case DRM_MODE_DPMS_ON: + fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + break; + } + RADEON_WRITE(RADEON_FP_GEN_CNTL, fp_gen_cntl); } static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) @@ -346,11 +518,87 @@ static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) } static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl; + int i; + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + tmp = tmds_pll_cntl = RADEON_READ(RADEON_TMDS_PLL_CNTL); + tmp &= 0xfffff; + if (dev_priv->chip_family == CHIP_RV280) { + /* bit 22 of TMDS_PLL_CNTL is read-back inverted */ + tmp ^= (1 << 22); + tmds_pll_cntl ^= (1 << 22); + } + for (i = 0; i < 4; i++) { + if (radeon_encoder->tmds_pll[i].freq == 0) + break; + if ((uint32_t)(mode->clock / 10) < radeon_encoder->tmds_pll[i].freq) { + tmp = radeon_encoder->tmds_pll[i].value ; + break; + } + } + + if (radeon_is_r300(dev_priv) || (dev_priv->chip_family == CHIP_RV280)) { + if (tmp & 0xfff00000) + tmds_pll_cntl = tmp; + else { + tmds_pll_cntl &= 0xfff00000; + tmds_pll_cntl |= tmp; + } + } else + tmds_pll_cntl = tmp; + + tmds_transmitter_cntl = RADEON_READ(RADEON_TMDS_TRANSMITTER_CNTL) & + ~(RADEON_TMDS_TRANSMITTER_PLLRST); + + if (dev_priv->chip_family == CHIP_R200 || + dev_priv->chip_family == CHIP_R100 || + radeon_is_r300(dev_priv)) + tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); + else /* RV chips got this bit reversed */ + tmds_transmitter_cntl |= RADEON_TMDS_TRANSMITTER_PLLEN; + + fp_gen_cntl = (RADEON_READ(RADEON_FP_GEN_CNTL) | + (RADEON_FP_CRTC_DONT_SHADOW_VPAR | + RADEON_FP_CRTC_DONT_SHADOW_HEND)); + + fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + + if (1) // FIXME rgbBits == 8 + fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ + else + fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ + + if (radeon_crtc->crtc_id == 0) { + if (radeon_is_r300(dev_priv) || dev_priv->chip_family == CHIP_R200) { + fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; + if (radeon_encoder->flags & RADEON_USE_RMX) + fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; + else + fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; + } else + fp_gen_cntl |= RADEON_FP_SEL_CRTC1; + } else { + if (radeon_is_r300(dev_priv) || dev_priv->chip_family == CHIP_R200) { + fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; + fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2; + } else + fp_gen_cntl |= RADEON_FP_SEL_CRTC2; + } + + RADEON_WRITE(RADEON_TMDS_PLL_CNTL, tmds_pll_cntl); + RADEON_WRITE(RADEON_TMDS_TRANSMITTER_CNTL, tmds_transmitter_cntl); + RADEON_WRITE(RADEON_FP_GEN_CNTL, fp_gen_cntl); } static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs = { @@ -389,3 +637,344 @@ struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, i radeon_combios_get_tmds_info(radeon_encoder); return encoder; } + +static bool radeon_legacy_tmds_ext_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + + switch(mode) { + case DRM_MODE_DPMS_ON: + fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; + fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + fp2_gen_cntl |= RADEON_FP2_BLANK_EN; + fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); + break; + } + + RADEON_WRITE(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); +} + +static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) +{ + radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) +{ + radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + if (1) // FIXME rgbBits == 8 + fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ + else + fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ + + fp2_gen_cntl &= ~(RADEON_FP2_ON | + RADEON_FP2_DVO_EN | + RADEON_FP2_DVO_RATE_SEL_SDR); + + /* XXX: these are oem specific */ + if (radeon_is_r300(dev_priv)) { + if ((dev->pdev->device == 0x4850) && + (dev->pdev->subsystem_vendor == 0x1028) && + (dev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */ + fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE; + else + fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE; + + /*if (mode->clock > 165000) + fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/ + } + + if (radeon_crtc->crtc_id == 0) { + if ((dev_priv->chip_family == CHIP_R200) || radeon_is_r300(dev_priv)) { + fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; + if (radeon_encoder->flags & RADEON_USE_RMX) + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX; + else + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1; + } else + fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2; + } else { + if ((dev_priv->chip_family == CHIP_R200) || radeon_is_r300(dev_priv)) { + fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK; + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; + } else + fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2; + } + + RADEON_WRITE(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); +} + +static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs = { + .dpms = radeon_legacy_tmds_ext_dpms, + .mode_fixup = radeon_legacy_tmds_ext_mode_fixup, + .prepare = radeon_legacy_tmds_ext_prepare, + .mode_set = radeon_legacy_tmds_ext_mode_set, + .commit = radeon_legacy_tmds_ext_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder; + struct drm_encoder *encoder; + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs, + DRM_MODE_ENCODER_TMDS); + + drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs); + + //radeon_combios_get_tmds_info(radeon_encoder); + return encoder; +} + +static bool radeon_legacy_tv_dac_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t fp2_gen_cntl, crtc2_gen_cntl, tv_master_cntl, tv_dac_cntl; + + if (dev_priv->chip_family == CHIP_R200) + fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + else { + crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); + // FIXME TV + //tv_master_cntl = RADEON_READ(RADEON_TV_MASTER_CNTL); + tv_dac_cntl = RADEON_READ(RADEON_TV_DAC_CNTL); + } + + switch(mode) { + case DRM_MODE_DPMS_ON: + if (dev_priv->chip_family == CHIP_R200) + fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); + else { + crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; + //tv_master_cntl |= RADEON_TV_ON; + if (dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_RV410) + tv_dac_cntl &= ~(R420_TV_DAC_RDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + else + tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + } + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + if (dev_priv->chip_family == CHIP_R200) + fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); + else { + crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; + //tv_master_cntl &= ~RADEON_TV_ON; + if (dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_RV410) + tv_dac_cntl |= (R420_TV_DAC_RDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + else + tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + } + break; + } + + if (dev_priv->chip_family == CHIP_R200) + RADEON_WRITE(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + else { + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + //RADEON_WRITE(RADEON_TV_MASTER_CNTL, tv_master_cntl); + RADEON_WRITE(RADEON_TV_DAC_CNTL, tv_dac_cntl); + } + +} + +static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) +{ + radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder) +{ + radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t tv_dac_cntl, gpiopad_a, dac2_cntl, disp_output_cntl, fp2_gen_cntl; + uint32_t disp_hw_debug; + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + if (dev_priv->chip_family != CHIP_R200) { + tv_dac_cntl = RADEON_READ(RADEON_TV_DAC_CNTL); + if (dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_RV410) { + tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | + RADEON_TV_DAC_BGADJ_MASK | + R420_TV_DAC_DACADJ_MASK | + R420_TV_DAC_RDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_TVENABLE); + } else { + tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | + RADEON_TV_DAC_BGADJ_MASK | + RADEON_TV_DAC_DACADJ_MASK | + RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_GDACPD); + } + + // FIXME TV + tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_DAC_STD_PS2 /*| + radeon_encoder->ps2_tvdac_adj*/); // fixme, get from bios + + RADEON_WRITE(RADEON_TV_DAC_CNTL, tv_dac_cntl); + } + + if (radeon_is_r300(dev_priv)) { + gpiopad_a = RADEON_READ(RADEON_GPIOPAD_A) | 1; + disp_output_cntl = RADEON_READ(RADEON_DISP_OUTPUT_CNTL); + } else if (dev_priv->chip_family == CHIP_R200) + fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + else + disp_hw_debug = RADEON_READ(RADEON_DISP_HW_DEBUG); + + dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL; + + if (radeon_crtc->crtc_id == 0) { + if (radeon_is_r300(dev_priv)) { + disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; + } else if (dev_priv->chip_family == CHIP_R200) { + fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + } else + disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + } else { + if (radeon_is_r300(dev_priv)) { + disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + } else if (dev_priv->chip_family == CHIP_R200) { + fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; + } else + disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; + } + + RADEON_WRITE(RADEON_DAC_CNTL2, dac2_cntl); + + if (radeon_is_r300(dev_priv)) { + RADEON_WRITE_P(RADEON_GPIOPAD_A, gpiopad_a, ~1); + RADEON_WRITE(RADEON_DISP_TV_OUT_CNTL, disp_output_cntl); + } else if (dev_priv->chip_family == CHIP_R200) + RADEON_WRITE(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + else + RADEON_WRITE(RADEON_DISP_HW_DEBUG, disp_hw_debug); + +} + +static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = { + .dpms = radeon_legacy_tv_dac_dpms, + .mode_fixup = radeon_legacy_tv_dac_mode_fixup, + .prepare = radeon_legacy_tv_dac_prepare, + .mode_set = radeon_legacy_tv_dac_mode_set, + .commit = radeon_legacy_tv_dac_commit, +}; + + +static const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int has_tv) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_encoder *radeon_encoder; + struct drm_encoder *encoder; + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) { + return NULL; + } + + encoder = &radeon_encoder->base; + + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs, + DRM_MODE_ENCODER_DAC); + + drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs); + + /* TODO get the tv dac vals from bios tables */ + //radeon_combios_get_lvds_info(radeon_encoder); + + return encoder; +} diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index 0f2d239c..887b2f84 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -556,6 +556,24 @@ # define RADEON_DAC_PDWN_R (1 << 16) # define RADEON_DAC_PDWN_G (1 << 17) # define RADEON_DAC_PDWN_B (1 << 18) +#define RADEON_DISP_PWR_MAN 0x0d08 +# define RADEON_DISP_PWR_MAN_D3_CRTC_EN (1 << 0) +# define RADEON_DISP_PWR_MAN_D3_CRTC2_EN (1 << 4) +# define RADEON_DISP_PWR_MAN_DPMS_ON (0 << 8) +# define RADEON_DISP_PWR_MAN_DPMS_STANDBY (1 << 8) +# define RADEON_DISP_PWR_MAN_DPMS_SUSPEND (2 << 8) +# define RADEON_DISP_PWR_MAN_DPMS_OFF (3 << 8) +# define RADEON_DISP_D3_RST (1 << 16) +# define RADEON_DISP_D3_REG_RST (1 << 17) +# define RADEON_DISP_D3_GRPH_RST (1 << 18) +# define RADEON_DISP_D3_SUBPIC_RST (1 << 19) +# define RADEON_DISP_D3_OV0_RST (1 << 20) +# define RADEON_DISP_D1D2_GRPH_RST (1 << 21) +# define RADEON_DISP_D1D2_SUBPIC_RST (1 << 22) +# define RADEON_DISP_D1D2_OV0_RST (1 << 23) +# define RADEON_DIG_TMDS_ENABLE_RST (1 << 24) +# define RADEON_TV_ENABLE_RST (1 << 25) +# define RADEON_AUTO_PWRUP_EN (1 << 26) #define RADEON_TV_DAC_CNTL 0x088c # define RADEON_TV_DAC_NBLANK (1 << 0) # define RADEON_TV_DAC_NHOLD (1 << 1) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index b751740c..53177bb0 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -185,7 +185,7 @@ void radeon_pll_errata_after_data(struct drm_radeon_private *dev_priv) } } -int RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr) +u32 RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr) { uint32_t data; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index df08b8d3..fb266093 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1277,7 +1277,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) #define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) -extern int RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr); +extern u32 RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr); extern void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data); #define RADEON_WRITE_P(reg, val, mask) \ -- cgit v1.2.3 From b6f5b8ec7169320b79561c88ad04aefa795b3497 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Aug 2008 14:26:43 -0400 Subject: unify connector, i2c handling for atom and legacy --- linux-core/radeon_atombios.c | 4 +++ linux-core/radeon_combios.c | 41 ++++++++++++--------------- linux-core/radeon_connectors.c | 64 +++++++++++++++++++++--------------------- linux-core/radeon_display.c | 27 +++++++++++------- linux-core/radeon_mode.h | 8 ++++-- 5 files changed, 77 insertions(+), 67 deletions(-) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index cdb001c1..eb482d92 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -62,12 +62,16 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio_for_ddc(struct drm_de i2c.put_data_reg = le16_to_cpu(gpio.usDataEnRegisterIndex) * 4; i2c.get_clk_reg = le16_to_cpu(gpio.usClkY_RegisterIndex) * 4; i2c.get_data_reg = le16_to_cpu(gpio.usDataY_RegisterIndex) * 4; + i2c.a_clk_reg = le16_to_cpu(gpio.usClkA_RegisterIndex) * 4; + i2c.a_data_reg = le16_to_cpu(gpio.usDataA_RegisterIndex) * 4; i2c.mask_clk_mask = (1 << gpio.ucClkMaskShift); i2c.mask_data_mask = (1 << gpio.ucDataMaskShift); i2c.put_clk_mask = (1 << gpio.ucClkEnShift); i2c.put_data_mask = (1 << gpio.ucDataEnShift); i2c.get_clk_mask = (1 << gpio.ucClkY_Shift); i2c.get_data_mask = (1 << gpio.ucDataY_Shift); + i2c.a_clk_mask = (1 << gpio.ucClkA_Shift); + i2c.a_data_mask = (1 << gpio.ucDataA_Shift); i2c.valid = true; return i2c; diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index 8a1dd8b3..3b01385c 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -57,8 +57,10 @@ struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) { struct radeon_i2c_bus_rec i2c; - i2c.mask_clk_mask = RADEON_GPIO_EN_1 | RADEON_GPIO_Y_1; - i2c.mask_data_mask = RADEON_GPIO_EN_0 | RADEON_GPIO_Y_0; + i2c.mask_clk_mask = RADEON_GPIO_EN_1; + i2c.mask_data_mask = RADEON_GPIO_EN_0; + i2c.a_clk_mask = RADEON_GPIO_A_1; + i2c.a_data_mask = RADEON_GPIO_A_0; i2c.put_clk_mask = RADEON_GPIO_EN_1; i2c.put_data_mask = RADEON_GPIO_EN_0; i2c.get_clk_mask = RADEON_GPIO_Y_1; @@ -67,6 +69,8 @@ struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) (ddc_line == RADEON_MDGPIO_EN_REG)) { i2c.mask_clk_reg = ddc_line; i2c.mask_data_reg = ddc_line; + i2c.a_clk_reg = ddc_line; + i2c.a_data_reg = ddc_line; i2c.put_clk_reg = ddc_line; i2c.put_data_reg = ddc_line; i2c.get_clk_reg = ddc_line + 4; @@ -74,17 +78,19 @@ struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) } else { i2c.mask_clk_reg = ddc_line; i2c.mask_data_reg = ddc_line; + i2c.a_clk_reg = ddc_line; + i2c.a_data_reg = ddc_line; i2c.put_clk_reg = ddc_line; i2c.put_data_reg = ddc_line; i2c.get_clk_reg = ddc_line; i2c.get_data_reg = ddc_line; } - + if (ddc_line) i2c.valid = true; else i2c.valid = false; - + return i2c; } @@ -196,7 +202,7 @@ bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder) if (n > 4) n = 4; for (i = 0; i < n; i++) { encoder->tmds_pll[i].value = radeon_bios32(dev_priv, tmp+i*10+0x08); - encoder->tmds_pll[i].freq = radeon_bios16(dev_priv, tmp+i*10+0x10); + encoder->tmds_pll[i].freq = radeon_bios16(dev_priv, tmp+i*10+0x10); } return true; } else if (ver == 4) { @@ -219,7 +225,7 @@ static void radeon_apply_legacy_quirks(struct drm_device *dev, int bios_index) struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_mode_info *mode_info = &dev_priv->mode_info; - /* on XPRESS chips, CRT2_DDC and MONID_DCC both use the + /* on XPRESS chips, CRT2_DDC and MONID_DCC both use the * MONID gpio, but use different pins. * CRT2_DDC uses the standard pinout, MONID_DDC uses * something else. @@ -231,17 +237,6 @@ static void radeon_apply_legacy_quirks(struct drm_device *dev, int bios_index) mode_info->bios_connector[bios_index].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); } - /* XPRESS desktop chips seem to have a proprietary connector listed for - * DVI-D, try and do the right thing here. - */ - if ((dev_priv->flags & RADEON_IS_MOBILITY) && - (mode_info->bios_connector[bios_index].connector_type == CONNECTOR_LVDS)) { - DRM_INFO("proprietary connector found. assuming DVI-D\n"); - mode_info->bios_connector[bios_index].dac_type = DAC_NONE; - mode_info->bios_connector[bios_index].tmds_type = TMDS_EXT; - mode_info->bios_connector[bios_index].connector_type = CONNECTOR_DVI_D; - } - /* Certain IBM chipset RN50s have a BIOS reporting two VGAs, one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */ if (dev->pdev->device == 0x515e && @@ -272,16 +267,16 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) enum radeon_combios_ddc ddctype; enum radeon_combios_connector connector_type; int i; - + DRM_DEBUG("\n"); offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x50); if (offset) { for (i = 0; i < 4; i++) { entry = offset + 2 + i * 2; - + if (!radeon_bios16(dev_priv, entry)) break; - + mode_info->bios_connector[i].valid = true; tmp = radeon_bios16(dev_priv, entry); @@ -291,7 +286,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) switch(connector_type) { case CONNECTOR_PROPRIETARY_LEGACY: - mode_info->bios_connector[i].connector_type = CONNECTOR_LVDS; + mode_info->bios_connector[i].connector_type = CONNECTOR_DVI_D; break; case CONNECTOR_CRT_LEGACY: mode_info->bios_connector[i].connector_type = CONNECTOR_VGA; @@ -406,7 +401,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { if (!mode_info->bios_connector[i].valid) continue; - + DRM_DEBUG("Port %d: ddc_type 0x%x, dac_type %d, tmds_type %d, connector type %d, hpd_mask %d\n", i, mode_info->bios_connector[i].ddc_i2c.mask_clk_reg, mode_info->bios_connector[i].dac_type, @@ -417,4 +412,4 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) return true; } - + diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c index 344b4f77..2cc0be06 100644 --- a/linux-core/radeon_connectors.c +++ b/linux-core/radeon_connectors.c @@ -36,9 +36,9 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) int ret = 0; struct edid *edid; - avivo_i2c_do_lock(radeon_connector, 1); + radeon_i2c_do_lock(radeon_connector, 1); edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); - avivo_i2c_do_lock(radeon_connector, 0); + radeon_i2c_do_lock(radeon_connector, 0); if (edid) { drm_mode_connector_update_edid_property(&radeon_connector->base, edid); ret = drm_add_edid_modes(&radeon_connector->base, edid); @@ -53,7 +53,7 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) return ret; radeon_encoder_update_panel_size(lvds_encoder, connector); -#endif +#endif return ret; } @@ -111,33 +111,33 @@ struct drm_connector_funcs radeon_lvds_connector_funcs = { .destroy = radeon_connector_destroy, }; -static int radeon_atom_vga_get_modes(struct drm_connector *connector) +static int radeon_vga_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); int ret; ret = radeon_ddc_get_modes(radeon_connector); - + return ret; } -static int radeon_atom_vga_mode_valid(struct drm_connector *connector, +static int radeon_vga_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { return MODE_OK; } -static enum drm_connector_status radeon_atom_vga_detect(struct drm_connector *connector) +static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector) { struct edid *edid; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; - avivo_i2c_do_lock(radeon_connector, 1); + radeon_i2c_do_lock(radeon_connector, 1); edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); - avivo_i2c_do_lock(radeon_connector, 0); + radeon_i2c_do_lock(radeon_connector, 0); if (edid) { kfree(edid); return connector_status_connected; @@ -152,20 +152,20 @@ static enum drm_connector_status radeon_atom_vga_detect(struct drm_connector *co return encoder_funcs->detect(encoder, connector); } -struct drm_connector_helper_funcs radeon_atom_vga_connector_helper_funcs = { - .get_modes = radeon_atom_vga_get_modes, - .mode_valid = radeon_atom_vga_mode_valid, +struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = { + .get_modes = radeon_vga_get_modes, + .mode_valid = radeon_vga_mode_valid, .best_encoder = radeon_best_single_encoder, }; -struct drm_connector_funcs radeon_atom_vga_connector_funcs = { - .detect = radeon_atom_vga_detect, +struct drm_connector_funcs radeon_vga_connector_funcs = { + .detect = radeon_vga_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = radeon_connector_destroy, }; -static enum drm_connector_status radeon_atom_dvi_detect(struct drm_connector *connector) +static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) { struct edid *edid; struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -175,9 +175,9 @@ static enum drm_connector_status radeon_atom_dvi_detect(struct drm_connector *co int i; enum drm_connector_status ret; - avivo_i2c_do_lock(radeon_connector, 1); + radeon_i2c_do_lock(radeon_connector, 1); edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); - avivo_i2c_do_lock(radeon_connector, 0); + radeon_i2c_do_lock(radeon_connector, 0); if (edid) { /* if the monitor is digital - set the bits */ if (edid->digital) @@ -212,7 +212,7 @@ static enum drm_connector_status radeon_atom_dvi_detect(struct drm_connector *co } /* okay need to be smart in here about which encoder to pick */ -struct drm_encoder *radeon_atom_dvi_encoder(struct drm_connector *connector) +struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) { int enc_id = connector->encoder_ids[0]; struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -253,14 +253,14 @@ struct drm_encoder *radeon_atom_dvi_encoder(struct drm_connector *connector) return NULL; } -struct drm_connector_helper_funcs radeon_atom_dvi_connector_helper_funcs = { - .get_modes = radeon_atom_vga_get_modes, - .mode_valid = radeon_atom_vga_mode_valid, - .best_encoder = radeon_atom_dvi_encoder, +struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { + .get_modes = radeon_vga_get_modes, + .mode_valid = radeon_vga_mode_valid, + .best_encoder = radeon_dvi_encoder, }; -struct drm_connector_funcs radeon_atom_dvi_connector_funcs = { - .detect = radeon_atom_dvi_detect, +struct drm_connector_funcs radeon_dvi_connector_funcs = { + .detect = radeon_dvi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = radeon_connector_destroy, }; @@ -272,12 +272,12 @@ static struct connector_funcs { struct drm_connector_helper_funcs *helper_funcs; int conn_type; char *i2c_id; -} connector_fns[] = { +} connector_fns[] = { { CONNECTOR_NONE, NULL, NULL, DRM_MODE_CONNECTOR_Unknown }, - { CONNECTOR_VGA, &radeon_atom_vga_connector_funcs, &radeon_atom_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA , "VGA"}, + { CONNECTOR_VGA, &radeon_vga_connector_funcs, &radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA , "VGA"}, { CONNECTOR_LVDS, &radeon_lvds_connector_funcs, &radeon_lvds_connector_helper_funcs, DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { CONNECTOR_DVI_A, &radeon_atom_vga_connector_funcs, &radeon_atom_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_DVIA, "DVI" }, - { CONNECTOR_DVI_I, &radeon_atom_dvi_connector_funcs, &radeon_atom_dvi_connector_helper_funcs, DRM_MODE_CONNECTOR_DVII, "DVI" }, + { CONNECTOR_DVI_A, &radeon_vga_connector_funcs, &radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_DVIA, "DVI" }, + { CONNECTOR_DVI_I, &radeon_dvi_connector_funcs, &radeon_dvi_connector_helper_funcs, DRM_MODE_CONNECTOR_DVII, "DVI" }, #if 0 { CONNECTOR_DVI_D, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, @@ -294,14 +294,14 @@ static struct connector_funcs { { CONNECTOR_DIN, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, { CONNECTOR_DISPLAY_PORT, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, #endif -}; - +}; + struct drm_connector *radeon_connector_add(struct drm_device *dev, int bios_index) { struct radeon_connector *radeon_connector; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_mode_info *mode_info = &dev_priv->mode_info; - struct drm_connector *connector; + struct drm_connector *connector; int table_idx; for (table_idx = 0; table_idx < ARRAY_SIZE(connector_fns); table_idx++) { @@ -323,7 +323,7 @@ struct drm_connector *radeon_connector_add(struct drm_device *dev, int bios_inde connector_fns[table_idx].conn_type); drm_connector_helper_add(&radeon_connector->base, connector_fns[table_idx].helper_funcs); - + if (mode_info->bios_connector[bios_index].ddc_i2c.valid) { radeon_connector->ddc_bus = radeon_i2c_create(dev, &mode_info->bios_connector[bios_index].ddc_i2c, connector_fns[table_idx].i2c_id); diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 97e9da55..5272d198 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -361,25 +361,35 @@ bool radeon_setup_enc_conn(struct drm_device *dev) -void avivo_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) +void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) { struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; uint32_t temp; struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec; + if (lock_state) { + temp = RADEON_READ(rec->a_clk_reg); + temp &= ~(rec->a_clk_mask); + RADEON_WRITE(rec->a_clk_reg, temp); + + temp = RADEON_READ(rec->a_data_reg); + temp &= ~(rec->a_data_mask); + RADEON_WRITE(rec->a_data_reg, temp); + } + temp = RADEON_READ(rec->mask_clk_reg); if (lock_state) - temp |= rec->put_clk_mask; + temp |= rec->mask_clk_mask; else - temp &= ~rec->put_clk_mask; + temp &= ~rec->mask_clk_mask; RADEON_WRITE(rec->mask_clk_reg, temp); temp = RADEON_READ(rec->mask_clk_reg); temp = RADEON_READ(rec->mask_data_reg); if (lock_state) - temp |= rec->put_data_mask; + temp |= rec->mask_data_mask; else - temp &= ~rec->put_data_mask; + temp &= ~rec->mask_data_mask; RADEON_WRITE(rec->mask_data_reg, temp); temp = RADEON_READ(rec->mask_data_reg); } @@ -392,12 +402,9 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if (!radeon_connector->ddc_bus) return -1; - - if (radeon_is_avivo(dev_priv)) - avivo_i2c_do_lock(radeon_connector, 1); + radeon_i2c_do_lock(radeon_connector, 1); edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); - if (radeon_is_avivo(dev_priv)) - avivo_i2c_do_lock(radeon_connector, 0); + radeon_i2c_do_lock(radeon_connector, 0); if (edid) { drm_mode_connector_update_edid_property(&radeon_connector->base, edid); ret = drm_add_edid_modes(&radeon_connector->base, edid); diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 91c6f48d..b92490fc 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -91,6 +91,8 @@ struct radeon_i2c_bus_rec { bool valid; uint32_t mask_clk_reg; uint32_t mask_data_reg; + uint32_t a_clk_reg; + uint32_t a_data_reg; uint32_t put_clk_reg; uint32_t put_data_reg; uint32_t get_clk_reg; @@ -101,6 +103,8 @@ struct radeon_i2c_bus_rec { uint32_t put_data_mask; uint32_t get_clk_mask; uint32_t get_data_mask; + uint32_t a_clk_mask; + uint32_t a_data_mask; }; struct radeon_bios_connector { @@ -121,7 +125,7 @@ struct radeon_tmds_pll { }; #define RADEON_MAX_BIOS_CONNECTOR 16 - + #define RADEON_PLL_USE_BIOS_DIVS (1 << 0) #define RADEON_PLL_NO_ODD_POST_DIV (1 << 1) #define RADEON_PLL_USE_REF_DIV (1 << 2) @@ -406,7 +410,7 @@ void radeon_atombios_init_crtc(struct drm_device *dev, struct radeon_crtc *radeon_crtc); void radeon_legacy_init_crtc(struct drm_device *dev, struct radeon_crtc *radeon_crtc); -void avivo_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state); +void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state); void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable); void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable); -- cgit v1.2.3 From 019745c41758173eacb910dde512de0beb6a69eb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Aug 2008 14:41:13 -0400 Subject: Add legacy dac detect stubs --- linux-core/radeon_legacy_encoders.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 0ef7e113..46cf791e 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -440,12 +440,23 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, RADEON_WRITE(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); } +static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + return connector_status_disconnected; + +} + static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = { .dpms = radeon_legacy_primary_dac_dpms, .mode_fixup = radeon_legacy_primary_dac_mode_fixup, .prepare = radeon_legacy_primary_dac_prepare, .mode_set = radeon_legacy_primary_dac_mode_set, .commit = radeon_legacy_primary_dac_commit, + .detect = radeon_legacy_primary_dac_detect, }; @@ -940,12 +951,23 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, } +static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + return connector_status_disconnected; + +} + static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = { .dpms = radeon_legacy_tv_dac_dpms, .mode_fixup = radeon_legacy_tv_dac_mode_fixup, .prepare = radeon_legacy_tv_dac_prepare, .mode_set = radeon_legacy_tv_dac_mode_set, .commit = radeon_legacy_tv_dac_commit, + .detect = radeon_legacy_tv_dac_detect, }; -- cgit v1.2.3 From d4f9eaa55a0f9c1c9b3f8d92d734eff4a6ae859e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Aug 2008 16:15:21 -0400 Subject: various cleanups - white space - move i2c_lock to radeon_i2c.c - enable tv dac on legacy --- linux-core/radeon_display.c | 69 +++++++++++++-------------------------------- linux-core/radeon_i2c.c | 36 +++++++++++++++++++++-- linux-core/radeon_mode.h | 2 ++ 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 5272d198..aa48e478 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -48,11 +48,11 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc) DRM_DEBUG("%d\n", radeon_crtc->crtc_id); RADEON_WRITE(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0); - + RADEON_WRITE(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); RADEON_WRITE(AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0); RADEON_WRITE(AVIVO_DC_LUTA_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0); - + RADEON_WRITE(AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff); RADEON_WRITE(AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff); RADEON_WRITE(AVIVO_DC_LUTA_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff); @@ -62,7 +62,6 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc) RADEON_WRITE(AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f); for (i = 0; i < 256; i++) { - RADEON_WRITE8(AVIVO_DC_LUT_RW_INDEX, i); RADEON_WRITE(AVIVO_DC_LUT_30_COLOR, (radeon_crtc->lut_r[i] << 22) | @@ -84,7 +83,6 @@ void radeon_crtc_load_lut(struct drm_crtc *crtc) if (!crtc->enabled) return; - if (radeon_is_avivo(dev_priv)) { avivo_crtc_load_lut(crtc); return; @@ -158,7 +156,7 @@ static int radeon_crtc_cursor_set(struct drm_crtc *crtc, } obj_priv = obj->driver_private; - + RADEON_WRITE(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 0); if (radeon_is_avivo(dev_priv)) { RADEON_WRITE(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, @@ -172,7 +170,7 @@ static int radeon_crtc_cursor_set(struct drm_crtc *crtc, mutex_lock(&crtc->dev->struct_mutex); drm_gem_object_unreference(obj); mutex_unlock(&crtc->dev->struct_mutex); - + return 0; } @@ -202,7 +200,7 @@ static int radeon_crtc_cursor_move(struct drm_crtc *crtc, RADEON_WRITE(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); avivo_lock_cursor(crtc, false); } - + return 0; } @@ -325,8 +323,8 @@ bool radeon_setup_enc_conn(struct drm_device *dev) } else { if (mode_info->bios_connector[i].dac_type == DAC_PRIMARY) encoder = radeon_encoder_legacy_primary_dac_add(dev, i, 0); -// else if (mode_info->bios_connector[i].dac_type == DAC_TVDAC) -// encoder radeon_encoder_legacy_secondary_dac_add(dev, i, 0); + else if (mode_info->bios_connector[i].dac_type == DAC_TVDAC) + encoder = radeon_encoder_legacy_tv_dac_add(dev, i, 0); } if (encoder) drm_mode_connector_attach_encoder(connector, encoder); @@ -340,6 +338,8 @@ bool radeon_setup_enc_conn(struct drm_device *dev) else { if (mode_info->bios_connector[i].tmds_type == TMDS_INT) encoder = radeon_encoder_legacy_tmds_int_add(dev, i); + else if (mode_info->bios_connector[i].dac_type == TMDS_EXT) + encoder = radeon_encoder_legacy_tmds_ext_add(dev, i); } if (encoder) drm_mode_connector_attach_encoder(connector, encoder); @@ -349,6 +349,10 @@ bool radeon_setup_enc_conn(struct drm_device *dev) if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN) { if (radeon_is_avivo(dev_priv)) encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 1); + else { + if (mode_info->bios_connector[i].dac_type == DAC_TVDAC) + encoder = radeon_encoder_legacy_tv_dac_add(dev, i, 0); + } if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } @@ -359,41 +363,6 @@ bool radeon_setup_enc_conn(struct drm_device *dev) return true; } - - -void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) -{ - struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; - uint32_t temp; - struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec; - - if (lock_state) { - temp = RADEON_READ(rec->a_clk_reg); - temp &= ~(rec->a_clk_mask); - RADEON_WRITE(rec->a_clk_reg, temp); - - temp = RADEON_READ(rec->a_data_reg); - temp &= ~(rec->a_data_mask); - RADEON_WRITE(rec->a_data_reg, temp); - } - - temp = RADEON_READ(rec->mask_clk_reg); - if (lock_state) - temp |= rec->mask_clk_mask; - else - temp &= ~rec->mask_clk_mask; - RADEON_WRITE(rec->mask_clk_reg, temp); - temp = RADEON_READ(rec->mask_clk_reg); - - temp = RADEON_READ(rec->mask_data_reg); - if (lock_state) - temp |= rec->mask_data_mask; - else - temp &= ~rec->mask_data_mask; - RADEON_WRITE(rec->mask_data_reg, temp); - temp = RADEON_READ(rec->mask_data_reg); -} - int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) { struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; @@ -422,7 +391,9 @@ int radeon_ddc_dump(struct drm_connector *connector) if (!radeon_connector->ddc_bus) return -1; + radeon_i2c_do_lock(radeon_connector, 1); edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); + radeon_i2c_do_lock(radeon_connector, 0); if (edid) { kfree(edid); } @@ -433,7 +404,7 @@ static inline uint32_t radeon_div(uint64_t n, uint32_t d) { uint64_t x, y, result; uint64_t mod; - + n += d / 2; mod = do_div(n, d); @@ -519,7 +490,7 @@ void radeon_compute_pll(struct radeon_pll *pll, current_freq = radeon_div((uint64_t)pll->reference_freq * 10000 * feedback_div, ref_div * post_div); - + error = abs(current_freq - freq); vco_diff = abs(vco - best_vco); @@ -550,7 +521,7 @@ void radeon_compute_pll(struct radeon_pll *pll, best_vco_diff = vco_diff; } } - + if (current_freq < freq) min_feed_div = feedback_div+1; else @@ -558,7 +529,7 @@ void radeon_compute_pll(struct radeon_pll *pll, } } } - + *dot_clock_p = best_freq / 10000; *fb_div_p = best_feedback_div; *ref_div_p = best_ref_div; @@ -680,7 +651,7 @@ int radeon_modeset_init(struct drm_device *dev) if (!ret) return ret; - + drm_helper_initial_config(dev, false); return 0; diff --git a/linux-core/radeon_i2c.c b/linux-core/radeon_i2c.c index eccec650..00fc7c0e 100644 --- a/linux-core/radeon_i2c.c +++ b/linux-core/radeon_i2c.c @@ -27,6 +27,38 @@ #include "radeon_drm.h" #include "radeon_drv.h" +void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) +{ + struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; + uint32_t temp; + struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec; + + if (lock_state) { + temp = RADEON_READ(rec->a_clk_reg); + temp &= ~(rec->a_clk_mask); + RADEON_WRITE(rec->a_clk_reg, temp); + + temp = RADEON_READ(rec->a_data_reg); + temp &= ~(rec->a_data_mask); + RADEON_WRITE(rec->a_data_reg, temp); + } + + temp = RADEON_READ(rec->mask_clk_reg); + if (lock_state) + temp |= rec->mask_clk_mask; + else + temp &= ~rec->mask_clk_mask; + RADEON_WRITE(rec->mask_clk_reg, temp); + temp = RADEON_READ(rec->mask_clk_reg); + + temp = RADEON_READ(rec->mask_data_reg); + if (lock_state) + temp |= rec->mask_data_mask; + else + temp &= ~rec->mask_data_mask; + RADEON_WRITE(rec->mask_data_reg, temp); + temp = RADEON_READ(rec->mask_data_reg); +} static int get_clock(void *i2c_priv) { @@ -88,7 +120,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, i2c = drm_calloc(1, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); if (i2c == NULL) return NULL; - + i2c->adapter.owner = THIS_MODULE; i2c->adapter.id = I2C_HW_B_RADEON; i2c->adapter.algo_data = &i2c->algo; @@ -113,7 +145,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, out_free: drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); return NULL; - + } void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index b92490fc..3e0ffc66 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -382,7 +382,9 @@ struct drm_encoder *radeon_encoder_atom_dac_add(struct drm_device *dev, int bios struct drm_encoder *radeon_encoder_atom_tmds_add(struct drm_device *dev, int bios_index, int tmds_type); struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index); struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev, int bios_index, int with_tv); +struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv); struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index); +struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); extern void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y); -- cgit v1.2.3 From e20c670a5a7896a7ad6c004c744993e3be3879dc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Aug 2008 16:29:19 -0400 Subject: LUT updates - Add gamma set for legacy chips - Add 16 bpp gamma set --- linux-core/radeon_display.c | 63 +++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index aa48e478..95258efa 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -72,33 +72,43 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc) RADEON_WRITE(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); } - -void radeon_crtc_load_lut(struct drm_crtc *crtc) +static void legacy_crtc_load_lut(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - u32 temp; int i; - if (!crtc->enabled) - return; - - if (radeon_is_avivo(dev_priv)) { - avivo_crtc_load_lut(crtc); - return; - } + uint32_t dac2_cntl; - temp = RADEON_READ(RADEON_DAC_CNTL2); + dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2); if (radeon_crtc->crtc_id == 0) - temp &= (uint32_t)~RADEON_DAC2_PALETTE_ACC_CTL; + dac2_cntl &= (uint32_t)~RADEON_DAC2_PALETTE_ACC_CTL; else - temp |= RADEON_DAC2_PALETTE_ACC_CTL; - RADEON_WRITE(RADEON_DAC_CNTL2, temp); + dac2_cntl |= RADEON_DAC2_PALETTE_ACC_CTL; + RADEON_WRITE(RADEON_DAC_CNTL2, dac2_cntl); for (i = 0; i < 256; i++) { -// OUTPAL(i, radeon_crtc->lut_r[i], radeon_crtc->lut_g[i], radeon_crtc->lut_b[i]); + RADEON_WRITE8(RADEON_PALETTE_INDEX, i); + RADEON_WRITE(RADEON_PALETTE_DATA, + (radeon_crtc->lut_r[i] << 16) | + (radeon_crtc->lut_g[i] << 8) | + (radeon_crtc->lut_b[i] << 0)); } +} + +void radeon_crtc_load_lut(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + if (!crtc->enabled) + return; + + if (radeon_is_avivo(dev_priv)) + avivo_crtc_load_lut(crtc); + else + legacy_crtc_load_lut(crtc); } /** Sets the color ramps on behalf of RandR */ @@ -208,15 +218,28 @@ static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, uint32_t size) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - int i; + int i, j; if (size != 256) return; - for (i = 0; i < 256; i++) { - radeon_crtc->lut_r[i] = red[i] >> 8; - radeon_crtc->lut_g[i] = green[i] >> 8; - radeon_crtc->lut_b[i] = blue[i] >> 8; + if (crtc->fb->depth == 16) { + for (i = 0; i < 64; i++) { + if (i <= 31) { + for (j = 0; j < 8; j++) { + radeon_crtc->lut_r[i * 8 + j] = red[i] >> 8; + radeon_crtc->lut_b[i * 8 + j] = blue[i] >> 8; + } + } + for (j = 0; j < 4; j++) + radeon_crtc->lut_g[i * 4 + j] = green[i] >> 8; + } + } else { + for (i = 0; i < 256; i++) { + radeon_crtc->lut_r[i] = red[i] >> 8; + radeon_crtc->lut_g[i] = green[i] >> 8; + radeon_crtc->lut_b[i] = blue[i] >> 8; + } } radeon_crtc_load_lut(crtc); -- cgit v1.2.3 From f2351ab38c8157bdbc839ad628b1dde6693f51bd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Aug 2008 17:02:18 -0400 Subject: atom: implement crtc lock --- linux-core/atombios_crtc.c | 74 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/linux-core/atombios_crtc.c b/linux-core/atombios_crtc.c index 1f372045..0a86f36b 100644 --- a/linux-core/atombios_crtc.c +++ b/linux-core/atombios_crtc.c @@ -31,6 +31,22 @@ #include "atom.h" #include "atom-bits.h" +static void atombios_lock_crtc(struct drm_crtc *crtc, int lock) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + int index = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); + ENABLE_CRTC_PS_ALLOCATION args; + + memset(&args, 0, sizeof(args)); + + args.ucCRTC = radeon_crtc->crtc_id; + args.ucEnable = lock; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + static void atombios_enable_crtc(struct drm_crtc *crtc, int state) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -127,7 +143,7 @@ void atombios_crtc_set_timing(struct drm_crtc *crtc, SET_CRTC_TIMING_PARAMETERS_ conv_param.ucOverscanRight = crtc_param->ucOverscanRight; conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft; conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom; - conv_param.ucOverscanTop = crtc_param->ucOverscanTop; + conv_param.ucOverscanTop = crtc_param->ucOverscanTop; conv_param.ucReserved = crtc_param->ucReserved; printk("executing set crtc timing\n"); @@ -150,29 +166,21 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, memset(&spc_param, 0, sizeof(SET_PIXEL_CLOCK_PS_ALLOCATION)); - if (radeon_is_avivo(dev_priv)) { - uint32_t temp; + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; - pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + radeon_compute_pll(&dev_priv->mode_info.pll, mode->clock, + &sclock, &fb_div, &ref_div, &post_div, pll_flags); - radeon_compute_pll(&dev_priv->mode_info.pll, mode->clock, - &temp, &fb_div, &ref_div, &post_div, pll_flags); - sclock = temp; + if (radeon_is_avivo(dev_priv)) { + uint32_t ss_cntl; if (radeon_crtc->crtc_id == 0) { - temp = RADEON_READ(AVIVO_P1PLL_INT_SS_CNTL); - RADEON_WRITE(AVIVO_P1PLL_INT_SS_CNTL, temp & ~1); + ss_cntl = RADEON_READ(AVIVO_P1PLL_INT_SS_CNTL); + RADEON_WRITE(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1); } else { - temp = RADEON_READ(AVIVO_P2PLL_INT_SS_CNTL); - RADEON_WRITE(AVIVO_P2PLL_INT_SS_CNTL, temp & ~1); + ss_cntl = RADEON_READ(AVIVO_P2PLL_INT_SS_CNTL); + RADEON_WRITE(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1); } - } else { -#if 0 // TODO r400 - sclock = save->dot_clock_freq; - fb_div = save->feedback_div; - post_div = save->post_div; - ref_div = save->ppll_ref_div; -#endif } /* */ @@ -201,7 +209,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, spc3_ptr->ucPostDiv = post_div; spc3_ptr->ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2); - + /* TODO insert output encoder object stuff herre for r600 */ break; default: @@ -220,7 +228,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y) { - 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_radeon_private *dev_priv = dev->dev_private; struct radeon_framebuffer *radeon_fb; @@ -251,19 +259,17 @@ void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y) DRM_ERROR("Unsupported screen depth %d\n", crtc->fb->bits_per_pixel); return; } - + /* TODO tiling */ if (radeon_crtc->crtc_id == 0) RADEON_WRITE(AVIVO_D1VGA_CONTROL, 0); else RADEON_WRITE(AVIVO_D2VGA_CONTROL, 0); - - RADEON_WRITE(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, AVIVO_D1GRPH_UPDATE_LOCK); - + RADEON_WRITE(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, fb_location); RADEON_WRITE(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, fb_location); RADEON_WRITE(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format); - + RADEON_WRITE(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0); RADEON_WRITE(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0); RADEON_WRITE(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, x); @@ -274,20 +280,13 @@ void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y) fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); RADEON_WRITE(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels); RADEON_WRITE(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); - - /* unlock the grph regs */ - RADEON_WRITE(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, 0); - - /* lock the mode regs */ - RADEON_WRITE(AVIVO_D1SCL_UPDATE + radeon_crtc->crtc_offset, AVIVO_D1SCL_UPDATE_LOCK); - + RADEON_WRITE(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, crtc->mode.vdisplay); RADEON_WRITE(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, (x << 16) | y); RADEON_WRITE(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); - /* unlock the mode regs */ - RADEON_WRITE(AVIVO_D1SCL_UPDATE + radeon_crtc->crtc_offset, 0); + } void atombios_crtc_mode_set(struct drm_crtc *crtc, @@ -324,7 +323,7 @@ void atombios_crtc_mode_set(struct drm_crtc *crtc, if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; - + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; @@ -337,9 +336,8 @@ void atombios_crtc_mode_set(struct drm_crtc *crtc, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; - if (radeon_is_avivo(dev_priv)) { + if (radeon_is_avivo(dev_priv)) atombios_crtc_set_base(crtc, x, y); - } atombios_crtc_set_pll(crtc, adjusted_mode, pll_flags); @@ -357,11 +355,13 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, static void atombios_crtc_prepare(struct drm_crtc *crtc) { atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + atombios_lock_crtc(crtc, 1); } static void atombios_crtc_commit(struct drm_crtc *crtc) { atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + atombios_lock_crtc(crtc, 0); } static const struct drm_crtc_helper_funcs atombios_helper_funcs = { -- cgit v1.2.3 From 5af426a2b29f5426ba5714cb6501aa5b270089b4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 11 Aug 2008 18:37:16 -0400 Subject: Restructure cursor handling and add support for legacy cursors --- linux-core/Makefile.kernel | 3 +- linux-core/radeon_cursor.c | 243 ++++++++++++++++++++++++++++++++++++++++++++ linux-core/radeon_display.c | 93 ----------------- linux-core/radeon_mode.h | 9 ++ linux-core/radeon_reg.h | 13 ++- 5 files changed, 262 insertions(+), 99 deletions(-) create mode 100644 linux-core/radeon_cursor.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 576de5b2..036461db 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -41,7 +41,8 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv50_fbcon.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_gem.o \ radeon_buffer.o radeon_fence.o atom.o radeon_display.o radeon_atombios.o radeon_i2c.o radeon_connectors.o radeon_cs.o \ - atombios_crtc.o radeon_encoders.o radeon_fb.o radeon_combios.o radeon_legacy_crtc.o radeon_legacy_encoders.o + atombios_crtc.o radeon_encoders.o radeon_fb.o radeon_combios.o radeon_legacy_crtc.o radeon_legacy_encoders.o \ + radeon_cursor.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/radeon_cursor.c b/linux-core/radeon_cursor.c new file mode 100644 index 00000000..e71b325d --- /dev/null +++ b/linux-core/radeon_cursor.c @@ -0,0 +1,243 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 + +static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock) +{ + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + uint32_t cur_lock; + + if (radeon_is_avivo(dev_priv)) { + cur_lock = RADEON_READ(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset); + if (lock) + cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK; + else + cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK; + RADEON_WRITE(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock); + } else { + switch(radeon_crtc->crtc_id) { + case 0: + cur_lock = RADEON_READ(RADEON_CUR_OFFSET); + if (lock) + cur_lock |= RADEON_CUR_LOCK; + else + cur_lock &= ~RADEON_CUR_LOCK; + RADEON_WRITE(RADEON_CUR_OFFSET, cur_lock); + break; + case 1: + cur_lock = RADEON_READ(RADEON_CUR2_OFFSET); + if (lock) + cur_lock |= RADEON_CUR2_LOCK; + else + cur_lock &= ~RADEON_CUR2_LOCK; + RADEON_WRITE(RADEON_CUR2_OFFSET, cur_lock); + break; + default: + break; + } + } +} + +static void radeon_hide_cursor(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + + if (radeon_is_avivo(dev_priv)) { + RADEON_WRITE(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); + RADEON_WRITE_P(RADEON_MM_DATA, 0, ~AVIVO_D1CURSOR_EN); + } else { + switch(radeon_crtc->crtc_id) { + case 0: + RADEON_WRITE(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); + break; + case 1: + RADEON_WRITE(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL); + break; + default: + return; + } + RADEON_WRITE_P(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN); + } +} + +static void radeon_show_cursor(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + + if (radeon_is_avivo(dev_priv)) { + RADEON_WRITE(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); + RADEON_WRITE(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | + (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); + } else { + switch(radeon_crtc->crtc_id) { + case 0: + RADEON_WRITE(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); + break; + case 1: + RADEON_WRITE(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL); + break; + default: + return; + } + + RADEON_WRITE_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN | + (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)), + ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK)); + } +} + +static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj, + uint32_t width, uint32_t height) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + struct drm_radeon_gem_object *obj_priv; + + obj_priv = obj->driver_private; + + if (radeon_is_avivo(dev_priv)) { + RADEON_WRITE(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + dev_priv->fb_location + obj_priv->bo->offset); + RADEON_WRITE(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, + (width - 1) << 16 | (height - 1)); + } else { + switch(radeon_crtc->crtc_id) { + case 0: + /* offset is from DISP_BASE_ADDRESS */ + RADEON_WRITE(RADEON_CUR_OFFSET, obj_priv->bo->offset); + break; + case 1: + /* offset is from DISP2_BASE_ADDRESS */ + RADEON_WRITE(RADEON_CUR2_OFFSET, obj_priv->bo->offset); + break; + default: + break; + } + } +} + +int radeon_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_gem_object *obj; + + if (!handle) { + /* turn off cursor */ + radeon_hide_cursor(crtc); + return 0; + } + + obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); + if (!obj) { + DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); + return -EINVAL; + } + + if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { + DRM_ERROR("bad cursor width or height %d x %d\n", width, height); + return -EINVAL; + } + + radeon_lock_cursor(crtc, true); + // XXX only 27 bit offset for legacy cursor + radeon_set_cursor(crtc, obj, width, height); + radeon_show_cursor(crtc); + radeon_lock_cursor(crtc, false); + + mutex_lock(&crtc->dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&crtc->dev->struct_mutex); + + return 0; +} + +int radeon_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_radeon_private *dev_priv = crtc->dev->dev_private; + int xorigin = 0, yorigin = 0; + + if (x < 0) + xorigin = -x + 1; + if (y < 0) + yorigin = -x + 1; + if (xorigin >= CURSOR_WIDTH) + xorigin = CURSOR_WIDTH - 1; + if (yorigin >= CURSOR_WIDTH) + yorigin = CURSOR_WIDTH - 1; + + radeon_lock_cursor(crtc, true); + if (radeon_is_avivo(dev_priv)) { + RADEON_WRITE(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, + ((xorigin ? 0: x) << 16) | + (yorigin ? 0 : y)); + RADEON_WRITE(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); + } else { + if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + y /= 2; + else if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) + y *= 2; + + switch(radeon_crtc->crtc_id) { + case 0: + RADEON_WRITE(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK + | (xorigin << 16) + | yorigin)); + RADEON_WRITE(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK + | ((xorigin ? 0 : x) << 16) + | (yorigin ? 0 : y))); + break; + case 1: + RADEON_WRITE(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK + | (xorigin << 16) + | yorigin)); + RADEON_WRITE(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK + | ((xorigin ? 0 : x) << 16) + | (yorigin ? 0 : y))); + break; + default: + break; + } + + } + radeon_lock_cursor(crtc, false); + + return 0; +} + diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 95258efa..39eb91eb 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -32,9 +32,6 @@ #include "drm_crtc_helper.h" -#define CURSOR_WIDTH 64 -#define CURSOR_HEIGHT 64 - int radeon_ddc_dump(struct drm_connector *connector); @@ -124,96 +121,6 @@ void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, radeon_crtc->lut_b[regno] = blue >> 8; } - - -static void avivo_lock_cursor(struct drm_crtc *crtc, bool lock) -{ - struct drm_radeon_private *dev_priv = crtc->dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - - uint32_t tmp; - - tmp = RADEON_READ(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset); - if (lock) - tmp |= AVIVO_D1CURSOR_UPDATE_LOCK; - else - tmp &= ~AVIVO_D1CURSOR_UPDATE_LOCK; - - RADEON_WRITE(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, tmp); -} - -static int radeon_crtc_cursor_set(struct drm_crtc *crtc, - struct drm_file *file_priv, - uint32_t handle, - uint32_t width, - uint32_t height) -{ - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct drm_radeon_private *dev_priv = crtc->dev->dev_private; - struct drm_gem_object *obj; - struct drm_radeon_gem_object *obj_priv; - - if (!handle) { - RADEON_WRITE(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 0); - return 0; - /* turn off cursor */ - } - - obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); - if (!obj) { - DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); - return -EINVAL; - } - - obj_priv = obj->driver_private; - - RADEON_WRITE(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, 0); - if (radeon_is_avivo(dev_priv)) { - RADEON_WRITE(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - dev_priv->fb_location + obj_priv->bo->offset); - RADEON_WRITE(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, - (CURSOR_WIDTH - 1) << 16 | (CURSOR_HEIGHT - 1)); - RADEON_WRITE(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset, - AVIVO_D1CURSOR_EN | (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); - } - - mutex_lock(&crtc->dev->struct_mutex); - drm_gem_object_unreference(obj); - mutex_unlock(&crtc->dev->struct_mutex); - - return 0; -} - -static int radeon_crtc_cursor_move(struct drm_crtc *crtc, - int x, int y) -{ - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct drm_radeon_private *dev_priv = crtc->dev->dev_private; - int xorigin = 0, yorigin = 0; - - if (x < 0) xorigin = -x+1; - if (y < 0) yorigin = -x+1; - if (xorigin >= CURSOR_WIDTH) xorigin = CURSOR_WIDTH - 1; - if (yorigin >= CURSOR_WIDTH) yorigin = CURSOR_WIDTH - 1; - - if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) - y /= 2; - else if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN) - y *= 2; - - if (radeon_is_avivo(dev_priv)) { - avivo_lock_cursor(crtc, true); - - RADEON_WRITE(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, - ((xorigin ? 0: x) << 16) | - (yorigin ? 0 : y)); - RADEON_WRITE(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); - avivo_lock_cursor(crtc, false); - } - - return 0; -} - static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, uint32_t size) { diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 3e0ffc66..6a2e275c 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -393,6 +393,15 @@ extern void atombios_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, int x, int y); extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); + +extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, + uint32_t width, + uint32_t height); +extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, + int x, int y); + extern bool radeon_atom_get_clock_info(struct drm_device *dev); extern bool radeon_combios_get_clock_info(struct drm_device *dev); extern void radeon_get_lvds_info(struct radeon_encoder *encoder); diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index 887b2f84..ad91e04c 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -374,6 +374,9 @@ # define RADEON_CRTC_ICON_EN (1 << 15) # define RADEON_CRTC_CUR_EN (1 << 16) # define RADEON_CRTC_CUR_MODE_MASK (7 << 20) +# define RADEON_CRTC_CUR_MODE_SHIFT 20 +# define RADEON_CRTC_CUR_MODE_MONO 0 +# define RADEON_CRTC_CUR_MODE_24BPP 2 # define RADEON_CRTC_EXT_DISP_EN (1 << 24) # define RADEON_CRTC_EN (1 << 25) # define RADEON_CRTC_DISP_REQ_EN_B (1 << 26) @@ -3591,14 +3594,14 @@ #define AVIVO_D1GRPH_X_END 0x6134 #define AVIVO_D1GRPH_Y_END 0x6138 #define AVIVO_D1GRPH_UPDATE 0x6144 -# define AVIVO_D1GRPH_UPDATE_LOCK (1<<16) +# define AVIVO_D1GRPH_UPDATE_LOCK (1 << 16) #define AVIVO_D1GRPH_FLIP_CONTROL 0x6148 #define AVIVO_D1CUR_CONTROL 0x6400 -# define AVIVO_D1CURSOR_EN (1<<0) -# define AVIVO_D1CURSOR_MODE_SHIFT 8 -# define AVIVO_D1CURSOR_MODE_MASK (0x3<<8) -# define AVIVO_D1CURSOR_MODE_24BPP (0x2) +# define AVIVO_D1CURSOR_EN (1 << 0) +# define AVIVO_D1CURSOR_MODE_SHIFT 8 +# define AVIVO_D1CURSOR_MODE_MASK (3 << 8) +# define AVIVO_D1CURSOR_MODE_24BPP 2 #define AVIVO_D1CUR_SURFACE_ADDRESS 0x6408 #define AVIVO_D1CUR_SIZE 0x6410 #define AVIVO_D1CUR_POSITION 0x6414 -- cgit v1.2.3 From ae89ced7ded55c164c620ebbd799fdb44ed9c09f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Aug 2008 02:11:44 -0400 Subject: Convert COM BIOS to table offset lookup function --- linux-core/radeon_combios.c | 631 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 513 insertions(+), 118 deletions(-) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index 3b01385c..c293cd71 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -30,6 +30,57 @@ /* old legacy ATI BIOS routines */ +/* COMBIOS table offsets */ +enum radeon_combios_table_offset +{ + /* absolute offset tables */ + COMBIOS_ASIC_INIT_1_TABLE, + COMBIOS_BIOS_SUPPORT_TABLE, + COMBIOS_DAC_PROGRAMMING_TABLE, + COMBIOS_MAX_COLOR_DEPTH_TABLE, + COMBIOS_CRTC_INFO_TABLE, + COMBIOS_PLL_INFO_TABLE, + COMBIOS_TV_INFO_TABLE, + COMBIOS_DFP_INFO_TABLE, + COMBIOS_HW_CONFIG_INFO_TABLE, + COMBIOS_MULTIMEDIA_INFO_TABLE, + COMBIOS_TV_STD_PATCH_TABLE, + COMBIOS_LCD_INFO_TABLE, + COMBIOS_MOBILE_INFO_TABLE, + COMBIOS_PLL_INIT_TABLE, + COMBIOS_MEM_CONFIG_TABLE, + COMBIOS_SAVE_MASK_TABLE, + COMBIOS_HARDCODED_EDID_TABLE, + COMBIOS_ASIC_INIT_2_TABLE, + COMBIOS_CONNECTOR_INFO_TABLE, + COMBIOS_DYN_CLK_1_TABLE, + COMBIOS_RESERVED_MEM_TABLE, + COMBIOS_EXT_TDMS_INFO_TABLE, + COMBIOS_MEM_CLK_INFO_TABLE, + COMBIOS_EXT_DAC_INFO_TABLE, + COMBIOS_MISC_INFO_TABLE, + COMBIOS_CRT_INFO_TABLE, + COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE, + COMBIOS_COMPONENT_VIDEO_INFO_TABLE, + COMBIOS_FAN_SPEED_INFO_TABLE, + COMBIOS_OVERDRIVE_INFO_TABLE, + COMBIOS_OEM_INFO_TABLE, + COMBIOS_DYN_CLK_2_TABLE, + COMBIOS_POWER_CONNECTOR_INFO_TABLE, + COMBIOS_I2C_INFO_TABLE, + /* relative offset tables */ + COMBIOS_ASIC_INIT_3_TABLE, /* offset from misc info */ + COMBIOS_ASIC_INIT_4_TABLE, /* offset from misc info */ + COMBIOS_ASIC_INIT_5_TABLE, /* offset from misc info */ + COMBIOS_RAM_RESET_TABLE, /* offset from mem config */ + COMBIOS_POWERPLAY_TABLE, /* offset from mobile info */ + COMBIOS_GPIO_INFO_TABLE, /* offset from mobile info */ + COMBIOS_LCD_DDC_INFO_TABLE, /* offset from mobile info */ + COMBIOS_TMDS_POWER_TABLE, /* offset from mobile info */ + COMBIOS_TMDS_POWER_ON_TABLE, /* offset from tmds power */ + COMBIOS_TMDS_POWER_OFF_TABLE, /* offset from tmds power */ +}; + enum radeon_combios_ddc { DDC_NONE_DETECTED, @@ -53,6 +104,283 @@ enum radeon_combios_connector CONNECTOR_UNSUPPORTED_LEGACY }; +static uint16_t combios_get_table_offset(struct drm_device *dev, enum radeon_combios_table_offset table) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + int rev; + uint16_t offset = 0, check_offset; + + switch (table) { + /* absolute offset tables */ + case COMBIOS_ASIC_INIT_1_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0xc); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_BIOS_SUPPORT_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x14); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_DAC_PROGRAMMING_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x2a); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MAX_COLOR_DEPTH_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x2c); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_CRTC_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x2e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_PLL_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x30); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_TV_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x32); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_DFP_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x34); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_HW_CONFIG_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x36); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MULTIMEDIA_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x38); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_TV_STD_PATCH_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x3e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_LCD_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x40); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MOBILE_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x42); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_PLL_INIT_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x46); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MEM_CONFIG_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x48); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_SAVE_MASK_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x4a); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_HARDCODED_EDID_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x4c); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_ASIC_INIT_2_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x4e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_CONNECTOR_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x50); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_DYN_CLK_1_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x52); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_RESERVED_MEM_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x54); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_EXT_TDMS_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x58); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MEM_CLK_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x5a); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_EXT_DAC_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x5c); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_MISC_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x5e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_CRT_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x60); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x62); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_COMPONENT_VIDEO_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x64); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_FAN_SPEED_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x66); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_OVERDRIVE_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x68); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_OEM_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x6a); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_DYN_CLK_2_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x6c); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_POWER_CONNECTOR_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x6e); + if (check_offset) + offset = check_offset; + break; + case COMBIOS_I2C_INFO_TABLE: + check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x70); + if (check_offset) + offset = check_offset; + break; + /* relative offset tables */ + case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */ + check_offset = combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); + if (check_offset) { + rev = radeon_bios8(dev_priv, check_offset); + if (rev > 0) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x3); + if (check_offset) + offset = check_offset; + } + } + break; + case COMBIOS_ASIC_INIT_4_TABLE: /* offset from misc info */ + check_offset = combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); + if (check_offset) { + rev = radeon_bios8(dev_priv, check_offset); + if (rev > 0) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x5); + if (check_offset) + offset = check_offset; + } + } + break; + case COMBIOS_ASIC_INIT_5_TABLE: /* offset from misc info */ + check_offset = combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE); + if (check_offset) { + rev = radeon_bios8(dev_priv, check_offset); + if (rev == 2) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x9); + if (check_offset) + offset = check_offset; + } + } + break; + case COMBIOS_RAM_RESET_TABLE: /* offset from mem config */ + check_offset = combios_get_table_offset(dev, COMBIOS_MEM_CONFIG_TABLE); + if (check_offset) { + while (radeon_bios8(dev_priv, check_offset++)); + check_offset += 2; + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_POWERPLAY_TABLE: /* offset from mobile info */ + check_offset = combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); + if (check_offset) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x11); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_GPIO_INFO_TABLE: /* offset from mobile info */ + check_offset = combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); + if (check_offset) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x13); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_LCD_DDC_INFO_TABLE: /* offset from mobile info */ + check_offset = combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); + if (check_offset) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x15); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_TMDS_POWER_TABLE: /* offset from mobile info */ + check_offset = combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); + if (check_offset) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x17); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_TMDS_POWER_ON_TABLE: /* offset from tmds power */ + check_offset = combios_get_table_offset(dev, COMBIOS_TMDS_POWER_TABLE); + if (check_offset) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x2); + if (check_offset) + offset = check_offset; + } + break; + case COMBIOS_TMDS_POWER_OFF_TABLE: /* offset from tmds power */ + check_offset = combios_get_table_offset(dev, COMBIOS_TMDS_POWER_TABLE); + if (check_offset) { + check_offset = radeon_bios16(dev_priv, check_offset + 0x4); + if (check_offset) + offset = check_offset; + } + break; + default: + break; + } + + return offset; + +} + struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) { struct radeon_i2c_bus_rec i2c; @@ -98,125 +426,130 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_mode_info *mode_info = &dev_priv->mode_info; - uint16_t pll_info_block; + uint16_t pll_info; struct radeon_pll *pll = &mode_info->pll; int rev; - pll_info_block = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x30); - rev = radeon_bios8(dev_priv, pll_info_block); + pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE); + if (pll_info) { + rev = radeon_bios8(dev_priv, pll_info); - pll->reference_freq = radeon_bios16(dev_priv, pll_info_block + 0xe); - pll->reference_div = radeon_bios16(dev_priv, pll_info_block + 0x10); - pll->pll_out_min = radeon_bios32(dev_priv, pll_info_block + 0x12); - pll->pll_out_max = radeon_bios32(dev_priv, pll_info_block + 0x16); + pll->reference_freq = radeon_bios16(dev_priv, pll_info + 0xe); + pll->reference_div = radeon_bios16(dev_priv, pll_info + 0x10); + pll->pll_out_min = radeon_bios32(dev_priv, pll_info + 0x12); + pll->pll_out_max = radeon_bios32(dev_priv, pll_info + 0x16); - if (rev > 9) { - pll->pll_in_min = radeon_bios32(dev_priv, pll_info_block + 0x36); - pll->pll_in_max = radeon_bios32(dev_priv, pll_info_block + 0x3a); - } else { - pll->pll_in_min = 40; - pll->pll_in_max = 500; - } + if (rev > 9) { + pll->pll_in_min = radeon_bios32(dev_priv, pll_info + 0x36); + pll->pll_in_max = radeon_bios32(dev_priv, pll_info + 0x3a); + } else { + pll->pll_in_min = 40; + pll->pll_in_max = 500; + } - pll->xclk = radeon_bios16(dev_priv, pll_info_block + 0x08); + pll->xclk = radeon_bios16(dev_priv, pll_info + 0x08); - // sclk/mclk use fixed point - - return true; + // sclk/mclk use fixed point + return true; + } + return false; } bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_radeon_private *dev_priv = dev->dev_private; - uint16_t tmp; + uint16_t lcd_info; char stmp[30]; - int tmp0; - int i; - - tmp = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x40); - if (!tmp) { - DRM_INFO("No panel info found in BIOS\n"); - return false; + int tmp, i; - } + lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); - for (i = 0; i < 24; i++) - stmp[i] = radeon_bios8(dev_priv, tmp + i + 1); - stmp[24] = 0; + if (lcd_info) { + for (i = 0; i < 24; i++) + stmp[i] = radeon_bios8(dev_priv, lcd_info + i + 1); + stmp[24] = 0; - DRM_INFO("Panel ID String: %s\n", stmp); + DRM_INFO("Panel ID String: %s\n", stmp); - encoder->panel_xres = radeon_bios16(dev_priv, tmp + 25); - encoder->panel_yres = radeon_bios16(dev_priv, tmp + 27); + encoder->panel_xres = radeon_bios16(dev_priv, lcd_info + 25); + encoder->panel_yres = radeon_bios16(dev_priv, lcd_info + 27); - DRM_INFO("Panel Size %dx%d\n", encoder->panel_xres, encoder->panel_yres); + DRM_INFO("Panel Size %dx%d\n", encoder->panel_xres, encoder->panel_yres); - encoder->panel_pwr_delay = radeon_bios16(dev_priv, tmp + 44); - if (encoder->panel_pwr_delay > 2000 || encoder->panel_pwr_delay < 0) - encoder->panel_pwr_delay = 2000; + encoder->panel_pwr_delay = radeon_bios16(dev_priv, lcd_info + 44); + if (encoder->panel_pwr_delay > 2000 || encoder->panel_pwr_delay < 0) + encoder->panel_pwr_delay = 2000; - for (i = 0; i < 32; i++) { - tmp0 = radeon_bios16(dev_priv, tmp + 64 + i * 2); - if (tmp0 == 0) break; + for (i = 0; i < 32; i++) { + tmp = radeon_bios16(dev_priv, lcd_info + 64 + i * 2); + if (tmp == 0) break; - if ((radeon_bios16(dev_priv, tmp0) == encoder->panel_xres) && - (radeon_bios16(dev_priv, tmp0 + 2) == encoder->panel_yres)) { - encoder->hblank = (radeon_bios16(dev_priv, tmp0 + 17) - - radeon_bios16(dev_priv, tmp0 + 19)) * 8; - encoder->hoverplus = (radeon_bios16(dev_priv, tmp0 + 21) - - radeon_bios16(dev_priv, tmp0 + 19) - 1) * 8; - encoder->hsync_width = radeon_bios8(dev_priv, tmp0 + 23) * 8; + if ((radeon_bios16(dev_priv, tmp) == encoder->panel_xres) && + (radeon_bios16(dev_priv, tmp + 2) == encoder->panel_yres)) { + encoder->hblank = (radeon_bios16(dev_priv, tmp + 17) - + radeon_bios16(dev_priv, tmp + 19)) * 8; + encoder->hoverplus = (radeon_bios16(dev_priv, tmp + 21) - + radeon_bios16(dev_priv, tmp + 19) - 1) * 8; + encoder->hsync_width = radeon_bios8(dev_priv, tmp + 23) * 8; - encoder->vblank = (radeon_bios16(dev_priv, tmp0 + 24) - - radeon_bios16(dev_priv, tmp0 + 26)); - encoder->voverplus = ((radeon_bios16(dev_priv, tmp0 + 28) & 0x7fff) - - radeon_bios16(dev_priv, tmp0 + 26)); - encoder->vsync_width = ((radeon_bios16(dev_priv, tmp0 + 28) & 0xf800) >> 11); - encoder->dotclock = radeon_bios16(dev_priv, tmp0 + 9) * 10; - encoder->flags = 0; + encoder->vblank = (radeon_bios16(dev_priv, tmp + 24) - + radeon_bios16(dev_priv, tmp + 26)); + encoder->voverplus = ((radeon_bios16(dev_priv, tmp + 28) & 0x7fff) - + radeon_bios16(dev_priv, tmp + 26)); + encoder->vsync_width = ((radeon_bios16(dev_priv, tmp + 28) & 0xf800) >> 11); + encoder->dotclock = radeon_bios16(dev_priv, tmp + 9) * 10; + encoder->flags = 0; + } } + return true; } - return true; + DRM_INFO("No panel info found in BIOS\n"); + return false; + } bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_radeon_private *dev_priv = dev->dev_private; - uint16_t tmp; + uint16_t tmds_info; int i, n; uint8_t ver; - tmp = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x34); - if (!tmp) { - DRM_INFO("No TMDS info found in BIOS\n"); - return false; - } - - ver = radeon_bios8(dev_priv, tmp); - DRM_INFO("DFP table revision: %d\n", ver); - if (ver == 3) { - n = radeon_bios8(dev_priv, tmp + 5) + 1; - if (n > 4) n = 4; - for (i = 0; i < n; i++) { - encoder->tmds_pll[i].value = radeon_bios32(dev_priv, tmp+i*10+0x08); - encoder->tmds_pll[i].freq = radeon_bios16(dev_priv, tmp+i*10+0x10); - } - return true; - } else if (ver == 4) { - int stride = 0; - n = radeon_bios8(dev_priv, tmp + 5) + 1; - if (n > 4) n = 4; - for (i = 0; i < n; i++) { - encoder->tmds_pll[i].value = radeon_bios32(dev_priv, tmp+stride+0x08); - encoder->tmds_pll[i].freq = radeon_bios16(dev_priv, tmp+stride+0x10); - if (i == 0) stride += 10; - else stride += 6; + tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); + + if (tmds_info) { + ver = radeon_bios8(dev_priv, tmds_info); + DRM_INFO("DFP table revision: %d\n", ver); + if (ver == 3) { + n = radeon_bios8(dev_priv, tmds_info + 5) + 1; + if (n > 4) + n = 4; + for (i = 0; i < n; i++) { + encoder->tmds_pll[i].value = radeon_bios32(dev_priv, tmds_info + i * 10 + 0x08); + encoder->tmds_pll[i].freq = radeon_bios16(dev_priv, tmds_info + i * 10 + 0x10); + } + return true; + } else if (ver == 4) { + int stride = 0; + n = radeon_bios8(dev_priv, tmds_info + 5) + 1; + if (n > 4) + n = 4; + for (i = 0; i < n; i++) { + encoder->tmds_pll[i].value = radeon_bios32(dev_priv, tmds_info + stride + 0x08); + encoder->tmds_pll[i].freq = radeon_bios16(dev_priv, tmds_info + stride + 0x10); + if (i == 0) + stride += 10; + else + stride += 6; + } + return true; } - return true; } + + DRM_INFO("No TMDS info found in BIOS\n"); return false; } @@ -262,17 +595,17 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_mode_info *mode_info = &dev_priv->mode_info; - uint32_t offset, entry; - uint16_t tmp0, tmp1, tmp; - enum radeon_combios_ddc ddctype; + uint32_t conn_info, entry; + uint16_t tmp; + enum radeon_combios_ddc ddc_type; enum radeon_combios_connector connector_type; int i; DRM_DEBUG("\n"); - offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x50); - if (offset) { + conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE); + if (conn_info) { for (i = 0; i < 4; i++) { - entry = offset + 2 + i * 2; + entry = conn_info + 2 + i * 2; if (!radeon_bios16(dev_priv, entry)) break; @@ -311,8 +644,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) mode_info->bios_connector[i].ddc_i2c.valid = false; - ddctype = (tmp >> 8) & 0xf; - switch (ddctype) { + ddc_type = (tmp >> 8) & 0xf; + switch (ddc_type) { case DDC_MONID: mode_info->bios_connector[i].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); break; @@ -347,9 +680,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) radeon_apply_legacy_quirks(dev, i); } } else { - DRM_INFO("no connector table found in BIOS\n"); - offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x34); - if (offset) { + uint16_t tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); + if (tmds_info) { DRM_DEBUG("Found DFP table, assuming DVI connector\n"); mode_info->bios_connector[0].valid = true; @@ -358,45 +690,108 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) mode_info->bios_connector[0].tmds_type = TMDS_INT; mode_info->bios_connector[0].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); } else { - DRM_DEBUG("No table found\n"); + DRM_DEBUG("No connector info found\n"); return false; } } - if (dev_priv->flags & RADEON_IS_MOBILITY) { - offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x40); - if (offset) { + if (dev_priv->flags & RADEON_IS_MOBILITY || + dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) { + uint16_t lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); + if (lcd_info) { + uint16_t lcd_ddc_info = lcd_ddc_info = combios_get_table_offset(dev, COMBIOS_LCD_DDC_INFO_TABLE); + mode_info->bios_connector[4].valid = true; mode_info->bios_connector[4].connector_type = CONNECTOR_LVDS; mode_info->bios_connector[4].dac_type = DAC_NONE; mode_info->bios_connector[4].tmds_type = TMDS_NONE; mode_info->bios_connector[4].ddc_i2c.valid = false; - tmp = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x42); - if (tmp) { - tmp0 = radeon_bios16(dev_priv, tmp + 0x15); - if (tmp0) { - tmp1 = radeon_bios8(dev_priv, tmp0 + 2) & 0x07; - if (tmp1) { - ddctype = tmp1; - - switch(ddctype) { - case DDC_MONID: - case DDC_DVI: - case DDC_CRT2: - case DDC_LCD: - case DDC_GPIO: - default: - break; - } - DRM_DEBUG("LCD DDC Info Table found!\n"); - } + if (lcd_ddc_info) { + ddc_type = radeon_bios8(dev_priv, lcd_ddc_info + 2); + switch(ddc_type) { + case DDC_MONID: + mode_info->bios_connector[4].ddc_i2c = + combios_setup_i2c_bus(RADEON_GPIO_MONID); + break; + case DDC_DVI: + mode_info->bios_connector[4].ddc_i2c = + combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + break; + case DDC_VGA: + mode_info->bios_connector[4].ddc_i2c = + combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + break; + case DDC_CRT2: + mode_info->bios_connector[4].ddc_i2c = + combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + break; + case DDC_LCD: + mode_info->bios_connector[4].ddc_i2c = + combios_setup_i2c_bus(RADEON_LCD_GPIO_MASK); + mode_info->bios_connector[4].ddc_i2c.mask_clk_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 3); + mode_info->bios_connector[4].ddc_i2c.mask_data_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 7); + mode_info->bios_connector[4].ddc_i2c.a_clk_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 3); + mode_info->bios_connector[4].ddc_i2c.a_data_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 7); + mode_info->bios_connector[4].ddc_i2c.put_clk_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 3); + mode_info->bios_connector[4].ddc_i2c.put_data_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 7); + mode_info->bios_connector[4].ddc_i2c.get_clk_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 3); + mode_info->bios_connector[4].ddc_i2c.get_data_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 7); + break; + case DDC_GPIO: + mode_info->bios_connector[4].ddc_i2c = + combios_setup_i2c_bus(RADEON_MDGPIO_EN_REG); + mode_info->bios_connector[4].ddc_i2c.mask_clk_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 3); + mode_info->bios_connector[4].ddc_i2c.mask_data_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 7); + mode_info->bios_connector[4].ddc_i2c.a_clk_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 3); + mode_info->bios_connector[4].ddc_i2c.a_data_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 7); + mode_info->bios_connector[4].ddc_i2c.put_clk_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 3); + mode_info->bios_connector[4].ddc_i2c.put_data_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 7); + mode_info->bios_connector[4].ddc_i2c.get_clk_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 3); + mode_info->bios_connector[4].ddc_i2c.get_data_mask = + radeon_bios32(dev_priv, lcd_ddc_info + 7); + break; + default: + break; } - } else - mode_info->bios_connector[4].ddc_i2c.valid = false; + DRM_DEBUG("LCD DDC Info Table found!\n"); + } + } else + mode_info->bios_connector[4].ddc_i2c.valid = false; + } + + /* check TV table */ + if (dev_priv->chip_family != CHIP_R100 && + dev_priv->chip_family != CHIP_R200) { + uint32_t tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); + if (tv_info) { + if (radeon_bios8(dev_priv, tv_info + 6) == 'T') { + mode_info->bios_connector[5].valid = true; + mode_info->bios_connector[5].connector_type = CONNECTOR_DIN; + mode_info->bios_connector[5].dac_type = DAC_TVDAC; + mode_info->bios_connector[5].tmds_type = TMDS_NONE; + mode_info->bios_connector[5].ddc_i2c.valid = false; + } } } + DRM_DEBUG("BIOS Connector table\n"); for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { if (!mode_info->bios_connector[i].valid) -- cgit v1.2.3 From 8867eca8721a02135f4b0e65a454d5e05141eee3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Aug 2008 03:05:11 -0400 Subject: set base in legacy crtc mode set --- linux-core/radeon_legacy_crtc.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index 6446f8cb..7f7ce617 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -917,6 +917,21 @@ static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, return true; } +void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + switch(radeon_crtc->crtc_id) { + case 0: + radeon_set_crtc1_base(crtc, x, y); + break; + case 1: + radeon_set_crtc2_base(crtc, x, y); + break; + + } +} + static void radeon_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -942,6 +957,8 @@ static void radeon_crtc_mode_set(struct drm_crtc *crtc, /* TODO TV */ + radeon_crtc_set_base(crtc, x, y); + switch(radeon_crtc->crtc_id) { case 0: radeon_set_crtc1_timing(crtc, adjusted_mode); @@ -955,21 +972,6 @@ static void radeon_crtc_mode_set(struct drm_crtc *crtc, } } -void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y) -{ - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - - switch(radeon_crtc->crtc_id) { - case 0: - radeon_set_crtc1_base(crtc, x, y); - break; - case 1: - radeon_set_crtc2_base(crtc, x, y); - break; - - } -} - static void radeon_crtc_prepare(struct drm_crtc *crtc) { radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); -- cgit v1.2.3 From b486ed7f7d89528c94f2345040324946f6eadc81 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Aug 2008 13:52:35 -0400 Subject: Get legacy working finally - extra ~ in RADEON_WRITE_P() - re-arrange crtc setup a bit - add debugging for tracing calls - fix pitch calculation --- linux-core/radeon_legacy_crtc.c | 74 ++++++++++++++++++++++--------------- linux-core/radeon_legacy_encoders.c | 38 ++++++++++++++++++- shared-core/radeon_drv.h | 2 +- 3 files changed, 83 insertions(+), 31 deletions(-) diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index 7f7ce617..6dea4d41 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -123,42 +123,43 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - uint32_t mask; + DRM_DEBUG("\n"); + mask = radeon_crtc->crtc_id ? (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_REQ_EN_B) : (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS); switch(mode) { case DRM_MODE_DPMS_ON: - if (radeon_crtc->crtc_id) { + if (radeon_crtc->crtc_id) RADEON_WRITE_P(RADEON_CRTC2_GEN_CNTL, 0, ~mask); - } else { + else { RADEON_WRITE_P(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, 0, ~mask); } break; case DRM_MODE_DPMS_STANDBY: - if (radeon_crtc->crtc_id) { + if (radeon_crtc->crtc_id) RADEON_WRITE_P(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS), ~mask); - } else { + else { RADEON_WRITE_P(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS), ~mask); } break; case DRM_MODE_DPMS_SUSPEND: - if (radeon_crtc->crtc_id) { + if (radeon_crtc->crtc_id) RADEON_WRITE_P(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS), ~mask); - } else { + else { RADEON_WRITE_P(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS), ~mask); } break; case DRM_MODE_DPMS_OFF: - if (radeon_crtc->crtc_id) { + if (radeon_crtc->crtc_id) RADEON_WRITE_P(RADEON_CRTC2_GEN_CNTL, mask, ~mask); - } else { + else { RADEON_WRITE_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~RADEON_CRTC_DISP_REQ_EN_B); RADEON_WRITE_P(RADEON_CRTC_EXT_CNTL, mask, ~mask); } @@ -179,6 +180,9 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) struct drm_radeon_gem_object *obj_priv; uint32_t base; uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0; + uint32_t crtc_pitch; + + DRM_DEBUG("\n"); radeon_fb = to_radeon_framebuffer(crtc->fb); @@ -243,11 +247,20 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) crtc_offset = base; + crtc_pitch = ((((crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8)) * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) - 1)) / + (crtc->fb->bits_per_pixel * 8)); + crtc_pitch |= crtc_pitch << 16; + + DRM_DEBUG("mc_fb_location: 0x%x\n", dev_priv->fb_location); + + RADEON_WRITE(RADEON_DISPLAY_BASE_ADDR, dev_priv->fb_location); + if (radeon_is_r300(dev_priv)) RADEON_WRITE(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0); - RADEON_WRITE(RADEON_CRTC_OFFSET_CNTL, crtc_offset_cntl); RADEON_WRITE(RADEON_CRTC_OFFSET, crtc_offset); + RADEON_WRITE(RADEON_CRTC_PITCH, crtc_pitch); return true; } @@ -267,10 +280,11 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo uint32_t crtc_h_sync_strt_wid; uint32_t crtc_v_total_disp; uint32_t crtc_v_sync_strt_wid; - uint32_t crtc_pitch; uint32_t disp_merge_cntl; - switch (crtc->fb->depth) { + DRM_DEBUG("\n"); + + switch (crtc->fb->bits_per_pixel) { case 15: /* 555 */ format = 3; @@ -302,7 +316,7 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo : 0)); crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); - crtc_ext_cntl |= (RADEON_XCRT_CNT_EN| + crtc_ext_cntl |= (RADEON_XCRT_CNT_EN | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_DISPLAY_DIS); @@ -338,11 +352,6 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo ? RADEON_CRTC_V_SYNC_POL : 0)); - crtc_pitch = (((crtc->fb->pitch * crtc->fb->bits_per_pixel) + - ((crtc->fb->bits_per_pixel * 8) -1)) / - (crtc->fb->bits_per_pixel * 8)); - crtc_pitch |= crtc_pitch << 16; - /* TODO -> Dell Server */ if (0) { uint32_t disp_hw_debug = RADEON_READ(RADEON_DISP_HW_DEBUG); @@ -381,7 +390,6 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo RADEON_WRITE(RADEON_CRTC_V_TOTAL_DISP, crtc_v_total_disp); RADEON_WRITE(RADEON_CRTC_V_SYNC_STRT_WID, crtc_v_sync_strt_wid); - RADEON_WRITE(RADEON_CRTC_PITCH, crtc_pitch); RADEON_WRITE(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); RADEON_WRITE(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); @@ -569,7 +577,7 @@ static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode RADEON_VCLK_SRC_SEL_PPLLCLK, ~(RADEON_VCLK_SRC_SEL_MASK)); - /*RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, state->vclk_ecp_cntl);*/ + /*RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl);*/ } @@ -580,8 +588,11 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_framebuffer *radeon_fb; struct drm_radeon_gem_object *obj_priv; - uint32_t crtc2_offset, crtc2_offset_cntl, crtc2_tile_x0_y0 = 0; uint32_t base; + uint32_t crtc2_offset, crtc2_offset_cntl, crtc2_tile_x0_y0 = 0; + uint32_t crtc2_pitch; + + DRM_DEBUG("\n"); radeon_fb = to_radeon_framebuffer(crtc->fb); @@ -646,10 +657,18 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) crtc2_offset = base; + crtc2_pitch = ((((crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8)) * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) - 1)) / + (crtc->fb->bits_per_pixel * 8)); + crtc2_pitch |= crtc2_pitch << 16; + + RADEON_WRITE(RADEON_DISPLAY2_BASE_ADDR, dev_priv->fb_location); + if (radeon_is_r300(dev_priv)) RADEON_WRITE(R300_CRTC2_TILE_X0_Y0, crtc2_tile_x0_y0); RADEON_WRITE(RADEON_CRTC2_OFFSET_CNTL, crtc2_offset_cntl); RADEON_WRITE(RADEON_CRTC2_OFFSET, crtc2_offset); + RADEON_WRITE(RADEON_CRTC2_PITCH, crtc2_pitch); return true; } @@ -668,12 +687,13 @@ static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mo uint32_t crtc2_h_sync_strt_wid; uint32_t crtc2_v_total_disp; uint32_t crtc2_v_sync_strt_wid; - uint32_t crtc2_pitch; uint32_t disp2_merge_cntl; uint32_t fp_h2_sync_strt_wid; uint32_t fp_v2_sync_strt_wid; - switch (crtc->fb->depth) { + DRM_DEBUG("\n"); + + switch (crtc->fb->bits_per_pixel) { case 15: /* 555 */ format = 3; @@ -720,11 +740,6 @@ static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mo ? RADEON_CRTC2_V_SYNC_POL : 0)); - crtc2_pitch = (((crtc->fb->pitch * crtc->fb->bits_per_pixel) + - ((crtc->fb->bits_per_pixel * 8) -1)) / - (crtc->fb->bits_per_pixel * 8)); - crtc2_pitch |= crtc2_pitch << 16; - /* check to see if TV DAC is enabled for another crtc and keep it enabled */ if (RADEON_READ(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_CRT2_ON) crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON; @@ -765,7 +780,6 @@ static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mo RADEON_WRITE(RADEON_FP_H2_SYNC_STRT_WID, fp_h2_sync_strt_wid); RADEON_WRITE(RADEON_FP_V2_SYNC_STRT_WID, fp_v2_sync_strt_wid); - RADEON_WRITE(RADEON_CRTC2_PITCH, crtc2_pitch); RADEON_WRITE(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); @@ -944,6 +958,8 @@ static void radeon_crtc_mode_set(struct drm_crtc *crtc, int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV; int i; + DRM_DEBUG("\n"); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 46cf791e..998a9f73 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -47,6 +47,7 @@ static void radeon_legacy_rmx_mode_set(struct drm_encoder *encoder, uint32_t fp_horz_stretch, fp_vert_stretch, crtc_more_cntl, fp_horz_vert_active; uint32_t fp_h_sync_strt_wid, fp_v_sync_strt_wid, fp_crtc_h_total_disp, fp_crtc_v_total_disp; + DRM_DEBUG("\n"); fp_vert_stretch = RADEON_READ(RADEON_FP_VERT_STRETCH) & (RADEON_VERT_STRETCH_RESERVED | @@ -199,7 +200,9 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; - switch(mode) { + DRM_DEBUG("\n"); + + switch (mode) { case DRM_MODE_DPMS_ON: disp_pwr_man = RADEON_READ(RADEON_DISP_PWR_MAN); disp_pwr_man |= RADEON_AUTO_PWRUP_EN; @@ -250,6 +253,8 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t lvds_pll_cntl, lvds_gen_cntl; + DRM_DEBUG("\n"); + if (radeon_crtc->crtc_id == 0) radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); @@ -319,6 +324,9 @@ struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int b struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; + + DRM_DEBUG("\n"); + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); if (!radeon_encoder) { return NULL; @@ -358,6 +366,8 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode uint32_t dac_cntl = RADEON_READ(RADEON_DAC_CNTL); uint32_t dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); + DRM_DEBUG("\n"); + switch(mode) { case DRM_MODE_DPMS_ON: crtc_ext_cntl |= RADEON_CRTC_CRT_ON; @@ -402,6 +412,8 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl; + DRM_DEBUG("\n"); + if (radeon_crtc->crtc_id == 0) radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); @@ -470,6 +482,9 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; + + DRM_DEBUG("\n"); + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); if (!radeon_encoder) { return NULL; @@ -504,6 +519,8 @@ static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t fp_gen_cntl = RADEON_READ(RADEON_FP_GEN_CNTL); + DRM_DEBUG("\n"); + switch(mode) { case DRM_MODE_DPMS_ON: fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); @@ -539,6 +556,8 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl; int i; + DRM_DEBUG("\n"); + if (radeon_crtc->crtc_id == 0) radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); @@ -631,6 +650,9 @@ struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, i struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; + + DRM_DEBUG("\n"); + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); if (!radeon_encoder) { return NULL; @@ -662,6 +684,8 @@ static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + DRM_DEBUG("\n"); + switch(mode) { case DRM_MODE_DPMS_ON: fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; @@ -698,6 +722,8 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + DRM_DEBUG("\n"); + if (radeon_crtc->crtc_id == 0) radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); @@ -762,6 +788,9 @@ struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, i struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; + + DRM_DEBUG("\n"); + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); if (!radeon_encoder) { return NULL; @@ -793,6 +822,8 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t fp2_gen_cntl, crtc2_gen_cntl, tv_master_cntl, tv_dac_cntl; + DRM_DEBUG("\n"); + if (dev_priv->chip_family == CHIP_R200) fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); else { @@ -876,6 +907,8 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, uint32_t tv_dac_cntl, gpiopad_a, dac2_cntl, disp_output_cntl, fp2_gen_cntl; uint32_t disp_hw_debug; + DRM_DEBUG("\n"); + if (radeon_crtc->crtc_id == 0) radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); @@ -981,6 +1014,9 @@ struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; + + DRM_DEBUG("\n"); + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); if (!radeon_encoder) { return NULL; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index fb266093..2b8d7f6e 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1283,7 +1283,7 @@ extern void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint #define RADEON_WRITE_P(reg, val, mask) \ do { \ uint32_t tmp = RADEON_READ(reg); \ - tmp &= ~(mask); \ + tmp &= (mask); \ tmp |= ((val) & ~(mask)); \ RADEON_WRITE(reg, tmp); \ } while(0) -- cgit v1.2.3 From a1f12024702d0636ead0ef512fd0372d6d1aa79f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Aug 2008 14:07:33 -0400 Subject: Fix warnings --- linux-core/radeon_legacy_crtc.c | 9 --------- linux-core/radeon_legacy_encoders.c | 34 +++++++++------------------------- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index 6dea4d41..08d4a477 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -173,7 +173,6 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_framebuffer *radeon_fb; @@ -267,7 +266,6 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mode *mode) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; int format; @@ -399,7 +397,6 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode, int flags) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t feedback_div = 0; @@ -583,7 +580,6 @@ static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_framebuffer *radeon_fb; @@ -675,7 +671,6 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mode *mode) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; int format; @@ -790,7 +785,6 @@ static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mo static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode, int flags) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; uint32_t feedback_div = 0; @@ -953,15 +947,12 @@ static void radeon_crtc_mode_set(struct drm_crtc *crtc, { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV; - int i; DRM_DEBUG("\n"); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); if (encoder->crtc == crtc) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 998a9f73..de9e8ac6 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -35,7 +35,6 @@ static void radeon_legacy_rmx_mode_set(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); int xres = mode->hdisplay; int yres = mode->vdisplay; @@ -207,6 +206,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) disp_pwr_man = RADEON_READ(RADEON_DISP_PWR_MAN); disp_pwr_man |= RADEON_AUTO_PWRUP_EN; RADEON_WRITE(RADEON_DISP_PWR_MAN, disp_pwr_man); + lvds_pll_cntl = RADEON_READ(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl |= RADEON_LVDS_PLL_EN; RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); udelay(1000); @@ -320,8 +320,6 @@ static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index) { - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; @@ -454,10 +452,7 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - + // FIXME return connector_status_disconnected; } @@ -478,8 +473,6 @@ static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev, int bios_index, int has_tv) { - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; @@ -507,8 +500,8 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev static bool radeon_legacy_tmds_int_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { return true; } @@ -646,8 +639,6 @@ static const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index) { - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; @@ -784,8 +775,6 @@ static const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index) { - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; @@ -820,7 +809,8 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - uint32_t fp2_gen_cntl, crtc2_gen_cntl, tv_master_cntl, tv_dac_cntl; + uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; + //uint32_t tv_master_cntl = 0; DRM_DEBUG("\n"); @@ -903,9 +893,8 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - uint32_t tv_dac_cntl, gpiopad_a, dac2_cntl, disp_output_cntl, fp2_gen_cntl; - uint32_t disp_hw_debug; + uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0; + uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0; DRM_DEBUG("\n"); @@ -986,10 +975,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - + // FIXME return connector_status_disconnected; } @@ -1010,8 +996,6 @@ static const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int has_tv) { - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_mode_info *mode_info = &dev_priv->mode_info; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; -- cgit v1.2.3 From 9b79d356c171e86e529ad1a4e5e145a36d1af601 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Aug 2008 15:33:20 -0400 Subject: Add additional quirks from ddx --- linux-core/radeon_combios.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index c293cd71..1080079f 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -558,16 +558,31 @@ static void radeon_apply_legacy_quirks(struct drm_device *dev, int bios_index) struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_mode_info *mode_info = &dev_priv->mode_info; - /* on XPRESS chips, CRT2_DDC and MONID_DCC both use the - * MONID gpio, but use different pins. - * CRT2_DDC uses the standard pinout, MONID_DDC uses - * something else. - */ + /* XPRESS DDC quirks */ if ((dev_priv->chip_family == CHIP_RS400 || dev_priv->chip_family == CHIP_RS480) && - mode_info->bios_connector[bios_index].connector_type == CONNECTOR_VGA && mode_info->bios_connector[bios_index].ddc_i2c.mask_clk_reg == RADEON_GPIO_CRT2_DDC) { mode_info->bios_connector[bios_index].ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); + } else if ((dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) && + mode_info->bios_connector[bios_index].ddc_i2c.mask_clk_reg == RADEON_GPIO_MONID) { + mode_info->bios_connector[bios_index].ddc_i2c.valid = true; + mode_info->bios_connector[bios_index].ddc_i2c.mask_clk_mask = (0x20 << 8); + mode_info->bios_connector[bios_index].ddc_i2c.mask_data_mask = 0x80; + mode_info->bios_connector[bios_index].ddc_i2c.a_clk_mask = (0x20 << 8); + mode_info->bios_connector[bios_index].ddc_i2c.a_data_mask = 0x80; + mode_info->bios_connector[bios_index].ddc_i2c.put_clk_mask = (0x20 << 8); + mode_info->bios_connector[bios_index].ddc_i2c.put_data_mask = 0x80; + mode_info->bios_connector[bios_index].ddc_i2c.get_clk_mask = (0x20 << 8); + mode_info->bios_connector[bios_index].ddc_i2c.get_data_mask = 0x80; + mode_info->bios_connector[bios_index].ddc_i2c.mask_clk_reg = RADEON_GPIOPAD_MASK; + mode_info->bios_connector[bios_index].ddc_i2c.mask_data_reg = RADEON_GPIOPAD_MASK; + mode_info->bios_connector[bios_index].ddc_i2c.a_clk_reg = RADEON_GPIOPAD_A; + mode_info->bios_connector[bios_index].ddc_i2c.a_data_reg = RADEON_GPIOPAD_A; + mode_info->bios_connector[bios_index].ddc_i2c.put_clk_reg = RADEON_GPIOPAD_EN; + mode_info->bios_connector[bios_index].ddc_i2c.put_data_reg = RADEON_GPIOPAD_EN; + mode_info->bios_connector[bios_index].ddc_i2c.get_clk_reg = RADEON_LCD_GPIO_Y_REG; + mode_info->bios_connector[bios_index].ddc_i2c.get_data_reg = RADEON_LCD_GPIO_Y_REG; } /* Certain IBM chipset RN50s have a BIOS reporting two VGAs, @@ -589,6 +604,15 @@ static void radeon_apply_legacy_quirks(struct drm_device *dev, int bios_index) } + /* X300 card with extra non-existent DVI port */ + if (dev->pdev->device == 0x5B60 && + dev->pdev->subsystem_vendor == 0x17af && + dev->pdev->subsystem_device == 0x201e && + bios_index == 2) { + if (mode_info->bios_connector[bios_index].connector_type == CONNECTOR_DVI_I) + mode_info->bios_connector[bios_index].valid = false; + } + } bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) -- cgit v1.2.3 From f38fff5416bc8e40ce9426f78bfea1bad415faab Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Aug 2008 18:13:21 -0400 Subject: Fill in and make use of more com bios tables on legacy chips --- linux-core/radeon_combios.c | 192 +++++++++++++++++++++++++++++++++++- linux-core/radeon_legacy_crtc.c | 172 +++++++++++++++++--------------- linux-core/radeon_legacy_encoders.c | 33 +++++-- linux-core/radeon_mode.h | 36 ++++++- linux-core/radeon_reg.h | 9 ++ 5 files changed, 348 insertions(+), 94 deletions(-) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index 1080079f..bb8d0b27 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -428,7 +428,7 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) struct radeon_mode_info *mode_info = &dev_priv->mode_info; uint16_t pll_info; struct radeon_pll *pll = &mode_info->pll; - int rev; + int8_t rev; pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE); if (pll_info) { @@ -450,17 +450,153 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) pll->xclk = radeon_bios16(dev_priv, pll_info + 0x08); // sclk/mclk use fixed point + //sclk = radeon_bios16(pll_info + 8) / 100.0; + //mclk = radeon_bios16(pll_info + 10) / 100.0; + //if (sclk == 0) sclk = 200; + //if (mclk == 0) mclk = 200; return true; } return false; } +bool radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint16_t dac_info; + uint8_t rev, bg, dac; + + /* first check TV table */ + dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); + if (dac_info) { + rev = radeon_bios8(dev_priv, dac_info + 0x3); + if (rev > 4) { + bg = radeon_bios8(dev_priv, dac_info + 0xc) & 0xf; + dac = radeon_bios8(dev_priv, dac_info + 0xd) & 0xf; + encoder->ps2_tvdac_adj = (bg << 16) | (dac << 20); + + bg = radeon_bios8(dev_priv, dac_info + 0xe) & 0xf; + dac = radeon_bios8(dev_priv, dac_info + 0xf) & 0xf; + encoder->pal_tvdac_adj = (bg << 16) | (dac << 20); + + bg = radeon_bios8(dev_priv, dac_info + 0x10) & 0xf; + dac = radeon_bios8(dev_priv, dac_info + 0x11) & 0xf; + encoder->ntsc_tvdac_adj = (bg << 16) | (dac << 20); + + return true; + } else if (rev > 1) { + bg = radeon_bios8(dev_priv, dac_info + 0xc) & 0xf; + dac = (radeon_bios8(dev_priv, dac_info + 0xc) >> 4) & 0xf; + encoder->ps2_tvdac_adj = (bg << 16) | (dac << 20); + + bg = radeon_bios8(dev_priv, dac_info + 0xd) & 0xf; + dac = (radeon_bios8(dev_priv, dac_info + 0xd) >> 4) & 0xf; + encoder->pal_tvdac_adj = (bg << 16) | (dac << 20); + + bg = radeon_bios8(dev_priv, dac_info + 0xe) & 0xf; + dac = (radeon_bios8(dev_priv, dac_info + 0xe) >> 4) & 0xf; + encoder->ntsc_tvdac_adj = (bg << 16) | (dac << 20); + + return true; + } + } + + /* then check CRT table */ + dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); + if (dac_info) { + rev = radeon_bios8(dev_priv, dac_info) & 0x3; + if (rev < 2) { + bg = radeon_bios8(dev_priv, dac_info + 0x3) & 0xf; + dac = (radeon_bios8(dev_priv, dac_info + 0x3) >> 4) & 0xf; + encoder->ps2_tvdac_adj = (bg << 16) | (dac << 20); + encoder->pal_tvdac_adj = encoder->ps2_tvdac_adj; + encoder->ntsc_tvdac_adj = encoder->ps2_tvdac_adj; + + return true; + } else { + bg = radeon_bios8(dev_priv, dac_info + 0x4) & 0xf; + dac = radeon_bios8(dev_priv, dac_info + 0x5) & 0xf; + encoder->ps2_tvdac_adj = (bg << 16) | (dac << 20); + encoder->pal_tvdac_adj = encoder->ps2_tvdac_adj; + encoder->ntsc_tvdac_adj = encoder->ps2_tvdac_adj; + + return true; + } + + } + + return false; +} + +bool radeon_combios_get_tv_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint16_t tv_info; + + tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); + if (tv_info) { + if (radeon_bios8(dev_priv, tv_info + 6) == 'T') { + switch (radeon_bios8(dev_priv, tv_info + 7) & 0xf) { + case 1: + encoder->tv_std = TV_STD_NTSC; + DRM_INFO("Default TV standard: NTSC\n"); + break; + case 2: + encoder->tv_std = TV_STD_PAL; + DRM_INFO("Default TV standard: PAL\n"); + break; + case 3: + encoder->tv_std = TV_STD_PAL_M; + DRM_INFO("Default TV standard: PAL-M\n"); + break; + case 4: + encoder->tv_std = TV_STD_PAL_60; + DRM_INFO("Default TV standard: PAL-60\n"); + break; + case 5: + encoder->tv_std = TV_STD_NTSC_J; + DRM_INFO("Default TV standard: NTSC-J\n"); + break; + case 6: + encoder->tv_std = TV_STD_SCART_PAL; + DRM_INFO("Default TV standard: SCART-PAL\n"); + break; + default: + encoder->tv_std = TV_STD_NTSC; + DRM_INFO("Unknown TV standard; defaulting to NTSC\n"); + break; + } + + switch ((radeon_bios8(dev_priv, tv_info + 9) >> 2) & 0x3) { + case 0: + DRM_INFO("29.498928713 MHz TV ref clk\n"); + break; + case 1: + DRM_INFO("28.636360000 MHz TV ref clk\n"); + break; + case 2: + DRM_INFO("14.318180000 MHz TV ref clk\n"); + break; + case 3: + DRM_INFO("27.000000000 MHz TV ref clk\n"); + break; + default: + break; + } + return true; + } + } + return false; +} + bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_radeon_private *dev_priv = dev->dev_private; uint16_t lcd_info; + uint32_t panel_setup; char stmp[30]; int tmp, i; @@ -478,9 +614,57 @@ bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder) DRM_INFO("Panel Size %dx%d\n", encoder->panel_xres, encoder->panel_yres); - encoder->panel_pwr_delay = radeon_bios16(dev_priv, lcd_info + 44); - if (encoder->panel_pwr_delay > 2000 || encoder->panel_pwr_delay < 0) - encoder->panel_pwr_delay = 2000; + encoder->panel_vcc_delay = radeon_bios16(dev_priv, lcd_info + 44); + if (encoder->panel_vcc_delay > 2000 || encoder->panel_vcc_delay < 0) + encoder->panel_vcc_delay = 2000; + + encoder->panel_pwr_delay = radeon_bios16(dev_priv, lcd_info + 0x24); + encoder->panel_digon_delay = radeon_bios16(dev_priv, lcd_info + 0x38) & 0xf; + encoder->panel_blon_delay = (radeon_bios16(dev_priv, lcd_info + 0x38) >> 4) & 0xf; + + encoder->panel_ref_divider = radeon_bios16(dev_priv, lcd_info + 46); + encoder->panel_post_divider = radeon_bios8(dev_priv, lcd_info + 48); + encoder->panel_fb_divider = radeon_bios16(dev_priv, lcd_info + 49); + if ((encoder->panel_ref_divider != 0) && + (encoder->panel_fb_divider > 3)) + encoder->use_bios_dividers = true; + + panel_setup = radeon_bios32(dev_priv, lcd_info + 0x39); + encoder->lvds_gen_cntl = 0; + if (panel_setup & 0x1) + encoder->lvds_gen_cntl |= RADEON_LVDS_PANEL_FORMAT; + + if ((panel_setup >> 4) & 0x1) + encoder->lvds_gen_cntl |= RADEON_LVDS_PANEL_TYPE; + + switch ((panel_setup >> 8) & 0x8) { + case 0: + encoder->lvds_gen_cntl |= RADEON_LVDS_NO_FM; + break; + case 1: + encoder->lvds_gen_cntl |= RADEON_LVDS_2_GREY; + break; + case 2: + encoder->lvds_gen_cntl |= RADEON_LVDS_4_GREY; + break; + default: + break; + } + + if ((panel_setup >> 16) & 0x1) + encoder->lvds_gen_cntl |= RADEON_LVDS_FP_POL_LOW; + + if ((panel_setup >> 17) & 0x1) + encoder->lvds_gen_cntl |= RADEON_LVDS_LP_POL_LOW; + + if ((panel_setup >> 18) & 0x1) + encoder->lvds_gen_cntl |= RADEON_LVDS_DTM_POL_LOW; + + if ((panel_setup >> 23) & 0x1) + encoder->lvds_gen_cntl |= RADEON_LVDS_BL_CLK_SEL; + + encoder->lvds_gen_cntl |= (panel_setup & 0xf0000000); + for (i = 0; i < 32; i++) { tmp = radeon_bios16(dev_priv, lcd_info + 64 + i * 2); diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index 08d4a477..6775ffc0 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -356,13 +356,9 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo uint32_t tv_dac_cntl = RADEON_READ(RADEON_TV_DAC_CNTL); uint32_t dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2); uint32_t crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); -// state->dac2_cntl = info->StatedReg->dac2_cntl; -// state->tv_dac_cntl = info->StatedReg->tv_dac_cntl; -// state->crtc2_gen_cntl = info->StatedReg->crtc2_gen_cntl; -// state->disp_hw_debug = info->StatedReg->disp_hw_debug; -// state->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; -// state->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; + dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; + dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; /* For CRT on DAC2, don't turn it on if BIOS didn't enable it, even it's detected. @@ -395,19 +391,22 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo return true; } -static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode, int flags) +static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder; uint32_t feedback_div = 0; uint32_t reference_div = 0; uint32_t post_divider = 0; uint32_t freq = 0; uint8_t pll_gain; + int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV; + bool use_bios_divs = false; /* PLL registers */ - uint32_t ppll_ref_div; - uint32_t ppll_div_3; - uint32_t htotal_cntl; + uint32_t ppll_ref_div = 0; + uint32_t ppll_div_3 = 0; + uint32_t htotal_cntl = 0; uint32_t vclk_ecp_cntl; struct radeon_pll *pll = &dev_priv->mode_info.pll; @@ -432,44 +431,56 @@ static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode { 0, 0 } }; -#if 0 // TODO - if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) { - ppll_ref_div = info->RefDivider; - ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16); - htotal_cntl = 0; - return; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) + pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->use_bios_dividers) { + ppll_ref_div = radeon_encoder->panel_ref_divider; + ppll_div_3 = (radeon_encoder->panel_fb_divider | + (radeon_encoder->panel_post_divider << 16)); + htotal_cntl = 0; + use_bios_divs = true; + } else + pll_flags |= RADEON_PLL_USE_REF_DIV; + } + } } -#endif DRM_DEBUG("\n"); - radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &reference_div, &post_divider, flags); - for (post_div = &post_divs[0]; post_div->divider; ++post_div) { - if (post_div->divider == post_divider) - break; - } + if (!use_bios_divs) { + radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &reference_div, &post_divider, pll_flags); - if (!post_div->divider) { - post_div = &post_divs[0]; - } + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + if (post_div->divider == post_divider) + break; + } - DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", - (unsigned)freq, - feedback_div, - reference_div, - post_divider); + if (!post_div->divider) { + post_div = &post_divs[0]; + } - ppll_ref_div = reference_div; + DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", + (unsigned)freq, + feedback_div, + reference_div, + post_divider); + ppll_ref_div = reference_div; #if defined(__powerpc__) && (0) /* TODO */ - /* apparently programming this otherwise causes a hang??? */ - if (info->MacModel == RADEON_MAC_IBOOK) - state->ppll_div_3 = 0x000600ad; - else + /* apparently programming this otherwise causes a hang??? */ + if (info->MacModel == RADEON_MAC_IBOOK) + state->ppll_div_3 = 0x000600ad; + else #endif - ppll_div_3 = (feedback_div | (post_div->bitvalue << 16)); + ppll_div_3 = (feedback_div | (post_div->bitvalue << 16)); + htotal_cntl = mode->htotal & 0x7; - htotal_cntl = mode->htotal & 0x7; + } vclk_ecp_cntl = (RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL) & ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK; @@ -783,19 +794,22 @@ static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mo } -static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode, int flags) +static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder; uint32_t feedback_div = 0; uint32_t reference_div = 0; uint32_t post_divider = 0; uint32_t freq = 0; uint8_t pll_gain; + int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV; + bool use_bios_divs = false; /* PLL2 registers */ - uint32_t p2pll_ref_div; - uint32_t p2pll_div_0; - uint32_t htotal_cntl2; + uint32_t p2pll_ref_div = 0; + uint32_t p2pll_div_0 = 0; + uint32_t htotal_cntl2 = 0; uint32_t pixclks_cntl; struct radeon_pll *pll = &dev_priv->mode_info.pll; @@ -819,37 +833,50 @@ static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode { 0, 0 } }; -#if 0 - if ((flags & RADEON_PLL_USE_BIOS_DIVS) && info->UseBiosDividers) { - p2pll_ref_div = info->RefDivider; - p2pll_div_0 = info->FeedbackDivider | (info->PostDivider << 16); - htotal_cntl2 = 0; - return; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) + pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->use_bios_dividers) { + p2pll_ref_div = radeon_encoder->panel_ref_divider; + p2pll_div_0 = (radeon_encoder->panel_fb_divider | + (radeon_encoder->panel_post_divider << 16)); + htotal_cntl2 = 0; + use_bios_divs = true; + } else + pll_flags |= RADEON_PLL_USE_REF_DIV; + } + } } -#endif - radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &reference_div, &post_divider, flags); + DRM_DEBUG("\n"); - for (post_div = &post_divs[0]; post_div->divider; ++post_div) { - if (post_div->divider == post_divider) - break; - } + if (!use_bios_divs) { + radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &reference_div, &post_divider, pll_flags); - if (!post_div->divider) { - post_div = &post_divs[0]; - } + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + if (post_div->divider == post_divider) + break; + } - DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", - (unsigned)freq, - feedback_div, - reference_div, - post_divider); + if (!post_div->divider) { + post_div = &post_divs[0]; + } - p2pll_ref_div = reference_div; + DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", + (unsigned)freq, + feedback_div, + reference_div, + post_divider); - p2pll_div_0 = (feedback_div | (post_div->bitvalue << 16)); + p2pll_ref_div = reference_div; + p2pll_div_0 = (feedback_div | (post_div->bitvalue << 16)); + htotal_cntl2 = mode->htotal & 0x7; - htotal_cntl2 = mode->htotal & 0x7; + } pixclks_cntl = ((RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL) & ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | @@ -946,22 +973,9 @@ static void radeon_crtc_mode_set(struct drm_crtc *crtc, int x, int y) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct drm_device *dev = crtc->dev; - struct drm_encoder *encoder; - int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV; DRM_DEBUG("\n"); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - - if (encoder->crtc == crtc) { - if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) - pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; - if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) - pll_flags |= RADEON_PLL_USE_BIOS_DIVS | RADEON_PLL_USE_REF_DIV; - } - } - /* TODO TV */ radeon_crtc_set_base(crtc, x, y); @@ -969,11 +983,11 @@ static void radeon_crtc_mode_set(struct drm_crtc *crtc, switch(radeon_crtc->crtc_id) { case 0: radeon_set_crtc1_timing(crtc, adjusted_mode); - radeon_set_pll1(crtc, adjusted_mode, pll_flags); + radeon_set_pll1(crtc, adjusted_mode); break; case 1: radeon_set_crtc2_timing(crtc, adjusted_mode); - radeon_set_pll2(crtc, adjusted_mode, pll_flags); + radeon_set_pll2(crtc, adjusted_mode); break; } diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index de9e8ac6..172f93de 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -213,10 +213,20 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) lvds_pll_cntl = RADEON_READ(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); + + /* enable lvds, turn on voltage */ lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); - lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN); + lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); + RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + udelay(radeon_encoder->panel_digon_delay * 1000); + + /* enable data */ lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); - udelay(radeon_encoder->panel_pwr_delay * 1000); + RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + udelay(radeon_encoder->panel_blon_delay * 1000); + + /* enable backlight */ + lvds_gen_cntl |= RADEON_LVDS_BLON; RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); break; case DRM_MODE_DPMS_STANDBY: @@ -226,7 +236,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; - lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN); + lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, pixclks_cntl); break; @@ -260,7 +270,10 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, lvds_pll_cntl = RADEON_READ(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN; - lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); + if (radeon_encoder->lvds_gen_cntl) + lvds_gen_cntl = radeon_encoder->lvds_gen_cntl; + else + lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | @@ -339,7 +352,6 @@ struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int b drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); - /* TODO get the LVDS info from the BIOS for panel size etc. */ /* get the lvds info from the bios */ radeon_combios_get_lvds_info(radeon_encoder); @@ -659,6 +671,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, i drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs); radeon_combios_get_tmds_info(radeon_encoder); + return encoder; } @@ -893,6 +906,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0; uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0; @@ -924,8 +938,8 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, // FIXME TV tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | - RADEON_TV_DAC_STD_PS2 /*| - radeon_encoder->ps2_tvdac_adj*/); // fixme, get from bios + RADEON_TV_DAC_STD_PS2 | + radeon_encoder->ps2_tvdac_adj); RADEON_WRITE(RADEON_TV_DAC_CNTL, tv_dac_cntl); } @@ -1015,8 +1029,9 @@ struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs); - /* TODO get the tv dac vals from bios tables */ - //radeon_combios_get_lvds_info(radeon_encoder); + /* get the tv dac vals from bios tables */ + radeon_combios_get_tv_info(radeon_encoder); + radeon_combios_get_tv_dac_info(radeon_encoder); return encoder; } diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 6a2e275c..3271375d 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -87,6 +87,17 @@ enum radeon_rmx_type { RMX_CENTER, }; +enum radeon_tv_std { + TV_STD_NTSC, + TV_STD_PAL, + TV_STD_PAL_M, + TV_STD_PAL_60, + TV_STD_NTSC_J, + TV_STD_SCART_PAL, + TV_STD_SECAM, + TV_STD_PAL_CN, +}; + struct radeon_i2c_bus_rec { bool valid; uint32_t mask_clk_reg; @@ -337,13 +348,33 @@ struct radeon_encoder { enum radeon_tmds_type tmds; } type; int atom_device; /* atom devices */ + + /* preferred mode */ uint32_t panel_xres, panel_yres; uint32_t hoverplus, hsync_width; uint32_t hblank; uint32_t voverplus, vsync_width; uint32_t vblank; - uint32_t panel_pwr_delay; uint32_t dotclock; + + /* legacy lvds */ + uint16_t panel_vcc_delay; + uint16_t panel_pwr_delay; + uint16_t panel_digon_delay; + uint16_t panel_blon_delay; + uint32_t panel_ref_divider; + uint32_t panel_post_divider; + uint32_t panel_fb_divider; + bool use_bios_dividers; + uint32_t lvds_gen_cntl; + + /* legacy tv dac */ + uint32_t ps2_tvdac_adj; + uint32_t ntsc_tvdac_adj; + uint32_t pal_tvdac_adj; + enum radeon_tv_std tv_std; + + /* legacy int tmds */ struct radeon_tmds_pll tmds_pll[4]; }; @@ -351,7 +382,6 @@ struct radeon_connector { struct drm_connector base; struct radeon_i2c_chan *ddc_bus; int use_digital; - }; struct radeon_framebuffer { @@ -407,6 +437,8 @@ extern bool radeon_combios_get_clock_info(struct drm_device *dev); extern void radeon_get_lvds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder); +extern bool radeon_combios_get_tv_info(struct radeon_encoder *encoder); +extern bool radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder); extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index ad91e04c..59108979 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -1027,14 +1027,23 @@ # define RADEON_LVDS_DISPLAY_DIS (1 << 1) # define RADEON_LVDS_PANEL_TYPE (1 << 2) # define RADEON_LVDS_PANEL_FORMAT (1 << 3) +# define RADEON_LVDS_NO_FM (0 << 4) +# define RADEON_LVDS_2_GREY (1 << 4) +# define RADEON_LVDS_4_GREY (2 << 4) # define RADEON_LVDS_RST_FM (1 << 6) # define RADEON_LVDS_EN (1 << 7) # define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 # define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) # define RADEON_LVDS_BL_MOD_EN (1 << 16) +# define RADEON_LVDS_BL_CLK_SEL (1 << 17) # define RADEON_LVDS_DIGON (1 << 18) # define RADEON_LVDS_BLON (1 << 19) +# define RADEON_LVDS_FP_POL_LOW (1 << 20) +# define RADEON_LVDS_LP_POL_LOW (1 << 21) +# define RADEON_LVDS_DTM_POL_LOW (1 << 22) # define RADEON_LVDS_SEL_CRTC2 (1 << 23) +# define RADEON_LVDS_FPDI_EN (1 << 27) +# define RADEON_LVDS_HSYNC_DELAY_SHIFT 28 #define RADEON_LVDS_PLL_CNTL 0x02d4 # define RADEON_HSYNC_DELAY_SHIFT 28 # define RADEON_HSYNC_DELAY_MASK (0xf << 28) -- cgit v1.2.3 From 2a65759d159478b126c660ef124777548dcc872c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Aug 2008 20:18:07 -0400 Subject: Add com bios asic init bits --- linux-core/radeon_combios.c | 255 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index bb8d0b27..56116463 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -1016,3 +1016,258 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) return true; } +static void combios_parse_mmio_table(struct drm_device *dev, uint16_t offset) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (offset) { + while (radeon_bios16(dev_priv, offset)) { + uint16_t cmd = ((radeon_bios16(dev_priv, offset) & 0xe000) >> 13); + uint32_t addr = (radeon_bios16(dev_priv, offset) & 0x1fff); + uint32_t val, and_mask, or_mask; + uint32_t tmp; + + offset += 2; + switch (cmd) { + case 0: + val = radeon_bios32(dev_priv, offset); + offset += 4; + RADEON_WRITE(addr, val); + break; + case 1: + val = radeon_bios32(dev_priv, offset); + offset += 4; + RADEON_WRITE(addr, val); + break; + case 2: + and_mask = radeon_bios32(dev_priv, offset); + offset += 4; + or_mask = radeon_bios32(dev_priv, offset); + offset += 4; + tmp = RADEON_READ(addr); + tmp &= and_mask; + tmp |= or_mask; + RADEON_WRITE(addr, tmp); + break; + case 3: + and_mask = radeon_bios32(dev_priv, offset); + offset += 4; + or_mask = radeon_bios32(dev_priv, offset); + offset += 4; + tmp = RADEON_READ(addr); + tmp &= and_mask; + tmp |= or_mask; + RADEON_WRITE(addr, tmp); + break; + case 4: + val = radeon_bios16(dev_priv, offset); + offset += 2; + udelay(val); + break; + case 5: + val = radeon_bios16(dev_priv, offset); + offset += 2; + switch (addr) { + case 8: + while (val--) { + if (!(RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL) & + RADEON_MC_BUSY)) + break; + } + break; + case 9: + while (val--) { + if ((RADEON_READ(RADEON_MC_STATUS) & + RADEON_MC_IDLE)) + break; + } + break; + default: + break; + } + break; + default: + break; + } + } + } +} + +static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + if (offset) { + while (radeon_bios8(dev_priv, offset)) { + uint8_t cmd = ((radeon_bios8(dev_priv, offset) & 0xc0) >> 6); + uint8_t addr = (radeon_bios8(dev_priv, offset) & 0x3f); + uint32_t val, shift, tmp; + uint32_t and_mask, or_mask; + + offset++; + switch (cmd) { + case 0: + val = radeon_bios32(dev_priv, offset); + offset += 4; + RADEON_WRITE_PLL(dev_priv, addr, val); + break; + case 1: + shift = radeon_bios8(dev_priv, offset) * 8; + offset++; + and_mask = radeon_bios8(dev_priv, offset) << shift; + and_mask |= ~(0xff << shift); + offset++; + or_mask = radeon_bios8(dev_priv, offset) << shift; + offset++; + tmp = RADEON_READ_PLL(dev_priv, addr); + tmp &= and_mask; + tmp |= or_mask; + RADEON_WRITE_PLL(dev_priv, addr, tmp); + break; + case 2: + case 3: + tmp = 1000; + switch (addr) { + case 1: + udelay(150); + break; + case 2: + udelay(1000); + break; + case 3: + while (tmp--) { + if (!(RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL) & + RADEON_MC_BUSY)) + break; + } + break; + case 4: + while (tmp--) { + if (RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL) & + RADEON_DLL_READY) + break; + } + break; + case 5: + tmp = RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL); + if (tmp & RADEON_CG_NO1_DEBUG_0) { +#if 0 + uint32_t mclk_cntl = RADEON_READ_PLL(RADEON_MCLK_CNTL); + mclk_cntl &= 0xffff0000; + //mclk_cntl |= 0x00001111; /* ??? */ + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, mclk_cntl); + udelay(10000); +#endif + RADEON_WRITE_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL, + tmp & ~RADEON_CG_NO1_DEBUG_0); + udelay(10000); + } + break; + default: + break; + } + break; + default: + break; + } + } + } +} + +static void combios_parse_ram_reset_table(struct drm_device *dev, uint16_t offset) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + if (offset) { + uint8_t val = radeon_bios8(dev_priv, offset); + while (val != 0xff) { + offset++; + + if (val == 0x0f) { + uint32_t channel_complete_mask; + + if (radeon_is_r300(dev_priv)) + channel_complete_mask = R300_MEM_PWRUP_COMPLETE; + else + channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE; + tmp = 20000; + while (tmp--) { + if ((RADEON_READ(RADEON_MEM_STR_CNTL) & + channel_complete_mask) == + channel_complete_mask) + break; + } + } else { + uint32_t or_mask = radeon_bios16(dev_priv, offset); + offset += 2; + + tmp = RADEON_READ(RADEON_MEM_SDRAM_MODE_REG); + tmp &= RADEON_SDRAM_MODE_MASK; + tmp |= or_mask; + RADEON_WRITE(RADEON_MEM_SDRAM_MODE_REG, tmp); + + or_mask = val << 24; + tmp = RADEON_READ(RADEON_MEM_SDRAM_MODE_REG); + tmp &= RADEON_B3MEM_RESET_MASK; + tmp |= or_mask; + RADEON_WRITE(RADEON_MEM_SDRAM_MODE_REG, tmp); + } + val = radeon_bios8(dev_priv, offset); + } + } +} + +void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable) +{ + uint16_t dyn_clk_info = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); + + if (dyn_clk_info) + combios_parse_pll_table(dev, dyn_clk_info); +} + +void radeon_combios_asic_init(struct drm_device *dev) +{ + uint16_t table; + + /* ASIC INIT 1 */ + table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_1_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + + /* PLL INIT */ + table = combios_get_table_offset(dev, COMBIOS_PLL_INIT_TABLE); + if (table) + combios_parse_pll_table(dev, table); + + /* ASIC INIT 2 */ + table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_2_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + + /* ASIC INIT 4 */ + table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_4_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + + /* RAM RESET */ + table = combios_get_table_offset(dev, COMBIOS_RAM_RESET_TABLE); + if (table) + combios_parse_ram_reset_table(dev, table); + + /* ASIC INIT 3 */ + table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_3_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + + /* DYN CLK 1 */ + table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); + if (table) + combios_parse_pll_table(dev, table); + + /* ASIC INIT 5 */ + table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_5_TABLE); + if (table) + combios_parse_mmio_table(dev, table); + +} -- cgit v1.2.3 From 9dff806802bad79242c58cc5dca3fd108099982b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 09:43:23 +1000 Subject: i915: fixup from last merge hopefully --- shared-core/i915_dma.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 7f025e62..ddc9cd5a 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -248,25 +248,6 @@ static int i915_initialize(struct drm_device * dev, */ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; - /* Program Hardware Status Page */ - if (!I915_NEED_GFX_HWS(dev)) { - dev_priv->status_page_dmah = - drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); - - if (!dev_priv->status_page_dmah) { - i915_dma_cleanup(dev); - DRM_ERROR("Can not allocate hardware status page\n"); - return -ENOMEM; - } - dev_priv->hws_vaddr = dev_priv->status_page_dmah->vaddr; - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; - - memset(dev_priv->hws_vaddr, 0, PAGE_SIZE); - - I915_WRITE(0x02080, dev_priv->dma_status_page); - } - DRM_DEBUG("Enabled hardware status page\n"); - #ifdef DRI2 if (init->func == I915_INIT_DMA2) { int ret = setup_dri2_sarea(dev, file_priv, init); -- cgit v1.2.3 From 5f9e4a764ac7acf1311388dd693bc4f0e6c0c4e9 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 13 Aug 2008 16:57:42 -0700 Subject: i915: update cursor handling to use GEM objects --- linux-core/intel_display.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index fbe06f7c..dfc0b502 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -982,12 +982,12 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_buffer_object *bo; + struct drm_gem_object *bo; + struct drm_i915_gem_object *obj_priv; int pipe = intel_crtc->pipe; uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; uint32_t temp; - int ret; size_t addr; DRM_DEBUG("\n"); @@ -1010,25 +1010,22 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, return -EINVAL; } - ret = drm_get_buffer_object(dev, &bo, handle); - if (ret) { - return -EINVAL; - } + bo = drm_gem_object_lookup(dev, file_priv, handle); + if (!bo) + return -ENOENT; - if ((bo->mem.flags & DRM_BO_MASK_MEM) != DRM_BO_FLAG_MEM_VRAM) { - DRM_ERROR("buffer needs to be in VRAM\n"); - return -ENOMEM; - } + obj_priv = bo->driver_private; - if (bo->mem.size < width * height * 4) { + if (bo->size < width * height * 4) { DRM_ERROR("buffer is to small\n"); return -ENOMEM; } - if (dev_priv->cursor_needs_physical) - addr = dev_priv->stolen_base + bo->offset; - else - addr = bo->offset; + if (dev_priv->cursor_needs_physical) { + addr = dev->agp->base + obj_priv->gtt_offset; + } else { + addr = obj_priv->gtt_offset; + } intel_crtc->cursor_addr = addr; temp = 0; -- cgit v1.2.3 From eb8f9b9da4d34b9bfa16dc3847e81976a12d2d0c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 14:41:15 +1000 Subject: radeon: add copy/solid regs for rn50 --- shared-core/r300_cmdbuf.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index 53961fc7..725829b2 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -303,6 +303,13 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R300_VAP_PVS_CODE_CNTL_0, 4); ADD_RANGE(R300_VAP_PVS_VECTOR_INDX_REG, 2); + + if (dev_priv->chip_family <= CHIP_RV280) { + ADD_RANGE(RADEON_RE_TOP_LEFT, 1); + ADD_RANGE(RADEON_RE_WIDTH_HEIGHT, 1); + ADD_RANGE(RADEON_AUX_SC_CNTL, 1); + ADD_RANGE(RADEON_RB3D_DSTCACHE_CTLSTAT, 1); + } } int r300_check_range(unsigned reg, int count) -- cgit v1.2.3 From 30ff279e42b3b0608e8ff6620d2958c174449798 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 14 Aug 2008 14:43:51 +1000 Subject: radeon: add support for memory map init --- linux-core/radeon_gem.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_cp.c | 42 +++++++++++++++++------ shared-core/radeon_drv.h | 7 +++- 3 files changed, 124 insertions(+), 11 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index df4ed4ce..bf8fb2e9 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -615,6 +615,90 @@ int radeon_alloc_gart_objects(struct drm_device *dev) } +static void radeon_init_memory_map(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + u32 mem_size, aper_size; + + dev_priv->mc_fb_location = radeon_read_fb_location(dev_priv); + radeon_read_agp_location(dev_priv, &dev_priv->mc_agp_loc_lo, &dev_priv->mc_agp_loc_hi); + + if (dev_priv->chip_family >= CHIP_R600) { + mem_size = RADEON_READ(R600_CONFIG_MEMSIZE); + aper_size = RADEON_READ(R600_CONFIG_APER_SIZE); + } else { + mem_size = RADEON_READ(RADEON_CONFIG_MEMSIZE); + aper_size = RADEON_READ(RADEON_CONFIG_APER_SIZE); + } + + /* M6s report illegal memory size */ + if (mem_size == 0) + mem_size = 8 * 1024 * 1024; + + /* for RN50/M6/M7 - Novell bug 204882 */ + if (aper_size > mem_size) + mem_size = aper_size; + + if ((dev_priv->chip_family != CHIP_RS600) && + (dev_priv->chip_family != CHIP_RS690) && + (dev_priv->chip_family != CHIP_RS740)) { + if (dev_priv->flags & RADEON_IS_IGP) + dev_priv->mc_fb_location = RADEON_READ(RADEON_NB_TOM); + else { + uint32_t aper0_base; + + if (dev_priv->chip_family >= CHIP_R600) + aper0_base = RADEON_READ(R600_CONFIG_F0_BASE); + else + aper0_base = RADEON_READ(RADEON_CONFIG_APER_0_BASE); + + + /* Some chips have an "issue" with the memory controller, the + * location must be aligned to the size. We just align it down, + * too bad if we walk over the top of system memory, we don't + * use DMA without a remapped anyway. + * Affected chips are rv280, all r3xx, and all r4xx, but not IGP + */ + if (dev_priv->chip_family == CHIP_RV280 || + dev_priv->chip_family == CHIP_R300 || + dev_priv->chip_family == CHIP_R350 || + dev_priv->chip_family == CHIP_RV350 || + dev_priv->chip_family == CHIP_RV380 || + dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_RV410) + aper0_base &= ~(mem_size - 1); + + if (dev_priv->chip_family >= CHIP_R600) { + dev_priv->mc_fb_location = (aper0_base >> 24) | + (((aper0_base + mem_size - 1) & 0xff000000U) >> 8); + } else { + dev_priv->mc_fb_location = (aper0_base >> 16) | + ((aper0_base + mem_size - 1) & 0xffff0000U); + } + } + } + + if (dev_priv->chip_family >= CHIP_R600) + dev_priv->fb_location = (dev_priv->mc_fb_location & 0xffff) << 24; + else + dev_priv->fb_location = (dev_priv->mc_fb_location & 0xffff) << 16; + + if (radeon_is_avivo(dev_priv)) { + if (dev_priv->chip_family >= CHIP_R600) + RADEON_WRITE(R600_HDP_NONSURFACE_BASE, (dev_priv->mc_fb_location << 16) & 0xff0000); + else + RADEON_WRITE(AVIVO_HDP_FB_LOCATION, dev_priv->mc_fb_location); + } + + radeon_write_fb_location(dev_priv, dev_priv->mc_fb_location); + + dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16; + dev_priv->fb_size = + ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000) + - dev_priv->fb_location; + +} + /* init memory manager - start with all of VRAM and a 32MB GART aperture for now */ int radeon_gem_mm_init(struct drm_device *dev) { @@ -624,6 +708,8 @@ int radeon_gem_mm_init(struct drm_device *dev) /* size the mappable VRAM memory for now */ radeon_vram_setup(dev); + radeon_init_memory_map(dev); + drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, /*dev_priv->mm.vram_offset >> PAGE_SHIFT,*/ (dev_priv->mm.vram_visible) >> PAGE_SHIFT, 0); diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 04f4b1f8..e30696fc 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -107,7 +107,33 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) return RADEON_READ(RADEON_MC_FB_LOCATION); } -static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) +void radeon_read_agp_location(drm_radeon_private_t *dev_priv, u32 *agp_lo, u32 *agp_hi) +{ + if (dev_priv->chip_family == CHIP_RV770) { + + } else if (dev_priv->chip_family == CHIP_R600) { + *agp_lo = RADEON_READ(R600_MC_VM_AGP_BOT); + *agp_hi = RADEON_READ(R600_MC_VM_AGP_TOP); + } else if (dev_priv->chip_family == CHIP_RV515) { + *agp_lo = radeon_read_mc_reg(dev_priv, RV515_MC_FB_LOCATION); + *agp_hi = 0; + } else if (dev_priv->chip_family == CHIP_RS600) { + *agp_lo = 0; + *agp_hi = 0; + } else if (dev_priv->chip_family == CHIP_RS690 || + dev_priv->chip_family == CHIP_RS740) { + *agp_lo = radeon_read_mc_reg(dev_priv, RS690_MC_AGP_LOCATION); + *agp_hi = 0; + } else if (dev_priv->chip_family >= CHIP_R520) { + *agp_lo = radeon_read_mc_reg(dev_priv, R520_MC_AGP_LOCATION); + *agp_hi = 0; + } else { + *agp_lo = RADEON_READ(RADEON_MC_FB_LOCATION); + *agp_hi = 0; + } +} + +void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc); @@ -119,7 +145,7 @@ static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc); } -static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc) +static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc, u32 agp_loc_hi) { if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc); @@ -672,7 +698,7 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, radeon_write_agp_location(dev_priv, (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & 0xffff0000) | - (dev_priv->gart_vm_start >> 16))); + (dev_priv->gart_vm_start >> 16)), 0); ring_start = (dev_priv->cp_ring->offset - dev->agp->base @@ -873,7 +899,7 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on) temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & 0xffff0000) | (dev_priv->gart_vm_start >> 16)); - radeon_write_agp_location(dev_priv, temp); + radeon_write_agp_location(dev_priv, temp, 0); temp = IGP_READ_MCIND(dev_priv, RS480_AGP_ADDRESS_SPACE_SIZE); IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | @@ -921,7 +947,7 @@ static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) dev_priv->gart_vm_start + dev_priv->gart_size - 1); - radeon_write_agp_location(dev_priv, 0xffffffc0); /* ?? */ + radeon_write_agp_location(dev_priv, 0xffffffc0, 0); /* ?? */ RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, RADEON_PCIE_TX_GART_EN); @@ -965,7 +991,7 @@ void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) /* Turn off AGP aperture -- is this required for PCI GART? */ - radeon_write_agp_location(dev_priv, 0xffffffc0); + radeon_write_agp_location(dev_priv, 0xffffffc0, 0); RADEON_WRITE(RADEON_AGP_COMMAND, 0); /* clear AGP_COMMAND */ } else { RADEON_WRITE(RADEON_AIC_CNTL, @@ -2482,10 +2508,6 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) if (drm_core_check_feature(dev, DRIVER_MODESET)) { - dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16; - dev_priv->fb_size = - ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000) - - dev_priv->fb_location; radeon_gem_mm_init(dev); radeon_modeset_init(dev); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index a40ff6dd..9edd3884 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -418,6 +418,10 @@ typedef struct drm_radeon_private { bool is_ddr; u32 ram_width; + uint32_t mc_fb_location; + uint32_t mc_agp_loc_lo; + uint32_t mc_agp_loc_hi; + enum radeon_pll_errata pll_errata; int num_gb_pipes; @@ -1655,7 +1659,8 @@ int radeon_modeset_init(struct drm_device *dev); void radeon_modeset_cleanup(struct drm_device *dev); extern u32 radeon_read_mc_reg(drm_radeon_private_t *dev_priv, int addr); extern void radeon_write_mc_reg(drm_radeon_private_t *dev_priv, u32 addr, u32 val); - +void radeon_read_agp_location(drm_radeon_private_t *dev_priv, u32 *agp_lo, u32 *agp_hi); +void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc); extern void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on); #define RADEONFB_CONN_LIMIT 4 -- cgit v1.2.3 From e0bbd04eb0e2395872983e243d242f5ba2f2306f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 15 Aug 2008 09:42:06 +1000 Subject: radeon: fix LVDS modes problem --- linux-core/radeon_connectors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c index 2cc0be06..32f969ab 100644 --- a/linux-core/radeon_connectors.c +++ b/linux-core/radeon_connectors.c @@ -43,7 +43,7 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) drm_mode_connector_update_edid_property(&radeon_connector->base, edid); ret = drm_add_edid_modes(&radeon_connector->base, edid); kfree(edid); - return 0; + return ret; } #if 0 -- cgit v1.2.3 From 2030db75328b7d896a5dd030fc171020b33149e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 15 Aug 2008 09:56:42 +1000 Subject: radeon: reserve 64k of VRAM for now for text mode so we don't trample it need to revisit this later I'm sure --- linux-core/radeon_gem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index bf8fb2e9..6a7529cd 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -704,14 +704,18 @@ int radeon_gem_mm_init(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; int ret; + u32 pg_offset; /* size the mappable VRAM memory for now */ radeon_vram_setup(dev); radeon_init_memory_map(dev); - drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, /*dev_priv->mm.vram_offset >> PAGE_SHIFT,*/ - (dev_priv->mm.vram_visible) >> PAGE_SHIFT, +#define VRAM_RESERVE_TEXT (64*1024) + dev_priv->mm.vram_visible -= VRAM_RESERVE_TEXT; + pg_offset = VRAM_RESERVE_TEXT >> PAGE_SHIFT; + drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, pg_offset, /*dev_priv->mm.vram_offset >> PAGE_SHIFT,*/ + ((dev_priv->mm.vram_visible) >> PAGE_SHIFT) - 16, 0); -- cgit v1.2.3 From 893315d49ed678de95cf6ac553efb6093cc7343c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 16 Aug 2008 11:35:10 -0700 Subject: i915: set domain properly on fb mapping, flush out changes The user visible ioctl does this, but since we call into GEM internals directly, we have to flush things ourselves. Fixes initial fb console corruption. --- linux-core/i915_gem.c | 6 +----- linux-core/intel_fb.c | 6 ++++++ shared-core/i915_drv.h | 3 +++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c index 64ffa356..6966c84f 100644 --- a/linux-core/i915_gem.c +++ b/linux-core/i915_gem.c @@ -32,10 +32,6 @@ #include "i915_drv.h" #include -static int -i915_gem_object_set_domain(struct drm_gem_object *obj, - uint32_t read_domains, - uint32_t write_domain); static int i915_gem_object_set_domain_range(struct drm_gem_object *obj, uint64_t offset, @@ -1318,7 +1314,7 @@ i915_gem_clflush_object(struct drm_gem_object *obj) * MI_FLUSH * drm_agp_chipset_flush */ -static int +int i915_gem_object_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uint32_t write_domain) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index ce8ac3d9..c1391c0a 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -716,12 +716,18 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height obj_priv = fbo->driver_private; mutex_lock(&dev->struct_mutex); + /* Flush everything out, we'll be doing GTT only from now on */ + i915_gem_object_set_domain(fbo, I915_GEM_DOMAIN_GTT, + I915_GEM_DOMAIN_GTT); + ret = i915_gem_object_pin(fbo, PAGE_SIZE); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; } + i915_gem_clflush_object(fbo); + fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); if (!fb) { DRM_ERROR("failed to allocate fb.\n"); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 087c6d64..a031afd2 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -627,6 +627,9 @@ int i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int i915_gem_do_init(struct drm_device *dev, unsigned long start, unsigned long end); +int i915_gem_object_set_domain(struct drm_gem_object *obj, + uint32_t read_domains, + uint32_t write_domain); void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_clflush_object(struct drm_gem_object *obj); #endif -- cgit v1.2.3 From a2adc696569de830c7a95722dd111bff706a0bbc Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 16 Aug 2008 12:09:24 -0700 Subject: i915: finish removing TTM bits Makes it build again. --- linux-core/i915_drv.c | 31 ------------------------- linux-core/i915_ioc32.c | 61 ------------------------------------------------- shared-core/i915_drv.h | 32 +------------------------- shared-core/i915_init.c | 3 --- shared-core/i915_irq.c | 3 --- 5 files changed, 1 insertion(+), 129 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 2e67eb71..38859474 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -48,31 +48,6 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); unsigned int i915_rightof = 1; module_param_named(i915_rightof, i915_rightof, int, 0400); -#if defined(I915_HAVE_FENCE) && defined(I915_TTM) -extern struct drm_fence_driver i915_fence_driver; -#endif - -#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) - -static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL}; -static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL}; - -static struct drm_bo_driver i915_bo_driver = { - .mem_type_prio = i915_mem_prios, - .mem_busy_prio = i915_busy_prios, - .num_mem_type_prio = sizeof(i915_mem_prios)/sizeof(uint32_t), - .num_mem_busy_prio = sizeof(i915_busy_prios)/sizeof(uint32_t), - .create_ttm_backend_entry = i915_create_ttm_backend_entry, - .fence_type = i915_fence_type, - .invalidate_caches = i915_invalidate_caches, - .init_mem_type = i915_init_mem_type, - .evict_flags = i915_evict_flags, - .move = i915_move, - .ttm_cache_flush = i915_flush_ttm, - .command_stream_barrier = NULL, -}; -#endif /* ttm */ - static int i915_suspend(struct drm_device *dev, pm_message_t state) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -175,12 +150,6 @@ static struct drm_driver driver = { .probe = probe, .remove = remove, }, -#if defined(I915_HAVE_FENCE) && defined(I915_TTM) - .fence_driver = &i915_fence_driver, -#endif -#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) - .bo_driver = &i915_bo_driver, -#endif .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/linux-core/i915_ioc32.c b/linux-core/i915_ioc32.c index 0b8fff19..d2d69a0b 100644 --- a/linux-core/i915_ioc32.c +++ b/linux-core/i915_ioc32.c @@ -183,73 +183,12 @@ static int compat_i915_alloc(struct file *file, unsigned int cmd, DRM_IOCTL_I915_ALLOC, (unsigned long) request); } -typedef struct drm_i915_execbuffer32 { - uint64_t ops_list; - uint32_t num_buffers; - struct _drm_i915_batchbuffer32 batch; - drm_context_t context; - struct drm_fence_arg fence_arg; -} drm_i915_execbuffer32_t; - -static int compat_i915_execbuffer(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_execbuffer32_t req32; - struct drm_i915_execbuffer __user *request; - int err; - - if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request)); - - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user(req32.ops_list, &request->ops_list) - || __put_user(req32.num_buffers, &request->num_buffers) - || __put_user(req32.context, &request->context) - || __copy_to_user(&request->fence_arg, &req32.fence_arg, - sizeof(req32.fence_arg)) - || __put_user(req32.batch.start, &request->batch.start) - || __put_user(req32.batch.used, &request->batch.used) - || __put_user(req32.batch.DR1, &request->batch.DR1) - || __put_user(req32.batch.DR4, &request->batch.DR4) - || __put_user(req32.batch.num_cliprects, - &request->batch.num_cliprects) - || __put_user((int __user *)(unsigned long)req32.batch.cliprects, - &request->batch.cliprects)) - return -EFAULT; - - err = drm_ioctl(file->f_dentry->d_inode, file, - DRM_IOCTL_I915_EXECBUFFER, (unsigned long)request); - - if (err) - return err; - - if (__get_user(req32.fence_arg.handle, &request->fence_arg.handle) - || __get_user(req32.fence_arg.fence_class, &request->fence_arg.fence_class) - || __get_user(req32.fence_arg.type, &request->fence_arg.type) - || __get_user(req32.fence_arg.flags, &request->fence_arg.flags) - || __get_user(req32.fence_arg.signaled, &request->fence_arg.signaled) - || __get_user(req32.fence_arg.error, &request->fence_arg.error) - || __get_user(req32.fence_arg.sequence, &request->fence_arg.sequence)) - return -EFAULT; - - if (copy_to_user((void __user *)arg, &req32, sizeof(req32))) - return -EFAULT; - - return 0; -} - - drm_ioctl_compat_t *i915_compat_ioctls[] = { [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer, [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer, [DRM_I915_GETPARAM] = compat_i915_getparam, [DRM_I915_IRQ_EMIT] = compat_i915_irq_emit, [DRM_I915_ALLOC] = compat_i915_alloc, -#ifdef I915_HAVE_BUFFER - [DRM_I915_EXECBUFFER] = compat_i915_execbuffer, -#endif }; /** diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a031afd2..04062c45 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -42,7 +42,6 @@ #define DRIVER_DATE "20080730" #if defined(__linux__) -#define I915_HAVE_FENCE #define I915_HAVE_BUFFER #endif @@ -62,7 +61,7 @@ * 1.12: TTM relocation optimization */ #define DRIVER_MAJOR 1 -#if defined(I915_HAVE_FENCE) && defined(I915_HAVE_BUFFER) +#if defined(I915_HAVE_BUFFER) #define DRIVER_MINOR 13 #else #define DRIVER_MINOR 6 @@ -176,12 +175,6 @@ struct drm_i915_private { struct drm_mm vram; -#ifdef I915_HAVE_FENCE - uint32_t flush_sequence; - uint32_t flush_flags; - uint32_t flush_pending; - uint32_t saved_flush_status; -#endif #ifdef I915_HAVE_BUFFER void *agp_iomap; unsigned int max_validate_buffers; @@ -556,30 +549,7 @@ extern void i915_mem_release(struct drm_device * dev, extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); -#ifdef I915_HAVE_FENCE -/* i915_fence.c */ -extern void i915_fence_handler(struct drm_device *dev); -extern void i915_invalidate_reported_sequence(struct drm_device *dev); - -#endif - -#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) -/* i915_buffer.c */ -extern struct drm_ttm_backend *i915_create_ttm_backend_entry(struct drm_device *dev); -extern int i915_fence_type(struct drm_buffer_object *bo, uint32_t *fclass, - uint32_t *type); -extern int i915_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags); -extern int i915_init_mem_type(struct drm_device *dev, uint32_t type, - struct drm_mem_type_manager *man); -extern uint64_t i915_evict_flags(struct drm_buffer_object *bo); -extern int i915_move(struct drm_buffer_object *bo, int evict, - int no_wait, struct drm_bo_mem_reg *new_mem); -void i915_flush_ttm(struct drm_ttm *ttm); -#endif /* ttm */ #ifdef I915_HAVE_BUFFER -/* i915_execbuf.c */ -int i915_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file_priv); /* i915_gem.c */ int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 7b88cc8d..d6383929 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -519,8 +519,5 @@ int i915_driver_firstopen(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; -#if defined(I915_HAVE_BUFFER) && defined(I915_TTM) - drm_bo_driver_init(dev); -#endif return 0; } diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 28fa35fd..ee83b14e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -554,9 +554,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) if (iir & I915_USER_INTERRUPT) { dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); DRM_WAKEUP(&dev_priv->irq_queue); -#ifdef I915_HAVE_FENCE - i915_fence_handler(dev); -#endif } if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| -- cgit v1.2.3 From 6af286079b57248405e543d7d99e111931983eac Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 17 Aug 2008 15:33:31 -0400 Subject: radeon: get primary dac adj info from bios tables --- linux-core/radeon_combios.c | 32 +++++++++++++++++++++++++++++++- linux-core/radeon_legacy_encoders.c | 11 ++++++++--- linux-core/radeon_mode.h | 4 ++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index 56116463..02f7335f 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -460,6 +460,36 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) return false; } +bool radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint16_t dac_info; + uint8_t rev, bg, dac; + + /* check CRT table */ + dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); + if (dac_info) { + rev = radeon_bios8(dev_priv, dac_info) & 0x3; + if (rev < 2) { + bg = radeon_bios8(dev_priv, dac_info + 0x2) & 0xf; + dac = (radeon_bios8(dev_priv, dac_info + 0x2) >> 4) & 0xf; + encoder->ps2_pdac_adj = (bg << 8) | (dac); + + return true; + } else { + bg = radeon_bios8(dev_priv, dac_info + 0x2) & 0xf; + dac = radeon_bios8(dev_priv, dac_info + 0x3) & 0xf; + encoder->ps2_pdac_adj = (bg << 8) | (dac); + + return true; + } + + } + + return false; +} + bool radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder) { struct drm_device *dev = encoder->base.dev; @@ -908,7 +938,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) dev_priv->chip_family == CHIP_RS480) { uint16_t lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); if (lcd_info) { - uint16_t lcd_ddc_info = lcd_ddc_info = combios_get_table_offset(dev, COMBIOS_LCD_DDC_INFO_TABLE); + uint16_t lcd_ddc_info = combios_get_table_offset(dev, COMBIOS_LCD_DDC_INFO_TABLE); mode_info->bios_connector[4].valid = true; mode_info->bios_connector[4].connector_type = CONNECTOR_LVDS; diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 172f93de..48cdd18c 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -420,6 +420,7 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl; DRM_DEBUG("\n"); @@ -458,7 +459,11 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, RADEON_DAC_RANGE_CNTL | RADEON_DAC_BLANKING); - dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); + if (radeon_encoder->ps2_pdac_adj) + dac_macro_cntl = radeon_encoder->ps2_pdac_adj; + else + dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); + dac_macro_cntl |= RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B; RADEON_WRITE(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); } @@ -504,8 +509,8 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs); - /* TODO get the primary dac vals from bios tables */ - //radeon_combios_get_lvds_info(radeon_encoder); + /* get the primary dac bg/adj vals from bios tables */ + radeon_combios_get_primary_dac_info(radeon_encoder); return encoder; } diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 3271375d..ee801604 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -368,6 +368,9 @@ struct radeon_encoder { bool use_bios_dividers; uint32_t lvds_gen_cntl; + /* legacy primary dac */ + uint32_t ps2_pdac_adj; + /* legacy tv dac */ uint32_t ps2_tvdac_adj; uint32_t ntsc_tvdac_adj; @@ -439,6 +442,7 @@ extern bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tv_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder); +extern bool radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder); extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, -- cgit v1.2.3 From 226c97e3b772f2f4bf09085374cd931b83dea2b0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 17 Aug 2008 15:38:05 -0400 Subject: radeon: remove unused legacy state --- linux-core/radeon_mode.h | 150 ----------------------------------------------- 1 file changed, 150 deletions(-) diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index ee801604..7278c42b 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -161,160 +161,10 @@ struct radeon_pll { uint32_t best_vco; }; -#define MAX_H_CODE_TIMING_LEN 32 -#define MAX_V_CODE_TIMING_LEN 32 - -struct radeon_legacy_state { - - uint32_t bus_cntl; - - /* DAC */ - uint32_t dac_cntl; - uint32_t dac2_cntl; - uint32_t dac_macro_cntl; - - /* CRTC 1 */ - uint32_t crtc_gen_cntl; - uint32_t crtc_ext_cntl; - uint32_t crtc_h_total_disp; - uint32_t crtc_h_sync_strt_wid; - uint32_t crtc_v_total_disp; - uint32_t crtc_v_sync_strt_wid; - uint32_t crtc_offset; - uint32_t crtc_offset_cntl; - uint32_t crtc_pitch; - uint32_t disp_merge_cntl; - uint32_t grph_buffer_cntl; - uint32_t crtc_more_cntl; - uint32_t crtc_tile_x0_y0; - - /* CRTC 2 */ - uint32_t crtc2_gen_cntl; - uint32_t crtc2_h_total_disp; - uint32_t crtc2_h_sync_strt_wid; - uint32_t crtc2_v_total_disp; - uint32_t crtc2_v_sync_strt_wid; - uint32_t crtc2_offset; - uint32_t crtc2_offset_cntl; - uint32_t crtc2_pitch; - uint32_t crtc2_tile_x0_y0; - - uint32_t disp_output_cntl; - uint32_t disp_tv_out_cntl; - uint32_t disp_hw_debug; - uint32_t disp2_merge_cntl; - uint32_t grph2_buffer_cntl; - - /* FP regs */ - uint32_t fp_crtc_h_total_disp; - uint32_t fp_crtc_v_total_disp; - uint32_t fp_gen_cntl; - uint32_t fp2_gen_cntl; - uint32_t fp_h_sync_strt_wid; - uint32_t fp_h2_sync_strt_wid; - uint32_t fp_horz_stretch; - uint32_t fp_horz_vert_active; - uint32_t fp_panel_cntl; - uint32_t fp_v_sync_strt_wid; - uint32_t fp_v2_sync_strt_wid; - uint32_t fp_vert_stretch; - uint32_t lvds_gen_cntl; - uint32_t lvds_pll_cntl; - uint32_t tmds_pll_cntl; - uint32_t tmds_transmitter_cntl; - - /* Computed values for PLL */ - uint32_t dot_clock_freq; - uint32_t pll_output_freq; - int feedback_div; - int reference_div; - int post_div; - - /* PLL registers */ - uint32_t ppll_ref_div; - uint32_t ppll_div_3; - uint32_t htotal_cntl; - uint32_t vclk_ecp_cntl; - - /* Computed values for PLL2 */ - uint32_t dot_clock_freq_2; - uint32_t pll_output_freq_2; - int feedback_div_2; - int reference_div_2; - int post_div_2; - - /* PLL2 registers */ - uint32_t p2pll_ref_div; - uint32_t p2pll_div_0; - uint32_t htotal_cntl2; - uint32_t pixclks_cntl; - - bool palette_valid; - uint32_t palette[256]; - uint32_t palette2[256]; - - uint32_t disp2_req_cntl1; - uint32_t disp2_req_cntl2; - uint32_t dmif_mem_cntl1; - uint32_t disp1_req_cntl1; - - uint32_t fp_2nd_gen_cntl; - uint32_t fp2_2_gen_cntl; - uint32_t tmds2_cntl; - uint32_t tmds2_transmitter_cntl; - - /* TV out registers */ - uint32_t tv_master_cntl; - uint32_t tv_htotal; - uint32_t tv_hsize; - uint32_t tv_hdisp; - uint32_t tv_hstart; - uint32_t tv_vtotal; - uint32_t tv_vdisp; - uint32_t tv_timing_cntl; - uint32_t tv_vscaler_cntl1; - uint32_t tv_vscaler_cntl2; - uint32_t tv_sync_size; - uint32_t tv_vrestart; - uint32_t tv_hrestart; - uint32_t tv_frestart; - uint32_t tv_ftotal; - uint32_t tv_clock_sel_cntl; - uint32_t tv_clkout_cntl; - uint32_t tv_data_delay_a; - uint32_t tv_data_delay_b; - uint32_t tv_dac_cntl; - uint32_t tv_pll_cntl; - uint32_t tv_pll_cntl1; - uint32_t tv_pll_fine_cntl; - uint32_t tv_modulator_cntl1; - uint32_t tv_modulator_cntl2; - uint32_t tv_frame_lock_cntl; - uint32_t tv_pre_dac_mux_cntl; - uint32_t tv_rgb_cntl; - uint32_t tv_y_saw_tooth_cntl; - uint32_t tv_y_rise_cntl; - uint32_t tv_y_fall_cntl; - uint32_t tv_uv_adr; - uint32_t tv_upsamp_and_gain_cntl; - uint32_t tv_gain_limit_settings; - uint32_t tv_linear_gain_settings; - uint32_t tv_crc_cntl; - uint32_t tv_sync_cntl; - uint32_t gpiopad_a; - uint32_t pll_test_cntl; - - uint16_t h_code_timing[MAX_H_CODE_TIMING_LEN]; - uint16_t v_code_timing[MAX_V_CODE_TIMING_LEN]; - - -}; - struct radeon_mode_info { struct atom_context *atom_context; struct radeon_bios_connector bios_connector[RADEON_MAX_BIOS_CONNECTOR]; struct radeon_pll pll; - struct radeon_legacy_state legacy_state; }; struct radeon_crtc { -- cgit v1.2.3 From aed70622ab33500721a30b06ec3783c581615cbb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 17 Aug 2008 18:09:07 -0400 Subject: radeon: first pass at bios scratch regs - todo: updated connected status --- linux-core/radeon_atombios.c | 52 ++++++++++ linux-core/radeon_combios.c | 41 ++++++++ linux-core/radeon_connectors.c | 3 +- linux-core/radeon_display.c | 1 - linux-core/radeon_encoders.c | 200 ++++++++++++++++++++++++++++++++---- linux-core/radeon_gem.c | 2 +- linux-core/radeon_legacy_encoders.c | 110 ++++++++++++++++++++ linux-core/radeon_mode.h | 5 + shared-core/radeon_cp.c | 6 +- 9 files changed, 398 insertions(+), 22 deletions(-) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index eb482d92..ca287bca 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -363,3 +363,55 @@ void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable) atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } +void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t bios_2_scratch, bios_6_scratch; + + if (dev_priv->chip_family >= CHIP_R600) { + bios_2_scratch = RADEON_READ(RADEON_BIOS_0_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + } else { + bios_2_scratch = RADEON_READ(RADEON_BIOS_0_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + } + + /* let the bios control the backlight */ + bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE; + + /* tell the bios not to handle mode switching */ + bios_6_scratch |= (ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH | + ATOM_S6_ACC_MODE); + + if (dev_priv->chip_family >= CHIP_R600) { + RADEON_WRITE(R600_BIOS_2_SCRATCH, bios_2_scratch); + RADEON_WRITE(R600_BIOS_6_SCRATCH, bios_6_scratch); + } else { + RADEON_WRITE(RADEON_BIOS_2_SCRATCH, bios_2_scratch); + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); + } + +} + +void +radeon_atom_output_lock(struct drm_encoder *encoder, bool lock) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t bios_6_scratch; + + if (dev_priv->chip_family >= CHIP_R600) + bios_6_scratch = RADEON_READ(R600_BIOS_6_SCRATCH); + else + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + + if (lock) + bios_6_scratch |= ATOM_S6_CRITICAL_STATE; + else + bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE; + + if (dev_priv->chip_family >= CHIP_R600) + RADEON_WRITE(R600_BIOS_6_SCRATCH, bios_6_scratch); + else + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); +} diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index 02f7335f..200761ee 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -1301,3 +1301,44 @@ void radeon_combios_asic_init(struct drm_device *dev) combios_parse_mmio_table(dev, table); } + +void radeon_combios_initialize_bios_scratch_regs(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t bios_0_scratch, bios_6_scratch, bios_7_scratch; + + bios_0_scratch = RADEON_READ(RADEON_BIOS_0_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + //bios_7_scratch = RADEON_READ(RADEON_BIOS_7_SCRATCH); + + /* let the bios control the backlight */ + bios_0_scratch &= ~RADEON_DRIVER_BRIGHTNESS_EN; + + /* tell the bios not to handle mode switching */ + bios_6_scratch |= (RADEON_DISPLAY_SWITCHING_DIS | + RADEON_ACC_MODE_CHANGE); + + /* tell the bios a driver is loaded */ + //bios_7_scratch |= RADEON_DRV_LOADED; + + RADEON_WRITE(RADEON_BIOS_0_SCRATCH, bios_0_scratch); + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); + //RADEON_WRITE(RADEON_BIOS_7_SCRATCH, bios_7_scratch); +} + +void +radeon_combios_output_lock(struct drm_encoder *encoder, bool lock) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t bios_6_scratch; + + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + + if (lock) + bios_6_scratch |= RADEON_DRIVER_CRITICAL; + else + bios_6_scratch &= ~RADEON_DRIVER_CRITICAL; + + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); +} diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c index 32f969ab..7b2d7c4d 100644 --- a/linux-core/radeon_connectors.c +++ b/linux-core/radeon_connectors.c @@ -66,6 +66,7 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector, static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector) { + // check acpi lid status ??? return connector_status_connected; } @@ -240,7 +241,7 @@ struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector) } /* see if we have a default encoder TODO */ - + /* then check use digitial */ /* pick the first one */ if (enc_id) { diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 39eb91eb..2877cd3b 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -600,4 +600,3 @@ void radeon_modeset_cleanup(struct drm_device *dev) { drm_mode_config_cleanup(dev); } - diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 04c57092..ec36e43d 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -134,7 +134,6 @@ static void atombios_display_device_control(struct drm_encoder *encoder, int ind atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } - static void atombios_scaler_setup(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -213,7 +212,7 @@ void atombios_set_crtc_source(struct drm_encoder *encoder, int source) default: return; } - + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)param); } @@ -264,7 +263,7 @@ static void radeon_lvtma_mode_set(struct drm_encoder *encoder, else args.ucMisc = 0; args.usPixelClock = cpu_to_le16(adjusted_mode->clock / 10); - + printk("executing set LVDS encoder\n"); atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } @@ -273,18 +272,44 @@ static void radeon_lvtma_mode_set(struct drm_encoder *encoder, static void radeon_lvtma_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); int index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + uint32_t bios_2_scratch, bios_3_scratch; + + if (dev_priv->chip_family >= CHIP_R600) { + bios_2_scratch = RADEON_READ(R600_BIOS_2_SCRATCH); + bios_3_scratch = RADEON_READ(R600_BIOS_3_SCRATCH); + } else { + bios_2_scratch = RADEON_READ(RADEON_BIOS_2_SCRATCH); + bios_3_scratch = RADEON_READ(RADEON_BIOS_3_SCRATCH); + } + + bios_2_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE; + bios_3_scratch |= (radeon_crtc->crtc_id << 17); switch(mode) { case DRM_MODE_DPMS_ON: atombios_display_device_control(encoder, index, ATOM_ENABLE); + bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE; + bios_3_scratch |= ATOM_S3_LCD1_ACTIVE; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: atombios_display_device_control(encoder, index, ATOM_DISABLE); + bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE; + bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE; break; } + + if (dev_priv->chip_family >= CHIP_R600) { + RADEON_WRITE(R600_BIOS_2_SCRATCH, bios_2_scratch); + RADEON_WRITE(R600_BIOS_3_SCRATCH, bios_3_scratch); + } else { + RADEON_WRITE(RADEON_BIOS_2_SCRATCH, bios_2_scratch); + RADEON_WRITE(RADEON_BIOS_3_SCRATCH, bios_3_scratch); + } } static bool radeon_lvtma_mode_fixup(struct drm_encoder *encoder, @@ -297,18 +322,20 @@ static bool radeon_lvtma_mode_fixup(struct drm_encoder *encoder, if (radeon_encoder->rmx_type != RMX_OFF) radeon_rmx_mode_fixup(encoder, mode, adjusted_mode); - + return true; } static void radeon_lvtma_prepare(struct drm_encoder *encoder) { + radeon_atom_output_lock(encoder, true); radeon_lvtma_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_lvtma_commit(struct drm_encoder *encoder) { radeon_lvtma_dpms(encoder, DRM_MODE_DPMS_ON); + radeon_atom_output_lock(encoder, false); } static const struct drm_encoder_helper_funcs radeon_atom_lvtma_helper_funcs = { @@ -366,25 +393,91 @@ static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); int atom_type = -1; int index; + uint32_t bios_2_scratch, bios_3_scratch; atom_type = atom_dac_find_atom_type(radeon_encoder, NULL); if (atom_type == -1) return; - + + if (dev_priv->chip_family >= CHIP_R600) { + bios_2_scratch = RADEON_READ(R600_BIOS_2_SCRATCH); + bios_3_scratch = RADEON_READ(R600_BIOS_3_SCRATCH); + } else { + bios_2_scratch = RADEON_READ(RADEON_BIOS_2_SCRATCH); + bios_3_scratch = RADEON_READ(RADEON_BIOS_3_SCRATCH); + } + switch(atom_type) { case ATOM_DEVICE_CRT1_INDEX: index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + bios_2_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE; + bios_3_scratch |= (radeon_crtc->crtc_id << 16); + switch(mode) { + case DRM_MODE_DPMS_ON: + bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE; + bios_3_scratch |= ATOM_S3_CRT1_ACTIVE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE; + bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE; + break; + } break; case ATOM_DEVICE_CRT2_INDEX: index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + bios_2_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE; + bios_3_scratch |= (radeon_crtc->crtc_id << 20); + switch(mode) { + case DRM_MODE_DPMS_ON: + bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE; + bios_3_scratch |= ATOM_S3_CRT2_ACTIVE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE; + bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE; + break; + } break; case ATOM_DEVICE_TV1_INDEX: index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE; + bios_3_scratch |= (radeon_crtc->crtc_id << 18); + switch(mode) { + case DRM_MODE_DPMS_ON: + bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE; + bios_3_scratch |= ATOM_S3_TV1_ACTIVE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE; + bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE; + break; + } break; case ATOM_DEVICE_CV_INDEX: index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + bios_2_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE; + bios_3_scratch |= (radeon_crtc->crtc_id << 24); + switch(mode) { + case DRM_MODE_DPMS_ON: + bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE; + bios_3_scratch |= ATOM_S3_CV_ACTIVE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + bios_2_scratch |= ATOM_S2_CV_DPMS_STATE; + bios_3_scratch &= ~ATOM_S3_CV_ACTIVE; + break; + } break; default: return; @@ -394,12 +487,20 @@ static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_ON: atombios_display_device_control(encoder, index, ATOM_ENABLE); break; - case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: atombios_display_device_control(encoder, index, ATOM_DISABLE); break; } + + if (dev_priv->chip_family >= CHIP_R600) { + RADEON_WRITE(R600_BIOS_2_SCRATCH, bios_2_scratch); + RADEON_WRITE(R600_BIOS_3_SCRATCH, bios_3_scratch); + } else { + RADEON_WRITE(RADEON_BIOS_2_SCRATCH, bios_2_scratch); + RADEON_WRITE(RADEON_BIOS_3_SCRATCH, bios_3_scratch); + } } static bool radeon_atom_dac_mode_fixup(struct drm_encoder *encoder, @@ -411,12 +512,14 @@ static bool radeon_atom_dac_mode_fixup(struct drm_encoder *encoder, static void radeon_atom_dac_prepare(struct drm_encoder *encoder) { + radeon_atom_output_lock(encoder, true); radeon_atom_dac_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_atom_dac_commit(struct drm_encoder *encoder) { radeon_atom_dac_dpms(encoder, DRM_MODE_DPMS_ON); + radeon_atom_output_lock(encoder, false); } static int atombios_dac_setup(struct drm_encoder *encoder, @@ -447,7 +550,7 @@ static int atombios_dac_setup(struct drm_encoder *encoder, args.ucDacStandard = id ? ATOM_DAC2_NTSC : ATOM_DAC1_NTSC; /* TODO PAL */ atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); - + return 0; } @@ -471,7 +574,7 @@ static int atombios_tv1_setup(struct drm_encoder *encoder, } args.sTVEncoder.usPixelClock = cpu_to_le16(mode->clock / 10); - + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); return 0; } @@ -496,7 +599,7 @@ static void radeon_atom_dac_mode_set(struct drm_encoder *encoder, if ((atom_type == ATOM_DEVICE_TV1_INDEX) || (atom_type == ATOM_DEVICE_CV_INDEX)) atombios_tv1_setup(encoder, adjusted_mode, atom_type); - + } static bool atom_dac_load_detect(struct drm_encoder *encoder, int atom_devices) @@ -525,11 +628,11 @@ static bool atom_dac_load_detect(struct drm_encoder *encoder, int atom_devices) args.sDacload.ucMisc = 1; } else return false; - + DRM_DEBUG("writing %x %x\n", args.sDacload.usDeviceID, args.sDacload.ucDacType); atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); return true; -} +} static enum drm_connector_status radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -551,7 +654,7 @@ static enum drm_connector_status radeon_atom_dac_detect(struct drm_encoder *enco } - if (dev_priv->chip_family >= CHIP_R600) + if (dev_priv->chip_family >= CHIP_R600) bios_0_scratch = RADEON_READ(R600_BIOS_0_SCRATCH); else bios_0_scratch = RADEON_READ(RADEON_BIOS_0_SCRATCH); @@ -607,7 +710,7 @@ static void atombios_tmds1_setup(struct drm_encoder *encoder, args.usPixelClock = cpu_to_le16(mode->clock / 10); - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } static void atombios_tmds2_setup(struct drm_encoder *encoder, @@ -628,7 +731,7 @@ static void atombios_tmds2_setup(struct drm_encoder *encoder, args.usPixelClock = cpu_to_le16(mode->clock / 10); - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } @@ -652,7 +755,7 @@ static void atombios_ext_tmds_setup(struct drm_encoder *encoder, // TODO 6-bit DAC // args.usPixelClock = cpu_to_le16(mode->clock / 10); - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } static void atombios_dig1_setup(struct drm_encoder *encoder, @@ -680,7 +783,7 @@ static void atombios_dig1_setup(struct drm_encoder *encoder, } // TODO Encoder MODE - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } static void atombios_ddia_setup(struct drm_encoder *encoder, @@ -699,7 +802,7 @@ static void atombios_ddia_setup(struct drm_encoder *encoder, else args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = 0; - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } struct drm_encoder *radeon_encoder_atom_dac_add(struct drm_device *dev, int bios_index, int dac_type, int with_tv) @@ -760,8 +863,10 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); int atom_type = -1; int index = -1; + uint32_t bios_2_scratch, bios_3_scratch; if (radeon_encoder->atom_device & ATOM_DEVICE_DFP1_SUPPORT) atom_type = ATOM_DEVICE_DFP1_INDEX; @@ -773,15 +878,65 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) if (atom_type == -1) return; + if (dev_priv->chip_family >= CHIP_R600) { + bios_2_scratch = RADEON_READ(R600_BIOS_2_SCRATCH); + bios_3_scratch = RADEON_READ(R600_BIOS_3_SCRATCH); + } else { + bios_2_scratch = RADEON_READ(RADEON_BIOS_2_SCRATCH); + bios_3_scratch = RADEON_READ(RADEON_BIOS_3_SCRATCH); + } + switch(atom_type) { case ATOM_DEVICE_DFP1_INDEX: index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); + bios_2_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE; + bios_3_scratch |= (radeon_crtc->crtc_id << 19); + switch(mode) { + case DRM_MODE_DPMS_ON: + bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE; + bios_3_scratch |= ATOM_S3_DFP1_ACTIVE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE; + bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE; + break; + } break; case ATOM_DEVICE_DFP2_INDEX: index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + bios_2_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE; + bios_3_scratch |= (radeon_crtc->crtc_id << 23); + switch(mode) { + case DRM_MODE_DPMS_ON: + bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE; + bios_3_scratch |= ATOM_S3_DFP2_ACTIVE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE; + bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE; + break; + } break; case ATOM_DEVICE_DFP3_INDEX: index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); + bios_2_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE; + bios_3_scratch |= (radeon_crtc->crtc_id << 25); + switch(mode) { + case DRM_MODE_DPMS_ON: + bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE; + bios_3_scratch |= ATOM_S3_DFP3_ACTIVE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE; + bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE; + break; + } break; } @@ -798,6 +953,14 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) atombios_display_device_control(encoder, index, ATOM_DISABLE); break; } + + if (dev_priv->chip_family >= CHIP_R600) { + RADEON_WRITE(R600_BIOS_2_SCRATCH, bios_2_scratch); + RADEON_WRITE(R600_BIOS_3_SCRATCH, bios_3_scratch); + } else { + RADEON_WRITE(RADEON_BIOS_2_SCRATCH, bios_2_scratch); + RADEON_WRITE(RADEON_BIOS_3_SCRATCH, bios_3_scratch); + } } static bool radeon_atom_tmds_mode_fixup(struct drm_encoder *encoder, @@ -845,12 +1008,14 @@ static void radeon_atom_tmds_mode_set(struct drm_encoder *encoder, static void radeon_atom_tmds_prepare(struct drm_encoder *encoder) { + radeon_atom_output_lock(encoder, true); radeon_atom_tmds_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_atom_tmds_commit(struct drm_encoder *encoder) { radeon_atom_tmds_dpms(encoder, DRM_MODE_DPMS_ON); + radeon_atom_output_lock(encoder, false); } static const struct drm_encoder_helper_funcs radeon_atom_tmds_helper_funcs = { @@ -894,4 +1059,3 @@ struct drm_encoder *radeon_encoder_atom_tmds_add(struct drm_device *dev, int bio radeon_encoder->atom_device &= analog_enc_mask; return encoder; } - diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 6a7529cd..d572008a 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -225,7 +225,7 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, args->addr_ptr = (uint64_t) addr; return 0; - + } int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 48cdd18c..64521547 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -197,10 +197,19 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; + uint32_t bios_5_scratch, bios_6_scratch; DRM_DEBUG("\n"); + // FIXME atom/legacy cards like r4xx + bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + + bios_5_scratch &= ~RADEON_LCD1_CRTC_MASK; + bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_LCD1_CRTC_SHIFT); + switch (mode) { case DRM_MODE_DPMS_ON: disp_pwr_man = RADEON_READ(RADEON_DISP_PWR_MAN); @@ -228,6 +237,11 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) /* enable backlight */ lvds_gen_cntl |= RADEON_LVDS_BLON; RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + + /* update bios scratch regs */ + bios_5_scratch |= RADEON_LCD1_ON; + bios_6_scratch |= RADEON_LCD_DPMS_ON; + break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -239,18 +253,27 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, pixclks_cntl); + + bios_5_scratch &= ~RADEON_LCD1_ON; + bios_6_scratch &= ~RADEON_LCD_DPMS_ON; break; } + RADEON_WRITE(RADEON_BIOS_5_SCRATCH, bios_5_scratch); + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); } static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) { + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, true); radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) { radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, false); } static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, @@ -372,9 +395,20 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); uint32_t crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); uint32_t dac_cntl = RADEON_READ(RADEON_DAC_CNTL); uint32_t dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); + uint32_t bios_5_scratch, bios_6_scratch; + + DRM_DEBUG("\n"); + + // FIXME atom/legacy cards like r4xx + bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + + bios_5_scratch &= ~RADEON_CRT1_CRTC_MASK; + bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_CRT1_CRTC_SHIFT); DRM_DEBUG("\n"); @@ -385,6 +419,8 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B); + bios_5_scratch |= RADEON_CRT1_ON; + bios_6_scratch |= RADEON_CRT_DPMS_ON; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -394,6 +430,8 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode dac_macro_cntl |= (RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B); + bios_5_scratch &= ~RADEON_CRT1_ON; + bios_6_scratch &= ~RADEON_CRT_DPMS_ON; break; } @@ -401,16 +439,22 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode RADEON_WRITE(RADEON_DAC_CNTL, dac_cntl); RADEON_WRITE(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + RADEON_WRITE(RADEON_BIOS_5_SCRATCH, bios_5_scratch); + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); } static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) { + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, true); radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) { radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON); + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, false); } static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, @@ -527,32 +571,52 @@ static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); uint32_t fp_gen_cntl = RADEON_READ(RADEON_FP_GEN_CNTL); + uint32_t bios_5_scratch, bios_6_scratch; DRM_DEBUG("\n"); + // FIXME atom/legacy cards like r4xx + bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + + bios_5_scratch &= ~RADEON_DFP1_CRTC_MASK; + bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_DFP1_CRTC_SHIFT); + switch(mode) { case DRM_MODE_DPMS_ON: fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); + bios_5_scratch |= RADEON_DFP1_ON; + bios_6_scratch |= RADEON_DFP_DPMS_ON; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + bios_5_scratch &= ~RADEON_DFP1_ON; + bios_6_scratch &= ~RADEON_DFP_DPMS_ON; break; } RADEON_WRITE(RADEON_FP_GEN_CNTL, fp_gen_cntl); + + RADEON_WRITE(RADEON_BIOS_5_SCRATCH, bios_5_scratch); + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); } static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) { + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, true); radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) { radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON); + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, true); } static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, @@ -691,34 +755,54 @@ static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); uint32_t fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + uint32_t bios_5_scratch, bios_6_scratch; DRM_DEBUG("\n"); + // FIXME atom/legacy cards like r4xx + bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + + bios_5_scratch &= ~RADEON_DFP2_CRTC_MASK; + bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_DFP2_CRTC_SHIFT); + switch(mode) { case DRM_MODE_DPMS_ON: fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN; fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); + bios_5_scratch |= RADEON_DFP2_ON; + bios_6_scratch |= RADEON_DFP_DPMS_ON; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: fp2_gen_cntl |= RADEON_FP2_BLANK_EN; fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); + bios_5_scratch &= ~RADEON_DFP2_ON; + bios_6_scratch &= ~RADEON_DFP_DPMS_ON; break; } RADEON_WRITE(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + + RADEON_WRITE(RADEON_BIOS_5_SCRATCH, bios_5_scratch); + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); } static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) { + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, true); radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) { radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON); + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, false); } static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, @@ -827,11 +911,23 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; //uint32_t tv_master_cntl = 0; + uint32_t bios_5_scratch, bios_6_scratch; DRM_DEBUG("\n"); + // FIXME atom/legacy cards like r4xx + bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + + bios_5_scratch &= ~RADEON_CRT2_CRTC_MASK; + bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_CRT2_CRTC_SHIFT); + // FIXME TV + //bios_5_scratch &= ~RADEON_TV1_CRTC_MASK; + //bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_TV1_CRTC_SHIFT); + if (dev_priv->chip_family == CHIP_R200) fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); else { @@ -860,6 +956,10 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) RADEON_TV_DAC_BDACPD | RADEON_TV_DAC_BGSLEEP); } + //bios_5_scratch |= RADEON_TV1_ON; + //bios_6_scratch |= RADEON_TV_DPMS_ON; + bios_5_scratch |= RADEON_CRT2_ON; + bios_6_scratch |= RADEON_CRT_DPMS_ON; break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: @@ -881,6 +981,10 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) RADEON_TV_DAC_BDACPD | RADEON_TV_DAC_BGSLEEP); } + //bios_5_scratch &= ~RADEON_TV1_ON; + //bios_6_scratch &= ~RADEON_TV_DPMS_ON; + bios_5_scratch &= ~RADEON_CRT2_ON; + bios_6_scratch &= ~RADEON_CRT_DPMS_ON; break; } @@ -892,16 +996,22 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) RADEON_WRITE(RADEON_TV_DAC_CNTL, tv_dac_cntl); } + RADEON_WRITE(RADEON_BIOS_5_SCRATCH, bios_5_scratch); + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); } static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) { + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, true); radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder) { radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON); + // fix me: atom/legacy r4xx + radeon_combios_output_lock(encoder, false); } static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 7278c42b..d7c60fa6 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -293,6 +293,10 @@ extern bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tv_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder); +extern void radeon_combios_output_lock(struct drm_encoder *encoder, bool lock); +extern void radeon_combios_initialize_bios_scratch_regs(struct drm_device *dev); +extern void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock); +extern void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev); extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, @@ -311,6 +315,7 @@ void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_stat void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable); void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable); +void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable); void radeon_get_clock_info(struct drm_device *dev); extern bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev); diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index e30696fc..6b71360f 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2409,8 +2409,12 @@ int radeon_modeset_preinit(struct drm_device *dev) if (dev_priv->is_atom_bios) { dev_priv->mode_info.atom_context = atom_parse(&card, dev_priv->bios); - } + radeon_atom_initialize_bios_scratch_regs(dev); + } else + radeon_combios_initialize_bios_scratch_regs(dev); + radeon_get_clock_info(dev); + return 0; } -- cgit v1.2.3 From 232c369a05bbd9db17a0453380229c993cbbc8bd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 17 Aug 2008 18:38:41 -0400 Subject: radeon: first pass at legacy dac detect - done: primary dac, vga on tvdac - todo: ext dac, tv on tvdac --- linux-core/radeon_legacy_encoders.c | 158 ++++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 5 deletions(-) diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 64521547..a418d1d4 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -511,11 +511,68 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, RADEON_WRITE(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); } -static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder, + struct drm_connector *connector) { - // FIXME - return connector_status_disconnected; + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t vclk_ecp_cntl, crtc_ext_cntl; + uint32_t dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp; + enum drm_connector_status found = connector_status_disconnected; + bool color = true; + + /* save the regs we need */ + vclk_ecp_cntl = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); + dac_ext_cntl = RADEON_READ(RADEON_DAC_EXT_CNTL); + dac_cntl = RADEON_READ(RADEON_DAC_CNTL); + dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); + + tmp = vclk_ecp_cntl & + ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + + tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; + RADEON_WRITE(RADEON_CRTC_EXT_CNTL, tmp); + + tmp = RADEON_DAC_FORCE_BLANK_OFF_EN | + RADEON_DAC_FORCE_DATA_EN; + + if (color) + tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; + else + tmp |= RADEON_DAC_FORCE_DATA_SEL_G; + + if (radeon_is_r300(dev_priv)) + tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else + tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); + + RADEON_WRITE(RADEON_DAC_EXT_CNTL, tmp); + + tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); + tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; + RADEON_WRITE(RADEON_DAC_CNTL, tmp); + + tmp &= ~(RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + + RADEON_WRITE(RADEON_DAC_MACRO_CNTL, tmp); + + udelay(2000); + + if (RADEON_READ(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) + found = connector_status_connected; + /* restore the regs we used */ + RADEON_WRITE(RADEON_DAC_CNTL, dac_cntl); + RADEON_WRITE(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + RADEON_WRITE(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + RADEON_WRITE(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl); + + return found; } static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = { @@ -1102,9 +1159,100 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, } -static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder, + struct drm_connector *connector) { - // FIXME + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; + uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp; + enum drm_connector_status found = connector_status_disconnected; + bool color = true; + + // FIXME tv + + /* save the regs we need */ + pixclks_cntl = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + gpiopad_a = radeon_is_r300(dev_priv) ? RADEON_READ(RADEON_GPIOPAD_A) : 0; + disp_output_cntl = radeon_is_r300(dev_priv) ? RADEON_READ(RADEON_DISP_OUTPUT_CNTL) : 0; + disp_hw_debug = radeon_is_r300(dev_priv) ? 0 : RADEON_READ(RADEON_DISP_HW_DEBUG); + crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); + tv_dac_cntl = RADEON_READ(RADEON_TV_DAC_CNTL); + dac_ext_cntl = RADEON_READ(RADEON_DAC_EXT_CNTL); + dac_cntl2 = RADEON_READ(RADEON_DAC_CNTL2); + + tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb + | RADEON_PIX2CLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + + if (radeon_is_r300(dev_priv)) + RADEON_WRITE_P(RADEON_GPIOPAD_A, 1, ~1); + + tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; + tmp |= RADEON_CRTC2_CRT2_ON | + (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); + + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, tmp); + + if (radeon_is_r300(dev_priv)) { + tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; + tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + RADEON_WRITE(RADEON_DISP_OUTPUT_CNTL, tmp); + } else { + tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; + RADEON_WRITE(RADEON_DISP_HW_DEBUG, tmp); + } + + tmp = RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_MONITOR_DETECT_EN | + RADEON_TV_DAC_STD_PS2; + + RADEON_WRITE(RADEON_TV_DAC_CNTL, tmp); + + tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN | + RADEON_DAC2_FORCE_DATA_EN; + + if (color) + tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; + else + tmp |= RADEON_DAC_FORCE_DATA_SEL_G; + + if (radeon_is_r300(dev_priv)) + tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else + tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); + + RADEON_WRITE(RADEON_DAC_EXT_CNTL, tmp); + + tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN; + RADEON_WRITE(RADEON_DAC_CNTL2, tmp); + + udelay(10000); + + if (radeon_is_r300(dev_priv)) { + if (RADEON_READ(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) + found = connector_status_connected; + } else { + if (RADEON_READ(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT) + found = connector_status_connected; + } + + /* restore regs we used */ + RADEON_WRITE(RADEON_DAC_CNTL2, dac_cntl2); + RADEON_WRITE(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + RADEON_WRITE(RADEON_TV_DAC_CNTL, tv_dac_cntl); + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + + if (radeon_is_r300(dev_priv)) { + RADEON_WRITE(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + RADEON_WRITE_P(RADEON_GPIOPAD_A, gpiopad_a, ~1 ); + } else { + RADEON_WRITE(RADEON_DISP_HW_DEBUG, disp_hw_debug); + } + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, pixclks_cntl); + + //return found; return connector_status_disconnected; } -- cgit v1.2.3 From 2d4cf9cc0f31ca316b109cceffc463ea52db92f2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 19 Aug 2008 08:18:46 +1000 Subject: radeon: oops set correct scratch --- shared-core/radeon_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 9edd3884..019491c7 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -717,7 +717,7 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define GET_SCRATCH( x ) (dev_priv->writeback_works ? \ (dev_priv->mm.ring_read.bo ? \ - readl(dev_priv->mm.ring_read.kmap.virtual + RADEON_SCRATCHOFF(0)) : \ + readl(dev_priv->mm.ring_read.kmap.virtual + RADEON_SCRATCHOFF(x)) : \ DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(x))) : \ RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x))) -- cgit v1.2.3 From b2c19c788a570f28a22c236e60ee31f5c1e180af Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Aug 2008 13:03:23 -0400 Subject: radeon: legacy lvds updates --- linux-core/radeon_legacy_encoders.c | 25 +++++++++++++------------ linux-core/radeon_reg.h | 3 +++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index a418d1d4..5b0047e4 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -223,19 +223,10 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); - /* enable lvds, turn on voltage */ lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); - lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); - RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); - udelay(radeon_encoder->panel_digon_delay * 1000); - - /* enable data */ + lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON); lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); - RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); - udelay(radeon_encoder->panel_blon_delay * 1000); - - /* enable backlight */ - lvds_gen_cntl |= RADEON_LVDS_BLON; + udelay(radeon_encoder->panel_pwr_delay); RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); /* update bios scratch regs */ @@ -251,6 +242,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); + udelay(radeon_encoder->panel_pwr_delay); RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, pixclks_cntl); @@ -284,7 +276,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - uint32_t lvds_pll_cntl, lvds_gen_cntl; + uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl; DRM_DEBUG("\n"); @@ -322,6 +314,15 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); + lvds_ss_gen_cntl = RADEON_READ(RADEON_LVDS_SS_GEN_CNTL); + if (radeon_encoder->panel_digon_delay && + radeon_encoder->panel_blon_delay) { + lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | + (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); + lvds_ss_gen_cntl |= ((radeon_encoder->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | + (radeon_encoder->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); + } + if (dev_priv->chip_family == CHIP_RV410) RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, 0); } diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index b4f0ac08..e7f30817 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -1053,6 +1053,9 @@ # define R300_LVDS_SRC_SEL_CRTC1 (0 << 18) # define R300_LVDS_SRC_SEL_CRTC2 (1 << 18) # define R300_LVDS_SRC_SEL_RMX (2 << 18) +#define RADEON_LVDS_SS_GEN_CNTL 0x02ec +# define RADEON_LVDS_PWRSEQ_DELAY1_SHIFT 16 +# define RADEON_LVDS_PWRSEQ_DELAY2_SHIFT 20 #define RADEON_MAX_LATENCY 0x0f3f /* PCI */ #define RADEON_MC_AGP_LOCATION 0x014c -- cgit v1.2.3 From ba61880ac8d5db0494816296aeef6092aadcb63f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Aug 2008 13:06:04 -0400 Subject: radeon: fix warning from radeon_legacy_state removal --- linux-core/radeon_legacy_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index 6775ffc0..58c2f9dc 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -29,7 +29,7 @@ #include "drm_crtc_helper.h" -void radeon_restore_common_regs(struct drm_device *dev, struct radeon_legacy_state *state) +void radeon_restore_common_regs(struct drm_device *dev) { /* don't need this yet */ } -- cgit v1.2.3 From 9afd2659430245c456cf887d47087de047c0aba8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 22 Aug 2008 07:08:29 +1000 Subject: drm: add gpu create script --- scripts/create_lk_gpu.sh | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100755 scripts/create_lk_gpu.sh diff --git a/scripts/create_lk_gpu.sh b/scripts/create_lk_gpu.sh new file mode 100755 index 00000000..4b323f7f --- /dev/null +++ b/scripts/create_lk_gpu.sh @@ -0,0 +1,58 @@ +#! /bin/bash +# script to create a Linux Kernel tree from the DRM tree for diffing etc.. +# +# Original author - Dave Airlie (C) 2004 - airlied@linux.ie +# kernel_version to remove below (e.g. 2.6.24) + +if [ $# -lt 2 ] ;then + echo usage: $0 output_dir kernel_version + exit 1 +fi + +if [ ! -d shared-core -o ! -d linux-core ] ;then + echo not in DRM toplevel + exit 1 +fi + +DRMDIR=$1/drivers/gpu/drm/ +HDRDIR=$1/include/drm/ +KERNEL_VERS=$2 +echo "Copying kernel independent files" +mkdir -p $DRMDIR/.tmp +mkdir -p $HDRDIR/.tmp + +( cd linux-core/ ; make drm_pciids.h ) +cp shared-core/*.[ch] $DRMDIR/.tmp +cp linux-core/*.[ch] $DRMDIR/.tmp +cp linux-core/Makefile.kernel $DRMDIR/.tmp/Makefile + +echo "Copying 2.6 Kernel files" +cp linux-core/Kconfig $DRMDIR/.tmp + +./scripts/drm-scripts-gentree.pl $KERNEL_VERS $DRMDIR/.tmp $DRMDIR +mv $DRMDIR/drm*.h $HDRDIR +mv $DRMDIR/*_drm.h $HDRDIR + +cd $DRMDIR +rm -rf .tmp +rm via_ds.[ch] +rm sis_ds.[ch] +rm amd*.[ch] +rm radeon_ms*.[ch] + +for i in radeon mach64 r128 mga i915 i810 via savage sis xgi nouveau tdfx ffb imagine +do +mkdir ./$i +mv $i*.[ch] $i/ +done + +mv r300*.[ch] radeon/ +mv r600*.[ch] radeon/ +mv ObjectID.h radeon/ +mv atom*.[ch] radeon/ + +mv nv*.[ch] nouveau/ +mv intel*.[ch] i915/ +mv dvo*.[ch] i915/ + +cd - -- cgit v1.2.3 From 4c8e8e0d0bad839cf5aacb22524885e49fe86715 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 26 Aug 2008 17:33:46 +1000 Subject: drm: add memory clean flag. When the mapping is clean this flag will be set. This can be used by a driver to save migrating and allocating pages for an object that will first be used in VRAM. --- linux-core/drm_bo.c | 7 ++++++- linux-core/drm_bo_move.c | 3 +++ linux-core/drm_objects.h | 7 ++++++- linux-core/drm_vm.c | 3 +++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 09b3fa39..ec63fa2a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1170,6 +1170,9 @@ out_unlock: DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, _DRM_BO_FLAG_UNFENCED); } + /* clear the clean flags */ + bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; + mutex_unlock(&dev->struct_mutex); mutex_unlock(&bm->evict_mutex); return ret; @@ -1493,12 +1496,14 @@ int drm_buffer_object_create(struct drm_device *dev, bo->buffer_start = buffer_start & PAGE_MASK; bo->priv_flags = 0; bo->mem.flags = (DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED | - DRM_BO_FLAG_MAPPABLE); + DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_CLEAN); bo->mem.proposed_flags = 0; atomic_inc(&bm->count); /* * Use drm_bo_modify_proposed_flags to error-check the proposed flags */ + flags |= DRM_BO_FLAG_CLEAN; /* or in the clean flag */ + ret = drm_bo_modify_proposed_flags (bo, flags, flags); if (ret) goto out_err; diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 5c290af2..e81967fd 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -562,6 +562,9 @@ int drm_bo_kmap(struct drm_buffer_object *bo, unsigned long start_page, if (ret) return ret; + /* clear the clean flags */ + bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; + if (bus_size == 0) { return drm_bo_kmap_ttm(bo, start_page, num_pages, map); } else { diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 925b4d67..3eb8b902 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -145,6 +145,12 @@ struct drm_fence_arg { #define DRM_BO_FLAG_FORCE_MAPPABLE (1ULL << 14) #define DRM_BO_FLAG_TILE (1ULL << 15) +/* + * Buffer has been mapped or touched since creation + * for VRAM we don't need to migrate, just fill with 0s for non-dirty + */ +#define DRM_BO_FLAG_CLEAN (1ULL << 16) + /* * Memory type flags that can be or'ed together in the mask, but only * one appears in flags. @@ -208,7 +214,6 @@ struct drm_fence_arg { */ #define DRM_BO_HINT_PRESUMED_OFFSET 0x00000010 - #define DRM_BO_MEM_LOCAL 0 #define DRM_BO_MEM_TT 1 #define DRM_BO_MEM_VRAM 2 diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 0aabf943..48d7b057 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -792,6 +792,9 @@ static void drm_bo_vm_open_locked(struct vm_area_struct *vma) { struct drm_buffer_object *bo = (struct drm_buffer_object *) vma->vm_private_data; + /* clear the clean flags */ + bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; + drm_vm_open_locked(vma); atomic_inc(&bo->usage); #ifdef DRM_ODD_MM_COMPAT -- cgit v1.2.3 From 361ab10d2fb0c7ad73e54d92af2563194dbf7080 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 26 Aug 2008 17:39:00 +1000 Subject: radeon: fixup domains and use them properly --- linux-core/radeon_gem.c | 143 +++++++++++++++++++++++++++++++++++------------ shared-core/radeon_drm.h | 9 +-- 2 files changed, 109 insertions(+), 43 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index d572008a..eceb5207 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -82,16 +82,18 @@ struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int ret; uint32_t flags; - DRM_DEBUG("size 0x%x, alignment %d, initial_domain %d\n", size, alignment, initial_domain); obj = drm_gem_object_alloc(dev, size); if (!obj) return NULL;; obj_priv = obj->driver_private; + flags = DRM_BO_FLAG_MAPPABLE; if (initial_domain == RADEON_GEM_DOMAIN_VRAM) - flags = DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MAPPABLE; + flags |= DRM_BO_FLAG_MEM_VRAM; + else if (initial_domain == RADEON_GEM_DOMAIN_GTT) + flags |= DRM_BO_FLAG_MEM_TT; else - flags = DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MAPPABLE; + flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; flags |= DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE; /* create a TTM BO */ @@ -102,6 +104,7 @@ struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, if (ret) goto fail; + DRM_DEBUG("%p : size 0x%x, alignment %d, initial_domain %d\n", obj_priv->bo, size, alignment, initial_domain); return obj; fail: @@ -144,6 +147,55 @@ fail: return ret; } +int radeon_gem_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uint32_t write_domain, uint32_t *flags_p, bool unfenced) +{ + struct drm_device *dev = obj->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_gem_object *obj_priv; + uint32_t flags = 0; + int ret; + + obj_priv = obj->driver_private; + + /* work out where to validate the buffer to */ + if (write_domain) { /* write domains always win */ + if (write_domain == RADEON_GEM_DOMAIN_VRAM) + flags = DRM_BO_FLAG_MEM_VRAM; + else if (write_domain == RADEON_GEM_DOMAIN_GTT) + flags = DRM_BO_FLAG_MEM_TT; // need a can write gart check + else + return -EINVAL; // we can't write to system RAM + } else { + /* okay for a read domain - prefer wherever the object is now or close enough */ + if ((read_domains == 0) || (read_domains == RADEON_GEM_DOMAIN_CPU)) + return -EINVAL; + + /* simple case no choice in domains */ + if (read_domains == RADEON_GEM_DOMAIN_VRAM) + flags = DRM_BO_FLAG_MEM_VRAM; + else if (read_domains == RADEON_GEM_DOMAIN_GTT) + flags = DRM_BO_FLAG_MEM_TT; + else if ((obj_priv->bo->mem.mem_type == DRM_BO_MEM_VRAM) && (read_domains & RADEON_GEM_DOMAIN_VRAM)) + flags = DRM_BO_FLAG_MEM_VRAM; + else if ((obj_priv->bo->mem.mem_type == DRM_BO_MEM_TT) && (read_domains & RADEON_GEM_DOMAIN_GTT)) + flags = DRM_BO_FLAG_MEM_TT; + else if (read_domains & RADEON_GEM_DOMAIN_VRAM) + flags = DRM_BO_FLAG_MEM_VRAM; + else if (read_domains & RADEON_GEM_DOMAIN_GTT) + flags = DRM_BO_FLAG_MEM_TT; + } + + ret = drm_bo_do_validate(obj_priv->bo, flags, DRM_BO_MASK_MEM | DRM_BO_FLAG_CACHED, + unfenced ? DRM_BO_HINT_DONT_FENCE : 0, 0); + if (ret) + return ret; + + if (flags_p) + *flags_p = flags; + return 0; + +} + int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -152,6 +204,7 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; struct drm_radeon_gem_object *obj_priv; int ret; + /* for now if someone requests domain CPU - just make sure the buffer is finished with */ /* just do a BO wait for now */ @@ -161,9 +214,7 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, obj_priv = obj->driver_private; - mutex_lock(&obj_priv->bo->mutex); - ret = drm_bo_wait(obj_priv->bo, 0, 1, 0, 0); - mutex_unlock(&obj_priv->bo->mutex); + ret = radeon_gem_set_domain(obj, args->read_domains, args->write_domain, NULL, true); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); @@ -180,7 +231,41 @@ int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - return -ENOSYS; + struct drm_radeon_gem_pwrite *args = data; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + int ret; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + obj_priv = obj->driver_private; + + /* check where the buffer is first - if not in VRAM + fallback to userspace copying for now */ + mutex_lock(&obj_priv->bo->mutex); + if (obj_priv->bo->mem.mem_type != DRM_BO_MEM_VRAM) { + ret = -EINVAL; + goto out_unlock; + } + + DRM_ERROR("pwriting data->size %lld %llx\n", args->size, args->offset); + ret = -EINVAL; + +#if 0 + /* so need to grab an IB, copy the data into it in a loop + and send them to VRAM using HDB */ + while ((buf = radeon_host_data_blit(dev, cpp, w, dst_pitch_off, &buf_pitch, + x, &y, (unsigned int*)&h, &hpass)) != 0) { + radeon_host_data_blit_copy_pass(dev, cpp, buf, (uint8_t *)src, + hpass, buf_pitch, src_pitch); + src += hpass * src_pitch; + } +#endif +out_unlock: + mutex_unlock(&obj_priv->bo->mutex); + return ret; } int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, @@ -215,7 +300,7 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, obj_priv->bo->map_list.hash.key); up_write(¤t->mm->mmap_sem); - DRM_DEBUG("got here %p\n", obj); + DRM_DEBUG("got here %p %d\n", obj, obj_priv->bo->mem.mem_type); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); @@ -246,8 +331,8 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, /* validate into a pin with no fence */ if (!(obj_priv->bo->type != drm_bo_type_kernel && !DRM_SUSER(DRM_CURPROC))) { - ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, 0); + ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0); } else ret = 0; @@ -342,18 +427,6 @@ int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, + obj_priv->bo->offset + start); int dwords = (end - start + 3) / sizeof(u32); -#if 0 - /* Indirect buffer data must be an even number of - * dwords, so if we've been given an odd number we must - * pad the data with a Type-2 CP packet. - */ - if (dwords & 1) { - u32 *data = (u32 *) - ((char *)dev->agp_buffer_map->handle - + buf->offset + start); - data[dwords++] = RADEON_CP_PACKET2; - } -#endif /* Fire off the indirect buffer */ BEGIN_RING(3); @@ -487,6 +560,7 @@ static int radeon_gart_init(struct drm_device *dev) /* setup a 32MB GART */ dev_priv->gart_size = dev_priv->mm.gart_size; + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; #if __OS_HAS_AGP @@ -706,6 +780,9 @@ int radeon_gem_mm_init(struct drm_device *dev) int ret; u32 pg_offset; + /* init TTM underneath */ + drm_bo_driver_init(dev); + /* size the mappable VRAM memory for now */ radeon_vram_setup(dev); @@ -747,8 +824,7 @@ void radeon_gem_mm_fini(struct drm_device *dev) radeon_gem_ib_destroy(dev); mutex_lock(&dev->struct_mutex); - - + if (dev_priv->mm.ring_read.bo) { drm_bo_kunmap(&dev_priv->mm.ring_read.kmap); drm_bo_usage_deref_locked(&dev_priv->mm.ring_read.bo); @@ -771,13 +847,13 @@ void radeon_gem_mm_fini(struct drm_device *dev) } if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { - DRM_DEBUG("delaying takedown of TTM memory\n"); + DRM_DEBUG("delaying takedown of VRAM memory\n"); } mutex_unlock(&dev->struct_mutex); drm_bo_driver_finish(dev); - dev_priv->mm_enabled = false; + dev_priv->mm_enabled = false; } int radeon_gem_object_pin(struct drm_gem_object *obj, @@ -899,7 +975,8 @@ static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_pri { drm_radeon_private_t *dev_priv = dev->dev_private; /* relocate the handle */ - int domains = reloc[2]; + uint32_t read_domains = reloc[2]; + uint32_t write_domain = reloc[3]; struct drm_gem_object *obj; int flags = 0; int ret; @@ -910,19 +987,11 @@ static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_pri return false; obj_priv = obj->driver_private; - if (domains == RADEON_GEM_DOMAIN_VRAM) { - flags = DRM_BO_FLAG_MEM_VRAM; - } else { - flags = DRM_BO_FLAG_MEM_TT; - } - - ret = drm_bo_do_validate(obj_priv->bo, flags, DRM_BO_MASK_MEM, 0, 0); - if (ret) - return ret; + radeon_gem_set_domain(obj, read_domains, write_domain, &flags, false); if (flags == DRM_BO_FLAG_MEM_VRAM) *offset = obj_priv->bo->offset + dev_priv->fb_location; - else + else if (flags == DRM_BO_FLAG_MEM_TT) *offset = obj_priv->bo->offset + dev_priv->gart_vm_start; /* BAD BAD BAD - LINKED LIST THE OBJS and UNREF ONCE IB is SUBMITTED */ diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index 8bb5d87c..bb81bef0 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -784,12 +784,9 @@ typedef struct drm_radeon_surface_free { #define DRM_RADEON_VBLANK_CRTC1 1 #define DRM_RADEON_VBLANK_CRTC2 2 -#define RADEON_GEM_DOMAIN_CPU 0x1 -#define RADEON_GEM_DOMAIN_VRAM 0x2 -#define RADEON_GEM_DOMAIN_2D 0x4 -#define RADEON_GEM_DOMAIN_3D 0x8 -#define RADEON_GEM_DOMAIN_TEXTURE 0x10 -#define RADEON_GEM_DOMAIN_GPU 0x20 // for vertex buffers +#define RADEON_GEM_DOMAIN_CPU 0x1 // Cached CPU domain +#define RADEON_GEM_DOMAIN_GTT 0x2 // GTT or cache flushed +#define RADEON_GEM_DOMAIN_VRAM 0x4 // VRAM domain /* return to userspace start/size of gtt and vram apertures */ struct drm_radeon_gem_info { -- cgit v1.2.3 From c72a4e20e8bb5cb0ec89eaf6effa0cea9c880a03 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 26 Aug 2008 17:42:36 +1000 Subject: drm/ttm: export drm_bo_add_ttm --- linux-core/drm_bo.c | 3 ++- linux-core/drm_objects.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index ec63fa2a..e3ee497a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -132,7 +132,7 @@ static void drm_bo_vm_post_move(struct drm_buffer_object *bo) * Call bo->mutex locked. */ -static int drm_bo_add_ttm(struct drm_buffer_object *bo) +int drm_bo_add_ttm(struct drm_buffer_object *bo) { struct drm_device *dev = bo->dev; int ret = 0; @@ -174,6 +174,7 @@ static int drm_bo_add_ttm(struct drm_buffer_object *bo) return ret; } +EXPORT_SYMBOL(drm_bo_add_ttm); static int drm_bo_handle_move_mem(struct drm_buffer_object *bo, struct drm_bo_mem_reg *mem, diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 3eb8b902..2493a804 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -801,6 +801,7 @@ extern void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo); * drm_bo_move.c */ +extern int drm_bo_add_ttm(struct drm_buffer_object *bo); extern int drm_bo_move_ttm(struct drm_buffer_object *bo, int evict, int no_wait, struct drm_bo_mem_reg *new_mem); -- cgit v1.2.3 From 203243eea5c6c91e89534cd01a1e52cc44980bfe Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 26 Aug 2008 17:43:12 +1000 Subject: drm: add move zero function to memset unclean buffers --- linux-core/drm_bo_move.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_objects.h | 2 ++ 2 files changed, 73 insertions(+) diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index e81967fd..207a5e07 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -272,6 +272,77 @@ out: } EXPORT_SYMBOL(drm_bo_move_memcpy); +static int drm_memset_io_page(void *dst, unsigned long page) +{ + dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); + memset_io(dst, 0, PAGE_SIZE); + return 0; +} + +static int drm_memset_ttm_page(struct drm_ttm *ttm, unsigned long page) +{ + struct page *d = drm_ttm_get_page(ttm, page); + void *dst; + + dst = kmap(d); + if (!dst) + return -ENOMEM; + + memset_io(dst, 0, PAGE_SIZE); + kunmap(d); + return 0; +} + +int drm_bo_move_zero(struct drm_buffer_object *bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem) +{ + struct drm_device *dev = bo->dev; + struct drm_mem_type_manager *man = &dev->bm.man[new_mem->mem_type]; + struct drm_ttm *ttm = bo->ttm; + void *new_iomap; + int ret; + struct drm_bo_mem_reg *old_mem = &bo->mem; + uint64_t save_flags = old_mem->flags; + uint64_t save_proposed_flags = old_mem->proposed_flags; + unsigned long i; + unsigned long page; + + ret = drm_mem_reg_ioremap(dev, new_mem, &new_iomap); + if (ret) + goto out; + + if (new_iomap == NULL && ttm == NULL) + goto out2; + + for (i = 0; i < new_mem->num_pages; ++i) { + if (new_iomap == NULL) + ret = drm_memset_ttm_page(ttm, i); + else + ret = drm_memset_io_page(new_iomap, i); + if (ret) + goto out1; + } + mb(); +out2: + drm_bo_free_old_node(bo); + + *old_mem = *new_mem; + new_mem->mm_node = NULL; + old_mem->proposed_flags = save_proposed_flags; + DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE); + + if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (ttm != NULL)) { + drm_ttm_unbind(ttm); + drm_ttm_destroy(ttm); + bo->ttm = NULL; + } +out1: + drm_mem_reg_iounmap(dev, new_mem, new_iomap); +out: + return ret; +} +EXPORT_SYMBOL(drm_bo_move_zero); + /* * Transfer a buffer object's memory and LRU status to a newly * created object. User-space references remains with the old diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 2493a804..e13475a2 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -808,6 +808,8 @@ extern int drm_bo_move_ttm(struct drm_buffer_object *bo, extern int drm_bo_move_memcpy(struct drm_buffer_object *bo, int evict, int no_wait, struct drm_bo_mem_reg *new_mem); +extern int drm_bo_move_zero(struct drm_buffer_object *bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem); extern int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo, int evict, int no_wait, uint32_t fence_class, uint32_t fence_type, -- cgit v1.2.3 From 01b2e7368a1f6f14b6d7b6377c804d482bb050cb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 26 Aug 2008 17:44:47 +1000 Subject: radeon/ttm: add support for zeroing the contents of VRAM buffers This uses a solid fill fastpath, falling back to the slow memset path. --- linux-core/radeon_buffer.c | 277 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 224 insertions(+), 53 deletions(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 900d450a..96a584f3 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -37,7 +37,7 @@ struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; - if(dev_priv->flags & RADEON_IS_AGP) + if (dev_priv->flags & RADEON_IS_AGP) return drm_agp_init_ttm(dev); else return ati_pcigart_init_ttm(dev, &dev_priv->gart_info, radeon_gart_flush); @@ -58,9 +58,10 @@ int radeon_invalidate_caches(struct drm_device * dev, uint64_t flags) if (!dev_priv->cp_running) return 0; - BEGIN_RING(4); - RADEON_FLUSH_CACHE(); - RADEON_FLUSH_ZCACHE(); + BEGIN_RING(6); + RADEON_PURGE_CACHE(); + RADEON_PURGE_ZCACHE(); + RADEON_WAIT_UNTIL_3D_IDLE(); ADVANCE_RING(); COMMIT_RING(); return 0; @@ -112,15 +113,17 @@ int radeon_init_mem_type(struct drm_device * dev, uint32_t type, return 0; } -static void radeon_emit_copy_blit(struct drm_device * dev, - uint32_t src_offset, - uint32_t dst_offset, - uint32_t pages, int direction) +void radeon_emit_copy_blit(struct drm_device * dev, + uint32_t src_offset, + uint32_t dst_offset, + uint32_t pages) { uint32_t cur_pages; - uint32_t stride = PAGE_SIZE; + uint32_t stride_bytes = PAGE_SIZE; drm_radeon_private_t *dev_priv = dev->dev_private; - uint32_t format, height; + uint32_t format, pitch; + const uint32_t clip = (0x1fff) | (0x1fff << 16); + uint32_t stride_pixels; RING_LOCALS; if (!dev_priv) @@ -130,67 +133,171 @@ static void radeon_emit_copy_blit(struct drm_device * dev, format = RADEON_COLOR_FORMAT_ARGB8888; /* radeon limited to 16k stride */ - stride &= 0x3fff; + stride_bytes &= 0x3fff; + /* radeon pitch is /64 */ + pitch = stride_bytes / 64; + + stride_pixels = stride_bytes / 4; + while(pages > 0) { cur_pages = pages; - if (cur_pages > 2048) - cur_pages = 2048; + if (cur_pages > 8191) + cur_pages = 8191; pages -= cur_pages; - /* needs verification */ - BEGIN_RING(7); - OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); + /* pages are in Y direction - height + page width in X direction - width */ + BEGIN_RING(10); + OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 8)); OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_SRC_CLIPPING | RADEON_GMC_DST_CLIPPING | RADEON_GMC_BRUSH_NONE | (format << 8) | RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_S | RADEON_DP_SRC_SOURCE_MEMORY | RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); - if (direction) { - OUT_RING((stride << 22) | (src_offset >> 10)); - OUT_RING((stride << 22) | (dst_offset >> 10)); - } else { - OUT_RING((stride << 22) | (dst_offset >> 10)); - OUT_RING((stride << 22) | (src_offset >> 10)); - } - OUT_RING(0); + OUT_RING((pitch << 22) | (src_offset >> 10)); + OUT_RING((pitch << 22) | (dst_offset >> 10)); + OUT_RING(clip); // SRC _SC BOT_RITE + OUT_RING(0); // SC_TOP_LEFT + OUT_RING(clip); // SC_BOT_RITE + + OUT_RING(pages); OUT_RING(pages); /* x - y */ - OUT_RING((stride << 16) | cur_pages); + OUT_RING(cur_pages | (stride_pixels << 16)); ADVANCE_RING(); } - BEGIN_RING(2); + BEGIN_RING(4); + OUT_RING(CP_PACKET0(RADEON_RB2D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(RADEON_RB2D_DC_FLUSH_ALL); RADEON_WAIT_UNTIL_2D_IDLE(); ADVANCE_RING(); + COMMIT_RING(); return; } -static int radeon_move_blit(struct drm_buffer_object * bo, - int evict, int no_wait, struct drm_bo_mem_reg *new_mem) +int radeon_move_blit(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem, + struct drm_bo_mem_reg *old_mem) { - struct drm_bo_mem_reg *old_mem = &bo->mem; - int dir = 0; + struct drm_device *dev = bo->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t old_start, new_start; - if ((old_mem->mem_type == new_mem->mem_type) && - (new_mem->mm_node->start < - old_mem->mm_node->start + old_mem->mm_node->size)) { - dir = 1; - } + old_start = old_mem->mm_node->start << PAGE_SHIFT; + new_start = new_mem->mm_node->start << PAGE_SHIFT; + + if (old_mem->mem_type == DRM_BO_MEM_VRAM) + old_start += dev_priv->fb_location; + if (old_mem->mem_type == DRM_BO_MEM_TT) + old_start += dev_priv->gart_vm_start; + + if (new_mem->mem_type == DRM_BO_MEM_VRAM) + new_start += dev_priv->fb_location; + if (new_mem->mem_type == DRM_BO_MEM_TT) + new_start += dev_priv->gart_vm_start; radeon_emit_copy_blit(bo->dev, - old_mem->mm_node->start << PAGE_SHIFT, - new_mem->mm_node->start << PAGE_SHIFT, - new_mem->num_pages, dir); + old_start, + new_start, + new_mem->num_pages); + + /* invalidate the chip caches */ - return drm_bo_move_accel_cleanup(bo, evict, no_wait, 0, DRM_FENCE_TYPE_EXE, 0, new_mem); } +void radeon_emit_solid_fill(struct drm_device * dev, + uint32_t dst_offset, + uint32_t pages, uint8_t value) +{ + uint32_t cur_pages; + uint32_t stride_bytes = PAGE_SIZE; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t format, pitch; + const uint32_t clip = (0x1fff) | (0x1fff << 16); + uint32_t stride_pixels; + RING_LOCALS; + + if (!dev_priv) + return; + + /* 32-bit copy format */ + format = RADEON_COLOR_FORMAT_ARGB8888; + + /* radeon limited to 16k stride */ + stride_bytes &= 0x3fff; + /* radeon pitch is /64 */ + pitch = stride_bytes / 64; + + stride_pixels = stride_bytes / 4; + + while(pages > 0) { + cur_pages = pages; + if (cur_pages > 8191) + cur_pages = 8191; + pages -= cur_pages; + + /* pages are in Y direction - height + page width in X direction - width */ + BEGIN_RING(8); + OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 6)); + OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_DST_CLIPPING | + RADEON_GMC_BRUSH_SOLID_COLOR | + (format << 8) | + RADEON_ROP3_S | + RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); + OUT_RING((pitch << 22) | (dst_offset >> 10)); // PITCH + OUT_RING(0); // SC_TOP_LEFT // DST CLIPPING + OUT_RING(clip); // SC_BOT_RITE + + OUT_RING(0); // COLOR + + OUT_RING(pages); /* x - y */ + OUT_RING(cur_pages | (stride_pixels << 16)); + ADVANCE_RING(); + } + + BEGIN_RING(4); + OUT_RING(CP_PACKET0(RADEON_RB2D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(RADEON_RB2D_DC_FLUSH_ALL); + RADEON_WAIT_UNTIL_2D_IDLE(); + ADVANCE_RING(); + + COMMIT_RING(); + return; +} + +int radeon_move_zero_fill(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem) +{ + struct drm_device *dev = bo->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t new_start; + + new_start = new_mem->mm_node->start << PAGE_SHIFT; + + if (new_mem->mem_type == DRM_BO_MEM_VRAM) + new_start += dev_priv->fb_location; + + radeon_emit_solid_fill(bo->dev, + new_start, + new_mem->num_pages, 0); + + /* invalidate the chip caches */ + + return drm_bo_move_accel_cleanup(bo, 1, no_wait, 0, + DRM_FENCE_TYPE_EXE, 0, + new_mem); +} + static int radeon_move_flip(struct drm_buffer_object * bo, int evict, int no_wait, struct drm_bo_mem_reg * new_mem) { @@ -200,8 +307,7 @@ static int radeon_move_flip(struct drm_buffer_object * bo, tmp_mem = *new_mem; tmp_mem.mm_node = NULL; - // tmp_mem.mask = DRM_BO_FLAG_MEM_TT | - // DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING; + tmp_mem.proposed_flags = DRM_BO_FLAG_MEM_TT; ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); if (ret) @@ -211,7 +317,7 @@ static int radeon_move_flip(struct drm_buffer_object * bo, if (ret) goto out_cleanup; - ret = radeon_move_blit(bo, 1, no_wait, &tmp_mem); + ret = radeon_move_blit(bo, 1, no_wait, &tmp_mem, &bo->mem); if (ret) goto out_cleanup; @@ -227,25 +333,90 @@ out_cleanup: return ret; } +static int radeon_move_vram(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg * new_mem) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg tmp_mem; + struct drm_bo_mem_reg *old_mem = &bo->mem; + int ret; + bool was_local = false; + + /* old - LOCAL memory node bo->mem + tmp - TT type memory node + new - VRAM memory node */ + + tmp_mem = *old_mem; + tmp_mem.mm_node = NULL; + + if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { + tmp_mem.proposed_flags = DRM_BO_FLAG_MEM_TT; + + ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); + if (ret) + return ret; + } + + if (!bo->ttm) { + ret = drm_bo_add_ttm(bo); + if (ret) + goto out_cleanup; + } + + if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { + ret = drm_bo_move_ttm(bo, evict, no_wait, &tmp_mem); + if (ret) + return ret; + } + + ret = radeon_move_blit(bo, 1, no_wait, new_mem, &bo->mem); + if (ret) + goto out_cleanup; + +out_cleanup: + if (tmp_mem.mm_node) { + mutex_lock(&dev->struct_mutex); + if (tmp_mem.mm_node != bo->pinned_node) + drm_mm_put_block(tmp_mem.mm_node); + tmp_mem.mm_node = NULL; + mutex_unlock(&dev->struct_mutex); + } + return ret; +} + int radeon_move(struct drm_buffer_object * bo, - int evict, int no_wait, struct drm_bo_mem_reg * new_mem) + int evict, int no_wait, struct drm_bo_mem_reg *new_mem) { + struct drm_device *dev = bo->dev; struct drm_bo_mem_reg *old_mem = &bo->mem; + drm_radeon_private_t *dev_priv = dev->dev_private; - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); -#if 0 - DRM_DEBUG("\n"); - if (old_mem->mem_type == DRM_BO_MEM_LOCAL) { - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); - } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + if (!dev_priv->cp_running) + goto fallback; + + if (bo->mem.flags & DRM_BO_FLAG_CLEAN) /* need to implement solid fill */ + { + if (radeon_move_zero_fill(bo, evict, no_wait, new_mem)) + return drm_bo_move_zero(bo, evict, no_wait, new_mem); + return 0; + } + + if (new_mem->mem_type == DRM_BO_MEM_VRAM) { + if (radeon_move_vram(bo, evict, no_wait, new_mem)) + goto fallback; + } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL){ if (radeon_move_flip(bo, evict, no_wait, new_mem)) - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + goto fallback; } else { - if (radeon_move_blit(bo, evict, no_wait, new_mem)) - return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); + if (radeon_move_flip(bo, evict, no_wait, new_mem)) + goto fallback; } return 0; -#endif +fallback: + if (bo->mem.flags & DRM_BO_FLAG_CLEAN) + return drm_bo_move_zero(bo, evict, no_wait, new_mem); + else + return drm_bo_move_memcpy(bo, evict, no_wait, new_mem); } -- cgit v1.2.3 From a4167e7b572859a998710ee599298e5131f51620 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 27 Aug 2008 11:12:19 +1000 Subject: radeon: avoid oops on encoders with no crtc set --- linux-core/radeon_encoders.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index ec36e43d..f662872d 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -863,11 +863,18 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_crtc *radeon_crtc = NULL; + int crtc_id = 0; int atom_type = -1; int index = -1; uint32_t bios_2_scratch, bios_3_scratch; + if (radeon_crtc) { + radeon_crtc = to_radeon_crtc(encoder->crtc); + crtc_id = radeon_crtc->crtc_id; + } else if (mode == DRM_MODE_DPMS_ON) + return; + if (radeon_encoder->atom_device & ATOM_DEVICE_DFP1_SUPPORT) atom_type = ATOM_DEVICE_DFP1_INDEX; if (radeon_encoder->atom_device & ATOM_DEVICE_DFP2_SUPPORT) @@ -890,7 +897,7 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) case ATOM_DEVICE_DFP1_INDEX: index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); bios_2_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE; - bios_3_scratch |= (radeon_crtc->crtc_id << 19); + bios_3_scratch |= (crtc_id << 19); switch(mode) { case DRM_MODE_DPMS_ON: bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE; @@ -907,7 +914,7 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) case ATOM_DEVICE_DFP2_INDEX: index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); bios_2_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE; - bios_3_scratch |= (radeon_crtc->crtc_id << 23); + bios_3_scratch |= (crtc_id << 23); switch(mode) { case DRM_MODE_DPMS_ON: bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE; @@ -924,7 +931,7 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) case ATOM_DEVICE_DFP3_INDEX: index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); bios_2_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE; - bios_3_scratch |= (radeon_crtc->crtc_id << 25); + bios_3_scratch |= (crtc_id << 25); switch(mode) { case DRM_MODE_DPMS_ON: bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE; -- cgit v1.2.3 From f9d4c58d4327741abd99cdfdbbbfb82c803e4698 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 27 Aug 2008 12:35:11 +1000 Subject: radeon: braino pointed out on mailing list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit thanks to Ville Syrjälä --- linux-core/radeon_encoders.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index f662872d..787102e7 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -869,7 +869,7 @@ static void radeon_atom_tmds_dpms(struct drm_encoder *encoder, int mode) int index = -1; uint32_t bios_2_scratch, bios_3_scratch; - if (radeon_crtc) { + if (encoder->crtc) { radeon_crtc = to_radeon_crtc(encoder->crtc); crtc_id = radeon_crtc->crtc_id; } else if (mode == DRM_MODE_DPMS_ON) -- cgit v1.2.3 From 7552b2a6c3b29da308a76dade4959180d0d1c57b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 27 Aug 2008 13:41:53 +1000 Subject: drm: fix some whitespace --- shared-core/drm.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index b177dfe5..6f93618a 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -887,11 +887,11 @@ struct drm_mode_get_blob { }; struct drm_mode_fb_cmd { - unsigned int buffer_id; - unsigned int width, height; - unsigned int pitch; - unsigned int bpp; - unsigned int handle; + unsigned int buffer_id; + unsigned int width, height; + unsigned int pitch; + unsigned int bpp; + unsigned int handle; unsigned int depth; }; -- cgit v1.2.3 From 6a27e019bc16ce901d6be6c85e63c0bad75dd16a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Aug 2008 11:30:20 +1000 Subject: radeon: fixup checks for crtc in dpms paths --- linux-core/radeon_encoders.c | 26 +++++++++++++----- linux-core/radeon_legacy_encoders.c | 55 +++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 787102e7..a889953e 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -273,9 +273,15 @@ static void radeon_lvtma_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_crtc *radeon_crtc; int index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); uint32_t bios_2_scratch, bios_3_scratch; + int crtc_id = 0; + + if (encoder->crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + crtc_id = radeon_crtc->crtc_id; + } if (dev_priv->chip_family >= CHIP_R600) { bios_2_scratch = RADEON_READ(R600_BIOS_2_SCRATCH); @@ -286,7 +292,7 @@ static void radeon_lvtma_dpms(struct drm_encoder *encoder, int mode) } bios_2_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE; - bios_3_scratch |= (radeon_crtc->crtc_id << 17); + bios_3_scratch |= (crtc_id << 17); switch(mode) { case DRM_MODE_DPMS_ON: @@ -393,10 +399,16 @@ static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_crtc *radeon_crtc; int atom_type = -1; int index; uint32_t bios_2_scratch, bios_3_scratch; + int crtc_id = 0; + + if (encoder->crtc) { + radeon_crtc = to_radeon_crtc(encoder->crtc); + crtc_id = radeon_crtc->crtc_id; + } atom_type = atom_dac_find_atom_type(radeon_encoder, NULL); if (atom_type == -1) @@ -414,7 +426,7 @@ static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) case ATOM_DEVICE_CRT1_INDEX: index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); bios_2_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE; - bios_3_scratch |= (radeon_crtc->crtc_id << 16); + bios_3_scratch |= (crtc_id << 16); switch(mode) { case DRM_MODE_DPMS_ON: bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE; @@ -431,7 +443,7 @@ static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) case ATOM_DEVICE_CRT2_INDEX: index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); bios_2_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE; - bios_3_scratch |= (radeon_crtc->crtc_id << 20); + bios_3_scratch |= (crtc_id << 20); switch(mode) { case DRM_MODE_DPMS_ON: bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE; @@ -448,7 +460,7 @@ static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) case ATOM_DEVICE_TV1_INDEX: index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE; - bios_3_scratch |= (radeon_crtc->crtc_id << 18); + bios_3_scratch |= (crtc_id << 18); switch(mode) { case DRM_MODE_DPMS_ON: bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE; @@ -465,7 +477,7 @@ static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) case ATOM_DEVICE_CV_INDEX: index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); bios_2_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE; - bios_3_scratch |= (radeon_crtc->crtc_id << 24); + bios_3_scratch |= (crtc_id << 24); switch(mode) { case DRM_MODE_DPMS_ON: bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE; diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 5b0047e4..3fae0076 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -197,18 +197,23 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_crtc *radeon_crtc; uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; uint32_t bios_5_scratch, bios_6_scratch; - + int crtc_id = 0; DRM_DEBUG("\n"); + if (encoder->crtc) { + radeon_crtc = to_radeon_crtc(encoder->crtc); + crtc_id = radeon_crtc->crtc_id; + } + // FIXME atom/legacy cards like r4xx bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); bios_5_scratch &= ~RADEON_LCD1_CRTC_MASK; - bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_LCD1_CRTC_SHIFT); + bios_5_scratch |= (crtc_id << RADEON_LCD1_CRTC_SHIFT); switch (mode) { case DRM_MODE_DPMS_ON: @@ -396,20 +401,26 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_crtc *radeon_crtc; uint32_t crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); uint32_t dac_cntl = RADEON_READ(RADEON_DAC_CNTL); uint32_t dac_macro_cntl = RADEON_READ(RADEON_DAC_MACRO_CNTL); uint32_t bios_5_scratch, bios_6_scratch; + int crtc_id = 0; DRM_DEBUG("\n"); + if (encoder->crtc) { + radeon_crtc = to_radeon_crtc(encoder->crtc); + crtc_id = radeon_crtc->crtc_id; + } + // FIXME atom/legacy cards like r4xx bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); bios_5_scratch &= ~RADEON_CRT1_CRTC_MASK; - bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_CRT1_CRTC_SHIFT); + bios_5_scratch |= (crtc_id << RADEON_CRT1_CRTC_SHIFT); DRM_DEBUG("\n"); @@ -629,18 +640,23 @@ static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_crtc *radeon_crtc; uint32_t fp_gen_cntl = RADEON_READ(RADEON_FP_GEN_CNTL); uint32_t bios_5_scratch, bios_6_scratch; - + int crtc_id = 0; DRM_DEBUG("\n"); + if (encoder->crtc) { + radeon_crtc = to_radeon_crtc(encoder->crtc); + crtc_id = radeon_crtc->crtc_id; + } + // FIXME atom/legacy cards like r4xx bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); bios_5_scratch &= ~RADEON_DFP1_CRTC_MASK; - bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_DFP1_CRTC_SHIFT); + bios_5_scratch |= (crtc_id << RADEON_DFP1_CRTC_SHIFT); switch(mode) { case DRM_MODE_DPMS_ON: @@ -813,18 +829,23 @@ static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_crtc *radeon_crtc; uint32_t fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); uint32_t bios_5_scratch, bios_6_scratch; - + int crtc_id = 0; DRM_DEBUG("\n"); + if (encoder->crtc) { + radeon_crtc = to_radeon_crtc(encoder->crtc); + crtc_id = radeon_crtc->crtc_id; + } + // FIXME atom/legacy cards like r4xx bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); bios_5_scratch &= ~RADEON_DFP2_CRTC_MASK; - bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_DFP2_CRTC_SHIFT); + bios_5_scratch |= (crtc_id << RADEON_DFP2_CRTC_SHIFT); switch(mode) { case DRM_MODE_DPMS_ON: @@ -969,22 +990,28 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_crtc *radeon_crtc; uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; //uint32_t tv_master_cntl = 0; uint32_t bios_5_scratch, bios_6_scratch; + int crtc_id = 0; DRM_DEBUG("\n"); + if (encoder->crtc) { + radeon_crtc = to_radeon_crtc(encoder->crtc); + crtc_id = radeon_crtc->crtc_id; + } + // FIXME atom/legacy cards like r4xx bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); bios_5_scratch &= ~RADEON_CRT2_CRTC_MASK; - bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_CRT2_CRTC_SHIFT); + bios_5_scratch |= (crtc_id << RADEON_CRT2_CRTC_SHIFT); // FIXME TV //bios_5_scratch &= ~RADEON_TV1_CRTC_MASK; - //bios_5_scratch |= (radeon_crtc->crtc_id << RADEON_TV1_CRTC_SHIFT); + //bios_5_scratch |= (crtc_id << RADEON_TV1_CRTC_SHIFT); if (dev_priv->chip_family == CHIP_R200) fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); -- cgit v1.2.3 From 9afe872ae9ef608269688e08f62beca2181f60dc Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Aug 2008 11:30:55 +1000 Subject: radeon: limit LVDS to first CRTC for now --- linux-core/radeon_encoders.c | 3 ++- linux-core/radeon_legacy_encoders.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index a889953e..897be82a 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -376,7 +376,8 @@ struct drm_encoder *radeon_encoder_lvtma_add(struct drm_device *dev, int bios_in encoder = &radeon_encoder->base; - encoder->possible_crtcs = 0x3; + /* Set LVTMA to only use crtc 0 */ + encoder->possible_crtcs = 0x1; encoder->possible_clones = 0; drm_encoder_init(dev, encoder, &radeon_atom_lvtma_enc_funcs, DRM_MODE_ENCODER_LVDS); diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 3fae0076..ba2036f7 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -374,7 +374,8 @@ struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int b encoder = &radeon_encoder->base; - encoder->possible_crtcs = 0x3; + /* Limit LVDS to crtc 0 for RMX */ + encoder->possible_crtcs = 0x1; encoder->possible_clones = 0; drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); -- cgit v1.2.3 From 23cb67dfbabe8c76ffd86b6c01abacc027d0fb72 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Aug 2008 16:18:09 +1000 Subject: drm: port X crtc picking algorithm. This mimics the X.org from ajax with less options --- linux-core/drm_crtc.h | 2 + linux-core/drm_crtc_helper.c | 294 ++++++++++++++++++++++++++----------------- 2 files changed, 184 insertions(+), 112 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 3a3a09aa..5f63dc2e 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -604,6 +604,8 @@ extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_set_name(struct drm_display_mode *mode); extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); +extern int drm_mode_width(struct drm_display_mode *mode); +extern int drm_mode_height(struct drm_display_mode *mode); /* for us by fb module */ extern int drm_mode_attachmode_crtc(struct drm_device *dev, diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index dc18dbb4..89d87a6c 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -196,139 +196,209 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) } EXPORT_SYMBOL(drm_helper_disable_unused_functions); -/** - * drm_pick_crtcs - pick crtcs for connector devices - * @dev: DRM device - * - * LOCKING: - * Caller must hold mode config lock. - */ -void drm_pick_crtcs (struct drm_device *dev) +static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height) { - int c, o, assigned; - struct drm_connector *connector, *connector_equal; - struct drm_encoder *encoder, *encoder_equal; - struct drm_crtc *crtc; - struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; - struct drm_connector_helper_funcs *connector_funcs; - int found; + struct drm_display_mode *mode; - DRM_DEBUG("\n"); - /* clean out all the encoder/crtc combos */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - encoder->crtc = NULL; + list_for_each_entry(mode, &connector->modes, head) { + if (drm_mode_width(mode) > width || + drm_mode_height(mode) > height) + continue; + if (mode->type & DRM_MODE_TYPE_PREFERRED) + return mode; + } + return NULL; +} + +static bool drm_connector_enabled(struct drm_connector *connector, bool strict) +{ + bool enable; + + if (strict) { + enable = connector->status == connector_status_connected; + } else { + enable = connector->status != connector_status_disconnected; + } + return enable; +} + +static void drm_enable_connectors(struct drm_device *dev, bool *enabled) +{ + bool any_enabled = false; + struct drm_connector *connector; + int i = 0; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + any_enabled |= enabled[i] = drm_connector_enabled(connector, true); + i++; + } + + if (!any_enabled) { + i = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + enabled[i] = drm_connector_enabled(connector, false); + i++; + } } +} + +static bool drm_target_preferred(struct drm_device *dev, struct drm_display_mode **modes, + bool *enabled, int width, int height) +{ + struct drm_connector *connector; + struct drm_display_mode *preferred; + int i = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector_funcs = connector->helper_private; - connector->encoder = NULL; - - /* Don't hook up connectors that are disconnected ?? - * - * This is debateable. Do we want fixed /dev/fbX or - * dynamic on hotplug (need mode code for that though) ? - * - * If we don't hook up connectors now, then we only create - * /dev/fbX for the connector that's enabled, that's good as - * the users console will be on that connector. - * - * If we do hook up connectors that are disconnected now, then - * the user may end up having to muck about with the fbcon - * map flags to assign his console to the enabled connector. Ugh. - */ - if (connector->status != connector_status_connected) - continue; - if (list_empty(&connector->modes)) + if (enabled[i] == false) { + i++; continue; - - des_mode = NULL; - found = 0; - list_for_each_entry(des_mode, &connector->modes, head) { - if (des_mode->type & DRM_MODE_TYPE_PREFERRED) { - found = 1; - break; - } } - /* No preferred mode, let's just select the first available */ - if (!found) { - des_mode = NULL; - list_for_each_entry(des_mode, &connector->modes, head) { + modes[i] = drm_has_preferred_mode(connector, width, height); + if (!modes[i]) { + list_for_each_entry(modes[i], &connector->modes, head) break; - } } + i++; + } + return true; +} - encoder = connector_funcs->best_encoder(connector); - if (!encoder) - continue; +static int drm_pick_crtcs(struct drm_device *dev, + struct drm_crtc **best_crtcs, + struct drm_display_mode **modes, + int n, int width, int height) +{ + int c, o; + struct drm_connector *connector; + struct drm_connector_helper_funcs *connector_funcs; + struct drm_encoder *encoder; + struct drm_crtc *best_crtc; + int my_score, best_score, score; + struct drm_crtc **crtcs, *crtc; + + if (n == dev->mode_config.num_connector) + return 0; + c = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (c == n) + break; + c++; + } - connector->encoder = encoder; + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); + if (modes[n] == NULL) { + return best_score; + } - c = -1; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - assigned = 0; + crtcs = kmalloc(dev->mode_config.num_connector * sizeof(struct drm_crtc *), GFP_KERNEL); + if (!crtcs) + return best_score; + + my_score = 1; + if (connector->status == connector_status_connected) + my_score++; + if (drm_has_preferred_mode(connector, width, height)) + my_score++; + + connector_funcs = connector->helper_private; + encoder = connector_funcs->best_encoder(connector); + if (!encoder) + goto out; + + connector->encoder = encoder; + + /* select a crtc for this connector and then attempt to configure + remaining connectors */ + c = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if ((connector->encoder->possible_crtcs & (1 << c)) == 0) { c++; - if ((encoder->possible_crtcs & (1 << c)) == 0) - continue; - - list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) { - if (encoder->base.id == encoder_equal->base.id) - continue; + continue; + } - /* Find out if crtc has been assigned before */ - if (encoder_equal->crtc == crtc) - assigned = 1; - } + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; -#if 1 /* continue for now */ - if (assigned) - continue; -#endif - - o = -1; - list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { - o++; - if (connector->base.id == connector_equal->base.id) - continue; - - encoder_equal = connector_equal->encoder; - - if (!encoder_equal) - continue; - - list_for_each_entry(modes, &connector->modes, head) { - list_for_each_entry(modes_equal, &connector_equal->modes, head) { - if (drm_mode_equal (modes, modes_equal)) { - if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->encoder->crtc == crtc)) { - printk("Cloning %s (0x%x) to %s (0x%x)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); - des_mode = modes; - assigned = 0; - goto clone; - } - } - } - } - } + if (o < n) { + /* ignore cloning for now */ + c++; + continue; + } -clone: - /* crtc has been assigned skip it */ - if (assigned) - continue; - - /* Found a CRTC to attach to, do it ! */ - encoder->crtc = crtc; - encoder->crtc->desired_mode = des_mode; - connector->initial_x = 0; - connector->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->base.id, des_mode->name); - break; - } + crtcs[n] = crtc; + memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); + score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, width, height); + if (score > best_score) { + best_crtc = crtc; + best_score = score; + memcpy(best_crtcs, crtcs, dev->mode_config.num_connector * sizeof(struct drm_crtc *)); + } + c++; } +out: + kfree(crtcs); + return best_score; } -EXPORT_SYMBOL(drm_pick_crtcs); +static void drm_setup_crtcs(struct drm_device *dev) +{ + struct drm_crtc **crtcs; + struct drm_display_mode **modes; + struct drm_encoder *encoder; + struct drm_connector *connector; + bool *enabled; + int width, height; + int i, ret; + + width = dev->mode_config.max_width; + height = dev->mode_config.max_height; + + /* clean out all the encoder/crtc combos */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder->crtc = NULL; + } + + crtcs = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_crtc *), GFP_KERNEL); + modes = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_display_mode *), GFP_KERNEL); + enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), GFP_KERNEL); + + drm_enable_connectors(dev, enabled); + + ret = drm_target_preferred(dev, modes, enabled, width, height); + if (!ret) + DRM_ERROR("Unable to find initial modes\n"); + + drm_pick_crtcs(dev, crtcs, modes, 0, width, height); + + i = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_display_mode *mode = modes[i]; + struct drm_crtc *crtc = crtcs[i]; + + if (connector->encoder == NULL) { + i++; + continue; + } + + if (mode && crtc) { + crtc->desired_mode = mode; + connector->encoder->crtc = crtc; + } else + connector->encoder->crtc = NULL; + i++; + } + + kfree(crtcs); + kfree(modes); + kfree(enabled); +} /** * drm_crtc_set_mode - set a mode * @crtc: CRTC to program @@ -644,7 +714,7 @@ bool drm_helper_plugged_event(struct drm_device *dev) drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); - drm_pick_crtcs(dev); + drm_setup_crtcs(dev); /* alert the driver fb layer */ dev->mode_config.funcs->fb_changed(dev); -- cgit v1.2.3 From 499170ad22aaf087fc01fdcf799035819becd571 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Aug 2008 16:35:25 +1000 Subject: radeon: get lvds atombios info set the correct values from atombios makes LVDS work a lot better --- linux-core/radeon_atombios.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index ca287bca..10e3a77d 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -332,8 +332,8 @@ void radeon_get_lvds_info(struct radeon_encoder *encoder) encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); encoder->vblank = le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); - encoder->hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); - encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); + encoder->voverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); + encoder->vsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); } -- cgit v1.2.3 From d88d1eac8925f6bbc8edf50b35639f09fac84019 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 29 Aug 2008 07:18:53 +1000 Subject: radeon: fixup LVDS mode getting if we have no DDC we were oopsing. fix that. then make a native panel mode --- linux-core/radeon_connectors.c | 108 ++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 38 deletions(-) diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c index 7b2d7c4d..5ce66d72 100644 --- a/linux-core/radeon_connectors.c +++ b/linux-core/radeon_connectors.c @@ -29,38 +29,89 @@ #include "radeon_drm.h" #include "radeon_drv.h" +struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) +{ + int enc_id = connector->encoder_ids[0]; + struct drm_mode_object *obj; + struct drm_encoder *encoder; + + /* pick the encoder ids */ + if (enc_id) { + obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); + if (!obj) + return NULL; + encoder = obj_to_encoder(obj); + return encoder; + } + return NULL; +} + +static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_display_mode *mode = NULL; + + if (radeon_encoder->panel_xres != 0 && + radeon_encoder->panel_yres != 0 && + radeon_encoder->dotclock != 0) { + mode = drm_mode_create(dev); + + mode->hdisplay = radeon_encoder->panel_xres; + mode->vdisplay = radeon_encoder->panel_yres; + + mode->htotal = mode->hdisplay + radeon_encoder->hblank; + mode->hsync_start = mode->hdisplay + radeon_encoder->hoverplus; + mode->hsync_end = mode->hsync_start + radeon_encoder->hsync_width; + mode->vtotal = mode->vdisplay + radeon_encoder->vblank; + mode->vsync_start = mode->vdisplay + radeon_encoder->voverplus; + mode->vsync_end = mode->vsync_start + radeon_encoder->vsync_width; + mode->clock = radeon_encoder->dotclock; + mode->flags = 0; + + mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; + + DRM_DEBUG("Adding native panel mode %dx%d\n", + radeon_encoder->panel_xres, radeon_encoder->panel_yres); + } + return mode; +} + static int radeon_lvds_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct drm_encoder *lvds_encoder; + struct drm_encoder *encoder; int ret = 0; struct edid *edid; - - radeon_i2c_do_lock(radeon_connector, 1); - edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); - radeon_i2c_do_lock(radeon_connector, 0); - if (edid) { - drm_mode_connector_update_edid_property(&radeon_connector->base, edid); - ret = drm_add_edid_modes(&radeon_connector->base, edid); - kfree(edid); - return ret; + struct drm_display_mode *mode; + + if (radeon_connector->ddc_bus) { + radeon_i2c_do_lock(radeon_connector, 1); + edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + radeon_i2c_do_lock(radeon_connector, 0); + if (edid) { + drm_mode_connector_update_edid_property(&radeon_connector->base, edid); + ret = drm_add_edid_modes(&radeon_connector->base, edid); + kfree(edid); + return ret; + } } -#if 0 - lvds_encoder = radeon_best_single_encoder(connector); - - if (!lvds_encoder) - return ret; - - radeon_encoder_update_panel_size(lvds_encoder, connector); -#endif + encoder = radeon_best_single_encoder(connector); + if (!encoder) + return connector_status_disconnected; + /* we have no EDID modes */ + mode = radeon_fp_native_mode(encoder); + if (mode) { + ret = 1; + drm_mode_probed_add(connector, mode); + } return ret; } static int radeon_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - return MODE_OK; } @@ -70,25 +121,6 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec return connector_status_connected; } - - -struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector) -{ - int enc_id = connector->encoder_ids[0]; - struct drm_mode_object *obj; - struct drm_encoder *encoder; - - /* pick the encoder ids */ - if (enc_id) { - obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER); - if (!obj) - return NULL; - encoder = obj_to_encoder(obj); - return encoder; - } - return NULL; -} - static void radeon_connector_destroy(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); -- cgit v1.2.3 From fe59d04a7c30692952652f77529deb22a3e0c8bb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 4 Sep 2008 11:57:00 +1000 Subject: radeon: fixup a number of avivo checks for rs690 --- linux-core/radeon_display.c | 2 +- linux-core/radeon_gem.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 2877cd3b..d105e1ae 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -194,7 +194,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index) radeon_crtc->lut_b[i] = i; } - if (dev_priv->is_atom_bios && dev_priv->chip_family > CHIP_RS690) + if (dev_priv->is_atom_bios && radeon_is_avivo(dev_priv)) radeon_atombios_init_crtc(dev, radeon_crtc); else radeon_legacy_init_crtc(dev, radeon_crtc); diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index eceb5207..44a0f1d1 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -483,7 +483,7 @@ static uint32_t radeon_get_accessible_vram(struct drm_device *dev) dev_priv->chip_family == CHIP_RV380 || dev_priv->chip_family == CHIP_R420 || dev_priv->chip_family == CHIP_RV410 || - dev_priv->chip_family >= CHIP_RS600) { + radeon_is_avivo(dev_priv)) { uint32_t temp = RADEON_READ(RADEON_HOST_PATH_CNTL); temp |= RADEON_HDP_APER_CNTL; RADEON_WRITE(RADEON_HOST_PATH_CNTL, temp); @@ -515,7 +515,7 @@ void radeon_vram_setup(struct drm_device *dev) uint32_t vram; uint32_t accessible, bar_size; - if ((dev_priv->chip_family <= CHIP_RV515) && (dev_priv->flags & RADEON_IS_IGP)) { + if (!radeon_is_avivo(dev_priv) && (dev_priv->flags & RADEON_IS_IGP)) { uint32_t tom = RADEON_READ(RADEON_NB_TOM); vram = (((tom >> 16) - (tom & 0xffff) + 1) << 6); -- cgit v1.2.3 From 9f9f171f8e0ad817414e6218b44579171d03cec0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Sep 2008 10:56:18 +1000 Subject: radeon: rs690 GART tables need to be in uncached memory. Allocate the rs480/690 tables from uncached memory. --- linux-core/ati_pcigart.c | 11 +++++++++++ linux-core/radeon_gem.c | 11 ++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 9b954291..50e990f1 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -90,6 +90,12 @@ int drm_ati_alloc_pcigart_table(struct drm_device *dev, if (gart_info->table_handle == NULL) return -ENOMEM; +#ifdef CONFIG_X86 + /* IGPs only exist on x86 in any case */ + if (gart_info->gart_reg_if == DRM_ATI_GART_IGP) + set_memory_uc(gart_info->table_handle->vaddr, gart_info->table_size >> PAGE_SHIFT); +#endif + memset(gart_info->table_handle->vaddr, 0, gart_info->table_size); return 0; } @@ -98,6 +104,11 @@ EXPORT_SYMBOL(drm_ati_alloc_pcigart_table); static void drm_ati_free_pcigart_table(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { +#ifdef CONFIG_X86 + /* IGPs only exist on x86 in any case */ + if (gart_info->gart_reg_if == DRM_ATI_GART_IGP) + set_memory_wb(gart_info->table_handle->vaddr, gart_info->table_size >> PAGE_SHIFT); +#endif drm_pci_free(dev, gart_info->table_handle); gart_info->table_handle = NULL; } diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 44a0f1d1..24c806a1 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -613,17 +613,18 @@ static int radeon_gart_init(struct drm_device *dev) } else if (!(dev_priv->flags & RADEON_IS_AGP)) { /* allocate PCI GART table */ dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); + dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; + if (dev_priv->flags & RADEON_IS_IGPGART) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; + ret = drm_ati_alloc_pcigart_table(dev, &dev_priv->gart_info); if (ret) { DRM_ERROR("cannot allocate PCI GART page!\n"); return -EINVAL; } - dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; - if (dev_priv->flags & RADEON_IS_IGPGART) - dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; - else - dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; dev_priv->gart_info.addr = dev_priv->gart_info.table_handle->vaddr; dev_priv->gart_info.bus_addr = dev_priv->gart_info.table_handle->busaddr; } -- cgit v1.2.3 From f60d9a04b892904e5dde7dd1d2876b6bd9eb80ef Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 7 Sep 2008 08:09:24 +1000 Subject: radeon: change interface from headers add pin_domain into padding --- shared-core/radeon_drm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index bb81bef0..c924c689 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -825,7 +825,7 @@ struct drm_radeon_gem_exec_buffer { struct drm_radeon_gem_pin { uint32_t handle; - uint32_t pad; + uint32_t pin_domain; uint64_t alignment; uint64_t offset; }; -- cgit v1.2.3 From e23d5c03c4c9850d5e54f323fe944329b389b042 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Sep 2008 18:16:25 -0400 Subject: radeon: fix legacy LVDS --- linux-core/radeon_combios.c | 4 ++-- linux-core/radeon_legacy_encoders.c | 22 +++++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index 200761ee..a4dd43b9 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -660,14 +660,14 @@ bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder) encoder->use_bios_dividers = true; panel_setup = radeon_bios32(dev_priv, lcd_info + 0x39); - encoder->lvds_gen_cntl = 0; + encoder->lvds_gen_cntl = 0xff00; if (panel_setup & 0x1) encoder->lvds_gen_cntl |= RADEON_LVDS_PANEL_FORMAT; if ((panel_setup >> 4) & 0x1) encoder->lvds_gen_cntl |= RADEON_LVDS_PANEL_TYPE; - switch ((panel_setup >> 8) & 0x8) { + switch ((panel_setup >> 8) & 0x7) { case 0: encoder->lvds_gen_cntl |= RADEON_LVDS_NO_FM; break; diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index ba2036f7..b48da9b8 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -224,6 +224,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) lvds_pll_cntl |= RADEON_LVDS_PLL_EN; RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); udelay(1000); + lvds_pll_cntl = RADEON_READ(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; RADEON_WRITE(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); @@ -231,7 +232,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON); lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); - udelay(radeon_encoder->panel_pwr_delay); + udelay(radeon_encoder->panel_pwr_delay * 1000); RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); /* update bios scratch regs */ @@ -242,13 +243,13 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - pixclks_cntl = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + pixclks_cntl = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); RADEON_WRITE_PLL_P(dev_priv, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); - lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); - lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; - lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); - udelay(radeon_encoder->panel_pwr_delay); - RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + lvds_gen_cntl = RADEON_READ(RADEON_LVDS_GEN_CNTL); + lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; + lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); + udelay(radeon_encoder->panel_pwr_delay * 1000); + RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, pixclks_cntl); bios_5_scratch &= ~RADEON_LCD1_ON; @@ -300,6 +301,8 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, RADEON_LVDS_EN | RADEON_LVDS_RST_FM); + DRM_INFO("bios LVDS_GEN_CNTL: 0x%x\n", radeon_encoder->lvds_gen_cntl); + if (radeon_is_r300(dev_priv)) lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK); @@ -310,9 +313,9 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, } else lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2; } else { - if (radeon_is_r300(dev_priv)) { + if (radeon_is_r300(dev_priv)) lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2; - } else + else lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2; } @@ -326,6 +329,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); lvds_ss_gen_cntl |= ((radeon_encoder->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | (radeon_encoder->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); + RADEON_WRITE(RADEON_LVDS_SS_GEN_CNTL, lvds_ss_gen_cntl); } if (dev_priv->chip_family == CHIP_RV410) -- cgit v1.2.3 From 1062d8dcff19ded743f046e27adb889f3596ab4d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 09:59:08 +1000 Subject: modesetting: Add helper to force restore modes on crtcs at resume time --- linux-core/drm_crtc_helper.c | 18 ++++++++++++++++++ linux-core/drm_crtc_helper.h | 3 +-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 89d87a6c..71bdc447 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -785,4 +785,22 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); +int drm_helper_resume_force_mode(struct drm_device *dev) +{ + struct drm_crtc *crtc; + int ret; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + + if (!crtc->enabled) + continue; + + ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, + crtc->y); + + if (ret == false) + DRM_ERROR("failed to set mode on crtc %p\n", crtc); + } + return 0; +} +EXPORT_SYMBOL(drm_helper_resume_force_mode); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index dcb46f98..c0719157 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -92,6 +92,5 @@ static inline void drm_connector_helper_add(struct drm_connector *connector, con connector->helper_private = (void *)funcs; } -extern int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle); - +extern int drm_helper_resume_force_mode(struct drm_device *dev); #endif -- cgit v1.2.3 From 2a6dad31d84252d505f392f91dffd90689bb947c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:05:59 +1000 Subject: radeon: add initial suspend/resume support plus a bunch of fixes --- linux-core/atom.c | 2 - linux-core/drm_bo.c | 53 +++++++++++++- linux-core/drm_fence.c | 3 - linux-core/drm_objects.h | 1 + linux-core/radeon_drv.c | 22 ------ linux-core/radeon_fb.c | 2 +- linux-core/radeon_fence.c | 3 + linux-core/radeon_gem.c | 59 +++++++++++++-- linux-core/radeon_pm.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_cp.c | 103 +++++++++++++++++--------- shared-core/radeon_drv.h | 21 +++++- 11 files changed, 377 insertions(+), 72 deletions(-) create mode 100644 linux-core/radeon_pm.c diff --git a/linux-core/atom.c b/linux-core/atom.c index 33fb02f0..2a660a4f 100644 --- a/linux-core/atom.c +++ b/linux-core/atom.c @@ -270,7 +270,6 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr, if(print) DEBUG("MC[0x%02X]", idx); val = gctx->card->mc_read(gctx->card, idx); - printk(KERN_INFO "MC registers are not implemented.\n"); return 0; } if(saved) @@ -452,7 +451,6 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr (*ptr)++; DEBUG("MC[0x%02X]", idx); gctx->card->mc_write(gctx->card, idx, val); - printk(KERN_INFO "MC registers are not implemented.\n"); return; } switch(align) { diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e3ee497a..fa3e055d 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -511,6 +511,7 @@ static void drm_bo_delayed_delete(struct drm_device *dev, int remove_all) entry = list_entry(list, struct drm_buffer_object, ddestroy); nentry = NULL; + DRM_DEBUG("bo is %p, %d\n", entry, entry->num_pages); if (next != &bm->ddestroy) { nentry = list_entry(next, struct drm_buffer_object, ddestroy); @@ -1330,14 +1331,15 @@ static int drm_bo_prepare_for_validate(struct drm_buffer_object *bo, int ret; - DRM_DEBUG("Proposed flags 0x%016llx, Old flags 0x%016llx\n", - (unsigned long long) bo->mem.proposed_flags, - (unsigned long long) bo->mem.flags); ret = drm_bo_modify_proposed_flags (bo, flags, mask); if (ret) return ret; + DRM_DEBUG("Proposed flags 0x%016llx, Old flags 0x%016llx\n", + (unsigned long long) bo->mem.proposed_flags, + (unsigned long long) bo->mem.flags); + ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) return ret; @@ -2084,3 +2086,48 @@ static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo) return 0; } + +/* used to EVICT VRAM lru at suspend time */ +void drm_bo_evict_mm(struct drm_device *dev, int mem_type, int no_wait) +{ + struct drm_buffer_manager *bm = &dev->bm; + struct drm_mem_type_manager *man = &bm->man[mem_type]; + struct drm_buffer_object *entry; + /* we need to migrate all objects in VRAM */ + struct list_head *lru; + int ret; + /* evict all buffers on the LRU - won't evict pinned buffers */ + + mutex_lock(&dev->struct_mutex); + do { + lru = &man->lru; + + if (lru->next == lru) { + DRM_ERROR("lru empty\n"); + break; + } + + entry = list_entry(lru->next, struct drm_buffer_object, lru); + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + + DRM_ERROR("Evicting %p %d\n", entry, entry->num_pages); + ret = drm_bo_evict(entry, mem_type, no_wait); + mutex_unlock(&entry->mutex); + + if (ret) + DRM_ERROR("Evict failed for BO\n"); + + mutex_lock(&entry->mutex); + (void)drm_bo_expire_fence(entry, 0); + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_unlocked(&entry); + + mutex_lock(&dev->struct_mutex); + } while(0); + + mutex_unlock(&dev->struct_mutex); + +} +EXPORT_SYMBOL(drm_bo_evict_mm); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 7130d1b0..f1c386c4 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -381,7 +381,6 @@ int drm_fence_object_wait(struct drm_fence_object *fence, if (driver->wait) return driver->wait(fence, lazy, !ignore_signals, mask); - drm_fence_object_flush(fence, mask); if (driver->has_irq(dev, fence->fence_class, mask)) { if (!ignore_signals) @@ -409,8 +408,6 @@ int drm_fence_object_wait(struct drm_fence_object *fence, } EXPORT_SYMBOL(drm_fence_object_wait); - - int drm_fence_object_emit(struct drm_fence_object *fence, uint32_t fence_flags, uint32_t fence_class, uint32_t type) { diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index e13475a2..acb10f96 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -796,6 +796,7 @@ extern struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file *file_ extern int drm_bo_evict_cached(struct drm_buffer_object *bo); extern void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo); +extern void drm_bo_evict_mm(struct drm_device *dev, int mem_type, int no_wait); /* * Buffer object memory move- and map helpers. * drm_bo_move.c diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 7676ca4c..9b3397ca 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -59,28 +59,6 @@ static int dri_library_name(struct drm_device * dev, char * buf) "r300")); } -static int radeon_suspend(struct drm_device *dev, pm_message_t state) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - - /* Disable *all* interrupts */ - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) - RADEON_WRITE(R500_DxMODE_INT_MASK, 0); - RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); - return 0; -} - -static int radeon_resume(struct drm_device *dev) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - - /* Restore interrupt registers */ - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) - RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); - RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); - return 0; -} - static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/linux-core/radeon_fb.c b/linux-core/radeon_fb.c index 5cb118c5..86459674 100644 --- a/linux-core/radeon_fb.c +++ b/linux-core/radeon_fb.c @@ -736,7 +736,7 @@ int radeonfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_heigh } obj_priv = fbo->driver_private; - ret = radeon_gem_object_pin(fbo, PAGE_SIZE); + ret = radeon_gem_object_pin(fbo, PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); mutex_lock(&dev->struct_mutex); diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c index 1b327369..591ad53b 100644 --- a/linux-core/radeon_fence.c +++ b/linux-core/radeon_fence.c @@ -45,6 +45,8 @@ int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, return -EINVAL; radeon_emit_irq(dev); + + DRM_DEBUG("emitting %d\n", dev_priv->counter); *sequence = (uint32_t) dev_priv->counter; *native_type = DRM_FENCE_TYPE_EXE; @@ -60,6 +62,7 @@ static void radeon_fence_poll(struct drm_device *dev, uint32_t fence_class, sequence = READ_BREADCRUMB(dev_priv); + DRM_DEBUG("polling %d\n", sequence); drm_fence_handler(dev, 0, sequence, DRM_FENCE_TYPE_EXE, 0); } diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 24c806a1..98105e7c 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -43,7 +43,6 @@ int radeon_gem_init_object(struct drm_gem_object *obj) obj->driver_private = obj_priv; obj_priv->obj = obj; - return 0; } @@ -320,6 +319,8 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; struct drm_radeon_gem_object *obj_priv; int ret; + int flags = DRM_BO_FLAG_NO_EVICT; + int mask = DRM_BO_FLAG_NO_EVICT; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) @@ -329,15 +330,24 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, DRM_DEBUG("got here %p %p %d\n", obj, obj_priv->bo, atomic_read(&obj_priv->bo->usage)); /* validate into a pin with no fence */ + if (args->pin_domain) { + mask |= DRM_BO_MASK_MEM; + if (args->pin_domain == RADEON_GEM_DOMAIN_GTT) + flags |= DRM_BO_FLAG_MEM_TT; + else if (args->pin_domain == RADEON_GEM_DOMAIN_VRAM) + flags |= DRM_BO_FLAG_MEM_VRAM; + else + return -EINVAL; + } if (!(obj_priv->bo->type != drm_bo_type_kernel && !DRM_SUSER(DRM_CURPROC))) { - ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, + ret = drm_bo_do_validate(obj_priv->bo, flags, mask, DRM_BO_HINT_DONT_FENCE, 0); } else ret = 0; args->offset = obj_priv->bo->offset; - DRM_DEBUG("got here %p %p\n", obj, obj_priv->bo); + DRM_DEBUG("got here %p %p %x\n", obj, obj_priv->bo, obj_priv->bo->offset); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); @@ -361,7 +371,7 @@ int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, /* validate into a pin with no fence */ - ret = drm_bo_do_validate(obj_priv->bo, DRM_BO_FLAG_NO_EVICT, DRM_BO_FLAG_NO_EVICT, + ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, DRM_BO_HINT_DONT_FENCE, 0); mutex_lock(&dev->struct_mutex); @@ -598,7 +608,11 @@ static int radeon_gart_init(struct drm_device *dev) if (ret) return -EINVAL; - DRM_DEBUG("pcie table bo created %p, %x\n", dev_priv->mm.pcie_table.bo, dev_priv->mm.pcie_table.bo->offset); + dev_priv->mm.pcie_table_backup = kzalloc(RADEON_PCIGART_TABLE_SIZE, GFP_KERNEL); + if (!dev_priv->mm.pcie_table_backup) + return -EINVAL; + + DRM_ERROR("pcie table bo created %p, %x\n", dev_priv->mm.pcie_table.bo, dev_priv->mm.pcie_table.bo->offset); ret = drm_bo_kmap(dev_priv->mm.pcie_table.bo, 0, RADEON_PCIGART_TABLE_SIZE >> PAGE_SHIFT, &dev_priv->mm.pcie_table.kmap); if (ret) @@ -690,10 +704,11 @@ int radeon_alloc_gart_objects(struct drm_device *dev) } -static void radeon_init_memory_map(struct drm_device *dev) +void radeon_init_memory_map(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; u32 mem_size, aper_size; + u32 tmp; dev_priv->mc_fb_location = radeon_read_fb_location(dev_priv); radeon_read_agp_location(dev_priv, &dev_priv->mc_agp_loc_lo, &dev_priv->mc_agp_loc_hi); @@ -841,6 +856,10 @@ void radeon_gem_mm_fini(struct drm_device *dev) } if (dev_priv->flags & RADEON_IS_PCIE) { + if (dev_priv->mm.pcie_table_backup) { + kfree(dev_priv->mm.pcie_table_backup); + dev_priv->mm.pcie_table_backup = NULL; + } if (dev_priv->mm.pcie_table.bo) { drm_bo_kunmap(&dev_priv->mm.pcie_table.kmap); drm_bo_usage_deref_locked(&dev_priv->mm.pcie_table.bo); @@ -858,7 +877,31 @@ void radeon_gem_mm_fini(struct drm_device *dev) } int radeon_gem_object_pin(struct drm_gem_object *obj, - uint32_t alignment) + uint32_t alignment, uint32_t pin_domain) +{ + struct drm_radeon_gem_object *obj_priv; + int ret; + uint32_t flags = DRM_BO_FLAG_NO_EVICT; + uint32_t mask = DRM_BO_FLAG_NO_EVICT; + + obj_priv = obj->driver_private; + + if (pin_domain) { + mask |= DRM_BO_MASK_MEM; + if (pin_domain == RADEON_GEM_DOMAIN_GTT) + flags |= DRM_BO_FLAG_MEM_TT; + else if (pin_domain == RADEON_GEM_DOMAIN_VRAM) + flags |= DRM_BO_FLAG_MEM_VRAM; + else + return -EINVAL; + } + ret = drm_bo_do_validate(obj_priv->bo, flags, mask, + DRM_BO_HINT_DONT_FENCE, 0); + + return ret; +} + +int radeon_gem_object_unpin(struct drm_gem_object *obj) { struct drm_radeon_gem_object *obj_priv; int ret; @@ -1335,3 +1378,5 @@ void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master dev_priv->color_fmt = RADEON_COLOR_FORMAT_ARGB8888; } + + diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c new file mode 100644 index 00000000..c7a57b97 --- /dev/null +++ b/linux-core/radeon_pm.c @@ -0,0 +1,180 @@ +/* + * Copyright 2007-8 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, 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: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#include "atom.h" + +#include "drm_crtc_helper.h" + +int radeon_suspend(struct drm_device *dev, pm_message_t state) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb; + int i; + + if (!dev || !dev_priv) { + return -ENODEV; + } + + if (state.event == PM_EVENT_PRETHAW) + return 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + /* unpin the front buffers */ + list_for_each_entry(fb, &dev->mode_config.fb_kernel_list, filp_head) { + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + + if (!radeon_fb) + continue; + + if (!radeon_fb->obj) + continue; + + radeon_gem_object_unpin(radeon_fb->obj); + } + + if (!(dev_priv->flags & RADEON_IS_IGP)) + drm_bo_evict_mm(dev, DRM_BO_MEM_VRAM, 0); + + if (dev_priv->flags & RADEON_IS_PCIE) { + memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, RADEON_PCIGART_TABLE_SIZE); + } + + dev_priv->pmregs.crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); + for (i = 0; i < 8; i++) + dev_priv->pmregs.bios_scratch[i] = RADEON_READ(RADEON_BIOS_0_SCRATCH + (i * 4)); + + radeon_modeset_cp_suspend(dev); + + pci_save_state(dev->pdev); + + if (state.event == PM_EVENT_SUSPEND) { + /* Shut down the device */ + pci_disable_device(dev->pdev); + pci_set_power_state(dev->pdev, PCI_D3hot); + } + return 0; +} + +int radeon_resume(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb; + int i; + u32 tmp; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + pci_set_power_state(dev->pdev, PCI_D0); + pci_restore_state(dev->pdev); + if (pci_enable_device(dev->pdev)) + return -1; + pci_set_master(dev->pdev); + + /* Turn on bus mastering */ + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); + + /* on atom cards re init the whole card + and set the modes again */ + + if (dev_priv->is_atom_bios) { + struct atom_context *ctx = dev_priv->mode_info.atom_context; + atom_asic_init(ctx); + } else { + radeon_combios_asic_init(dev); + } + + for (i = 0; i < 8; i++) + RADEON_WRITE(RADEON_BIOS_0_SCRATCH + (i * 4), dev_priv->pmregs.bios_scratch[i]); + + /* VGA render mayhaps */ + if (dev_priv->chip_family >= CHIP_RS600) { + uint32_t tmp; + + RADEON_WRITE(AVIVO_D1VGA_CONTROL, 0); + RADEON_WRITE(AVIVO_D2VGA_CONTROL, 0); + tmp = RADEON_READ(0x300); + tmp &= ~(3 << 16); + RADEON_WRITE(0x300, tmp); + RADEON_WRITE(0x308, (1 << 8)); + RADEON_WRITE(0x310, dev_priv->fb_location); + RADEON_WRITE(0x594, 0); + } + + RADEON_WRITE(RADEON_CRTC_EXT_CNTL, dev_priv->pmregs.crtc_ext_cntl); + + radeon_static_clocks_init(dev); + + radeon_init_memory_map(dev); + + if (dev_priv->flags & RADEON_IS_PCIE) { + memcpy_toio(dev_priv->mm.pcie_table.kmap.virtual, dev_priv->mm.pcie_table_backup, RADEON_PCIGART_TABLE_SIZE); + } + + if (dev_priv->mm.ring.kmap.virtual) + memset(dev_priv->mm.ring.kmap.virtual, 0, RADEON_DEFAULT_RING_SIZE); + + if (dev_priv->mm.ring_read.kmap.virtual) + memset(dev_priv->mm.ring_read.kmap.virtual, 0, PAGE_SIZE); + + radeon_modeset_cp_resume(dev); + + /* reset swi reg */ + RADEON_WRITE(RADEON_LAST_SWI_REG, dev_priv->counter); + + radeon_enable_interrupt(dev); + + /* reset the context for userspace */ + if (dev->primary->master) { + struct drm_radeon_master_private *master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->ctx_owner = 0; + } + + /* unpin the front buffers */ + list_for_each_entry(fb, &dev->mode_config.fb_kernel_list, filp_head) { + + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + + if (!radeon_fb) + continue; + + if (!radeon_fb->obj) + continue; + + radeon_gem_object_pin(radeon_fb->obj, PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); + } + /* blat the mode back in */ + drm_helper_resume_force_mode(dev); + + return 0; +} diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 6b71360f..a34c6530 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -521,7 +521,6 @@ static void radeon_do_cp_flush(drm_radeon_private_t * dev_priv) DRM_DEBUG("\n"); #if 0 u32 tmp; - tmp = RADEON_READ(RADEON_CP_RB_WPTR) | (1 << 31); RADEON_WRITE(RADEON_CP_RB_WPTR, tmp); #endif @@ -761,8 +760,6 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, dev_priv->ring.size_l2qw); #endif - /* Start with assuming that writeback doesn't work */ - dev_priv->writeback_works = 0; /* Initialize the scratch register pointer. This will cause * the scratch register values to be written out to memory @@ -1341,6 +1338,9 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, radeon_set_pcigart(dev_priv, 1); } + /* Start with assuming that writeback doesn't work */ + dev_priv->writeback_works = 0; + radeon_cp_load_microcode(dev_priv); radeon_cp_init_ring_buffer(dev, dev_priv); @@ -2301,14 +2301,64 @@ static void radeon_set_dynamic_clock(struct drm_device *dev, int mode) } -int radeon_modeset_cp_init(struct drm_device *dev) +int radeon_modeset_cp_suspend(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; + + ret = radeon_do_cp_idle(dev_priv); + if (ret) + DRM_ERROR("failed to idle CP on suspend\n"); + + radeon_do_cp_stop(dev_priv); + radeon_do_engine_reset(dev); + if (dev_priv->flags & RADEON_IS_AGP) { + } else { + radeon_set_pcigart(dev_priv, 0); + } + + return 0; +} + +int radeon_modeset_cp_resume(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; uint32_t tmp; + radeon_do_wait_for_idle(dev_priv); +#if __OS_HAS_AGP + if (dev_priv->flags & RADEON_IS_AGP) { + /* Turn off PCI GART */ + radeon_set_pcigart(dev_priv, 0); + } else +#endif + { + /* Turn on PCI GART */ + radeon_set_pcigart(dev_priv, 1); + } + radeon_gart_flush(dev); + + DRM_ERROR("microcode loading\n"); + radeon_cp_load_microcode(dev_priv); + radeon_cp_init_ring_buffer(dev, dev_priv); + + DRM_ERROR("engine init\n"); + radeon_do_engine_reset(dev); + + radeon_do_cp_start(dev_priv); + return 0; +} + +int radeon_modeset_cp_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + /* allocate a ring and ring rptr bits from GART space */ /* these are allocated in GEM files */ + /* Start with assuming that writeback doesn't work */ + dev_priv->writeback_works = 0; + dev_priv->usec_timeout = RADEON_DEFAULT_CP_TIMEOUT; dev_priv->ring.size = RADEON_DEFAULT_RING_SIZE; dev_priv->cp_mode = RADEON_CSQ_PRIBM_INDBM; @@ -2327,23 +2377,8 @@ int radeon_modeset_cp_init(struct drm_device *dev) dev_priv->new_memmap = true; r300_init_reg_flags(dev); - - radeon_cp_load_microcode(dev_priv); - DRM_DEBUG("ring offset is %x %x\n", dev_priv->mm.ring.bo->offset, dev_priv->mm.ring_read.bo->offset); - - radeon_cp_init_ring_buffer(dev, dev_priv); - - /* need to enable BUS mastering in Buscntl */ - tmp = RADEON_READ(RADEON_BUS_CNTL); - tmp &= ~RADEON_BUS_MASTER_DIS; - RADEON_WRITE(RADEON_BUS_CNTL, tmp); - - radeon_do_engine_reset(dev); - radeon_test_writeback(dev_priv); - - radeon_do_cp_start(dev_priv); - return 0; + return radeon_modeset_cp_resume(dev); } static bool radeon_get_bios(struct drm_device *dev) @@ -2418,6 +2453,20 @@ int radeon_modeset_preinit(struct drm_device *dev) return 0; } +int radeon_static_clocks_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if ((dev_priv->flags & RADEON_IS_MOBILITY) && !radeon_is_avivo(dev_priv)) { + radeon_set_dynamic_clock(dev, radeon_dynclks); + } else if (radeon_is_avivo(dev_priv)) { + if (radeon_dynclks) { + radeon_atom_static_pwrmgt_setup(dev, 1); + radeon_atom_dyn_clk_setup(dev, 1); + } + } + radeon_force_some_clocks(dev); +} int radeon_driver_load(struct drm_device *dev, unsigned long flags) { @@ -2473,7 +2522,6 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) if (drm_core_check_feature(dev, DRIVER_MODESET)) radeon_modeset_preinit(dev); - radeon_get_vram_type(dev); dev_priv->pll_errata = 0; @@ -2493,17 +2541,8 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->pll_errata |= CHIP_ERRATA_PLL_DELAY; - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - if ((dev_priv->flags & RADEON_IS_MOBILITY) && !radeon_is_avivo(dev_priv)) { - radeon_set_dynamic_clock(dev, radeon_dynclks); - } else if (radeon_is_avivo(dev_priv)) { - if (radeon_dynclks) { - radeon_atom_static_pwrmgt_setup(dev, 1); - radeon_atom_dyn_clk_setup(dev, 1); - } - } - radeon_force_some_clocks(dev); - } + if (drm_core_check_feature(dev, DRIVER_MODESET)) + radeon_static_clocks_init(dev); /* init memory manager - start with all of VRAM and a 32MB GART aperture for now */ dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 019491c7..662d9cc3 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -273,6 +273,8 @@ struct radeon_mm_info { uint64_t gart_start; uint64_t gart_size; + + void *pcie_table_backup; struct radeon_mm_obj pcie_table; struct radeon_mm_obj ring; @@ -314,6 +316,11 @@ struct drm_radeon_cs_priv { uint32_t *reloc, uint32_t *offset); }; +struct radeon_pm_regs { + uint32_t crtc_ext_cntl; + uint32_t bios_scratch[8]; +}; + typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; @@ -432,6 +439,8 @@ typedef struct drm_radeon_private { /* ib bitmap */ uint64_t ib_alloc_bitmap; // TO DO replace with a real bitmap struct drm_radeon_cs_priv cs; + + struct radeon_pm_regs pmregs; } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { @@ -527,6 +536,11 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, struct drm_file *file_priv, drm_radeon_kcmd_buffer_t *cmdbuf); +extern int radeon_modeset_cp_suspend(struct drm_device *dev); +extern int radeon_modeset_cp_resume(struct drm_device *dev); +/* radeon_pm.c */ +int radeon_suspend(struct drm_device *dev, pm_message_t state); +int radeon_resume(struct drm_device *dev); /* Flags for stats.boxes */ #define RADEON_BOX_DMA_IDLE 0x1 @@ -1464,7 +1478,7 @@ do { \ * Ring control */ -#define RADEON_VERBOSE 0 +#define RADEON_VERBOSE 1 #define RING_LOCALS int write, _nr; unsigned int mask; u32 *ring; @@ -1648,7 +1662,8 @@ extern int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, extern int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int radeon_gem_object_pin(struct drm_gem_object *obj, - uint32_t alignment); + uint32_t alignment, uint32_t pin_domain); +int radeon_gem_object_unpin(struct drm_gem_object *obj); int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, @@ -1670,6 +1685,8 @@ extern void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master * extern int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv); extern int radeon_cs_init(struct drm_device *dev); void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master); +void radeon_init_memory_map(struct drm_device *dev); + #define MARK_SAFE 1 #define MARK_CHECK_OFFSET 2 -- cgit v1.2.3 From 8f23d4a44cdb17abff8f1ab3585e533ae0572224 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:11:43 +1000 Subject: make text reserve 256k --- linux-core/radeon_gem.c | 2 +- shared-core/radeon_drv.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 98105e7c..12a03588 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -804,7 +804,7 @@ int radeon_gem_mm_init(struct drm_device *dev) radeon_init_memory_map(dev); -#define VRAM_RESERVE_TEXT (64*1024) +#define VRAM_RESERVE_TEXT (256*1024) /* need to reserve 256 for text mode for now */ dev_priv->mm.vram_visible -= VRAM_RESERVE_TEXT; pg_offset = VRAM_RESERVE_TEXT >> PAGE_SHIFT; drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, pg_offset, /*dev_priv->mm.vram_offset >> PAGE_SHIFT,*/ diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 662d9cc3..96f9a98c 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1478,7 +1478,7 @@ do { \ * Ring control */ -#define RADEON_VERBOSE 1 +#define RADEON_VERBOSE 0 #define RING_LOCALS int write, _nr; unsigned int mask; u32 *ring; -- cgit v1.2.3 From 0e384803c5f2528735e43b8d30f90ea82f6b3f47 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:13:30 +1000 Subject: radeon: don't do full edid for detection purposes --- linux-core/radeon_connectors.c | 22 ++++++---------------- linux-core/radeon_display.c | 6 ++++++ linux-core/radeon_i2c.c | 33 +++++++++++++++++++++++++++++++++ linux-core/radeon_mode.h | 1 + 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c index 5ce66d72..f217fe77 100644 --- a/linux-core/radeon_connectors.c +++ b/linux-core/radeon_connectors.c @@ -163,18 +163,16 @@ static int radeon_vga_mode_valid(struct drm_connector *connector, static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector) { - struct edid *edid; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; + bool ret; radeon_i2c_do_lock(radeon_connector, 1); - edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + ret = radeon_ddc_probe(radeon_connector); radeon_i2c_do_lock(radeon_connector, 0); - if (edid) { - kfree(edid); + if (ret) return connector_status_connected; - } /* if EDID fails to a load detect */ encoder = radeon_best_single_encoder(connector); @@ -200,27 +198,19 @@ struct drm_connector_funcs radeon_vga_connector_funcs = { static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) { - struct edid *edid; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; struct drm_mode_object *obj; int i; enum drm_connector_status ret; + bool dret; radeon_i2c_do_lock(radeon_connector, 1); - edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + dret = radeon_ddc_probe(radeon_connector); radeon_i2c_do_lock(radeon_connector, 0); - if (edid) { - /* if the monitor is digital - set the bits */ - if (edid->digital) - radeon_connector->use_digital = 1; - else - radeon_connector->use_digital = 0; - - kfree(edid); + if (dret) return connector_status_connected; - } for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] == 0) diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index d105e1ae..c532ef0f 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -31,6 +31,7 @@ #include #include "drm_crtc_helper.h" +#include "drm_edid.h" int radeon_ddc_dump(struct drm_connector *connector); @@ -305,6 +306,11 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); radeon_i2c_do_lock(radeon_connector, 0); if (edid) { + /* update digital bits here */ + if (edid->digital) + radeon_connector->use_digital = 1; + else + radeon_connector->use_digital = 0; drm_mode_connector_update_edid_property(&radeon_connector->base, edid); ret = drm_add_edid_modes(&radeon_connector->base, edid); kfree(edid); diff --git a/linux-core/radeon_i2c.c b/linux-core/radeon_i2c.c index 00fc7c0e..94a485ba 100644 --- a/linux-core/radeon_i2c.c +++ b/linux-core/radeon_i2c.c @@ -27,6 +27,38 @@ #include "radeon_drm.h" #include "radeon_drv.h" +/** + * radeon_ddc_probe + * + */ +bool radeon_ddc_probe(struct radeon_connector *radeon_connector) +{ + u8 out_buf[] = { 0x0, 0x0}; + u8 buf[2]; + int ret; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } + }; + + ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); + if (ret == 2) + return true; + + return false; +} + + void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state) { struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; @@ -161,3 +193,4 @@ struct drm_encoder *radeon_best_encoder(struct drm_connector *connector) { return NULL; } + diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index d7c60fa6..e8a0106e 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -247,6 +247,7 @@ extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, struct radeon_i2c_bus_rec *rec, const char *name); extern void radeon_i2c_destroy(struct radeon_i2c_chan *i2c); +extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern struct drm_connector *radeon_connector_add(struct drm_device *dev, int bios_index); -- cgit v1.2.3 From ed961cb428a73a35d473c27f62809ef80bde8706 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:14:32 +1000 Subject: radeon: remove unneeded debugging --- linux-core/radeon_gem.c | 1 - shared-core/radeon_cp.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 12a03588..382d348b 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -612,7 +612,6 @@ static int radeon_gart_init(struct drm_device *dev) if (!dev_priv->mm.pcie_table_backup) return -EINVAL; - DRM_ERROR("pcie table bo created %p, %x\n", dev_priv->mm.pcie_table.bo, dev_priv->mm.pcie_table.bo->offset); ret = drm_bo_kmap(dev_priv->mm.pcie_table.bo, 0, RADEON_PCIGART_TABLE_SIZE >> PAGE_SHIFT, &dev_priv->mm.pcie_table.kmap); if (ret) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index a34c6530..8fc43756 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2338,11 +2338,9 @@ int radeon_modeset_cp_resume(struct drm_device *dev) } radeon_gart_flush(dev); - DRM_ERROR("microcode loading\n"); radeon_cp_load_microcode(dev_priv); radeon_cp_init_ring_buffer(dev, dev_priv); - DRM_ERROR("engine init\n"); radeon_do_engine_reset(dev); radeon_do_cp_start(dev_priv); -- cgit v1.2.3 From 5081ce12217d31d8d197e66ac3bc71adc650d463 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:15:43 +1000 Subject: radeon: sort out atom vs combios tables for r400 cards --- linux-core/radeon_atombios.c | 38 ++++++++++++++++++++++++++- linux-core/radeon_combios.c | 19 ++++++++++++-- linux-core/radeon_encoders.c | 2 +- linux-core/radeon_legacy_encoders.c | 52 ++++++++++++++++++++++++++++--------- linux-core/radeon_mode.h | 4 ++- 5 files changed, 98 insertions(+), 17 deletions(-) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index 10e3a77d..4d98cba2 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -305,12 +305,48 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) return true; } + +void radeon_atombios_get_tmds_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + int index = GetIndexIntoMasterTable(DATA, TMDS_Info); + uint16_t data_offset; + struct _ATOM_TMDS_INFO *tmds_info; + uint8_t frev, crev; + uint16_t maxfreq; + int i; + + atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); + + tmds_info = (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios + data_offset); + + maxfreq = le16_to_cpu(tmds_info->usMaxFrequency); + for (i = 0; i < 4; i++) { + encoder->tmds_pll[i].freq = le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency); + encoder->tmds_pll[i].value = tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f; + encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VCO_Gain & 0x3f << 6); + encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_DutyCycle & 0xf << 12); + encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VoltageSwing & 0xf << 16); + + DRM_DEBUG("TMDS PLL From BIOS %u %x\n", + encoder->tmds_pll[i].freq, + encoder->tmds_pll[i].value); + + if (maxfreq == encoder->tmds_pll[i].freq) { + encoder->tmds_pll[i].freq = 0xffffffff; + break; + } + } +} + union lvds_info { struct _ATOM_LVDS_INFO info; struct _ATOM_LVDS_INFO_V12 info_12; }; -void radeon_get_lvds_info(struct radeon_encoder *encoder) +void radeon_atombios_get_lvds_info(struct radeon_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_radeon_private *dev_priv = dev->dev_private; diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index a4dd43b9..1bacc464 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -55,7 +55,7 @@ enum radeon_combios_table_offset COMBIOS_CONNECTOR_INFO_TABLE, COMBIOS_DYN_CLK_1_TABLE, COMBIOS_RESERVED_MEM_TABLE, - COMBIOS_EXT_TDMS_INFO_TABLE, + COMBIOS_EXT_TMDS_INFO_TABLE, COMBIOS_MEM_CLK_INFO_TABLE, COMBIOS_EXT_DAC_INFO_TABLE, COMBIOS_MISC_INFO_TABLE, @@ -217,7 +217,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev, enum radeon_com if (check_offset) offset = check_offset; break; - case COMBIOS_EXT_TDMS_INFO_TABLE: + case COMBIOS_EXT_TMDS_INFO_TABLE: check_offset = radeon_bios16(dev_priv, dev_priv->bios_header_start + 0x58); if (check_offset) offset = check_offset; @@ -767,6 +767,21 @@ bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder) return false; } +bool radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + uint16_t ext_tmds_info; + uint8_t ver; + + ext_tmds_info = combios_get_table_offset(dev, COMBIOS_EXT_TMDS_INFO_TABLE); + if (ext_tmds_info) { + ver = radeon_bios8(dev_priv, ext_tmds_info); + DRM_INFO("External TMDS Table revision: %d\n", ver); + // TODO + } +} + static void radeon_apply_legacy_quirks(struct drm_device *dev, int bios_index) { struct drm_radeon_private *dev_priv = dev->dev_private; diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 897be82a..82ffcfb0 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -387,7 +387,7 @@ struct drm_encoder *radeon_encoder_lvtma_add(struct drm_device *dev, int bios_in /* TODO get the LVDS info from the BIOS for panel size etc. */ /* get the lvds info from the bios */ - radeon_get_lvds_info(radeon_encoder); + radeon_atombios_get_lvds_info(radeon_encoder); /* LVDS gets default RMX full scaling */ radeon_encoder->rmx_type = RMX_FULL; diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index b48da9b8..1a1db534 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -262,16 +262,20 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) { + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; // fix me: atom/legacy r4xx - radeon_combios_output_lock(encoder, true); + if (!dev_priv->is_atom_bios) + radeon_combios_output_lock(encoder, true); radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_lvds_commit(struct drm_encoder *encoder) { + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON); // fix me: atom/legacy r4xx - radeon_combios_output_lock(encoder, false); + if (!dev_priv->is_atom_bios) + radeon_combios_output_lock(encoder, false); } static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, @@ -366,6 +370,7 @@ static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; @@ -387,7 +392,10 @@ struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int b drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); /* get the lvds info from the bios */ - radeon_combios_get_lvds_info(radeon_encoder); + if (dev_priv->is_atom_bios) + radeon_atombios_get_lvds_info(radeon_encoder); + else + radeon_combios_get_lvds_info(radeon_encoder); /* LVDS gets default RMX full scaling */ radeon_encoder->rmx_type = RMX_FULL; @@ -462,16 +470,20 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) { + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; // fix me: atom/legacy r4xx - radeon_combios_output_lock(encoder, true); + if (!dev_priv->is_atom_bios) + radeon_combios_output_lock(encoder, true); radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder) { + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON); // fix me: atom/legacy r4xx - radeon_combios_output_lock(encoder, false); + if (!dev_priv->is_atom_bios) + radeon_combios_output_lock(encoder, false); } static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, @@ -608,6 +620,7 @@ static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev, int bios_index, int has_tv) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; @@ -628,7 +641,8 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs); /* get the primary dac bg/adj vals from bios tables */ - radeon_combios_get_primary_dac_info(radeon_encoder); + if (!dev_priv->is_atom_bios) + radeon_combios_get_primary_dac_info(radeon_encoder); return encoder; } @@ -686,16 +700,20 @@ static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) { + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; // fix me: atom/legacy r4xx - radeon_combios_output_lock(encoder, true); + if (!dev_priv->is_atom_bios) + radeon_combios_output_lock(encoder, true); radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder) { + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON); // fix me: atom/legacy r4xx - radeon_combios_output_lock(encoder, true); + if (!dev_priv->is_atom_bios) + radeon_combios_output_lock(encoder, true); } static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, @@ -799,6 +817,7 @@ static const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; @@ -818,7 +837,10 @@ struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, i drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs); - radeon_combios_get_tmds_info(radeon_encoder); + if (dev_priv->is_atom_bios) + radeon_atombios_get_tmds_info(radeon_encoder); + else + radeon_combios_get_tmds_info(radeon_encoder); return encoder; } @@ -877,16 +899,20 @@ static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) { + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; // fix me: atom/legacy r4xx - radeon_combios_output_lock(encoder, true); + if (!dev_priv->is_atom_bios) + radeon_combios_output_lock(encoder, true); radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF); } static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder) { + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON); // fix me: atom/legacy r4xx - radeon_combios_output_lock(encoder, false); + if (!dev_priv->is_atom_bios) + radeon_combios_output_lock(encoder, false); } static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, @@ -961,6 +987,7 @@ static const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = { struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder; struct drm_encoder *encoder; @@ -980,7 +1007,8 @@ struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, i drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs); - //radeon_combios_get_tmds_info(radeon_encoder); + if (!dev_priv->is_atom_bios) + radeon_combios_get_ext_tmds_info(radeon_encoder); return encoder; } diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index e8a0106e..f12a1161 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -288,9 +288,11 @@ extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, extern bool radeon_atom_get_clock_info(struct drm_device *dev); extern bool radeon_combios_get_clock_info(struct drm_device *dev); -extern void radeon_get_lvds_info(struct radeon_encoder *encoder); +extern void radeon_atombios_get_lvds_info(struct radeon_encoder *encoder); +extern void radeon_atombios_get_tmds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder); +extern bool radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tv_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder); -- cgit v1.2.3 From 9b728fe4b0c154acd2291f9bec747ee67f8cce02 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:16:09 +1000 Subject: radeon: fixup reference counting properly --- linux-core/radeon_gem.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 382d348b..c0218a3f 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -264,6 +264,9 @@ int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, #endif out_unlock: mutex_unlock(&obj_priv->bo->mutex); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -322,14 +325,7 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, int flags = DRM_BO_FLAG_NO_EVICT; int mask = DRM_BO_FLAG_NO_EVICT; - obj = drm_gem_object_lookup(dev, file_priv, args->handle); - if (obj == NULL) - return -EINVAL; - - obj_priv = obj->driver_private; - - DRM_DEBUG("got here %p %p %d\n", obj, obj_priv->bo, atomic_read(&obj_priv->bo->usage)); - /* validate into a pin with no fence */ + /* check for valid args */ if (args->pin_domain) { mask |= DRM_BO_MASK_MEM; if (args->pin_domain == RADEON_GEM_DOMAIN_GTT) @@ -340,6 +336,14 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, return -EINVAL; } + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + obj_priv = obj->driver_private; + + /* validate into a pin with no fence */ + DRM_DEBUG("got here %p %p %d\n", obj, obj_priv->bo, atomic_read(&obj_priv->bo->usage)); if (!(obj_priv->bo->type != drm_bo_type_kernel && !DRM_SUSER(DRM_CURPROC))) { ret = drm_bo_do_validate(obj_priv->bo, flags, mask, DRM_BO_HINT_DONT_FENCE, 0); @@ -1027,7 +1031,7 @@ static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_pri obj = drm_gem_object_lookup(dev, file_priv, reloc[1]); if (!obj) - return false; + return -EINVAL; obj_priv = obj->driver_private; radeon_gem_set_domain(obj, read_domains, write_domain, &flags, false); -- cgit v1.2.3 From b6c1a2f7eea256dad7d38020f784ed6a94accd9d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:16:41 +1000 Subject: radeon: fix return value --- linux-core/radeon_combios.c | 2 +- linux-core/radeon_mode.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index 1bacc464..3219b993 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -767,7 +767,7 @@ bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder) return false; } -bool radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder) +void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_radeon_private *dev_priv = dev->dev_private; diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index f12a1161..261bf8e0 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -292,7 +292,7 @@ extern void radeon_atombios_get_lvds_info(struct radeon_encoder *encoder); extern void radeon_atombios_get_tmds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tmds_info(struct radeon_encoder *encoder); -extern bool radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder); +extern void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tv_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder); extern bool radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder); -- cgit v1.2.3 From 515aa0800cf2d91bdf4706463e0531c5081a2679 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:17:27 +1000 Subject: radeon: do proper memory controller init and setup --- linux-core/radeon_gem.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++- shared-core/radeon_cp.c | 2 +- shared-core/radeon_drv.h | 1 + 3 files changed, 180 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index c0218a3f..58162e52 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -707,6 +707,176 @@ int radeon_alloc_gart_objects(struct drm_device *dev) } +static bool avivo_get_mc_idle(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (dev_priv->chip_family >= CHIP_R600) { + /* no idea where this is on r600 yet */ + return true; + } else if (dev_priv->chip_family == CHIP_RV515) { + if (radeon_read_mc_reg(dev_priv, RV515_MC_STATUS) & RV515_MC_STATUS_IDLE) + return true; + else + return false; + } else if (dev_priv->chip_family == CHIP_RS600) { + if (radeon_read_mc_reg(dev_priv, RS600_MC_STATUS) & RS600_MC_STATUS_IDLE) + return true; + else + return false; + } else if ((dev_priv->chip_family == CHIP_RS690) || + (dev_priv->chip_family == CHIP_RS740)) { + if (radeon_read_mc_reg(dev_priv, RS690_MC_STATUS) & RS690_MC_STATUS_IDLE) + return true; + else + return false; + } else { + if (radeon_read_mc_reg(dev_priv, R520_MC_STATUS) & R520_MC_STATUS_IDLE) + return true; + else + return false; + } +} + + +static void avivo_disable_mc_clients(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t tmp; + int timeout; + + radeon_do_wait_for_idle(dev_priv); + + RADEON_WRITE(AVIVO_D1VGA_CONTROL, RADEON_READ(AVIVO_D1VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); + RADEON_WRITE(AVIVO_D2VGA_CONTROL, RADEON_READ(AVIVO_D2VGA_CONTROL) & ~AVIVO_DVGA_CONTROL_MODE_ENABLE); + + tmp = RADEON_READ(AVIVO_D1CRTC_CONTROL); + RADEON_WRITE(AVIVO_D1CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); + + tmp = RADEON_READ(AVIVO_D2CRTC_CONTROL); + RADEON_WRITE(AVIVO_D2CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN); + + tmp = RADEON_READ(AVIVO_D2CRTC_CONTROL); + + udelay(1000); + + timeout = 0; + while (!(avivo_get_mc_idle(dev))) { + if (++timeout > 100000) { + DRM_ERROR("Timeout waiting for memory controller to update settings\n"); + DRM_ERROR("Bad things may or may not happen\n"); + } + udelay(10); + } +} + +static inline u32 radeon_busy_wait(struct drm_device *dev, uint32_t reg, uint32_t bits, + unsigned int timeout) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + u32 status; + + do { + udelay(10); + status = RADEON_READ(reg); + timeout--; + } while(status != 0xffffffff && (status & bits) && (timeout > 0)); + + if (timeout == 0) + status = 0xffffffff; + + return status; +} + +/* Wait for vertical sync on primary CRTC */ +static void radeon_wait_for_vsync(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t crtc_gen_cntl; + int ret; + + crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL); + if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) || + !(crtc_gen_cntl & RADEON_CRTC_EN)) + return; + + /* Clear the CRTC_VBLANK_SAVE bit */ + RADEON_WRITE(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR); + + radeon_busy_wait(dev, RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE, 2000); + +} + +/* Wait for vertical sync on primary CRTC */ +static void radeon_wait_for_vsync2(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t crtc2_gen_cntl; + struct timeval timeout; + + crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); + if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) || + !(crtc2_gen_cntl & RADEON_CRTC2_EN)) + return; + + /* Clear the CRTC_VBLANK_SAVE bit */ + RADEON_WRITE(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR); + + radeon_busy_wait(dev, RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE, 2000); +} + +static void legacy_disable_mc_clients(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t old_mc_status, status_idle; + uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl; + uint32_t status; + + radeon_do_wait_for_idle(dev_priv); + + if (dev_priv->flags & RADEON_IS_IGP) + return; + + old_mc_status = RADEON_READ(RADEON_MC_STATUS); + + /* stop display and memory access */ + ov0_scale_cntl = RADEON_READ(RADEON_OV0_SCALE_CNTL); + RADEON_WRITE(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE); + crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); + RADEON_WRITE(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS); + crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL); + + radeon_wait_for_vsync(dev); + + RADEON_WRITE(RADEON_CRTC_GEN_CNTL, + (crtc_gen_cntl & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN)) | + RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN); + + if (!(dev_priv->flags & RADEON_SINGLE_CRTC)) { + crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); + + radeon_wait_for_vsync2(dev); + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, + (crtc2_gen_cntl & + ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN)) | + RADEON_CRTC2_DISP_REQ_EN_B); + } + + udelay(500); + + if (radeon_is_r300(dev_priv)) + status_idle = R300_MC_IDLE; + else + status_idle = RADEON_MC_IDLE; + + status = radeon_busy_wait(dev, RADEON_MC_STATUS, status_idle, 200000); + if (status == 0xffffffff) { + DRM_ERROR("Timeout waiting for memory controller to update settings\n"); + DRM_ERROR("Bad things may or may not happen\n"); + } +} + + void radeon_init_memory_map(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -776,6 +946,14 @@ void radeon_init_memory_map(struct drm_device *dev) else dev_priv->fb_location = (dev_priv->mc_fb_location & 0xffff) << 16; + /* updating mc regs here */ + if (radeon_is_avivo(dev_priv)) + avivo_disable_mc_clients(dev); + else + legacy_disable_mc_clients(dev); + + radeon_write_fb_location(dev_priv, dev_priv->mc_fb_location); + if (radeon_is_avivo(dev_priv)) { if (dev_priv->chip_family >= CHIP_R600) RADEON_WRITE(R600_HDP_NONSURFACE_BASE, (dev_priv->mc_fb_location << 16) & 0xff0000); @@ -783,8 +961,6 @@ void radeon_init_memory_map(struct drm_device *dev) RADEON_WRITE(AVIVO_HDP_FB_LOCATION, dev_priv->mc_fb_location); } - radeon_write_fb_location(dev_priv, dev_priv->mc_fb_location); - dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16; dev_priv->fb_size = ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 8fc43756..63957cd7 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -356,7 +356,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries) return -EBUSY; } -static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) +int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) { int i, ret; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 96f9a98c..82d9d001 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -491,6 +491,7 @@ extern struct drm_buf *radeon_freelist_get(struct drm_device * dev); extern int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n); +extern int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv); extern int radeon_do_cp_idle(drm_radeon_private_t * dev_priv); extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); -- cgit v1.2.3 From 8f38c28a3924dbda5babcf035911e103f27f9a05 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:19:08 +1000 Subject: radeon: fail properly if we can't create the ring. Normally this will be due to an AGP driver needing updating --- linux-core/radeon_gem.c | 15 +++++++++++---- shared-core/radeon_cp.c | 8 +++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 58162e52..821a3e13 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -667,7 +667,10 @@ int radeon_alloc_gart_objects(struct drm_device *dev) DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_NO_EVICT, 0, 1, 0, &dev_priv->mm.ring.bo); if (ret) { - DRM_ERROR("failed to allocate ring\n"); + if (dev_priv->flags & RADEON_IS_AGP) + DRM_ERROR("failed to allocate ring - most likely an AGP driver bug\n"); + else + DRM_ERROR("failed to allocate ring\n"); return -EINVAL; } @@ -1004,8 +1007,10 @@ int radeon_gem_mm_init(struct drm_device *dev) /* need to allocate some objects in the GART */ /* ring + ring read ptr */ ret = radeon_alloc_gart_objects(dev); - if (ret) + if (ret) { + radeon_gem_mm_fini(dev); return -EINVAL; + } dev_priv->mm_enabled = true; return 0; @@ -1508,8 +1513,10 @@ static void radeon_gem_dma_bufs_destroy(struct drm_device *dev) struct drm_radeon_private *dev_priv = dev->dev_private; drm_dma_takedown(dev); - drm_bo_kunmap(&dev_priv->mm.dma_bufs.kmap); - drm_bo_usage_deref_unlocked(&dev_priv->mm.dma_bufs.bo); + if (dev_priv->mm.dma_bufs.bo) { + drm_bo_kunmap(&dev_priv->mm.dma_bufs.kmap); + drm_bo_usage_deref_unlocked(&dev_priv->mm.dma_bufs.bo); + } } diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 63957cd7..6c5bf03b 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2549,7 +2549,9 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) if (drm_core_check_feature(dev, DRIVER_MODESET)) { - radeon_gem_mm_init(dev); + ret = radeon_gem_mm_init(dev); + if (ret) + goto modeset_fail; radeon_modeset_init(dev); radeon_modeset_cp_init(dev); @@ -2559,6 +2561,10 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) } + return ret; +modeset_fail: + dev->driver->driver_features &= ~DRIVER_MODESET; + drm_put_minor(&dev->control); return ret; } -- cgit v1.2.3 From 13e24fa7c03a4da6ba85b42d97290b4360c5ba8c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:19:53 +1000 Subject: [PATCH] radeon: disable blit moves --- linux-core/radeon_buffer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 96a584f3..5b2ba42f 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -401,6 +401,9 @@ int radeon_move(struct drm_buffer_object * bo, return 0; } + /* disable these blit moves for now that appear to be failing */ + goto fallback; + if (new_mem->mem_type == DRM_BO_MEM_VRAM) { if (radeon_move_vram(bo, evict, no_wait, new_mem)) goto fallback; -- cgit v1.2.3 From f426f458f7e766cd47bb30736004ccfc9209f27f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:20:29 +1000 Subject: [PATCH] radeon: fixup GEM domain setting - allows more userspace paths also dirty buffer on validate --- linux-core/radeon_gem.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 821a3e13..8338f8f5 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -166,8 +166,16 @@ int radeon_gem_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uin return -EINVAL; // we can't write to system RAM } else { /* okay for a read domain - prefer wherever the object is now or close enough */ - if ((read_domains == 0) || (read_domains == RADEON_GEM_DOMAIN_CPU)) + if (read_domains == 0) return -EINVAL; + + /* if its already a local memory and CPU is valid do nothing */ + if (read_domains & RADEON_GEM_DOMAIN_CPU) { + if (obj_priv->bo->mem.mem_type == DRM_BO_MEM_LOCAL) + return 0; + if (read_domains == RADEON_GEM_DOMAIN_CPU) + return -EINVAL; + } /* simple case no choice in domains */ if (read_domains == RADEON_GEM_DOMAIN_VRAM) @@ -178,12 +186,19 @@ int radeon_gem_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uin flags = DRM_BO_FLAG_MEM_VRAM; else if ((obj_priv->bo->mem.mem_type == DRM_BO_MEM_TT) && (read_domains & RADEON_GEM_DOMAIN_GTT)) flags = DRM_BO_FLAG_MEM_TT; + else if ((obj_priv->bo->mem.mem_type == DRM_BO_MEM_LOCAL) && (read_domains & RADEON_GEM_DOMAIN_GTT)) + flags = DRM_BO_FLAG_MEM_TT; else if (read_domains & RADEON_GEM_DOMAIN_VRAM) flags = DRM_BO_FLAG_MEM_VRAM; else if (read_domains & RADEON_GEM_DOMAIN_GTT) flags = DRM_BO_FLAG_MEM_TT; } + /* if this BO is pinned then we ain't moving it anywhere */ + if (obj_priv->bo->pinned_mem_type && unfenced) + return 0; + + DRM_DEBUG("validating %p from %d into %x %d %d\n", obj_priv->bo, obj_priv->bo->mem.mem_type, flags, read_domains, write_domain); ret = drm_bo_do_validate(obj_priv->bo, flags, DRM_BO_MASK_MEM | DRM_BO_FLAG_CACHED, unfenced ? DRM_BO_HINT_DONT_FENCE : 0, 0); if (ret) @@ -1217,6 +1232,7 @@ static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_pri obj_priv = obj->driver_private; radeon_gem_set_domain(obj, read_domains, write_domain, &flags, false); + obj_priv->bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; if (flags == DRM_BO_FLAG_MEM_VRAM) *offset = obj_priv->bo->offset + dev_priv->fb_location; else if (flags == DRM_BO_FLAG_MEM_TT) -- cgit v1.2.3 From 3a497db7862dc091a8582d8ea3ebfd7fe0f16b58 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:22:23 +1000 Subject: radeon: fixup buffer and cs bits --- linux-core/radeon_buffer.c | 3 --- shared-core/radeon_cs.c | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 5b2ba42f..fe2aa6fd 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -407,9 +407,6 @@ int radeon_move(struct drm_buffer_object * bo, if (new_mem->mem_type == DRM_BO_MEM_VRAM) { if (radeon_move_vram(bo, evict, no_wait, new_mem)) goto fallback; - } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL){ - if (radeon_move_flip(bo, evict, no_wait, new_mem)) - goto fallback; } else { if (radeon_move_flip(bo, evict, no_wait, new_mem)) goto fallback; diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index b0c4abe8..a00ec21b 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -368,13 +368,14 @@ void r300_cs_id_emit(struct drm_device *dev, uint32_t *id) /* ISYNC_CNTL should not have CPSCRACTH bit set */ *id = radeon_cs_id_get(dev_priv); /* emit id in SCRATCH6 */ - BEGIN_RING(6); + BEGIN_RING(8); OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 0)); OUT_RING(6); OUT_RING(CP_PACKET0(R300_CP_RESYNC_DATA, 0)); OUT_RING(*id); OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); OUT_RING(R300_RB3D_DC_FINISH); + RADEON_WAIT_UNTIL_3D_IDLE(); ADVANCE_RING(); } -- cgit v1.2.3 From 6a0248cbf2197d64f51d557f85bf2fdbaa505870 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 10:28:42 +1000 Subject: fixup radeon stuff - need to checkout irqs --- linux-core/Makefile.kernel | 2 +- linux-core/radeon_mode.h | 7 +++++++ linux-core/radeon_pm.c | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index b370e015..392abaf9 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -44,7 +44,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_gem.o \ radeon_buffer.o radeon_fence.o atom.o radeon_display.o radeon_atombios.o radeon_i2c.o radeon_connectors.o radeon_cs.o \ atombios_crtc.o radeon_encoders.o radeon_fb.o radeon_combios.o radeon_legacy_crtc.o radeon_legacy_encoders.o \ - radeon_cursor.o + radeon_cursor.o radeon_pm.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 261bf8e0..a4ee78a8 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -326,5 +326,12 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); void radeon_enc_destroy(struct drm_encoder *encoder); +void radeon_emit_copy_blit(struct drm_device * dev, + uint32_t src_offset, + uint32_t dst_offset, + uint32_t pages); +void radeon_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj); +void radeon_combios_asic_init(struct drm_device *dev); +extern int radeon_static_clocks_init(struct drm_device *dev); #endif diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index c7a57b97..e9a6130a 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -151,7 +151,7 @@ int radeon_resume(struct drm_device *dev) /* reset swi reg */ RADEON_WRITE(RADEON_LAST_SWI_REG, dev_priv->counter); - radeon_enable_interrupt(dev); +// radeon_enable_interrupt(dev); /* reset the context for userspace */ if (dev->primary->master) { -- cgit v1.2.3 From 6d0de5a899ea883693737333b4b0511c28f32d92 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Sep 2008 14:30:05 -0400 Subject: Export drm_put_minor --- linux-core/drm_stub.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 1257b0d4..cd6cd4b5 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -492,3 +492,5 @@ int drm_put_minor(struct drm_minor **minor_p) *minor_p = NULL; return 0; } + +EXPORT_SYMBOL(drm_put_minor); -- cgit v1.2.3 From e1e782af5ddafdd24a4cf741139bb0b8e682e543 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Sep 2008 15:11:48 -0400 Subject: Radeon: restructure PLL data - store pixel clocks, core clock, and memory clocks separately - grab all pll limits from bios tables --- linux-core/atombios_crtc.c | 12 +++- linux-core/radeon_atombios.c | 141 +++++++++++++++++++++++++++------------- linux-core/radeon_combios.c | 73 ++++++++++++++++----- linux-core/radeon_display.c | 63 ++++++++++++++---- linux-core/radeon_legacy_crtc.c | 8 +-- linux-core/radeon_mode.h | 24 ++++--- shared-core/radeon_cp.c | 4 +- 7 files changed, 232 insertions(+), 93 deletions(-) diff --git a/linux-core/atombios_crtc.c b/linux-core/atombios_crtc.c index 0a86f36b..03077a13 100644 --- a/linux-core/atombios_crtc.c +++ b/linux-core/atombios_crtc.c @@ -163,13 +163,19 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr; uint32_t sclock = mode->clock; uint32_t ref_div = 0, fb_div = 0, post_div = 0; + struct radeon_pll *pll; memset(&spc_param, 0, sizeof(SET_PIXEL_CLOCK_PS_ALLOCATION)); pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; - radeon_compute_pll(&dev_priv->mode_info.pll, mode->clock, - &sclock, &fb_div, &ref_div, &post_div, pll_flags); + if (radeon_crtc->crtc_id == 0) + pll = &dev_priv->mode_info.p1pll; + else + pll = &dev_priv->mode_info.p2pll; + + radeon_compute_pll(pll, mode->clock, &sclock, + &fb_div, &ref_div, &post_div, pll_flags); if (radeon_is_avivo(dev_priv)) { uint32_t ss_cntl; @@ -338,6 +344,8 @@ void atombios_crtc_mode_set(struct drm_crtc *crtc, if (radeon_is_avivo(dev_priv)) atombios_crtc_set_base(crtc, x, y); + else + radeon_crtc_set_base(crtc, x, y); atombios_crtc_set_pll(crtc, adjusted_mode, pll_flags); diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index 4d98cba2..8bf6a7ce 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -37,7 +37,7 @@ union atom_supported_devices { struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; }; -static inline struct radeon_i2c_bus_rec radeon_lookup_gpio_for_ddc(struct drm_device *dev, uint8_t id) +static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *dev, uint8_t id) { struct drm_radeon_private *dev_priv = dev->dev_private; struct atom_context *ctx = dev_priv->mode_info.atom_context; @@ -160,13 +160,13 @@ bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device (dev_priv->chip_family == CHIP_RS740)) { if ((i == ATOM_DEVICE_DFP2_INDEX) || (i == ATOM_DEVICE_DFP3_INDEX)) mode_info->bios_connector[i].ddc_i2c = - radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1); + radeon_lookup_gpio(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1); else mode_info->bios_connector[i].ddc_i2c = - radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux); + radeon_lookup_gpio(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux); } else mode_info->bios_connector[i].ddc_i2c = - radeon_lookup_gpio_for_ddc(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux); + radeon_lookup_gpio(dev, ci.sucI2cId.sbfAccess.bfI2C_LineMux); if (i == ATOM_DEVICE_DFP1_INDEX) mode_info->bios_connector[i].tmds_type = TMDS_INT; @@ -277,32 +277,79 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); union firmware_info *firmware_info; uint8_t frev, crev; - struct radeon_pll *pll = &mode_info->pll; + struct radeon_pll *p1pll = &mode_info->p1pll; + struct radeon_pll *p2pll = &mode_info->p2pll; + struct radeon_pll *spll = &mode_info->spll; + struct radeon_pll *mpll = &mode_info->mpll; uint16_t data_offset; atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); firmware_info = (union firmware_info *)(mode_info->atom_context->bios + data_offset); - pll->reference_freq = le16_to_cpu(firmware_info->info.usReferenceClock); - pll->reference_div = 0; + if (firmware_info) { + /* pixel clocks */ + p1pll->reference_freq = le16_to_cpu(firmware_info->info.usReferenceClock); + p1pll->reference_div = 0; - pll->pll_out_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); - pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); + p1pll->pll_out_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output); + p1pll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); - if (pll->pll_out_min == 0) { - if (radeon_is_avivo(dev_priv)) - pll->pll_out_min = 64800; - else - pll->pll_out_min = 20000; - } + if (p1pll->pll_out_min == 0) { + if (radeon_is_avivo(dev_priv)) + p1pll->pll_out_min = 64800; + else + p1pll->pll_out_min = 20000; + } - pll->pll_in_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input); - pll->pll_in_max = le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input); + p1pll->pll_in_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input); + p1pll->pll_in_max = le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input); - pll->xclk = le16_to_cpu(firmware_info->info.usMaxPixelClock); + *p2pll = *p1pll; - return true; + /* system clock */ + spll->reference_freq = le16_to_cpu(firmware_info->info.usReferenceClock); + spll->reference_div = 0; + + spll->pll_out_min = le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output); + spll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output); + + /* ??? */ + if (spll->pll_out_min == 0) { + if (radeon_is_avivo(dev_priv)) + spll->pll_out_min = 64800; + else + spll->pll_out_min = 20000; + } + + spll->pll_in_min = le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input); + spll->pll_in_max = le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input); + + + /* memory clock */ + mpll->reference_freq = le16_to_cpu(firmware_info->info.usReferenceClock); + mpll->reference_div = 0; + + mpll->pll_out_min = le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output); + mpll->pll_out_max = le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output); + + /* ??? */ + if (mpll->pll_out_min == 0) { + if (radeon_is_avivo(dev_priv)) + mpll->pll_out_min = 64800; + else + mpll->pll_out_min = 20000; + } + + mpll->pll_in_min = le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input); + mpll->pll_in_max = le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input); + + mode_info->sclk = le32_to_cpu(firmware_info->info.ulDefaultEngineClock); + mode_info->mclk = le32_to_cpu(firmware_info->info.ulDefaultMemoryClock); + + return true; + } + return false; } @@ -322,21 +369,23 @@ void radeon_atombios_get_tmds_info(struct radeon_encoder *encoder) tmds_info = (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios + data_offset); - maxfreq = le16_to_cpu(tmds_info->usMaxFrequency); - for (i = 0; i < 4; i++) { - encoder->tmds_pll[i].freq = le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency); - encoder->tmds_pll[i].value = tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f; - encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VCO_Gain & 0x3f << 6); - encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_DutyCycle & 0xf << 12); - encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VoltageSwing & 0xf << 16); - - DRM_DEBUG("TMDS PLL From BIOS %u %x\n", - encoder->tmds_pll[i].freq, - encoder->tmds_pll[i].value); - - if (maxfreq == encoder->tmds_pll[i].freq) { - encoder->tmds_pll[i].freq = 0xffffffff; - break; + if (tmds_info) { + maxfreq = le16_to_cpu(tmds_info->usMaxFrequency); + for (i = 0; i < 4; i++) { + encoder->tmds_pll[i].freq = le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency); + encoder->tmds_pll[i].value = tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f; + encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VCO_Gain & 0x3f << 6); + encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_DutyCycle & 0xf << 12); + encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VoltageSwing & 0xf << 16); + + DRM_DEBUG("TMDS PLL From BIOS %u %x\n", + encoder->tmds_pll[i].freq, + encoder->tmds_pll[i].value); + + if (maxfreq == encoder->tmds_pll[i].freq) { + encoder->tmds_pll[i].freq = 0xffffffff; + break; + } } } } @@ -360,17 +409,19 @@ void radeon_atombios_get_lvds_info(struct radeon_encoder *encoder) lvds_info = (union lvds_info *)(mode_info->atom_context->bios + data_offset); - encoder->dotclock = le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10; - encoder->panel_xres = le16_to_cpu(lvds_info->info.sLCDTiming.usHActive); - encoder->panel_yres = le16_to_cpu(lvds_info->info.sLCDTiming.usVActive); - encoder->hblank = le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time); - encoder->hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset); - encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); - - encoder->vblank = le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); - encoder->voverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); - encoder->vsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); - encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); + if (lvds_info) { + encoder->dotclock = le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10; + encoder->panel_xres = le16_to_cpu(lvds_info->info.sLCDTiming.usHActive); + encoder->panel_yres = le16_to_cpu(lvds_info->info.sLCDTiming.usVActive); + encoder->hblank = le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time); + encoder->hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset); + encoder->hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); + + encoder->vblank = le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); + encoder->voverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); + encoder->vsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); + encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); + } } void radeon_atom_dyn_clk_setup(struct drm_device *dev, int enable) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index 3219b993..f1693e69 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -73,7 +73,7 @@ enum radeon_combios_table_offset COMBIOS_ASIC_INIT_4_TABLE, /* offset from misc info */ COMBIOS_ASIC_INIT_5_TABLE, /* offset from misc info */ COMBIOS_RAM_RESET_TABLE, /* offset from mem config */ - COMBIOS_POWERPLAY_TABLE, /* offset from mobile info */ + COMBIOS_POWERPLAY_INFO_TABLE, /* offset from mobile info */ COMBIOS_GPIO_INFO_TABLE, /* offset from mobile info */ COMBIOS_LCD_DDC_INFO_TABLE, /* offset from mobile info */ COMBIOS_TMDS_POWER_TABLE, /* offset from mobile info */ @@ -325,7 +325,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev, enum radeon_com offset = check_offset; } break; - case COMBIOS_POWERPLAY_TABLE: /* offset from mobile info */ + case COMBIOS_POWERPLAY_INFO_TABLE: /* offset from mobile info */ check_offset = combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE); if (check_offset) { check_offset = radeon_bios16(dev_priv, check_offset + 0x11); @@ -427,33 +427,72 @@ bool radeon_combios_get_clock_info(struct drm_device *dev) struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_mode_info *mode_info = &dev_priv->mode_info; uint16_t pll_info; - struct radeon_pll *pll = &mode_info->pll; + struct radeon_pll *p1pll = &mode_info->p1pll; + struct radeon_pll *p2pll = &mode_info->p2pll; + struct radeon_pll *spll = &mode_info->spll; + struct radeon_pll *mpll = &mode_info->mpll; int8_t rev; + uint16_t sclk, mclk; pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE); if (pll_info) { rev = radeon_bios8(dev_priv, pll_info); - pll->reference_freq = radeon_bios16(dev_priv, pll_info + 0xe); - pll->reference_div = radeon_bios16(dev_priv, pll_info + 0x10); - pll->pll_out_min = radeon_bios32(dev_priv, pll_info + 0x12); - pll->pll_out_max = radeon_bios32(dev_priv, pll_info + 0x16); + /* pixel clocks */ + p1pll->reference_freq = radeon_bios16(dev_priv, pll_info + 0xe); + p1pll->reference_div = radeon_bios16(dev_priv, pll_info + 0x10); + p1pll->pll_out_min = radeon_bios32(dev_priv, pll_info + 0x12); + p1pll->pll_out_max = radeon_bios32(dev_priv, pll_info + 0x16); if (rev > 9) { - pll->pll_in_min = radeon_bios32(dev_priv, pll_info + 0x36); - pll->pll_in_max = radeon_bios32(dev_priv, pll_info + 0x3a); + p1pll->pll_in_min = radeon_bios32(dev_priv, pll_info + 0x36); + p1pll->pll_in_max = radeon_bios32(dev_priv, pll_info + 0x3a); } else { - pll->pll_in_min = 40; - pll->pll_in_max = 500; + p1pll->pll_in_min = 40; + p1pll->pll_in_max = 500; } + *p2pll = *p1pll; - pll->xclk = radeon_bios16(dev_priv, pll_info + 0x08); + /* system clock */ + spll->reference_freq = radeon_bios16(dev_priv, pll_info + 0x1a); + spll->reference_div = radeon_bios16(dev_priv, pll_info + 0x1c); + spll->pll_out_min = radeon_bios32(dev_priv, pll_info + 0x1e); + spll->pll_out_max = radeon_bios32(dev_priv, pll_info + 0x22); - // sclk/mclk use fixed point - //sclk = radeon_bios16(pll_info + 8) / 100.0; - //mclk = radeon_bios16(pll_info + 10) / 100.0; - //if (sclk == 0) sclk = 200; - //if (mclk == 0) mclk = 200; + if (rev > 10) { + spll->pll_in_min = radeon_bios32(dev_priv, pll_info + 0x48); + spll->pll_in_max = radeon_bios32(dev_priv, pll_info + 0x4c); + } else { + /* ??? */ + spll->pll_in_min = 40; + spll->pll_in_max = 500; + } + + /* memory clock */ + mpll->reference_freq = radeon_bios16(dev_priv, pll_info + 0x26); + mpll->reference_div = radeon_bios16(dev_priv, pll_info + 0x28); + mpll->pll_out_min = radeon_bios32(dev_priv, pll_info + 0x2a); + mpll->pll_out_max = radeon_bios32(dev_priv, pll_info + 0x2e); + + if (rev > 10) { + mpll->pll_in_min = radeon_bios32(dev_priv, pll_info + 0x5a); + mpll->pll_in_max = radeon_bios32(dev_priv, pll_info + 0x5e); + } else { + /* ??? */ + mpll->pll_in_min = 40; + mpll->pll_in_max = 500; + } + + /* default sclk/mclk */ + sclk = radeon_bios16(dev_priv, pll_info + 0x8); + mclk = radeon_bios16(dev_priv, pll_info + 0xa); + if (sclk == 0) + sclk = 200; + if (mclk == 0) + mclk = 200; + + mode_info->sclk = sclk; + mode_info->mclk = mclk; return true; } diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index c532ef0f..74037191 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -396,7 +396,10 @@ void radeon_compute_pll(struct radeon_pll *pll, (post_div == 7) || (post_div == 9) || (post_div == 10) || - (post_div == 11)) + (post_div == 11) || + (post_div == 13) || + (post_div == 14) || + (post_div == 15)) continue; } @@ -475,7 +478,10 @@ void radeon_compute_pll(struct radeon_pll *pll, void radeon_get_clock_info(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct radeon_pll *pll = &dev_priv->mode_info.pll; + struct radeon_pll *p1pll = &dev_priv->mode_info.p1pll; + struct radeon_pll *p2pll = &dev_priv->mode_info.p2pll; + struct radeon_pll *spll = &dev_priv->mode_info.spll; + struct radeon_pll *mpll = &dev_priv->mode_info.mpll; int ret; if (dev_priv->is_atom_bios) @@ -484,25 +490,56 @@ void radeon_get_clock_info(struct drm_device *dev) ret = radeon_combios_get_clock_info(dev); if (ret) { - - if (pll->reference_div < 2) pll->reference_div = 12; + if (p1pll->reference_div < 2) + p1pll->reference_div = 12; + if (p2pll->reference_div < 2) + p2pll->reference_div = 12; } else { // TODO FALLBACK } + /* pixel clocks */ if (radeon_is_avivo(dev_priv)) { - pll->min_post_div = 2; - pll->max_post_div = 0x7f; + p1pll->min_post_div = 2; + p1pll->max_post_div = 0x7f; + p2pll->min_post_div = 2; + p2pll->max_post_div = 0x7f; } else { - pll->min_post_div = 1; - pll->max_post_div = 12; // 16 on crtc 0?? + p1pll->min_post_div = 1; + p1pll->max_post_div = 16; + p2pll->min_post_div = 1; + p2pll->max_post_div = 12; } - pll->min_ref_div = 2; - pll->max_ref_div = 0x3ff; - pll->min_feedback_div = 4; - pll->max_feedback_div = 0x7ff; - pll->best_vco = 0; + p1pll->min_ref_div = 2; + p1pll->max_ref_div = 0x3ff; + p1pll->min_feedback_div = 4; + p1pll->max_feedback_div = 0x7ff; + p1pll->best_vco = 0; + + p2pll->min_ref_div = 2; + p2pll->max_ref_div = 0x3ff; + p2pll->min_feedback_div = 4; + p2pll->max_feedback_div = 0x7ff; + p2pll->best_vco = 0; + + /* system clock */ + spll->min_post_div = 1; + spll->max_post_div = 1; + spll->min_ref_div = 2; + spll->max_ref_div = 0xff; + spll->min_feedback_div = 4; + spll->max_feedback_div = 0xff; + spll->best_vco = 0; + + /* memory clock */ + mpll->min_post_div = 1; + mpll->max_post_div = 1; + mpll->min_ref_div = 2; + mpll->max_ref_div = 0xff; + mpll->min_feedback_div = 4; + mpll->max_feedback_div = 0xff; + mpll->best_vco = 0; } diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index 58c2f9dc..f029c478 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -409,7 +409,7 @@ static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode uint32_t htotal_cntl = 0; uint32_t vclk_ecp_cntl; - struct radeon_pll *pll = &dev_priv->mode_info.pll; + struct radeon_pll *pll = &dev_priv->mode_info.p1pll; struct { int divider; @@ -485,7 +485,7 @@ static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode vclk_ecp_cntl = (RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL) & ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK; - pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.pll.reference_freq, + pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.p1pll.reference_freq, ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK); @@ -812,7 +812,7 @@ static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode uint32_t htotal_cntl2 = 0; uint32_t pixclks_cntl; - struct radeon_pll *pll = &dev_priv->mode_info.pll; + struct radeon_pll *pll = &dev_priv->mode_info.p2pll; struct { int divider; @@ -882,7 +882,7 @@ static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); - pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.pll.reference_freq, + pll_gain = radeon_compute_pll_gain(dev_priv->mode_info.p2pll.reference_freq, p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK); diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index a4ee78a8..62672c33 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -161,10 +161,22 @@ struct radeon_pll { uint32_t best_vco; }; +struct radeon_i2c_chan { + struct drm_device *dev; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; + struct radeon_i2c_bus_rec rec; +}; + struct radeon_mode_info { struct atom_context *atom_context; struct radeon_bios_connector bios_connector[RADEON_MAX_BIOS_CONNECTOR]; - struct radeon_pll pll; + struct radeon_pll p1pll; + struct radeon_pll p2pll; + struct radeon_pll spll; + struct radeon_pll mpll; + uint32_t mclk; + uint32_t sclk; }; struct radeon_crtc { @@ -178,14 +190,6 @@ struct radeon_crtc { struct drm_mode_set mode_set; }; -struct radeon_i2c_chan { - struct drm_device *dev; - struct i2c_adapter adapter; - struct i2c_algo_bit_data algo; - struct radeon_i2c_bus_rec rec; -}; - - #define RADEON_USE_RMX 1 struct radeon_encoder { @@ -278,6 +282,8 @@ extern void atombios_crtc_mode_set(struct drm_crtc *crtc, int x, int y); extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); +extern void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y); + extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 6c5bf03b..1ad005b7 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2506,8 +2506,6 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) else dev_priv->flags |= RADEON_IS_PCI; - - DRM_DEBUG("%s card detected\n", ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); @@ -2527,7 +2525,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) if (dev_priv->chip_family == CHIP_R300 && (RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) == RADEON_CFG_ATI_REV_A11) dev_priv->pll_errata |= CHIP_ERRATA_R300_CG; - + if (dev_priv->chip_family == CHIP_RV200 || dev_priv->chip_family == CHIP_RS200) dev_priv->pll_errata |= CHIP_ERRATA_PLL_DUMMYREADS; -- cgit v1.2.3 From 34af71c42a66e5ef6a9a08250ca541030ca3cc4f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Sep 2008 16:07:41 -0400 Subject: radeon: add function to configure PCIE lanes --- linux-core/radeon_pm.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ linux-core/radeon_reg.h | 18 +++++++++++++++ shared-core/radeon_cp.c | 2 +- shared-core/radeon_drv.h | 1 + 4 files changed, 80 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index e9a6130a..5d14384c 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -178,3 +178,63 @@ int radeon_resume(struct drm_device *dev) return 0; } + +bool radeon_set_pcie_lanes(struct drm_device *dev, int lanes) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t link_width_cntl, mask; + + /* FIXME wait for idle */ + + + switch (lanes) { + case 0: + mask = RADEON_PCIE_LC_LINK_WIDTH_X0; + break; + case 1: + mask = RADEON_PCIE_LC_LINK_WIDTH_X1; + break; + case 2: + mask = RADEON_PCIE_LC_LINK_WIDTH_X2; + break; + case 4: + mask = RADEON_PCIE_LC_LINK_WIDTH_X4; + break; + case 8: + mask = RADEON_PCIE_LC_LINK_WIDTH_X8; + break; + case 12: + mask = RADEON_PCIE_LC_LINK_WIDTH_X12; + break; + case 16: + default: + mask = RADEON_PCIE_LC_LINK_WIDTH_X16; + break; + } + + link_width_cntl = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) == + (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT)) + return true; + + link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK | + RADEON_PCIE_LC_RECONFIG_NOW | + RADEON_PCIE_LC_RECONFIG_LATER | + RADEON_PCIE_LC_SHORT_RECONFIG_EN); + link_width_cntl |= mask; + RADEON_WRITE_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl); + RADEON_WRITE_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl | RADEON_PCIE_LC_RECONFIG_NOW); + + /* wait for lane set to complete */ + link_width_cntl = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_LC_LINK_WIDTH_CNTL); + while (link_width_cntl == 0xffffffff) + link_width_cntl = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_LC_LINK_WIDTH_CNTL); + + if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) == + (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT)) + return true; + else + return false; +} + diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index e7f30817..c4bc7a80 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -274,6 +274,24 @@ #define RADEON_BUS_CNTL1 0x0034 # define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4) +//#define RADEON_PCIE_INDEX 0x0030 +//#define RADEON_PCIE_DATA 0x0034 +#define RADEON_PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE */ +# define RADEON_PCIE_LC_LINK_WIDTH_SHIFT 0 +# define RADEON_PCIE_LC_LINK_WIDTH_MASK 0x7 +# define RADEON_PCIE_LC_LINK_WIDTH_X0 0 +# define RADEON_PCIE_LC_LINK_WIDTH_X1 1 +# define RADEON_PCIE_LC_LINK_WIDTH_X2 2 +# define RADEON_PCIE_LC_LINK_WIDTH_X4 3 +# define RADEON_PCIE_LC_LINK_WIDTH_X8 4 +# define RADEON_PCIE_LC_LINK_WIDTH_X12 5 +# define RADEON_PCIE_LC_LINK_WIDTH_X16 6 +# define RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT 4 +# define RADEON_PCIE_LC_LINK_WIDTH_RD_MASK 0x70 +# define RADEON_PCIE_LC_RECONFIG_NOW (1 << 8) +# define RADEON_PCIE_LC_RECONFIG_LATER (1 << 9) +# define RADEON_PCIE_LC_SHORT_RECONFIG_EN (1 << 10) + #define RADEON_CACHE_CNTL 0x1724 #define RADEON_CACHE_LINE 0x0f0c /* PCI */ #define RADEON_CAPABILITIES_ID 0x0f50 /* PCI */ diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 1ad005b7..b934d3bc 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -235,7 +235,7 @@ void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t da radeon_pll_errata_after_data(dev_priv); } -static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) +u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) { RADEON_WRITE8(RADEON_PCIE_INDEX, addr & 0xff); return RADEON_READ(RADEON_PCIE_DATA); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 82d9d001..25a07e30 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1298,6 +1298,7 @@ int radeon_resume(struct drm_device *dev); extern u32 RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr); extern void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data); +extern u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr); #define RADEON_WRITE_P(reg, val, mask) \ do { \ -- cgit v1.2.3 From 6988176195450da9033a0f0f21eafc6ae0a7a6a4 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Sep 2008 16:42:22 -0400 Subject: radeon: Add functions to set mem/eng clocks --- linux-core/radeon_atombios.c | 26 +++++++++++++++++++++++++ linux-core/radeon_display.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ linux-core/radeon_reg.h | 7 +++++++ 3 files changed, 78 insertions(+) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index 8bf6a7ce..4d48593b 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -450,6 +450,32 @@ void radeon_atom_static_pwrmgt_setup(struct drm_device *dev, int enable) atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } +void radeon_atom_set_engine_clock(struct drm_device *dev, int eng_clock) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct atom_context *ctx = mode_info->atom_context; + SET_ENGINE_CLOCK_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock); + + args.ulTargetEngineClock = eng_clock; /* 10 khz */ + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + +void radeon_atom_set_memory_clock(struct drm_device *dev, int mem_clock) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct atom_context *ctx = mode_info->atom_context; + SET_MEMORY_CLOCK_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock); + + args.ulTargetMemoryClock = mem_clock; /* 10 khz */ + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); +} + void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 74037191..fd0855e5 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -543,6 +543,51 @@ void radeon_get_clock_info(struct drm_device *dev) } +/* not sure of the best place for these */ +/* 10 khz */ +void radeon_legacy_set_engine_clock(struct drm_device *dev, int eng_clock) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_pll *spll = &mode_info->spll; + uint32_t ref_div, fb_div; + uint32_t m_spll_ref_fb_div; + + /* FIXME wait for idle */ + + m_spll_ref_fb_div = RADEON_READ_PLL(dev_priv, RADEON_M_SPLL_REF_FB_DIV); + m_spll_ref_fb_div &= ((RADEON_M_SPLL_REF_DIV_MASK << RADEON_M_SPLL_REF_DIV_SHIFT) | + (RADEON_MPLL_FB_DIV_MASK << RADEON_MPLL_FB_DIV_SHIFT)); + ref_div = m_spll_ref_fb_div & RADEON_M_SPLL_REF_DIV_MASK; + + fb_div = radeon_div(eng_clock * ref_div, spll->reference_freq); + m_spll_ref_fb_div |= (fb_div & RADEON_SPLL_FB_DIV_MASK) << RADEON_SPLL_FB_DIV_SHIFT; + RADEON_WRITE_PLL(dev_priv, RADEON_M_SPLL_REF_FB_DIV, m_spll_ref_fb_div); + +} + +/* 10 khz */ +void radeon_legacy_set_memory_clock(struct drm_device *dev, int mem_clock) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct radeon_pll *mpll = &mode_info->mpll; + uint32_t ref_div, fb_div; + uint32_t m_spll_ref_fb_div; + + /* FIXME wait for idle */ + + m_spll_ref_fb_div = RADEON_READ_PLL(dev_priv, RADEON_M_SPLL_REF_FB_DIV); + m_spll_ref_fb_div &= ((RADEON_M_SPLL_REF_DIV_MASK << RADEON_M_SPLL_REF_DIV_SHIFT) | + (RADEON_SPLL_FB_DIV_MASK << RADEON_SPLL_FB_DIV_SHIFT)); + ref_div = m_spll_ref_fb_div & RADEON_M_SPLL_REF_DIV_MASK; + + fb_div = radeon_div(mem_clock * ref_div, mpll->reference_freq); + m_spll_ref_fb_div |= (fb_div & RADEON_MPLL_FB_DIV_MASK) << RADEON_MPLL_FB_DIV_SHIFT; + RADEON_WRITE_PLL(dev_priv, RADEON_M_SPLL_REF_FB_DIV, m_spll_ref_fb_div); + +} + static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index c4bc7a80..113a8267 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -1549,6 +1549,13 @@ #define RADEON_SC_TOP_LEFT_C 0x1c88 # define RADEON_SC_SIGN_MASK_LO 0x8000 # define RADEON_SC_SIGN_MASK_HI 0x80000000 +#define RADEON_M_SPLL_REF_FB_DIV 0x000a /* PLL */ +# define RADEON_M_SPLL_REF_DIV_SHIFT 0 +# define RADEON_M_SPLL_REF_DIV_MASK 0xff +# define RADEON_MPLL_FB_DIV_SHIFT 8 +# define RADEON_MPLL_FB_DIV_MASK 0xff +# define RADEON_SPLL_FB_DIV_SHIFT 16 +# define RADEON_SPLL_FB_DIV_MASK 0xff #define RADEON_SCLK_CNTL 0x000d /* PLL */ # define RADEON_SCLK_SRC_SEL_MASK 0x0007 # define RADEON_DYN_STOP_LAT_MASK 0x00007ff8 -- cgit v1.2.3 From 075ed1d6fd1d58c1f46d556df79f44153f10edd8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 18 Sep 2008 17:27:00 -0400 Subject: radeon: pll and interlace updates from the ddx also some formatting cleanup in radeon_reg.h --- linux-core/atombios_crtc.c | 22 +++++++++++++++----- linux-core/radeon_display.c | 7 ++++++- linux-core/radeon_encoders.c | 16 +++++++++++++-- linux-core/radeon_legacy_crtc.c | 7 ++++++- linux-core/radeon_mode.h | 15 +++++++++----- linux-core/radeon_reg.h | 45 +++++++++++++++++++++-------------------- 6 files changed, 76 insertions(+), 36 deletions(-) diff --git a/linux-core/atombios_crtc.c b/linux-core/atombios_crtc.c index 03077a13..cefe9225 100644 --- a/linux-core/atombios_crtc.c +++ b/linux-core/atombios_crtc.c @@ -150,8 +150,7 @@ void atombios_crtc_set_timing(struct drm_crtc *crtc, SET_CRTC_TIMING_PARAMETERS_ atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&conv_param); } -void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, - int pll_flags) +void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; @@ -164,10 +163,17 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, uint32_t sclock = mode->clock; uint32_t ref_div = 0, fb_div = 0, post_div = 0; struct radeon_pll *pll; + int pll_flags = 0; memset(&spc_param, 0, sizeof(SET_PIXEL_CLOCK_PS_ALLOCATION)); - pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + if (!radeon_is_avivo(dev_priv)) + pll_flags |= RADEON_PLL_LEGACY; + + if (mode->clock > 120000) /* range limits??? */ + pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + else + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; if (radeon_crtc->crtc_id == 0) pll = &dev_priv->mode_info.p1pll; @@ -293,6 +299,12 @@ void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y) RADEON_WRITE(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); + if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + RADEON_WRITE(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, + AVIVO_D1MODE_INTERLEAVE_EN); + else + RADEON_WRITE(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, + 0); } void atombios_crtc_mode_set(struct drm_crtc *crtc, @@ -305,7 +317,6 @@ void atombios_crtc_mode_set(struct drm_crtc *crtc, struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; - int pll_flags = 0; /* TODO color tiling */ memset(&crtc_timing, 0, sizeof(crtc_timing)); @@ -347,9 +358,10 @@ void atombios_crtc_mode_set(struct drm_crtc *crtc, else radeon_crtc_set_base(crtc, x, y); - atombios_crtc_set_pll(crtc, adjusted_mode, pll_flags); + atombios_crtc_set_pll(crtc, adjusted_mode); atombios_crtc_set_timing(crtc, &crtc_timing); + } static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index fd0855e5..e2d02be0 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -451,7 +451,12 @@ void radeon_compute_pll(struct radeon_pll *pll, best_freq = current_freq; best_error = error; best_vco_diff = vco_diff; - } else if ((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) { + } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || + ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || + ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || + ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || + ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || + ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) { best_post_div = post_div; best_ref_div = ref_div; best_feedback_div = feedback_div; diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 82ffcfb0..98be7057 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -517,9 +517,15 @@ static void radeon_atom_dac_dpms(struct drm_encoder *encoder, int mode) } static bool radeon_atom_dac_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { + + /* hw bug */ + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) + && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; + return true; } @@ -987,6 +993,12 @@ static bool radeon_atom_tmds_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + + /* hw bug */ + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) + && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; + return true; } diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index f029c478..d51fc52d 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -401,7 +401,7 @@ static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode uint32_t post_divider = 0; uint32_t freq = 0; uint8_t pll_gain; - int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV; + int pll_flags = RADEON_PLL_LEGACY; bool use_bios_divs = false; /* PLL registers */ uint32_t ppll_ref_div = 0; @@ -431,6 +431,11 @@ static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode { 0, 0 } }; + if (mode->clock > 120000) /* range limits??? */ + pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + else + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 62672c33..d4b33dd9 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -137,11 +137,16 @@ struct radeon_tmds_pll { #define RADEON_MAX_BIOS_CONNECTOR 16 -#define RADEON_PLL_USE_BIOS_DIVS (1 << 0) -#define RADEON_PLL_NO_ODD_POST_DIV (1 << 1) -#define RADEON_PLL_USE_REF_DIV (1 << 2) -#define RADEON_PLL_LEGACY (1 << 3) -#define RADEON_PLL_PREFER_LOW_REF_DIV (1 << 4) +#define RADEON_PLL_USE_BIOS_DIVS (1 << 0) +#define RADEON_PLL_NO_ODD_POST_DIV (1 << 1) +#define RADEON_PLL_USE_REF_DIV (1 << 2) +#define RADEON_PLL_LEGACY (1 << 3) +#define RADEON_PLL_PREFER_LOW_REF_DIV (1 << 4) +#define RADEON_PLL_PREFER_HIGH_REF_DIV (1 << 5) +#define RADEON_PLL_PREFER_LOW_FB_DIV (1 << 6) +#define RADEON_PLL_PREFER_HIGH_FB_DIV (1 << 7) +#define RADEON_PLL_PREFER_LOW_POST_DIV (1 << 8) +#define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9) struct radeon_pll { uint16_t reference_freq; diff --git a/linux-core/radeon_reg.h b/linux-core/radeon_reg.h index 113a8267..8698e861 100644 --- a/linux-core/radeon_reg.h +++ b/linux-core/radeon_reg.h @@ -3583,7 +3583,7 @@ #define AVIVO_D1CRTC_V_SYNC_B_CNTL 0x6034 #define AVIVO_D1CRTC_CONTROL 0x6080 -# define AVIVO_CRTC_EN (1<<0) +# define AVIVO_CRTC_EN (1 << 0) #define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 #define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 #define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c @@ -3595,30 +3595,30 @@ #define AVIVO_D1GRPH_ENABLE 0x6100 #define AVIVO_D1GRPH_CONTROL 0x6104 -# define AVIVO_D1GRPH_CONTROL_DEPTH_8BPP (0<<0) -# define AVIVO_D1GRPH_CONTROL_DEPTH_16BPP (1<<0) -# define AVIVO_D1GRPH_CONTROL_DEPTH_32BPP (2<<0) -# define AVIVO_D1GRPH_CONTROL_DEPTH_64BPP (3<<0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_8BPP (0 << 0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_16BPP (1 << 0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_32BPP (2 << 0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_64BPP (3 << 0) -# define AVIVO_D1GRPH_CONTROL_8BPP_INDEXED (0<<8) +# define AVIVO_D1GRPH_CONTROL_8BPP_INDEXED (0 << 8) -# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555 (0<<8) -# define AVIVO_D1GRPH_CONTROL_16BPP_RGB565 (1<<8) -# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444 (2<<8) -# define AVIVO_D1GRPH_CONTROL_16BPP_AI88 (3<<8) -# define AVIVO_D1GRPH_CONTROL_16BPP_MONO16 (4<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555 (0 << 8) +# define AVIVO_D1GRPH_CONTROL_16BPP_RGB565 (1 << 8) +# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444 (2 << 8) +# define AVIVO_D1GRPH_CONTROL_16BPP_AI88 (3 << 8) +# define AVIVO_D1GRPH_CONTROL_16BPP_MONO16 (4 << 8) -# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888 (0<<8) -# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010 (1<<8) -# define AVIVO_D1GRPH_CONTROL_32BPP_DIGITAL (2<<8) -# define AVIVO_D1GRPH_CONTROL_32BPP_8B_ARGB2101010 (3<<8) +# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888 (0 << 8) +# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010 (1 << 8) +# define AVIVO_D1GRPH_CONTROL_32BPP_DIGITAL (2 << 8) +# define AVIVO_D1GRPH_CONTROL_32BPP_8B_ARGB2101010 (3 << 8) -# define AVIVO_D1GRPH_CONTROL_64BPP_ARGB16161616 (0<<8) +# define AVIVO_D1GRPH_CONTROL_64BPP_ARGB16161616 (0 << 8) -# define AVIVO_D1GRPH_SWAP_RB (1<<16) -# define AVIVO_D1GRPH_TILED (1<<20) -# define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1<<21) +# define AVIVO_D1GRPH_SWAP_RB (1 << 16) +# define AVIVO_D1GRPH_TILED (1 << 20) +# define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1 << 21) #define AVIVO_D1GRPH_LUT_SEL 0x6108 #define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 @@ -3644,7 +3644,7 @@ #define AVIVO_D1CUR_POSITION 0x6414 #define AVIVO_D1CUR_HOT_SPOT 0x6418 #define AVIVO_D1CUR_UPDATE 0x6424 -# define AVIVO_D1CURSOR_UPDATE_LOCK (1 << 16) +# define AVIVO_D1CURSOR_UPDATE_LOCK (1 << 16) #define AVIVO_DC_LUT_RW_SELECT 0x6480 #define AVIVO_DC_LUT_RW_MODE 0x6484 @@ -3664,7 +3664,8 @@ #define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 #define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 - +#define AVIVO_D1MODE_DATA_FORMAT 0x6528 +# define AVIVO_D1MODE_INTERLEAVE_EN (1 << 0) #define AVIVO_D1MODE_DESKTOP_HEIGHT 0x652C #define AVIVO_D1MODE_VIEWPORT_START 0x6580 #define AVIVO_D1MODE_VIEWPORT_SIZE 0x6584 @@ -3674,7 +3675,7 @@ #define AVIVO_D1SCL_SCALER_ENABLE 0x6590 #define AVIVO_D1SCL_SCALER_TAP_CONTROL 0x6594 #define AVIVO_D1SCL_UPDATE 0x65cc -# define AVIVO_D1SCL_UPDATE_LOCK (1<<16) +# define AVIVO_D1SCL_UPDATE_LOCK (1 << 16) /* second crtc */ #define AVIVO_D2CRTC_H_TOTAL 0x6800 -- cgit v1.2.3 From dc3a6834f615a538cf582ec7e583f203d43ba204 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 19 Sep 2008 08:03:34 +1000 Subject: radeon: tmds bracket failure found by krh. --- linux-core/radeon_atombios.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index 4d48593b..0915a7f8 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -374,9 +374,9 @@ void radeon_atombios_get_tmds_info(struct radeon_encoder *encoder) for (i = 0; i < 4; i++) { encoder->tmds_pll[i].freq = le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency); encoder->tmds_pll[i].value = tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f; - encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VCO_Gain & 0x3f << 6); - encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_DutyCycle & 0xf << 12); - encoder->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VoltageSwing & 0xf << 16); + encoder->tmds_pll[i].value |= ((tmds_info->asMiscInfo[i].ucPLL_VCO_Gain & 0x3f) << 6); + encoder->tmds_pll[i].value |= ((tmds_info->asMiscInfo[i].ucPLL_DutyCycle & 0xf) << 12); + encoder->tmds_pll[i].value |= ((tmds_info->asMiscInfo[i].ucPLL_VoltageSwing & 0xf) << 16); DRM_DEBUG("TMDS PLL From BIOS %u %x\n", encoder->tmds_pll[i].freq, -- cgit v1.2.3 From d6b853cf81c3cd29ab81b9f93909b31330142750 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 20 Sep 2008 00:48:11 +1000 Subject: radeon: fix voverplus calculation --- linux-core/radeon_combios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index f1693e69..ae1ef2f9 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -749,7 +749,7 @@ bool radeon_combios_get_lvds_info(struct radeon_encoder *encoder) encoder->vblank = (radeon_bios16(dev_priv, tmp + 24) - radeon_bios16(dev_priv, tmp + 26)); - encoder->voverplus = ((radeon_bios16(dev_priv, tmp + 28) & 0x7fff) - + encoder->voverplus = ((radeon_bios16(dev_priv, tmp + 28) & 0x7ff) - radeon_bios16(dev_priv, tmp + 26)); encoder->vsync_width = ((radeon_bios16(dev_priv, tmp + 28) & 0xf800) >> 11); encoder->dotclock = radeon_bios16(dev_priv, tmp + 9) * 10; -- cgit v1.2.3 From 66237cd3c26faa20403ddb6903252ce49cc1fd72 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 19 Sep 2008 11:19:00 -0400 Subject: radeon: rmx_fixup() fixes for legacy chips --- linux-core/radeon_encoders.c | 77 +++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 98be7057..03878609 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -35,47 +35,50 @@ void radeon_rmx_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + if (mode->hdisplay < radeon_encoder->panel_xres || mode->vdisplay < radeon_encoder->panel_yres) { radeon_encoder->flags |= RADEON_USE_RMX; - adjusted_mode->hdisplay = radeon_encoder->panel_xres; - adjusted_mode->vdisplay = radeon_encoder->panel_yres; - adjusted_mode->htotal = radeon_encoder->panel_xres + radeon_encoder->hblank; - adjusted_mode->hsync_start = radeon_encoder->panel_xres + radeon_encoder->hoverplus; - adjusted_mode->hsync_end = adjusted_mode->hsync_start + radeon_encoder->hsync_width; - adjusted_mode->vtotal = radeon_encoder->panel_yres + radeon_encoder->vblank; - adjusted_mode->vsync_start = radeon_encoder->panel_yres + radeon_encoder->voverplus; - adjusted_mode->vsync_end = adjusted_mode->vsync_start + radeon_encoder->vsync_width; - /* update crtc values */ - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); - /* adjust crtc values */ - adjusted_mode->crtc_hdisplay = radeon_encoder->panel_xres; - adjusted_mode->crtc_vdisplay = radeon_encoder->panel_yres; - adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + radeon_encoder->hblank; - adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + radeon_encoder->hoverplus; - adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + radeon_encoder->hsync_width; - adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + radeon_encoder->vblank; - adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + radeon_encoder->voverplus; - adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + radeon_encoder->vsync_width; - } else { - adjusted_mode->htotal = radeon_encoder->panel_xres + radeon_encoder->hblank; - adjusted_mode->hsync_start = radeon_encoder->panel_xres + radeon_encoder->hoverplus; - adjusted_mode->hsync_end = adjusted_mode->hsync_start + radeon_encoder->hsync_width; - adjusted_mode->vtotal = radeon_encoder->panel_yres + radeon_encoder->vblank; - adjusted_mode->vsync_start = radeon_encoder->panel_yres + radeon_encoder->voverplus; - adjusted_mode->vsync_end = adjusted_mode->vsync_start + radeon_encoder->vsync_width; - /* update crtc values */ - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); - /* adjust crtc values */ - adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + radeon_encoder->hblank; - adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + radeon_encoder->hoverplus; - adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + radeon_encoder->hsync_width; - adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + radeon_encoder->vblank; - adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + radeon_encoder->voverplus; - adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + radeon_encoder->vsync_width; + if (radeon_is_avivo(dev_priv)) { + adjusted_mode->hdisplay = radeon_encoder->panel_xres; + adjusted_mode->vdisplay = radeon_encoder->panel_yres; + adjusted_mode->htotal = radeon_encoder->panel_xres + radeon_encoder->hblank; + adjusted_mode->hsync_start = radeon_encoder->panel_xres + radeon_encoder->hoverplus; + adjusted_mode->hsync_end = adjusted_mode->hsync_start + radeon_encoder->hsync_width; + adjusted_mode->vtotal = radeon_encoder->panel_yres + radeon_encoder->vblank; + adjusted_mode->vsync_start = radeon_encoder->panel_yres + radeon_encoder->voverplus; + adjusted_mode->vsync_end = adjusted_mode->vsync_start + radeon_encoder->vsync_width; + /* update crtc values */ + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + /* adjust crtc values */ + adjusted_mode->crtc_hdisplay = radeon_encoder->panel_xres; + adjusted_mode->crtc_vdisplay = radeon_encoder->panel_yres; + adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + radeon_encoder->hblank; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + radeon_encoder->hoverplus; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + radeon_encoder->hsync_width; + adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + radeon_encoder->vblank; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + radeon_encoder->voverplus; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + radeon_encoder->vsync_width; + } else { + adjusted_mode->htotal = radeon_encoder->panel_xres + radeon_encoder->hblank; + adjusted_mode->hsync_start = radeon_encoder->panel_xres + radeon_encoder->hoverplus; + adjusted_mode->hsync_end = adjusted_mode->hsync_start + radeon_encoder->hsync_width; + adjusted_mode->vtotal = radeon_encoder->panel_yres + radeon_encoder->vblank; + adjusted_mode->vsync_start = radeon_encoder->panel_yres + radeon_encoder->voverplus; + adjusted_mode->vsync_end = adjusted_mode->vsync_start + radeon_encoder->vsync_width; + /* update crtc values */ + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + /* adjust crtc values */ + adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + radeon_encoder->hblank; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + radeon_encoder->hoverplus; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + radeon_encoder->hsync_width; + adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + radeon_encoder->vblank; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + radeon_encoder->voverplus; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + radeon_encoder->vsync_width; + } } - adjusted_mode->clock = radeon_encoder->dotclock; - adjusted_mode->flags = radeon_encoder->flags; } -- cgit v1.2.3 From a2216491c619082ad9a01bc949648834dc5a0d2f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Aug 2008 21:20:19 +1000 Subject: drm: fix brace placement --- linux-core/drm_crtc_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 71bdc447..b5073155 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -291,9 +291,8 @@ static int drm_pick_crtcs(struct drm_device *dev, best_crtcs[n] = NULL; best_crtc = NULL; best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); - if (modes[n] == NULL) { + if (modes[n] == NULL) return best_score; - } crtcs = kmalloc(dev->mode_config.num_connector * sizeof(struct drm_crtc *), GFP_KERNEL); if (!crtcs) -- cgit v1.2.3 From 5fdfbee22acb8eaaa834457c30e6f68883ab1353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 23 Sep 2008 16:47:34 +1000 Subject: Store the buffer object backing the fb as a void pointer, not a handle. This lets us defer handle creation until userspace acutally asks for one, at which point we also have a drm_file to associate it with. --- linux-core/atombios_crtc.c | 4 +++- linux-core/drm_crtc.c | 2 +- linux-core/drm_crtc.h | 5 ++++- linux-core/drm_crtc_helper.c | 5 +++-- linux-core/drm_crtc_helper.h | 3 ++- linux-core/radeon_display.c | 42 ++++++++++++++++++++++++++--------------- linux-core/radeon_fb.c | 6 ++---- linux-core/radeon_legacy_crtc.c | 8 ++++++-- linux-core/radeon_mode.h | 7 +++---- linux-core/radeon_pm.c | 9 +++++---- 10 files changed, 56 insertions(+), 35 deletions(-) diff --git a/linux-core/atombios_crtc.c b/linux-core/atombios_crtc.c index cefe9225..16bcbe87 100644 --- a/linux-core/atombios_crtc.c +++ b/linux-core/atombios_crtc.c @@ -244,6 +244,7 @@ void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y) struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_framebuffer *radeon_fb; + struct drm_gem_object *obj; struct drm_radeon_gem_object *obj_priv; uint32_t fb_location, fb_format, fb_pitch_pixels; @@ -252,7 +253,8 @@ void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y) radeon_fb = to_radeon_framebuffer(crtc->fb); - obj_priv = radeon_fb->obj->driver_private; + obj = radeon_fb->base.mm_private; + obj_priv = obj->driver_private; fb_location = obj_priv->bo->offset + dev_priv->fb_location; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index aa6749d6..2fefd1d2 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1631,8 +1631,8 @@ int drm_mode_getfb(struct drm_device *dev, r->width = fb->width; r->depth = fb->depth; r->bpp = fb->bits_per_pixel; - r->handle = fb->mm_handle; r->pitch = fb->pitch; + fb->funcs->create_handle(fb, file_priv, &r->handle); out: mutex_unlock(&dev->mode_config.mutex); diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 5f63dc2e..6a73a71b 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -220,6 +220,9 @@ struct drm_display_info { struct drm_framebuffer_funcs { void (*destroy)(struct drm_framebuffer *framebuffer); + int (*create_handle)(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle); }; struct drm_framebuffer { @@ -237,7 +240,7 @@ struct drm_framebuffer { void *fbdev; u32 pseudo_palette[17]; struct list_head filp_head; - uint32_t mm_handle; + void *mm_private; }; struct drm_property_blob { diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index b5073155..b334f5b5 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -771,14 +771,15 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev) EXPORT_SYMBOL(drm_helper_hotplug_stage_two); int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd *mode_cmd) + struct drm_mode_fb_cmd *mode_cmd, + void *mm_private) { fb->width = mode_cmd->width; fb->height = mode_cmd->height; fb->pitch = mode_cmd->pitch; fb->bits_per_pixel = mode_cmd->bpp; fb->depth = mode_cmd->depth; - fb->mm_handle = mode_cmd->handle; + fb->mm_private = mm_private; return 0; } diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index c0719157..01b14239 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -75,7 +75,8 @@ extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_m extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd *mode_cmd); + struct drm_mode_fb_cmd *mode_cmd, + void *mm_private); static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) { diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index e2d02be0..e8d141ec 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -605,15 +605,25 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) kfree(radeon_fb); } +static int radeon_user_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + struct drm_gem_object *object = fb->mm_private; + + return drm_gem_handle_create(file_priv, object, handle); +} + static const struct drm_framebuffer_funcs radeon_fb_funcs = { .destroy = radeon_user_framebuffer_destroy, + .create_handle = radeon_user_framebuffer_create_handle, }; -struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, - struct drm_file *filp, - struct drm_mode_fb_cmd *mode_cmd) +struct drm_framebuffer * +radeon_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + void *mm_private) { - struct radeon_framebuffer *radeon_fb; radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); @@ -621,20 +631,22 @@ struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, return NULL; drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs); - drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd); - - if (filp) { - radeon_fb->obj = drm_gem_object_lookup(dev, filp, - mode_cmd->handle); - if (!radeon_fb->obj) { - kfree(radeon_fb); - return NULL; - } - drm_gem_object_unreference(radeon_fb->obj); - } + drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd, mm_private); return &radeon_fb->base; } +static struct drm_framebuffer * +radeon_user_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, + struct drm_mode_fb_cmd *mode_cmd) +{ + struct radeon_framebuffer *radeon_fb; + void *mm_private; + + mm_private = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); + return radeon_framebuffer_create(dev, mode_cmd, mm_private); +} + static const struct drm_mode_config_funcs radeon_mode_funcs = { .fb_create = radeon_user_framebuffer_create, .fb_changed = radeonfb_probe, diff --git a/linux-core/radeon_fb.c b/linux-core/radeon_fb.c index 86459674..8c9461da 100644 --- a/linux-core/radeon_fb.c +++ b/linux-core/radeon_fb.c @@ -744,7 +744,7 @@ int radeonfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_heigh } mutex_lock(&dev->struct_mutex); - fb = radeon_user_framebuffer_create(dev, NULL, &mode_cmd); + fb = radeon_framebuffer_create(dev, &mode_cmd, fbo); if (!fb) { DRM_ERROR("failed to allocate fb.\n"); ret = -ENOMEM; @@ -756,8 +756,6 @@ int radeonfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_heigh radeon_fb = to_radeon_framebuffer(fb); *radeon_fb_p = radeon_fb; - radeon_fb->obj = fbo; - info = framebuffer_alloc(sizeof(struct radeonfb_par), device); if (!info) { ret = -ENOMEM; @@ -1150,7 +1148,7 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) unregister_framebuffer(info); drm_bo_kunmap(&radeon_fb->kmap_obj); mutex_lock(&dev->struct_mutex); - drm_gem_object_unreference(radeon_fb->obj); + drm_gem_object_unreference(fb->mm_private); mutex_unlock(&dev->struct_mutex); framebuffer_release(info); } diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index d51fc52d..bc28c436 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -176,6 +176,7 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_framebuffer *radeon_fb; + struct drm_gem_object *obj; struct drm_radeon_gem_object *obj_priv; uint32_t base; uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0; @@ -185,7 +186,8 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) radeon_fb = to_radeon_framebuffer(crtc->fb); - obj_priv = radeon_fb->obj->driver_private; + obj = radeon_fb->base.mm_private; + obj_priv = obj->driver_private; crtc_offset = obj_priv->bo->offset; @@ -599,6 +601,7 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_framebuffer *radeon_fb; + struct drm_gem_object *obj; struct drm_radeon_gem_object *obj_priv; uint32_t base; uint32_t crtc2_offset, crtc2_offset_cntl, crtc2_tile_x0_y0 = 0; @@ -608,7 +611,8 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) radeon_fb = to_radeon_framebuffer(crtc->fb); - obj_priv = radeon_fb->obj->driver_private; + obj = radeon_fb->base.mm_private; + obj_priv = obj->driver_private; crtc2_offset = obj_priv->bo->offset; diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index d4b33dd9..577c3cf9 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -248,7 +248,6 @@ struct radeon_connector { struct radeon_framebuffer { struct drm_framebuffer base; - struct drm_gem_object *obj; struct drm_bo_kmap_obj kmap_obj; }; @@ -313,9 +312,9 @@ extern void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock); extern void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev); extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); -struct drm_framebuffer *radeon_user_framebuffer_create(struct drm_device *dev, - struct drm_file *filp, - struct drm_mode_fb_cmd *mode_cmd); +struct drm_framebuffer *radeon_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + void *mm_private); int radeonfb_probe(struct drm_device *dev); diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index 5d14384c..de107797 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -54,10 +54,10 @@ int radeon_suspend(struct drm_device *dev, pm_message_t state) if (!radeon_fb) continue; - if (!radeon_fb->obj) + if (!radeon_fb->base.mm_private) continue; - radeon_gem_object_unpin(radeon_fb->obj); + radeon_gem_object_unpin(radeon_fb->base.mm_private); } if (!(dev_priv->flags & RADEON_IS_IGP)) @@ -168,10 +168,11 @@ int radeon_resume(struct drm_device *dev) if (!radeon_fb) continue; - if (!radeon_fb->obj) + if (!radeon_fb->base.mm_private) continue; - radeon_gem_object_pin(radeon_fb->obj, PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); + radeon_gem_object_pin(radeon_fb->base.mm_private, + PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); } /* blat the mode back in */ drm_helper_resume_force_mode(dev); -- cgit v1.2.3 From 3d1825729370a8009f4d7ceae91a16cfd6b7956c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 23 Sep 2008 16:50:22 +1000 Subject: radeon: Fix type in check for tmds type. --- linux-core/radeon_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index e8d141ec..257f0ac7 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -269,7 +269,7 @@ bool radeon_setup_enc_conn(struct drm_device *dev) else { if (mode_info->bios_connector[i].tmds_type == TMDS_INT) encoder = radeon_encoder_legacy_tmds_int_add(dev, i); - else if (mode_info->bios_connector[i].dac_type == TMDS_EXT) + else if (mode_info->bios_connector[i].tmds_type == TMDS_EXT) encoder = radeon_encoder_legacy_tmds_ext_add(dev, i); } if (encoder) -- cgit v1.2.3 From 0130aa0de940a49c086a0fb080e524d55b55ec8b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 23 Sep 2008 16:50:39 +1000 Subject: radeon: fix minor cursor issues --- linux-core/radeon_cursor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/radeon_cursor.c b/linux-core/radeon_cursor.c index e71b325d..d352d10f 100644 --- a/linux-core/radeon_cursor.c +++ b/linux-core/radeon_cursor.c @@ -196,11 +196,11 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, if (x < 0) xorigin = -x + 1; if (y < 0) - yorigin = -x + 1; + yorigin = -y + 1; if (xorigin >= CURSOR_WIDTH) xorigin = CURSOR_WIDTH - 1; - if (yorigin >= CURSOR_WIDTH) - yorigin = CURSOR_WIDTH - 1; + if (yorigin >= CURSOR_HEIGHT) + yorigin = CURSOR_HEIGHT - 1; radeon_lock_cursor(crtc, true); if (radeon_is_avivo(dev_priv)) { -- cgit v1.2.3 From 840c9a305481ed59820bbd87fbcf78dd242d5702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 23 Sep 2008 16:52:06 +1000 Subject: Update intel modesetting to use mm_private instead of mm_handle. --- linux-core/intel_display.c | 57 ++++++++++++++++++++++++++++++---------------- linux-core/intel_drv.h | 8 +++---- linux-core/intel_fb.c | 6 ++--- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index dfc0b502..5a275c6c 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -370,6 +370,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj_priv; + struct drm_gem_object *obj; int pipe = intel_crtc->pipe; unsigned long Start, Offset; int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); @@ -386,7 +387,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) intel_fb = to_intel_framebuffer(crtc->fb); - obj_priv = intel_fb->obj->driver_private; + obj = intel_fb->base.mm_private; + obj_priv = obj->driver_private; Start = obj_priv->gtt_offset; Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); @@ -1481,21 +1483,34 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_device *dev = fb->dev; + if (fb->fbdev) intelfb_remove(dev, fb); drm_framebuffer_cleanup(fb); + drm_gem_object_unreference(fb->mm_private); kfree(intel_fb); } + +static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + struct drm_gem_object *object = fb->mm_private; + + return drm_gem_handle_create(file_priv, object, handle); +} static const struct drm_framebuffer_funcs intel_fb_funcs = { .destroy = intel_user_framebuffer_destroy, + .create_handle = intel_user_framebuffer_create_handle, }; -struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, - struct drm_file *filp, - struct drm_mode_fb_cmd *mode_cmd) +struct drm_framebuffer * +intel_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + void *mm_private) { struct intel_framebuffer *intel_fb; @@ -1506,20 +1521,26 @@ struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, if (!drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs)) return NULL; - drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); + drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd, mm_private); - if (filp) { - intel_fb->obj = drm_gem_object_lookup(dev, filp, - mode_cmd->handle); - if (!intel_fb->obj) { - kfree(intel_fb); - return NULL; - } - } - drm_gem_object_unreference(intel_fb->obj); return &intel_fb->base; } + +static struct drm_framebuffer * +intel_user_framebuffer_create(struct drm_device *dev, + struct drm_file *filp, + struct drm_mode_fb_cmd *mode_cmd) +{ + struct drm_gem_object *obj; + + obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); + if (!obj) + return NULL; + + return intel_framebuffer_create(dev, mode_cmd, obj); +} + static int intel_insert_new_fb(struct drm_device *dev, struct drm_file *file_priv, struct drm_framebuffer *fb, struct drm_mode_fb_cmd *mode_cmd) { @@ -1536,14 +1557,10 @@ static int intel_insert_new_fb(struct drm_device *dev, struct drm_file *file_pri mutex_unlock(&dev->struct_mutex); return -EINVAL; } - drm_helper_mode_fill_fb_struct(fb, mode_cmd); - - drm_gem_object_unreference(intel_fb->obj); - drm_gem_object_unreference(obj); + drm_gem_object_unreference(intel_fb->base.mm_private); + drm_helper_mode_fill_fb_struct(fb, mode_cmd, obj); mutex_unlock(&dev->struct_mutex); - intel_fb->obj = obj; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb == fb) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index bffbeef0..256deac7 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -50,7 +50,6 @@ struct intel_i2c_chan { struct intel_framebuffer { struct drm_framebuffer base; - struct drm_gem_object *obj; }; @@ -119,7 +118,8 @@ extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); -extern struct drm_framebuffer *intel_user_framebuffer_create(struct drm_device *dev, - struct drm_file *file_priv, - struct drm_mode_fb_cmd *mode_cmd); +extern struct drm_framebuffer * +intel_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + void *mm_private); #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index c1391c0a..3d786ea3 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -728,7 +728,7 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height i915_gem_clflush_object(fbo); - fb = intel_user_framebuffer_create(dev, NULL, &mode_cmd); + fb = intel_framebuffer_create(dev, &mode_cmd, fbo); if (!fb) { DRM_ERROR("failed to allocate fb.\n"); ret = -ENOMEM; @@ -740,8 +740,6 @@ int intelfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_height intel_fb = to_intel_framebuffer(fb); *intel_fb_p = intel_fb; - intel_fb->obj = fbo; - info = framebuffer_alloc(sizeof(struct intelfb_par), device); if (!info) { ret = -ENOMEM; @@ -1137,7 +1135,7 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) unregister_framebuffer(info); iounmap(info->screen_base); mutex_lock(&dev->struct_mutex); - drm_gem_object_unreference(intel_fb->obj); + drm_gem_object_unreference(intel_fb->base.mm_private); mutex_unlock(&dev->struct_mutex); framebuffer_release(info); } -- cgit v1.2.3 From dcf73de059d45ff894c417bb9234933bc650b6b2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 24 Sep 2008 13:58:26 +1000 Subject: radeon: add parsing for r6xx object tables --- linux-core/radeon_atombios.c | 168 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index 0915a7f8..90a367a0 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -77,6 +77,11 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de return i2c; } +static struct radeon_i2c_bus_rec radeon_parse_i2c_record(struct drm_device *dev, ATOM_I2C_RECORD *record) +{ + return radeon_lookup_gpio(dev, record->sucI2cId.bfI2C_LineMux); +} + static void radeon_atom_apply_quirks(struct drm_device *dev, int index) { struct drm_radeon_private *dev_priv = dev->dev_private; @@ -100,6 +105,165 @@ static void radeon_atom_apply_quirks(struct drm_device *dev, int index) } } +const int object_connector_convert[] = +{ CONNECTOR_NONE, + CONNECTOR_DVI_I, + CONNECTOR_DVI_I, + CONNECTOR_DVI_D, + CONNECTOR_DVI_D, + CONNECTOR_VGA, + CONNECTOR_CTV, + CONNECTOR_STV, + CONNECTOR_NONE, + CONNECTOR_DIN, + CONNECTOR_SCART, + CONNECTOR_HDMI_TYPE_A, + CONNECTOR_HDMI_TYPE_B, + CONNECTOR_HDMI_TYPE_B, + CONNECTOR_LVDS, + CONNECTOR_DIN, + CONNECTOR_NONE, + CONNECTOR_NONE, + CONNECTOR_NONE, + CONNECTOR_DISPLAY_PORT, +}; + +bool radeon_get_atom_connector_info_from_bios_object_table(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + struct atom_context *ctx = mode_info->atom_context; + int index = GetIndexIntoMasterTable(DATA, Object_Header); + uint16_t size, data_offset; + uint8_t frev, crev; + ATOM_CONNECTOR_OBJECT_TABLE *con_obj; + ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj = NULL; + ATOM_OBJECT_HEADER *obj_header; + int i, j; + + atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); + + if (crev < 2) + return false; + + + obj_header = (ATOM_OBJECT_HEADER *)(ctx->bios + data_offset); + + con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)(ctx->bios + data_offset + obj_header->usConnectorObjectTableOffset); + DRM_ERROR("Num of objects %d\n", con_obj->ucNumberOfObjects); + + for (i = 0; i < con_obj->ucNumberOfObjects; i++) { + ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *src_dst_table; + ATOM_COMMON_RECORD_HEADER *record; + uint8_t obj_id, num, obj_type; + int record_base; + uint16_t con_obj_id = le16_to_cpu(con_obj->asObjects[i].usObjectID); + + obj_id = (con_obj_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + num = (con_obj_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT; + obj_type = (con_obj_id & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; + if (obj_type != GRAPH_OBJECT_TYPE_CONNECTOR) + continue; + + DRM_ERROR("offset is %04x\n", le16_to_cpu(con_obj->asObjects[i].usSrcDstTableOffset)); + src_dst_table = (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) + (ctx->bios + data_offset + le16_to_cpu(con_obj->asObjects[i].usSrcDstTableOffset)); + + DRM_ERROR("object id %04x %02x\n", obj_id, src_dst_table->ucNumberOfSrc); + + if ((dev_priv->chip_family == CHIP_RS780) && + (obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) { + uint32_t slot_config, ct; + + // TODO + } else + mode_info->bios_connector[i].connector_type = object_connector_convert[obj_id]; + + if (mode_info->bios_connector[i].connector_type == CONNECTOR_NONE) + mode_info->bios_connector[i].valid = false; + else + mode_info->bios_connector[i].valid = true; + mode_info->bios_connector[i].devices = 0; + + for (j = 0; j < src_dst_table->ucNumberOfSrc; j++) { + uint8_t sobj_id; + + sobj_id = (src_dst_table->usSrcObjectID[j] & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + DRM_ERROR("src object id %04x %d\n", src_dst_table->usSrcObjectID[j], sobj_id); + + switch(sobj_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_LCD1_INDEX); + break; + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP1_INDEX); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + if (num == 1) + mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP1_INDEX); + else + mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP2_INDEX); + mode_info->bios_connector[i].tmds_type = TMDS_UNIPHY; + break; + case ENCODER_OBJECT_ID_INTERNAL_TMDS2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP2_INDEX); + mode_info->bios_connector[i].tmds_type = TMDS_EXT; + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP3_INDEX); + mode_info->bios_connector[i].tmds_type = TMDS_LVTMA; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN || + mode_info->bios_connector[i].connector_type == CONNECTOR_STV || + mode_info->bios_connector[i].connector_type == CONNECTOR_CTV) + mode_info->bios_connector[i].valid = false; + else + mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_CRT1_INDEX); + mode_info->bios_connector[i].dac_type = DAC_PRIMARY; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN || + mode_info->bios_connector[i].connector_type == CONNECTOR_STV || + mode_info->bios_connector[i].connector_type == CONNECTOR_CTV) + mode_info->bios_connector[i].valid = false; + else + mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_CRT2_INDEX); + mode_info->bios_connector[i].dac_type = DAC_TVDAC; + break; + } + } + + record = (ATOM_COMMON_RECORD_HEADER *) + (ctx->bios + data_offset + le16_to_cpu(con_obj->asObjects[i].usRecordOffset)); + record_base = le16_to_cpu(con_obj->asObjects[i].usRecordOffset); + + while (record->ucRecordType > 0 && + record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { + DRM_ERROR("record type %d\n", record->ucRecordType); + + switch(record->ucRecordType) { + case ATOM_I2C_RECORD_TYPE: + mode_info->bios_connector[i].ddc_i2c = radeon_parse_i2c_record(dev, (ATOM_I2C_RECORD *)record); + break; + case ATOM_HPD_INT_RECORD_TYPE: + break; + case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE: + break; + } + record = (ATOM_COMMON_RECORD_HEADER *)((char *)record + record->ucRecordSize); + } + + } + return true; +} + + bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev) { struct drm_radeon_private *dev_priv = dev->dev_private; @@ -112,6 +276,10 @@ bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device union atom_supported_devices *supported_devices; int i,j; + + if (radeon_get_atom_connector_info_from_bios_object_table(dev)) + return true; + atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); supported_devices = (union atom_supported_devices *)(ctx->bios + data_offset); -- cgit v1.2.3 From 35e379ce5a0d23f4c812739f89e02703900cd91b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 24 Sep 2008 15:25:35 +1000 Subject: radeon: add r600 modesetting registers writes --- linux-core/radeon_gem.c | 19 +++++++++++++++---- shared-core/radeon_cp.c | 19 +++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 8338f8f5..7cdcf47d 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -979,10 +979,16 @@ void radeon_init_memory_map(struct drm_device *dev) RADEON_WRITE(AVIVO_HDP_FB_LOCATION, dev_priv->mc_fb_location); } - dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16; - dev_priv->fb_size = - ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000) - - dev_priv->fb_location; + if (dev_priv->chip_family >= CHIP_R600) { + dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffffff) << 24; + dev_priv->fb_size = ((radeon_read_fb_location(dev_priv) & 0xff000000u) + 0x1000000) + - dev_priv->fb_location; + } else { + dev_priv->fb_location = (radeon_read_fb_location(dev_priv) & 0xffff) << 16; + dev_priv->fb_size = + ((radeon_read_fb_location(dev_priv) & 0xffff0000u) + 0x10000) + - dev_priv->fb_location; + } } @@ -1009,6 +1015,11 @@ int radeon_gem_mm_init(struct drm_device *dev) 0); + if (dev_priv->chip_family > CHIP_R600) { + dev_priv->mm_enabled = true; + return 0; + } + dev_priv->mm.gart_size = (32 * 1024 * 1024); dev_priv->mm.gart_start = 0; ret = radeon_gart_init(dev); diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index b934d3bc..ffe066fc 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -101,6 +101,10 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION); else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) + return RADEON_READ(R700_MC_VM_FB_LOCATION); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) + return RADEON_READ(R600_MC_VM_FB_LOCATION); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION); else @@ -110,7 +114,8 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) void radeon_read_agp_location(drm_radeon_private_t *dev_priv, u32 *agp_lo, u32 *agp_hi) { if (dev_priv->chip_family == CHIP_RV770) { - + *agp_lo = RADEON_READ(R600_MC_VM_AGP_BOT); + *agp_hi = RADEON_READ(R600_MC_VM_AGP_TOP); } else if (dev_priv->chip_family == CHIP_R600) { *agp_lo = RADEON_READ(R600_MC_VM_AGP_BOT); *agp_hi = RADEON_READ(R600_MC_VM_AGP_TOP); @@ -139,6 +144,10 @@ void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) + RADEON_WRITE(R700_MC_VM_FB_LOCATION, fb_loc); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) + RADEON_WRITE(R600_MC_VM_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc); else @@ -151,7 +160,10 @@ static void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_lo R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc); - else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) + else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) { + RADEON_WRITE(R600_MC_VM_AGP_BOT, agp_loc); + RADEON_WRITE(R600_MC_VM_AGP_TOP, agp_loc_hi); + } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc); else RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_loc); @@ -2357,6 +2369,9 @@ int radeon_modeset_cp_init(struct drm_device *dev) /* Start with assuming that writeback doesn't work */ dev_priv->writeback_works = 0; + if (dev_priv->chip_family > CHIP_R600) + return; + dev_priv->usec_timeout = RADEON_DEFAULT_CP_TIMEOUT; dev_priv->ring.size = RADEON_DEFAULT_RING_SIZE; dev_priv->cp_mode = RADEON_CSQ_PRIBM_INDBM; -- cgit v1.2.3 From ea9711b954ba9093546ba13052fb8bbda860b9e4 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 25 Sep 2008 23:12:07 +0200 Subject: Seperate modesetting userspace bits into drm_mode.h --- linux-core/drm_mode.h | 1 + shared-core/drm.h | 244 +------------------------------------------ shared-core/drm_mode.h | 278 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 280 insertions(+), 243 deletions(-) create mode 120000 linux-core/drm_mode.h create mode 100644 shared-core/drm_mode.h diff --git a/linux-core/drm_mode.h b/linux-core/drm_mode.h new file mode 120000 index 00000000..a43f1385 --- /dev/null +++ b/linux-core/drm_mode.h @@ -0,0 +1 @@ +../shared-core/drm_mode.h \ No newline at end of file diff --git a/shared-core/drm.h b/shared-core/drm.h index 6f93618a..ec5fd3b5 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -700,249 +700,7 @@ struct drm_gem_open { uint64_t size; }; -/* - * Drm mode setting - */ -#define DRM_DISPLAY_INFO_LEN 32 -#define DRM_CONNECTOR_NAME_LEN 32 -#define DRM_DISPLAY_MODE_LEN 32 -#define DRM_PROP_NAME_LEN 32 - -#define DRM_MODE_TYPE_BUILTIN (1<<0) -#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) -#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) -#define DRM_MODE_TYPE_PREFERRED (1<<3) -#define DRM_MODE_TYPE_DEFAULT (1<<4) -#define DRM_MODE_TYPE_USERDEF (1<<5) -#define DRM_MODE_TYPE_DRIVER (1<<6) - -/* Video mode flags */ -/* bit compatible with the xorg definitions. */ -#define DRM_MODE_FLAG_PHSYNC (1<<0) -#define DRM_MODE_FLAG_NHSYNC (1<<1) -#define DRM_MODE_FLAG_PVSYNC (1<<2) -#define DRM_MODE_FLAG_NVSYNC (1<<3) -#define DRM_MODE_FLAG_INTERLACE (1<<4) -#define DRM_MODE_FLAG_DBLSCAN (1<<5) -#define DRM_MODE_FLAG_CSYNC (1<<6) -#define DRM_MODE_FLAG_PCSYNC (1<<7) -#define DRM_MODE_FLAG_NCSYNC (1<<8) -#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ -#define DRM_MODE_FLAG_BCAST (1<<10) -#define DRM_MODE_FLAG_PIXMUX (1<<11) -#define DRM_MODE_FLAG_DBLCLK (1<<12) -#define DRM_MODE_FLAG_CLKDIV2 (1<<13) - -/* DPMS flags */ -/* bit compatible with the xorg definitions. */ -#define DRM_MODE_DPMS_ON 0 -#define DRM_MODE_DPMS_STANDBY 1 -#define DRM_MODE_DPMS_SUSPEND 2 -#define DRM_MODE_DPMS_OFF 3 - -/* Scaling mode options */ -#define DRM_MODE_SCALE_NON_GPU 0 -#define DRM_MODE_SCALE_FULLSCREEN 1 -#define DRM_MODE_SCALE_NO_SCALE 2 -#define DRM_MODE_SCALE_ASPECT 3 - -/* Dithering mode options */ -#define DRM_MODE_DITHERING_OFF 0 -#define DRM_MODE_DITHERING_ON 1 - -struct drm_mode_modeinfo { - unsigned int clock; - unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; - unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; - - unsigned int vrefresh; /* vertical refresh * 1000 */ - - unsigned int flags; - unsigned int type; - char name[DRM_DISPLAY_MODE_LEN]; -}; - -struct drm_mode_card_res { - uint64_t fb_id_ptr; - uint64_t crtc_id_ptr; - uint64_t connector_id_ptr; - uint64_t encoder_id_ptr; - int count_fbs; - int count_crtcs; - int count_connectors; - int count_encoders; - int min_width, max_width; - int min_height, max_height; -}; - -struct drm_mode_crtc { - uint64_t set_connectors_ptr; - int count_connectors; - - unsigned int crtc_id; /**< Id */ - unsigned int fb_id; /**< Id of framebuffer */ - - int x, y; /**< Position on the frameuffer */ - - uint32_t gamma_size; - int mode_valid; - struct drm_mode_modeinfo mode; -}; - -#define DRM_MODE_ENCODER_NONE 0 -#define DRM_MODE_ENCODER_DAC 1 -#define DRM_MODE_ENCODER_TMDS 2 -#define DRM_MODE_ENCODER_LVDS 3 -#define DRM_MODE_ENCODER_TVDAC 4 - -struct drm_mode_get_encoder { - - unsigned int encoder_type; - unsigned int encoder_id; - - unsigned int crtc_id; /**< Id of crtc */ - - uint32_t possible_crtcs; - uint32_t possible_clones; -}; - -/* This is for connectors with multiple signal types. */ -/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ -#define DRM_MODE_SUBCONNECTOR_Automatic 0 -#define DRM_MODE_SUBCONNECTOR_Unknown 0 -#define DRM_MODE_SUBCONNECTOR_DVID 3 -#define DRM_MODE_SUBCONNECTOR_DVIA 4 -#define DRM_MODE_SUBCONNECTOR_Composite 5 -#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 -#define DRM_MODE_SUBCONNECTOR_Component 8 - -#define DRM_MODE_CONNECTOR_Unknown 0 -#define DRM_MODE_CONNECTOR_VGA 1 -#define DRM_MODE_CONNECTOR_DVII 2 -#define DRM_MODE_CONNECTOR_DVID 3 -#define DRM_MODE_CONNECTOR_DVIA 4 -#define DRM_MODE_CONNECTOR_Composite 5 -#define DRM_MODE_CONNECTOR_SVIDEO 6 -#define DRM_MODE_CONNECTOR_LVDS 7 -#define DRM_MODE_CONNECTOR_Component 8 -#define DRM_MODE_CONNECTOR_9PinDIN 9 -#define DRM_MODE_CONNECTOR_DisplayPort 10 -#define DRM_MODE_CONNECTOR_HDMIA 11 -#define DRM_MODE_CONNECTOR_HDMIB 12 - -struct drm_mode_get_connector { - - uint64_t encoders_ptr; - uint64_t modes_ptr; - uint64_t props_ptr; - uint64_t prop_values_ptr; - - int count_modes; - int count_props; - int count_encoders; - - unsigned int encoder_id; /**< Current Encoder */ - unsigned int connector_id; /**< Id */ - unsigned int connector_type; - unsigned int connector_type_id; - - unsigned int connection; - unsigned int mm_width, mm_height; /**< HxW in millimeters */ - unsigned int subpixel; -}; - -#define DRM_MODE_PROP_PENDING (1<<0) -#define DRM_MODE_PROP_RANGE (1<<1) -#define DRM_MODE_PROP_IMMUTABLE (1<<2) -#define DRM_MODE_PROP_ENUM (1<<3) // enumerated type with text strings -#define DRM_MODE_PROP_BLOB (1<<4) - -struct drm_mode_property_enum { - uint64_t value; - unsigned char name[DRM_PROP_NAME_LEN]; -}; - -struct drm_mode_get_property { - uint64_t values_ptr; /* values and blob lengths */ - uint64_t enum_blob_ptr; /* enum and blob id ptrs */ - - unsigned int prop_id; - unsigned int flags; - unsigned char name[DRM_PROP_NAME_LEN]; - - int count_values; - int count_enum_blobs; -}; - -struct drm_mode_connector_set_property { - uint64_t value; - unsigned int prop_id; - unsigned int connector_id; -}; - -struct drm_mode_get_blob { - uint32_t blob_id; - uint32_t length; - uint64_t data; -}; - -struct drm_mode_fb_cmd { - unsigned int buffer_id; - unsigned int width, height; - unsigned int pitch; - unsigned int bpp; - unsigned int handle; - unsigned int depth; -}; - -struct drm_mode_mode_cmd { - unsigned int connector_id; - struct drm_mode_modeinfo mode; -}; - -#define DRM_MODE_CURSOR_BO 0x01 -#define DRM_MODE_CURSOR_MOVE 0x02 - -/* - * depending on the value in flags diffrent members are used. - * - * CURSOR_BO uses - * crtc - * width - * height - * handle - if 0 turns the cursor of - * - * CURSOR_MOVE uses - * crtc - * x - * y - */ -struct drm_mode_cursor { - unsigned int flags; - unsigned int crtc; - int x; - int y; - uint32_t width; - uint32_t height; - unsigned int handle; -}; - -/* - * oh so ugly hotplug - */ -struct drm_mode_hotplug { - uint32_t counter; -}; - -struct drm_mode_crtc_lut { - - uint32_t crtc_id; - uint32_t gamma_size; - - uint64_t red; - uint64_t green; - uint64_t blue; -}; +#include "drm_mode.h" /** * \name Ioctls Definitions diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h new file mode 100644 index 00000000..678dc230 --- /dev/null +++ b/shared-core/drm_mode.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2007 Dave Airlie + * Copyright (c) 2007 Jakob Bornecrantz + * Copyright (c) 2008 Red Hat Inc. + * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA + * Copyright (c) 2007-2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _DRM_MODE_H +#define _DRM_MODE_H + +#if !defined(__KERNEL__) && !defined(_KERNEL) +#include +#else +#include +#endif + +#define DRM_DISPLAY_INFO_LEN 32 +#define DRM_CONNECTOR_NAME_LEN 32 +#define DRM_DISPLAY_MODE_LEN 32 +#define DRM_PROP_NAME_LEN 32 + +#define DRM_MODE_TYPE_BUILTIN (1<<0) +#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED (1<<3) +#define DRM_MODE_TYPE_DEFAULT (1<<4) +#define DRM_MODE_TYPE_USERDEF (1<<5) +#define DRM_MODE_TYPE_DRIVER (1<<6) + +/* Video mode flags */ +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_FLAG_PHSYNC (1<<0) +#define DRM_MODE_FLAG_NHSYNC (1<<1) +#define DRM_MODE_FLAG_PVSYNC (1<<2) +#define DRM_MODE_FLAG_NVSYNC (1<<3) +#define DRM_MODE_FLAG_INTERLACE (1<<4) +#define DRM_MODE_FLAG_DBLSCAN (1<<5) +#define DRM_MODE_FLAG_CSYNC (1<<6) +#define DRM_MODE_FLAG_PCSYNC (1<<7) +#define DRM_MODE_FLAG_NCSYNC (1<<8) +#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ +#define DRM_MODE_FLAG_BCAST (1<<10) +#define DRM_MODE_FLAG_PIXMUX (1<<11) +#define DRM_MODE_FLAG_DBLCLK (1<<12) +#define DRM_MODE_FLAG_CLKDIV2 (1<<13) + +/* DPMS flags */ +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_DPMS_ON 0 +#define DRM_MODE_DPMS_STANDBY 1 +#define DRM_MODE_DPMS_SUSPEND 2 +#define DRM_MODE_DPMS_OFF 3 + +/* Scaling mode options */ +#define DRM_MODE_SCALE_NON_GPU 0 +#define DRM_MODE_SCALE_FULLSCREEN 1 +#define DRM_MODE_SCALE_NO_SCALE 2 +#define DRM_MODE_SCALE_ASPECT 3 + +/* Dithering mode options */ +#define DRM_MODE_DITHERING_OFF 0 +#define DRM_MODE_DITHERING_ON 1 + +struct drm_mode_modeinfo { + unsigned int clock; + unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; + unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; + + unsigned int vrefresh; /* vertical refresh * 1000 */ + + unsigned int flags; + unsigned int type; + char name[DRM_DISPLAY_MODE_LEN]; +}; + +struct drm_mode_card_res { + uint64_t fb_id_ptr; + uint64_t crtc_id_ptr; + uint64_t connector_id_ptr; + uint64_t encoder_id_ptr; + int count_fbs; + int count_crtcs; + int count_connectors; + int count_encoders; + int min_width, max_width; + int min_height, max_height; +}; + +struct drm_mode_crtc { + uint64_t set_connectors_ptr; + int count_connectors; + + unsigned int crtc_id; /**< Id */ + unsigned int fb_id; /**< Id of framebuffer */ + + int x, y; /**< Position on the frameuffer */ + + uint32_t gamma_size; + int mode_valid; + struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 + +struct drm_mode_get_encoder { + + unsigned int encoder_type; + unsigned int encoder_id; + + unsigned int crtc_id; /**< Id of crtc */ + + uint32_t possible_crtcs; + uint32_t possible_clones; +}; + +/* This is for connectors with multiple signal types. */ +/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 3 +#define DRM_MODE_SUBCONNECTOR_DVIA 4 +#define DRM_MODE_SUBCONNECTOR_Composite 5 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +#define DRM_MODE_SUBCONNECTOR_Component 8 + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 + +struct drm_mode_get_connector { + + uint64_t encoders_ptr; + uint64_t modes_ptr; + uint64_t props_ptr; + uint64_t prop_values_ptr; + + int count_modes; + int count_props; + int count_encoders; + + unsigned int encoder_id; /**< Current Encoder */ + unsigned int connector_id; /**< Id */ + unsigned int connector_type; + unsigned int connector_type_id; + + unsigned int connection; + unsigned int mm_width, mm_height; /**< HxW in millimeters */ + unsigned int subpixel; +}; + +#define DRM_MODE_PROP_PENDING (1<<0) +#define DRM_MODE_PROP_RANGE (1<<1) +#define DRM_MODE_PROP_IMMUTABLE (1<<2) +#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */ +#define DRM_MODE_PROP_BLOB (1<<4) + +struct drm_mode_property_enum { + uint64_t value; + unsigned char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_mode_get_property { + uint64_t values_ptr; /* values and blob lengths */ + uint64_t enum_blob_ptr; /* enum and blob id ptrs */ + + unsigned int prop_id; + unsigned int flags; + unsigned char name[DRM_PROP_NAME_LEN]; + + int count_values; + int count_enum_blobs; +}; + +struct drm_mode_connector_set_property { + uint64_t value; + unsigned int prop_id; + unsigned int connector_id; +}; + +struct drm_mode_get_blob { + uint32_t blob_id; + uint32_t length; + uint64_t data; +}; + +struct drm_mode_fb_cmd { + unsigned int buffer_id; + unsigned int width, height; + unsigned int pitch; + unsigned int bpp; + unsigned int handle; + unsigned int depth; +}; + +struct drm_mode_mode_cmd { + unsigned int connector_id; + struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_CURSOR_BO 0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 + +/* + * depending on the value in flags diffrent members are used. + * + * CURSOR_BO uses + * crtc + * width + * height + * handle - if 0 turns the cursor of + * + * CURSOR_MOVE uses + * crtc + * x + * y + */ +struct drm_mode_cursor { + unsigned int flags; + unsigned int crtc; + int x; + int y; + uint32_t width; + uint32_t height; + unsigned int handle; +}; + +/* + * oh so ugly hotplug + */ +struct drm_mode_hotplug { + uint32_t counter; +}; + +struct drm_mode_crtc_lut { + + uint32_t crtc_id; + uint32_t gamma_size; + + /* pointers to arrays */ + uint64_t red; + uint64_t green; + uint64_t blue; +}; + +#endif -- cgit v1.2.3 From d883347f087eb1ce410392a379dfa6a44b2d14d1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 25 Sep 2008 18:45:07 -0400 Subject: radeon: first pass at using atombios on r4xx hw --- linux-core/atombios_crtc.c | 71 +++++++++++++++++++++++++++++++---- linux-core/radeon_display.c | 32 +++------------- linux-core/radeon_encoders.c | 15 +++++++- linux-core/radeon_legacy_crtc.c | 82 +++++++++++++++++++++++++++++++++-------- 4 files changed, 149 insertions(+), 51 deletions(-) diff --git a/linux-core/atombios_crtc.c b/linux-core/atombios_crtc.c index 16bcbe87..922cc7e0 100644 --- a/linux-core/atombios_crtc.c +++ b/linux-core/atombios_crtc.c @@ -121,6 +121,29 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) } } +static void +atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, SET_CRTC_USING_DTD_TIMING_PARAMETERS *crtc_param) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + SET_CRTC_USING_DTD_TIMING_PARAMETERS conv_param; + int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); + + conv_param.usH_Size = cpu_to_le16(crtc_param->usH_Size); + conv_param.usH_Blanking_Time = cpu_to_le16(crtc_param->usH_Blanking_Time); + conv_param.usV_Size = cpu_to_le16(crtc_param->usV_Size); + conv_param.usV_Blanking_Time = cpu_to_le16(crtc_param->usV_Blanking_Time); + conv_param.usH_SyncOffset = cpu_to_le16(crtc_param->usH_SyncOffset); + conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth); + conv_param.usV_SyncOffset = cpu_to_le16(crtc_param->usV_SyncOffset); + conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth); + conv_param.susModeMiscInfo.usAccess = cpu_to_le16(crtc_param->susModeMiscInfo.usAccess); + conv_param.ucCRTC = crtc_param->ucCRTC; + + printk("executing set crtc dtd timing\n"); + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&conv_param); +} void atombios_crtc_set_timing(struct drm_crtc *crtc, SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_param) { @@ -170,7 +193,7 @@ void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) if (!radeon_is_avivo(dev_priv)) pll_flags |= RADEON_PLL_LEGACY; - if (mode->clock > 120000) /* range limits??? */ + if (mode->clock > 200000) /* range limits??? */ pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; @@ -319,8 +342,8 @@ void atombios_crtc_mode_set(struct drm_crtc *crtc, struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; - /* TODO color tiling */ + /* TODO color tiling */ memset(&crtc_timing, 0, sizeof(crtc_timing)); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -355,14 +378,48 @@ void atombios_crtc_mode_set(struct drm_crtc *crtc, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; + atombios_crtc_set_pll(crtc, adjusted_mode); + atombios_crtc_set_timing(crtc, &crtc_timing); + if (radeon_is_avivo(dev_priv)) atombios_crtc_set_base(crtc, x, y); - else + else { + if (radeon_crtc->crtc_id == 0) { + SET_CRTC_USING_DTD_TIMING_PARAMETERS crtc_dtd_timing; + memset(&crtc_dtd_timing, 0, sizeof(crtc_dtd_timing)); + + /* setup FP shadow regs on R4xx */ + crtc_dtd_timing.ucCRTC = radeon_crtc->crtc_id; + crtc_dtd_timing.usH_Size = adjusted_mode->crtc_hdisplay; + crtc_dtd_timing.usV_Size = adjusted_mode->crtc_vdisplay; + crtc_dtd_timing.usH_Blanking_Time = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hdisplay; + crtc_dtd_timing.usV_Blanking_Time = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vdisplay; + crtc_dtd_timing.usH_SyncOffset = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay; + crtc_dtd_timing.usV_SyncOffset = adjusted_mode->crtc_vsync_start - adjusted_mode->crtc_vdisplay; + crtc_dtd_timing.usH_SyncWidth = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start; + crtc_dtd_timing.usV_SyncWidth = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start; + //crtc_dtd_timing.ucH_Border = adjusted_mode->crtc_hborder; + //crtc_dtd_timing.ucV_Border = adjusted_mode->crtc_vborder; + + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + crtc_dtd_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; + + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + crtc_dtd_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; + + if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC) + crtc_dtd_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC; + + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + crtc_dtd_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE; + + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) + crtc_dtd_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE; + + atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing); + } radeon_crtc_set_base(crtc, x, y); - - atombios_crtc_set_pll(crtc, adjusted_mode); - - atombios_crtc_set_timing(crtc, &crtc_timing); + } } diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 257f0ac7..5c86f74c 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -195,7 +195,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index) radeon_crtc->lut_b[i] = i; } - if (dev_priv->is_atom_bios && radeon_is_avivo(dev_priv)) + if (dev_priv->is_atom_bios) radeon_atombios_init_crtc(dev, radeon_crtc); else radeon_legacy_init_crtc(dev, radeon_crtc); @@ -237,10 +237,7 @@ bool radeon_setup_enc_conn(struct drm_device *dev) encoder = NULL; /* if we find an LVDS connector */ if (mode_info->bios_connector[i].connector_type == CONNECTOR_LVDS) { - if (radeon_is_avivo(dev_priv)) - encoder = radeon_encoder_lvtma_add(dev, i); - else - encoder = radeon_encoder_legacy_lvds_add(dev, i); + encoder = radeon_encoder_lvtma_add(dev, i); if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } @@ -249,14 +246,7 @@ bool radeon_setup_enc_conn(struct drm_device *dev) if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_A) || (mode_info->bios_connector[i].connector_type == CONNECTOR_VGA)) { - if (radeon_is_avivo(dev_priv)) { - encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 0); - } else { - if (mode_info->bios_connector[i].dac_type == DAC_PRIMARY) - encoder = radeon_encoder_legacy_primary_dac_add(dev, i, 0); - else if (mode_info->bios_connector[i].dac_type == DAC_TVDAC) - encoder = radeon_encoder_legacy_tv_dac_add(dev, i, 0); - } + encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 0); if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } @@ -264,26 +254,14 @@ bool radeon_setup_enc_conn(struct drm_device *dev) /* TMDS on DVI */ if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D)) { - if (radeon_is_avivo(dev_priv)) - encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].tmds_type); - else { - if (mode_info->bios_connector[i].tmds_type == TMDS_INT) - encoder = radeon_encoder_legacy_tmds_int_add(dev, i); - else if (mode_info->bios_connector[i].tmds_type == TMDS_EXT) - encoder = radeon_encoder_legacy_tmds_ext_add(dev, i); - } + encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].tmds_type); if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } /* TVDAC on DIN */ if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN) { - if (radeon_is_avivo(dev_priv)) - encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 1); - else { - if (mode_info->bios_connector[i].dac_type == DAC_TVDAC) - encoder = radeon_encoder_legacy_tv_dac_add(dev, i, 0); - } + encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 1); if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 03878609..04ab03a0 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -146,6 +146,10 @@ static void atombios_scaler_setup(struct drm_encoder *encoder, struct drm_displa ENABLE_SCALER_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); + /* pre-avivo chips only have 1 scaler */ + if (!radeon_is_avivo(dev_priv) && radeon_crtc->crtc_id) + return; + memset(&args, 0, sizeof(args)); args.ucScaler = radeon_crtc->crtc_id; @@ -154,8 +158,12 @@ static void atombios_scaler_setup(struct drm_encoder *encoder, struct drm_displa args.ucEnable = ATOM_SCALER_EXPANSION; else if (radeon_encoder->rmx_type == RMX_CENTER) args.ucEnable = ATOM_SCALER_CENTER; - } else - args.ucEnable = ATOM_SCALER_DISABLE; + } else { + if (radeon_is_avivo(dev_priv)) + args.ucEnable = ATOM_SCALER_DISABLE; + else + args.ucEnable = ATOM_SCALER_CENTER; + } atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } @@ -225,6 +233,9 @@ static void radeon_dfp_disable_dither(struct drm_encoder *encoder, int device) struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; + if (!radeon_is_avivo(dev_priv)) + return; + switch (device) { case ATOM_DEVICE_DFP1_INDEX: RADEON_WRITE(AVIVO_TMDSA_BIT_DEPTH_CONTROL, 0); /* TMDSA */ diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index bc28c436..f99cbdaa 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -171,6 +171,50 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } } +/* properly set crtc bpp when using atombios */ +static void radeon_legacy_atom_set_surface(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + int format; + uint32_t crtc_gen_cntl, crtc2_gen_cntl; + + switch (crtc->fb->bits_per_pixel) { + case 15: /* 555 */ + format = 3; + break; + case 16: /* 565 */ + format = 4; + break; + case 24: /* RGB */ + format = 5; + break; + case 32: /* xRGB */ + format = 6; + break; + default: + return; + } + + switch (radeon_crtc->crtc_id) { + case 0: + crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL) & 0xfffff0ff; + crtc_gen_cntl |= (format << 8); + crtc_gen_cntl |= RADEON_CRTC_EXT_DISP_EN; + RADEON_WRITE(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); + break; + case 1: + crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL) & 0xfffff0ff; + crtc2_gen_cntl |= (format << 8); + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + // not sure we need these... + RADEON_WRITE(RADEON_FP_H2_SYNC_STRT_WID, RADEON_READ(RADEON_CRTC2_H_SYNC_STRT_WID)); + RADEON_WRITE(RADEON_FP_V2_SYNC_STRT_WID, RADEON_READ(RADEON_CRTC2_V_SYNC_STRT_WID)); + break; + } +} + static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) { struct drm_device *dev = crtc->dev; @@ -181,6 +225,7 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) uint32_t base; uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0; uint32_t crtc_pitch; + uint32_t disp_merge_cntl; DRM_DEBUG("\n"); @@ -263,6 +308,13 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) RADEON_WRITE(RADEON_CRTC_OFFSET, crtc_offset); RADEON_WRITE(RADEON_CRTC_PITCH, crtc_pitch); + disp_merge_cntl = RADEON_READ(RADEON_DISP_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + RADEON_WRITE(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); + + if (dev_priv->is_atom_bios) + radeon_legacy_atom_set_surface(crtc); + return true; } @@ -280,12 +332,10 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo uint32_t crtc_h_sync_strt_wid; uint32_t crtc_v_total_disp; uint32_t crtc_v_sync_strt_wid; - uint32_t disp_merge_cntl; DRM_DEBUG("\n"); switch (crtc->fb->bits_per_pixel) { - case 15: /* 555 */ format = 3; break; @@ -321,9 +371,6 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_DISPLAY_DIS); - disp_merge_cntl = RADEON_READ(RADEON_DISP_MERGE_CNTL); - disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; - crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff) | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16)); @@ -386,8 +433,6 @@ static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mo RADEON_WRITE(RADEON_CRTC_V_TOTAL_DISP, crtc_v_total_disp); RADEON_WRITE(RADEON_CRTC_V_SYNC_STRT_WID, crtc_v_sync_strt_wid); - RADEON_WRITE(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); - RADEON_WRITE(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); return true; @@ -433,7 +478,7 @@ static void radeon_set_pll1(struct drm_crtc *crtc, struct drm_display_mode *mode { 0, 0 } }; - if (mode->clock > 120000) /* range limits??? */ + if (mode->clock > 200000) /* range limits??? */ pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; @@ -606,6 +651,7 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) uint32_t base; uint32_t crtc2_offset, crtc2_offset_cntl, crtc2_tile_x0_y0 = 0; uint32_t crtc2_pitch; + uint32_t disp2_merge_cntl; DRM_DEBUG("\n"); @@ -686,6 +732,13 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) RADEON_WRITE(RADEON_CRTC2_OFFSET, crtc2_offset); RADEON_WRITE(RADEON_CRTC2_PITCH, crtc2_pitch); + disp2_merge_cntl = RADEON_READ(RADEON_DISP2_MERGE_CNTL); + disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; + RADEON_WRITE(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); + + if (dev_priv->is_atom_bios) + radeon_legacy_atom_set_surface(crtc); + return true; } @@ -702,7 +755,6 @@ static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mo uint32_t crtc2_h_sync_strt_wid; uint32_t crtc2_v_total_disp; uint32_t crtc2_v_sync_strt_wid; - uint32_t disp2_merge_cntl; uint32_t fp_h2_sync_strt_wid; uint32_t fp_v2_sync_strt_wid; @@ -776,9 +828,6 @@ static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mo ? RADEON_CRTC2_INTERLACE_EN : 0)); - disp2_merge_cntl = RADEON_READ(RADEON_DISP2_MERGE_CNTL); - disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; - fp_h2_sync_strt_wid = crtc2_h_sync_strt_wid; fp_v2_sync_strt_wid = crtc2_v_sync_strt_wid; @@ -795,8 +844,6 @@ static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mo RADEON_WRITE(RADEON_FP_H2_SYNC_STRT_WID, fp_h2_sync_strt_wid); RADEON_WRITE(RADEON_FP_V2_SYNC_STRT_WID, fp_v2_sync_strt_wid); - RADEON_WRITE(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); - RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); return true; @@ -813,7 +860,7 @@ static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode uint32_t post_divider = 0; uint32_t freq = 0; uint8_t pll_gain; - int pll_flags = RADEON_PLL_LEGACY | RADEON_PLL_PREFER_LOW_REF_DIV; + int pll_flags = RADEON_PLL_LEGACY; bool use_bios_divs = false; /* PLL2 registers */ uint32_t p2pll_ref_div = 0; @@ -842,6 +889,11 @@ static void radeon_set_pll2(struct drm_crtc *crtc, struct drm_display_mode *mode { 0, 0 } }; + if (mode->clock > 200000) /* range limits??? */ + pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + else + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) -- cgit v1.2.3 From 09b2dfcedc8cb35444567626131ccc25db79a8c6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Sep 2008 17:20:04 -0400 Subject: radeon: make atom on r4xx a module option default is legacy modesetting. pass module option r4xx_atom to try using atom on r4xx. --- linux-core/atombios_crtc.c | 1 + linux-core/radeon_atombios.c | 6 ++++-- linux-core/radeon_display.c | 32 +++++++++++++++++++++++++++----- linux-core/radeon_drv.c | 4 ++++ linux-core/radeon_legacy_crtc.c | 8 +------- linux-core/radeon_mode.h | 1 + shared-core/radeon_drv.h | 1 + 7 files changed, 39 insertions(+), 14 deletions(-) diff --git a/linux-core/atombios_crtc.c b/linux-core/atombios_crtc.c index 922cc7e0..3856f8ca 100644 --- a/linux-core/atombios_crtc.c +++ b/linux-core/atombios_crtc.c @@ -419,6 +419,7 @@ void atombios_crtc_mode_set(struct drm_crtc *crtc, atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing); } radeon_crtc_set_base(crtc, x, y); + radeon_legacy_atom_set_surface(crtc); } } diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index 90a367a0..a763e766 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -277,8 +277,10 @@ bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device union atom_supported_devices *supported_devices; int i,j; - if (radeon_get_atom_connector_info_from_bios_object_table(dev)) - return true; + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) + // FIXME this should return false for pre-r6xx chips + if (radeon_get_atom_connector_info_from_bios_object_table(dev)) + return true; atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 5c86f74c..ddc933cc 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -195,7 +195,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index) radeon_crtc->lut_b[i] = i; } - if (dev_priv->is_atom_bios) + if (dev_priv->is_atom_bios && (radeon_is_avivo(dev_priv) || radeon_r4xx_atom)) radeon_atombios_init_crtc(dev, radeon_crtc); else radeon_legacy_init_crtc(dev, radeon_crtc); @@ -237,7 +237,10 @@ bool radeon_setup_enc_conn(struct drm_device *dev) encoder = NULL; /* if we find an LVDS connector */ if (mode_info->bios_connector[i].connector_type == CONNECTOR_LVDS) { - encoder = radeon_encoder_lvtma_add(dev, i); + if (radeon_is_avivo(dev_priv) || radeon_r4xx_atom) + encoder = radeon_encoder_lvtma_add(dev, i); + else + encoder = radeon_encoder_legacy_lvds_add(dev, i); if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } @@ -246,7 +249,14 @@ bool radeon_setup_enc_conn(struct drm_device *dev) if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_A) || (mode_info->bios_connector[i].connector_type == CONNECTOR_VGA)) { - encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 0); + if (radeon_is_avivo(dev_priv) || radeon_r4xx_atom) + encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 0); + else { + if (mode_info->bios_connector[i].dac_type == DAC_PRIMARY) + encoder = radeon_encoder_legacy_primary_dac_add(dev, i, 0); + else if (mode_info->bios_connector[i].dac_type == DAC_TVDAC) + encoder = radeon_encoder_legacy_tv_dac_add(dev, i, 0); + } if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } @@ -254,14 +264,26 @@ bool radeon_setup_enc_conn(struct drm_device *dev) /* TMDS on DVI */ if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D)) { - encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].tmds_type); + if (radeon_is_avivo(dev_priv) || radeon_r4xx_atom) + encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].tmds_type); + else { + if (mode_info->bios_connector[i].tmds_type == TMDS_INT) + encoder = radeon_encoder_legacy_tmds_int_add(dev, i); + else if (mode_info->bios_connector[i].tmds_type == TMDS_EXT) + encoder = radeon_encoder_legacy_tmds_ext_add(dev, i); + } if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } /* TVDAC on DIN */ if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN) { - encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 1); + if (radeon_is_avivo(dev_priv) || radeon_r4xx_atom) + encoder = radeon_encoder_atom_dac_add(dev, i, mode_info->bios_connector[i].dac_type, 1); + else { + if (mode_info->bios_connector[i].dac_type == DAC_TVDAC) + encoder = radeon_encoder_legacy_tv_dac_add(dev, i, 0); + } if (encoder) drm_mode_connector_attach_encoder(connector, encoder); } diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 9b3397ca..79bcc3e6 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -38,6 +38,7 @@ int radeon_no_wb; int radeon_dynclks = 1; +int radeon_r4xx_atom = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers\n"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -48,6 +49,9 @@ module_param_named(modeset, radeon_modeset, int, 0400); MODULE_PARM_DESC(dynclks, "Disable/Enable dynamic clocks"); module_param_named(dynclks, radeon_dynclks, int, 0444); +MODULE_PARM_DESC(r4xx_atom, "Enable ATOMBIOS modesetting for R4xx"); +module_param_named(r4xx_atom, radeon_r4xx_atom, int, 0444); + static int dri_library_name(struct drm_device * dev, char * buf) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index f99cbdaa..820bd548 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -172,7 +172,7 @@ void radeon_crtc_dpms(struct drm_crtc *crtc, int mode) } /* properly set crtc bpp when using atombios */ -static void radeon_legacy_atom_set_surface(struct drm_crtc *crtc) +void radeon_legacy_atom_set_surface(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_radeon_private *dev_priv = dev->dev_private; @@ -312,9 +312,6 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; RADEON_WRITE(RADEON_DISP_MERGE_CNTL, disp_merge_cntl); - if (dev_priv->is_atom_bios) - radeon_legacy_atom_set_surface(crtc); - return true; } @@ -736,9 +733,6 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; RADEON_WRITE(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl); - if (dev_priv->is_atom_bios) - radeon_legacy_atom_set_surface(crtc); - return true; } diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 577c3cf9..8074eb7c 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -287,6 +287,7 @@ extern void atombios_crtc_mode_set(struct drm_crtc *crtc, extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); extern void radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y); +extern void radeon_legacy_atom_set_surface(struct drm_crtc *crtc); extern int radeon_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 25a07e30..3490ddbe 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -456,6 +456,7 @@ typedef struct drm_radeon_kcmd_buffer { extern int radeon_no_wb; extern int radeon_dynclks; +extern int radeon_r4xx_atom; extern struct drm_ioctl_desc radeon_ioctls[]; extern int radeon_max_ioctl; -- cgit v1.2.3 From 9c6732e790b123bebab0a6d05c592598f9cd2327 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 26 Sep 2008 17:32:15 -0400 Subject: radeon: use atom for ext tmds on r4xx --- linux-core/radeon_encoders.c | 4 ++-- linux-core/radeon_legacy_encoders.c | 43 +++++++++++++++++++++---------------- linux-core/radeon_mode.h | 2 ++ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index 04ab03a0..e5c95c9a 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -768,8 +768,8 @@ static void atombios_tmds2_setup(struct drm_encoder *encoder, } -static void atombios_ext_tmds_setup(struct drm_encoder *encoder, - struct drm_display_mode *mode) +void atombios_ext_tmds_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 1a1db534..261501d1 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -923,33 +923,40 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - uint32_t fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + uint32_t fp2_gen_cntl; DRM_DEBUG("\n"); if (radeon_crtc->crtc_id == 0) radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); - if (1) // FIXME rgbBits == 8 - fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ - else - fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ - - fp2_gen_cntl &= ~(RADEON_FP2_ON | - RADEON_FP2_DVO_EN | - RADEON_FP2_DVO_RATE_SEL_SDR); + if (dev_priv->is_atom_bios) { + atombios_ext_tmds_setup(encoder, adjusted_mode); + fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + } else { + fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); - /* XXX: these are oem specific */ - if (radeon_is_r300(dev_priv)) { - if ((dev->pdev->device == 0x4850) && - (dev->pdev->subsystem_vendor == 0x1028) && - (dev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */ - fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE; + if (1) // FIXME rgbBits == 8 + fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ else - fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE; + fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ + + fp2_gen_cntl &= ~(RADEON_FP2_ON | + RADEON_FP2_DVO_EN | + RADEON_FP2_DVO_RATE_SEL_SDR); + + /* XXX: these are oem specific */ + if (radeon_is_r300(dev_priv)) { + if ((dev->pdev->device == 0x4850) && + (dev->pdev->subsystem_vendor == 0x1028) && + (dev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */ + fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE; + else + fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE; - /*if (mode->clock > 165000) - fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/ + /*if (mode->clock > 165000) + fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/ + } } if (radeon_crtc->crtc_id == 0) { diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 8074eb7c..fef27380 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -277,6 +277,8 @@ struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv); struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index); struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index); +extern void atombios_ext_tmds_setup(struct drm_encoder *encoder, + struct drm_display_mode *mode); extern void radeon_crtc_load_lut(struct drm_crtc *crtc); extern void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y); -- cgit v1.2.3 From af2323b4b3b76070fb453531147a8956161b3718 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 30 Sep 2008 16:35:26 -0700 Subject: intel bufmgr: reinstate buffer handle tracking We need a way of getting at the underlying handle for use with mode setting. We can either export it in the dri_bo object or provide a new callback to get it. --- libdrm/intel/intel_bufmgr.h | 4 ++++ libdrm/intel/intel_bufmgr_gem.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libdrm/intel/intel_bufmgr.h b/libdrm/intel/intel_bufmgr.h index c44d596b..67dba6a1 100644 --- a/libdrm/intel/intel_bufmgr.h +++ b/libdrm/intel/intel_bufmgr.h @@ -59,6 +59,10 @@ struct _dri_bo { /** Buffer manager context associated with this buffer object */ dri_bufmgr *bufmgr; + /** + * MM-specific handle for accessing object + */ + int handle; }; dri_bo *dri_bo_alloc(dri_bufmgr *bufmgr, const char *name, unsigned long size, diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 4ca49d0a..70cdca74 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -316,7 +316,7 @@ dri_gem_bo_alloc(dri_bufmgr *bufmgr, const char *name, ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_CREATE, &create); bo_gem->gem_handle = create.handle; - //bo_gem->bo.handle = bo_gem->gem_handle; + bo_gem->bo.handle = bo_gem->gem_handle; if (ret != 0) { free(bo_gem); return NULL; -- cgit v1.2.3 From a981a6860365065682f3ca295939e629b989a9d1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Oct 2008 16:39:25 +1000 Subject: drm/radeon: fixup clean flag handling --- linux-core/drm_bo.c | 1 + linux-core/drm_bo_move.c | 1 + linux-core/drm_vm.c | 1 + linux-core/radeon_gem.c | 2 ++ 4 files changed, 5 insertions(+) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index fa3e055d..ecf65c20 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1174,6 +1174,7 @@ out_unlock: } /* clear the clean flags */ bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; + bo->mem.proposed_flags &= ~DRM_BO_FLAG_CLEAN; mutex_unlock(&dev->struct_mutex); mutex_unlock(&bm->evict_mutex); diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 207a5e07..7fe12f45 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -635,6 +635,7 @@ int drm_bo_kmap(struct drm_buffer_object *bo, unsigned long start_page, /* clear the clean flags */ bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; + bo->mem.proposed_flags &= ~DRM_BO_FLAG_CLEAN; if (bus_size == 0) { return drm_bo_kmap_ttm(bo, start_page, num_pages, map); diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 48d7b057..228ea6cd 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -794,6 +794,7 @@ static void drm_bo_vm_open_locked(struct vm_area_struct *vma) /* clear the clean flags */ bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; + bo->mem.proposed_flags &= ~DRM_BO_FLAG_CLEAN; drm_vm_open_locked(vma); atomic_inc(&bo->usage); diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 7cdcf47d..8c6f836f 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1244,6 +1244,8 @@ static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_pri radeon_gem_set_domain(obj, read_domains, write_domain, &flags, false); obj_priv->bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; + obj_priv->bo->mem.proposed_flags &= ~DRM_BO_FLAG_CLEAN; + if (flags == DRM_BO_FLAG_MEM_VRAM) *offset = obj_priv->bo->offset + dev_priv->fb_location; else if (flags == DRM_BO_FLAG_MEM_TT) -- cgit v1.2.3 From 4a4d7727c6c6eff4cf19d5debb91a6fcac555832 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Oct 2008 16:40:20 +1000 Subject: radeon: fix pin ioctl interface to mesa can find offset for pinned buffers --- linux-core/radeon_gem.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 8c6f836f..b9c3b80d 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -347,8 +347,9 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, flags |= DRM_BO_FLAG_MEM_TT; else if (args->pin_domain == RADEON_GEM_DOMAIN_VRAM) flags |= DRM_BO_FLAG_MEM_VRAM; - else - return -EINVAL; + else /* hand back the offset we currently have if no args supplied + - this is to allow old mesa to work - its a hack */ + flags = 0; } obj = drm_gem_object_lookup(dev, file_priv, args->handle); @@ -359,11 +360,11 @@ int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, /* validate into a pin with no fence */ DRM_DEBUG("got here %p %p %d\n", obj, obj_priv->bo, atomic_read(&obj_priv->bo->usage)); - if (!(obj_priv->bo->type != drm_bo_type_kernel && !DRM_SUSER(DRM_CURPROC))) { + if (flags && !(obj_priv->bo->type != drm_bo_type_kernel && !DRM_SUSER(DRM_CURPROC))) { ret = drm_bo_do_validate(obj_priv->bo, flags, mask, DRM_BO_HINT_DONT_FENCE, 0); } else - ret = 0; + ret = 0; args->offset = obj_priv->bo->offset; DRM_DEBUG("got here %p %p %x\n", obj, obj_priv->bo, obj_priv->bo->offset); -- cgit v1.2.3 From 4d1031a9f0e5cddb6ca403afdbd1f019c9c3df2e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Oct 2008 16:40:45 +1000 Subject: radeon: fix alignment so Xv works again --- linux-core/radeon_gem.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index b9c3b80d..225f0269 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -80,10 +80,11 @@ struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, struct drm_radeon_gem_object *obj_priv; int ret; uint32_t flags; + uint32_t page_align; obj = drm_gem_object_alloc(dev, size); if (!obj) - return NULL;; + return NULL; obj_priv = obj->driver_private; flags = DRM_BO_FLAG_MAPPABLE; @@ -95,10 +96,15 @@ struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; flags |= DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE; + + if (alignment == 0) + alignment = PAGE_SIZE; + + page_align = alignment >> PAGE_SHIFT; /* create a TTM BO */ ret = drm_buffer_object_create(dev, size, drm_bo_type_device, - flags, 0, alignment, + flags, 0, page_align, 0, &obj_priv->bo); if (ret) goto fail; @@ -188,10 +194,14 @@ int radeon_gem_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uin flags = DRM_BO_FLAG_MEM_TT; else if ((obj_priv->bo->mem.mem_type == DRM_BO_MEM_LOCAL) && (read_domains & RADEON_GEM_DOMAIN_GTT)) flags = DRM_BO_FLAG_MEM_TT; - else if (read_domains & RADEON_GEM_DOMAIN_VRAM) - flags = DRM_BO_FLAG_MEM_VRAM; - else if (read_domains & RADEON_GEM_DOMAIN_GTT) - flags = DRM_BO_FLAG_MEM_TT; + + /* no idea here just set whatever we are input */ + if (flags == 0) { + if (read_domains & RADEON_GEM_DOMAIN_VRAM) + flags |= DRM_BO_FLAG_MEM_VRAM; + if (read_domains & RADEON_GEM_DOMAIN_GTT) + flags |= DRM_BO_FLAG_MEM_TT; + } } /* if this BO is pinned then we ain't moving it anywhere */ -- cgit v1.2.3 From e4fa03f7ddb86720fa19cfc839689e1df72bb928 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 7 Oct 2008 14:10:39 -0400 Subject: radeon: pull in recent fixes from ddx - fixup atom digital encoder setup - pull in add get edid (currently disabled due to lack of support for atom fb/scratch space) --- linux-core/radeon_atombios.c | 57 +++++++++++++ linux-core/radeon_combios.c | 2 + linux-core/radeon_encoders.c | 192 +++++++++++++++++++++---------------------- linux-core/radeon_mode.h | 6 ++ 4 files changed, 159 insertions(+), 98 deletions(-) diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index a763e766..61732274 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -72,11 +72,66 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de i2c.get_data_mask = (1 << gpio.ucDataY_Shift); i2c.a_clk_mask = (1 << gpio.ucClkA_Shift); i2c.a_data_mask = (1 << gpio.ucDataA_Shift); + i2c.hw_line = gpio.sucI2cId.sbfAccess.bfI2C_LineMux; + i2c.hw_capable = gpio.sucI2cId.sbfAccess.bfHW_Capable; i2c.valid = true; return i2c; } +#if 0 +// TODO fix atom FB/scratch space access +struct edid *radeon_atom_get_edid(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_radeon_private *dev_priv = radeon_connector->base.dev->dev_private; + struct radeon_mode_info *mode_info = &dev_priv->mode_info; + READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION edid_param; + int i2c_clock = 50; + int prescale; + unsigned char *raw_edid; + struct edid *edid = NULL; + int index = GetIndexIntoMasterTable(COMMAND, ReadEDIDFromHWAssistedI2C); + + if (!radeon_connector->ddc_bus) + return edid; + + if (!radeon_connector->ddc_bus->rec.hw_capable) + return edid; + + if (info->atomBIOS->fbBase) + raw_edid = (unsigned char *)info->FB + info->atomBIOS->fbBase; + else if (info->atomBIOS->scratchBase) + raw_edid = (unsigned char *)info->atomBIOS->scratchBase; + else + return edid; + + memset(raw_edid, 0, ATOM_EDID_RAW_DATASIZE); + + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R520) + prescale = (127 << 8) + (mode_info->sclk * 10) / (4 * 127 * i2c_clock); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R600) + prescale = (((mode_info->sclk * 10)/(4 * 128 * 100) + 1) << 8) + 128; + else + prescale = (mode_info->spll.reference_freq * 10) / i2c_clock; + + edid_param.usPrescale = prescale; + edid_param.usVRAMAddress = 0; + edid_param.ucSlaveAddr = 0xa0; + edid_param.ucLineNumber = radeon_connector->ddc_bus->rec.hw_line; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&edid_param); + + if (raw_edid[1] == 0xff) { + edid = kmalloc(size_of(struct edid), GFP_KERNEL); + *edid = raw_edid; + } + + return edid; + +} +#endif + static struct radeon_i2c_bus_rec radeon_parse_i2c_record(struct drm_device *dev, ATOM_I2C_RECORD *record) { return radeon_lookup_gpio(dev, record->sucI2cId.bfI2C_LineMux); @@ -591,6 +646,8 @@ void radeon_atombios_get_lvds_info(struct radeon_encoder *encoder) encoder->voverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); encoder->vsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); encoder->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); + encoder->lvds_misc = lvds_info->info.ucLVDS_Misc; + encoder->lvds_ss_id = lvds_info->info.ucSS_Id; } } diff --git a/linux-core/radeon_combios.c b/linux-core/radeon_combios.c index ae1ef2f9..f89bf88a 100644 --- a/linux-core/radeon_combios.c +++ b/linux-core/radeon_combios.c @@ -385,6 +385,8 @@ struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line) { struct radeon_i2c_bus_rec i2c; + i2c.hw_line = 0; + i2c.hw_capable = false; // actually depends on chip i2c.mask_clk_mask = RADEON_GPIO_EN_1; i2c.mask_data_mask = RADEON_GPIO_EN_0; i2c.a_clk_mask = RADEON_GPIO_A_1; diff --git a/linux-core/radeon_encoders.c b/linux-core/radeon_encoders.c index e5c95c9a..87d9184f 100644 --- a/linux-core/radeon_encoders.c +++ b/linux-core/radeon_encoders.c @@ -228,58 +228,105 @@ void atombios_set_crtc_source(struct drm_encoder *encoder, int source) } -static void radeon_dfp_disable_dither(struct drm_encoder *encoder, int device) +static void atombios_output_digital_mode_set(struct drm_encoder *encoder, + int device, + struct drm_display_mode *mode) { - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - - if (!radeon_is_avivo(dev_priv)) - return; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + uint8_t frev, crev; + int index; + LVDS_ENCODER_CONTROL_PS_ALLOCATION args; + LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 args2; + uint32_t *param = NULL; switch (device) { case ATOM_DEVICE_DFP1_INDEX: - RADEON_WRITE(AVIVO_TMDSA_BIT_DEPTH_CONTROL, 0); /* TMDSA */ + index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); break; - case ATOM_DEVICE_DFP2_INDEX: - if ((dev_priv->chip_family == CHIP_RS600) || - (dev_priv->chip_family == CHIP_RS690) || - (dev_priv->chip_family == CHIP_RS740)) - RADEON_WRITE(AVIVO_DDIA_BIT_DEPTH_CONTROL, 0); /* DDIA */ - else - RADEON_WRITE(AVIVO_DVOA_BIT_DEPTH_CONTROL, 0); /* DVO */ + case ATOM_DEVICE_LCD1_INDEX: + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); break; - /*case ATOM_DEVICE_LCD1_INDEX:*/ /* LVDS panels need dither enabled */ case ATOM_DEVICE_DFP3_INDEX: - RADEON_WRITE(AVIVO_LVTMA_BIT_DEPTH_CONTROL, 0); /* LVTMA */ + index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); break; default: + return; + } + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + switch (frev) { + case 0: + case 1: + switch (crev) { + case 0: + case 1: + memset(&args, 0, sizeof(args)); + args.ucAction = PANEL_ENCODER_ACTION_ENABLE; + // TODO HDMI + //if (radeon_encoder->type == OUTPUT_HDMI) + //disp_data.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.usPixelClock = cpu_to_le16(mode->clock / 10); + if (device == ATOM_DEVICE_LCD1_INDEX) { + if (radeon_encoder->lvds_misc & (1 << 0)) + args.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (radeon_encoder->lvds_misc & (1 << 1)) + args.ucMisc |= (1 << 1); + } else { + if (mode->clock > 165000) + args.ucMisc |= PANEL_ENCODER_MISC_DUAL; + // TODO 6-bit DAC + args.ucMisc |= (1 << 1); + } + param = (uint32_t *)&args; + break; + case 2: + case 3: + memset(&args2, 0, sizeof(args2)); + args2.ucAction = PANEL_ENCODER_ACTION_ENABLE; + if (crev == 3) { + // TODO coherent mode + //if (encoder->coherent_mode) + //args2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; + } + // TODO HDMI + //if (radeon_encoder->type == OUTPUT_HDMI) + //args2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + if (device == ATOM_DEVICE_LCD1_INDEX) { + if (radeon_encoder->lvds_misc & (1 << 0)) + args2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (radeon_encoder->lvds_misc & (1 << 5)) { + args2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; + if (radeon_encoder->lvds_misc & (1 << 1)) + args2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; + } + if (radeon_encoder->lvds_misc & (1 << 6)) { + args2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; + if (radeon_encoder->lvds_misc & (1 << 1)) + args2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; + } + } else { + if (mode->clock > 165000) + args2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + } + param = (uint32_t *)&args2; + break; + } break; } -} + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)param); +} static void radeon_lvtma_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - LVDS_ENCODER_CONTROL_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); - memset(&args, 0, sizeof(args)); atombios_scaler_setup(encoder, mode); atombios_set_crtc_source(encoder, ATOM_DEVICE_LCD1_INDEX); - - args.ucAction = 1; - if (adjusted_mode->clock > 165000) - args.ucMisc = 1; - else - args.ucMisc = 0; - args.usPixelClock = cpu_to_le16(adjusted_mode->clock / 10); - - printk("executing set LVDS encoder\n"); - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + atombios_output_digital_mode_set(encoder, ATOM_DEVICE_LCD1_INDEX, adjusted_mode); } @@ -287,7 +334,6 @@ static void radeon_lvtma_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_crtc *radeon_crtc; int index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); uint32_t bios_2_scratch, bios_3_scratch; int crtc_id = 0; @@ -593,7 +639,6 @@ static int atombios_tv1_setup(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); TV_ENCODER_CONTROL_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); @@ -617,7 +662,6 @@ static void radeon_atom_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); int atom_type = -1; @@ -724,69 +768,22 @@ static const struct drm_encoder_funcs radeon_atom_dac_enc_funcs = { . destroy = radeon_enc_destroy, }; - -static void atombios_tmds1_setup(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - TMDS1_ENCODER_CONTROL_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); - - memset(&args, 0, sizeof(args)); - args.ucAction = 1; - if (mode->clock > 165000) - args.ucMisc = 1; - else - args.ucMisc = 0; - - args.usPixelClock = cpu_to_le16(mode->clock / 10); - - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); -} - -static void atombios_tmds2_setup(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - struct drm_device *dev = encoder->dev; - struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - TMDS2_ENCODER_CONTROL_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); - - memset(&args, 0, sizeof(args)); - args.ucAction = 1; - if (mode->clock > 165000) - args.ucMisc = 1; - else - args.ucMisc = 0; - - args.usPixelClock = cpu_to_le16(mode->clock / 10); - - atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); -} - - void atombios_ext_tmds_setup(struct drm_encoder *encoder, struct drm_display_mode *mode) { struct drm_device *dev = encoder->dev; struct drm_radeon_private *dev_priv = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); memset(&args, 0, sizeof(args)); - args.sXTmdsEncoder.ucEnable = 1; + args.sXTmdsEncoder.ucEnable = PANEL_ENCODER_ACTION_ENABLE; if (mode->clock > 165000) - args.sXTmdsEncoder.ucMisc = 1; - else - args.sXTmdsEncoder.ucMisc = 0; + args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; // TODO 6-bit DAC -// args.usPixelClock = cpu_to_le16(mode->clock / 10); + args.sXTmdsEncoder.ucMisc |= (1 << 1); atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } @@ -799,7 +796,8 @@ static void atombios_dig1_setup(struct drm_encoder *encoder, DIG_ENCODER_CONTROL_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); - args.ucAction = 1; + memset(&args, 0, sizeof(args)); + args.ucAction = ATOM_ENABLE; args.usPixelClock = mode->clock / 10; args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER1; @@ -827,13 +825,12 @@ static void atombios_ddia_setup(struct drm_encoder *encoder, DVO_ENCODER_CONTROL_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); - args.sDVOEncoder.ucAction = ATOM_ENABLE; - args.sDVOEncoder.usPixelClock = mode->clock / 10; + memset(&args, 0, sizeof(args)); + args.sDVOEncoder.ucAction = PANEL_ENCODER_ACTION_ENABLE; + args.sDVOEncoder.usPixelClock = cpu_to_le16(mode->clock / 10); if (mode->clock > 165000) args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; - else - args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = 0; atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); } @@ -846,8 +843,10 @@ struct drm_encoder *radeon_encoder_atom_dac_add(struct drm_device *dev, int bios struct drm_encoder *encoder; int type = with_tv ? DRM_MODE_ENCODER_TVDAC : DRM_MODE_ENCODER_DAC; int found = 0; - int digital_enc_mask = ~(ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT | - ATOM_DEVICE_LCD1_SUPPORT); + int digital_enc_mask = ~(ATOM_DEVICE_DFP1_SUPPORT | + ATOM_DEVICE_DFP2_SUPPORT | + ATOM_DEVICE_DFP3_SUPPORT | + ATOM_DEVICE_LCD1_SUPPORT); /* we may already have added this encoder */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->encoder_type != DRM_MODE_ENCODER_DAC || @@ -1036,7 +1035,7 @@ static void radeon_atom_tmds_mode_set(struct drm_encoder *encoder, atombios_set_crtc_source(encoder, atom_type); if (atom_type == ATOM_DEVICE_DFP1_INDEX) - atombios_tmds1_setup(encoder, adjusted_mode); + atombios_output_digital_mode_set(encoder, ATOM_DEVICE_DFP1_INDEX, adjusted_mode); if (atom_type == ATOM_DEVICE_DFP2_INDEX) { if ((dev_priv->chip_family == CHIP_RS600) || (dev_priv->chip_family == CHIP_RS690) || @@ -1046,10 +1045,7 @@ static void radeon_atom_tmds_mode_set(struct drm_encoder *encoder, atombios_ext_tmds_setup(encoder, adjusted_mode); } if (atom_type == ATOM_DEVICE_DFP3_INDEX) - atombios_tmds2_setup(encoder, adjusted_mode); - radeon_dfp_disable_dither(encoder, atom_type); - - + atombios_output_digital_mode_set(encoder, ATOM_DEVICE_DFP3_INDEX, adjusted_mode); } static void radeon_atom_tmds_prepare(struct drm_encoder *encoder) @@ -1085,7 +1081,7 @@ struct drm_encoder *radeon_encoder_atom_tmds_add(struct drm_device *dev, int bio struct drm_encoder *encoder; int analog_enc_mask = ~(ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT); - radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); if (!radeon_encoder) { return NULL; } diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index fef27380..64608e35 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -116,6 +116,8 @@ struct radeon_i2c_bus_rec { uint32_t get_data_mask; uint32_t a_clk_mask; uint32_t a_data_mask; + int hw_line; + bool hw_capable; }; struct radeon_bios_connector { @@ -227,6 +229,10 @@ struct radeon_encoder { bool use_bios_dividers; uint32_t lvds_gen_cntl; + /* atom lvds */ + int lvds_misc; + int lvds_ss_id; + /* legacy primary dac */ uint32_t ps2_pdac_adj; -- cgit v1.2.3 From fc33686ef044a4a59d48da2a648a0c2d0a1a7fd6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:49:58 +1000 Subject: drm/radeon: initial suspend/resume fix. This enables the evict code and also sets radeon up to allow evict from VRAM to LOCAL --- linux-core/drm_bo.c | 2 +- linux-core/radeon_buffer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index ecf65c20..94a81559 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2126,7 +2126,7 @@ void drm_bo_evict_mm(struct drm_device *dev, int mem_type, int no_wait) drm_bo_usage_deref_unlocked(&entry); mutex_lock(&dev->struct_mutex); - } while(0); + } while(1); mutex_unlock(&dev->struct_mutex); diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index fe2aa6fd..c375100c 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -436,6 +436,6 @@ uint64_t radeon_evict_flags(struct drm_buffer_object *bo) case DRM_BO_MEM_TT: return DRM_BO_FLAG_MEM_LOCAL; default: - return DRM_BO_FLAG_MEM_TT; + return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_LOCAL; } } -- cgit v1.2.3 From 11320fd6b106c1255f3fad0860cb4da71697b46a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:50:31 +1000 Subject: drm: add discardable flag. This discards memory contents on suspend/resume with the hope the upper layers know something we don't. --- linux-core/drm_bo.c | 13 ++++++++++--- linux-core/drm_objects.h | 6 ++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 94a81559..93df229f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2098,22 +2098,29 @@ void drm_bo_evict_mm(struct drm_device *dev, int mem_type, int no_wait) struct list_head *lru; int ret; /* evict all buffers on the LRU - won't evict pinned buffers */ - + + drm_mm_dump(&man->manager); mutex_lock(&dev->struct_mutex); do { lru = &man->lru; - if (lru->next == lru) { +redo: + if (lru->next == &man->lru) { DRM_ERROR("lru empty\n"); break; } entry = list_entry(lru->next, struct drm_buffer_object, lru); + + if (entry->mem.flags & DRM_BO_FLAG_DISCARDABLE) { + lru = lru->next; + goto redo; + } + atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); - DRM_ERROR("Evicting %p %d\n", entry, entry->num_pages); ret = drm_bo_evict(entry, mem_type, no_wait); mutex_unlock(&entry->mutex); diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index acb10f96..0c8ffe92 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -117,6 +117,12 @@ struct drm_fence_arg { */ #define DRM_BO_FLAG_NO_MOVE (1ULL << 8) +/* + * Mask: if set the note the buffer contents are discardable + * Flags: if set the buffer contents are discardable on migration + */ +#define DRM_BO_FLAG_DISCARDABLE (1ULL << 9) + /* Mask: Make sure the buffer is in cached memory when mapped. In conjunction * with DRM_BO_FLAG_CACHED it also allows the buffer to be bound into the GART * with unsnooped PTEs instead of snooped, by using chipset-specific cache -- cgit v1.2.3 From d958cd7bb95558aa6c49824e2ae2b302f1433d2e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:51:31 +1000 Subject: radeon: use discardable flags on no backing store objects --- linux-core/radeon_fb.c | 2 +- linux-core/radeon_gem.c | 7 +++++-- shared-core/radeon_drv.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/linux-core/radeon_fb.c b/linux-core/radeon_fb.c index 8c9461da..8d4181e8 100644 --- a/linux-core/radeon_fb.c +++ b/linux-core/radeon_fb.c @@ -728,7 +728,7 @@ int radeonfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_heigh size = mode_cmd.pitch * mode_cmd.height; aligned_size = ALIGN(size, PAGE_SIZE); - fbo = radeon_gem_object_alloc(dev, aligned_size, 1, RADEON_GEM_DOMAIN_VRAM); + fbo = radeon_gem_object_alloc(dev, aligned_size, 1, RADEON_GEM_DOMAIN_VRAM, 0); if (!fbo) { printk(KERN_ERR "failed to allocate framebuffer\n"); ret = -ENOMEM; diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 225f0269..5e2ad98b 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -74,7 +74,7 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, } struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, - int initial_domain) + int initial_domain, bool discardable) { struct drm_gem_object *obj; struct drm_radeon_gem_object *obj_priv; @@ -97,6 +97,9 @@ struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, flags |= DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE; + if (discardable) + flags |= DRM_BO_FLAG_DISCARDABLE; + if (alignment == 0) alignment = PAGE_SIZE; @@ -129,7 +132,7 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, /* create a gem object to contain this object in */ args->size = roundup(args->size, PAGE_SIZE); - obj = radeon_gem_object_alloc(dev, args->size, args->alignment, args->initial_domain); + obj = radeon_gem_object_alloc(dev, args->size, args->alignment, args->initial_domain, args->no_backing_store); if (!obj) return -EINVAL; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 3490ddbe..c37f23d6 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1672,7 +1672,7 @@ int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, - int initial_domain); + int initial_domain, bool discardable); int radeon_modeset_init(struct drm_device *dev); void radeon_modeset_cleanup(struct drm_device *dev); extern u32 radeon_read_mc_reg(drm_radeon_private_t *dev_priv, int addr); -- cgit v1.2.3 From 09f99dc5febecac63d8c636abadea53e89d879aa Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:51:56 +1000 Subject: drm: remove stray debug code --- linux-core/drm_bo.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 93df229f..36af51c2 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -2099,7 +2099,6 @@ void drm_bo_evict_mm(struct drm_device *dev, int mem_type, int no_wait) int ret; /* evict all buffers on the LRU - won't evict pinned buffers */ - drm_mm_dump(&man->manager); mutex_lock(&dev->struct_mutex); do { lru = &man->lru; -- cgit v1.2.3 From 3e3280eccc38cd080cbab7b471aad1b9cd12fd1b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:52:28 +1000 Subject: radeon: move memcpy until after CP is stopped --- linux-core/radeon_pm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index de107797..1a814d91 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -63,16 +63,16 @@ int radeon_suspend(struct drm_device *dev, pm_message_t state) if (!(dev_priv->flags & RADEON_IS_IGP)) drm_bo_evict_mm(dev, DRM_BO_MEM_VRAM, 0); - if (dev_priv->flags & RADEON_IS_PCIE) { - memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, RADEON_PCIGART_TABLE_SIZE); - } - dev_priv->pmregs.crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); for (i = 0; i < 8; i++) dev_priv->pmregs.bios_scratch[i] = RADEON_READ(RADEON_BIOS_0_SCRATCH + (i * 4)); radeon_modeset_cp_suspend(dev); + if (dev_priv->flags & RADEON_IS_PCIE) { + memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, RADEON_PCIGART_TABLE_SIZE); + } + pci_save_state(dev->pdev); if (state.event == PM_EVENT_SUSPEND) { -- cgit v1.2.3 From b18e6b0a0d9ef6902e4be1809ba710200f4c37be Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:52:53 +1000 Subject: radeon: fix buffer copying for VRAM->TT --- linux-core/radeon_buffer.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index c375100c..9090000e 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -306,22 +306,32 @@ static int radeon_move_flip(struct drm_buffer_object * bo, int ret; tmp_mem = *new_mem; - tmp_mem.mm_node = NULL; - tmp_mem.proposed_flags = DRM_BO_FLAG_MEM_TT; - ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); - if (ret) - return ret; + /* if we are flipping into LOCAL memory we have no TTM so create one */ + if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + tmp_mem.mm_node = NULL; + tmp_mem.proposed_flags = DRM_BO_FLAG_MEM_TT; - ret = drm_ttm_bind(bo->ttm, &tmp_mem); - if (ret) - goto out_cleanup; + ret = drm_bo_mem_space(bo, &tmp_mem, no_wait); + if (ret) + return ret; + + ret = drm_ttm_bind(bo->ttm, &tmp_mem); + if (ret) + goto out_cleanup; + } ret = radeon_move_blit(bo, 1, no_wait, &tmp_mem, &bo->mem); if (ret) goto out_cleanup; - ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); + if (new_mem->mem_type == DRM_BO_MEM_LOCAL) { + ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem); + } else { + tmp_mem.mm_node = NULL; + new_mem->mm_node = NULL; + } + out_cleanup: if (tmp_mem.mm_node) { mutex_lock(&dev->struct_mutex); -- cgit v1.2.3 From 9c5819fc60808b00949f6aee55424f17a8b4f419 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:53:26 +1000 Subject: radeon: re-enable hw blits for copying from VRAM --- linux-core/radeon_buffer.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 9090000e..e5a90892 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -411,9 +411,6 @@ int radeon_move(struct drm_buffer_object * bo, return 0; } - /* disable these blit moves for now that appear to be failing */ - goto fallback; - if (new_mem->mem_type == DRM_BO_MEM_VRAM) { if (radeon_move_vram(bo, evict, no_wait, new_mem)) goto fallback; -- cgit v1.2.3 From 318770a78dc563a9a2780614fa3bf6c813584889 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:53:55 +1000 Subject: radeon: fixup suspend/resume bus master enable --- linux-core/radeon_pm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index 1a814d91..0a068cb8 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -97,12 +97,14 @@ int radeon_resume(struct drm_device *dev) pci_restore_state(dev->pdev); if (pci_enable_device(dev->pdev)) return -1; - pci_set_master(dev->pdev); - /* Turn on bus mastering */ - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; - RADEON_WRITE(RADEON_BUS_CNTL, tmp); + /* Turn on bus mastering -todo fix properly */ + if (dev_priv->chip_family < CHIP_RV380) { + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); + } + DRM_ERROR("\n"); /* on atom cards re init the whole card and set the modes again */ @@ -113,6 +115,8 @@ int radeon_resume(struct drm_device *dev) radeon_combios_asic_init(dev); } + pci_set_master(dev->pdev); + for (i = 0; i < 8; i++) RADEON_WRITE(RADEON_BIOS_0_SCRATCH + (i * 4), dev_priv->pmregs.bios_scratch[i]); @@ -160,7 +164,7 @@ int radeon_resume(struct drm_device *dev) master_priv->sarea_priv->ctx_owner = 0; } - /* unpin the front buffers */ + /* pin the front buffers */ list_for_each_entry(fb, &dev->mode_config.fb_kernel_list, filp_head) { struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); -- cgit v1.2.3 From 66740cbd5411a870dc6cc282c19a72809dd992be Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:55:24 +1000 Subject: radeon: fixup interrupt suspend/resume --- linux-core/radeon_pm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index 0a068cb8..6b1e6f84 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -69,6 +69,11 @@ int radeon_suspend(struct drm_device *dev, pm_message_t state) radeon_modeset_cp_suspend(dev); + /* Disable *all* interrupts */ + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) + RADEON_WRITE(R500_DxMODE_INT_MASK, 0); + RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); + if (dev_priv->flags & RADEON_IS_PCIE) { memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, RADEON_PCIGART_TABLE_SIZE); } @@ -155,7 +160,9 @@ int radeon_resume(struct drm_device *dev) /* reset swi reg */ RADEON_WRITE(RADEON_LAST_SWI_REG, dev_priv->counter); -// radeon_enable_interrupt(dev); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) + RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); + RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); /* reset the context for userspace */ if (dev->primary->master) { -- cgit v1.2.3 From 8d9a11c55cf3692bd537c68044b4378aba53f438 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:57:31 +1000 Subject: radeon: add CS support for r100/r200 in 2D driver --- shared-core/r300_cmdbuf.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_cs.c | 5 ++++ 2 files changed, 69 insertions(+) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index 725829b2..b15e8928 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -35,6 +35,7 @@ #include "drm.h" #include "radeon_drm.h" #include "radeon_drv.h" +#include "radeon_reg.h" #include "r300_reg.h" #define R300_SIMULTANEOUS_CLIPRECTS 4 @@ -309,6 +310,69 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(RADEON_RE_WIDTH_HEIGHT, 1); ADD_RANGE(RADEON_AUX_SC_CNTL, 1); ADD_RANGE(RADEON_RB3D_DSTCACHE_CTLSTAT, 1); + ADD_RANGE(RADEON_RB3D_PLANEMASK, 1); + ADD_RANGE(RADEON_SE_CNTL, 1); + ADD_RANGE(RADEON_PP_CNTL, 1); + ADD_RANGE(RADEON_RB3D_CNTL, 1); + ADD_RANGE_MARK(RADEON_RB3D_COLOROFFSET, 1, MARK_CHECK_OFFSET); + ADD_RANGE(RADEON_RB3D_COLORPITCH, 1); + ADD_RANGE(RADEON_RB3D_BLENDCNTL, 1); + + if (dev_priv->chip_family >= CHIP_R200) { + ADD_RANGE(R200_PP_CNTL_X, 1); + ADD_RANGE(R200_PP_TXMULTI_CTL_0, 1); + ADD_RANGE(R200_SE_VTX_STATE_CNTL, 1); + ADD_RANGE(R200_RE_CNTL, 1); + ADD_RANGE(R200_SE_VTE_CNTL, 1); + ADD_RANGE(R200_SE_VAP_CNTL, 1); + + ADD_RANGE(R200_PP_TXFILTER_0, 1); + ADD_RANGE(R200_PP_TXFORMAT_0, 1); + ADD_RANGE(R200_PP_TXFORMAT_X_0, 1); + ADD_RANGE(R200_PP_TXSIZE_0, 1); + ADD_RANGE(R200_PP_TXPITCH_0, 1); + ADD_RANGE(R200_PP_TFACTOR_0, 1); + + ADD_RANGE(R200_PP_TXFILTER_1, 1); + ADD_RANGE(R200_PP_TXFORMAT_1, 1); + ADD_RANGE(R200_PP_TXFORMAT_X_1, 1); + ADD_RANGE(R200_PP_TXSIZE_1, 1); + ADD_RANGE(R200_PP_TXPITCH_1, 1); + ADD_RANGE(R200_PP_TFACTOR_1, 1); + + ADD_RANGE_MARK(R200_PP_TXOFFSET_0, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_1, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_2, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_3, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_4, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_5, 1, MARK_CHECK_OFFSET); + + ADD_RANGE(R200_SE_VTX_FMT_0, 1); + ADD_RANGE(R200_SE_VTX_FMT_1, 1); + ADD_RANGE(R200_PP_TXCBLEND_0, 1); + ADD_RANGE(R200_PP_TXCBLEND2_0, 1); + ADD_RANGE(R200_PP_TXABLEND_0, 1); + ADD_RANGE(R200_PP_TXABLEND2_0, 1); + + } else { + + ADD_RANGE(RADEON_PP_TXFILTER_0, 1); + ADD_RANGE(RADEON_PP_TXFORMAT_0, 1); + ADD_RANGE(RADEON_PP_TEX_SIZE_0, 1); + ADD_RANGE(RADEON_PP_TEX_PITCH_0, 1); + + ADD_RANGE(RADEON_PP_TXFILTER_1, 1); + ADD_RANGE(RADEON_PP_TXFORMAT_1, 1); + ADD_RANGE(RADEON_PP_TEX_SIZE_1, 1); + ADD_RANGE(RADEON_PP_TEX_PITCH_1, 1); + + ADD_RANGE(RADEON_PP_TXCBLEND_0, 1); + ADD_RANGE(RADEON_PP_TXABLEND_0, 1); + ADD_RANGE(RADEON_SE_VTX_FMT, 1); + ADD_RANGE_MARK(RADEON_PP_TXOFFSET_0, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_PP_TXOFFSET_1, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_PP_TXOFFSET_2, 1, MARK_CHECK_OFFSET); + } } } diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index a00ec21b..f9147136 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -139,10 +139,15 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct offset >>= 10; val |= offset; break; + case RADEON_RB3D_COLOROFFSET: case R300_RB3D_COLOROFFSET0: case R300_ZB_DEPTHOFFSET: case R300_TX_OFFSET_0: case R300_TX_OFFSET_0+4: + case R200_PP_TXOFFSET_0: + case R200_PP_TXOFFSET_1: + case RADEON_PP_TXOFFSET_0: + case RADEON_PP_TXOFFSET_1: ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset); if (ret) return ret; -- cgit v1.2.3 From 26076bf24a4e720e389d0a3ea616a8350397fdfc Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Oct 2008 10:59:31 +1000 Subject: radeon: add initial agp support. This add agpmode command line option. --- linux-core/radeon_drv.c | 5 +++ shared-core/radeon_cp.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++- shared-core/radeon_drv.h | 1 + 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 79bcc3e6..f1fe3012 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -39,6 +39,7 @@ int radeon_no_wb; int radeon_dynclks = 1; int radeon_r4xx_atom = 0; +int radeon_agpmode = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers\n"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -52,6 +53,10 @@ module_param_named(dynclks, radeon_dynclks, int, 0444); MODULE_PARM_DESC(r4xx_atom, "Enable ATOMBIOS modesetting for R4xx"); module_param_named(r4xx_atom, radeon_r4xx_atom, int, 0444); +MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); +module_param_named(agpmode, radeon_agpmode, int, 0444); + + static int dri_library_name(struct drm_device * dev, char * buf) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 9825d709..190b1432 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2334,7 +2334,6 @@ int radeon_modeset_cp_suspend(struct drm_device *dev) int radeon_modeset_cp_resume(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; - uint32_t tmp; radeon_do_wait_for_idle(dev_priv); #if __OS_HAS_AGP @@ -2358,6 +2357,95 @@ int radeon_modeset_cp_resume(struct drm_device *dev) return 0; } +#if __OS_HAS_AGP +int radeon_modeset_agp_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_agp_mode mode; + struct drm_agp_info info; + int ret; + int default_mode; + uint32_t agp_status; + bool is_v3; + + /* Acquire AGP. */ + ret = drm_agp_acquire(dev); + if (ret) { + DRM_ERROR("Unable to acquire AGP: %d\n", ret); + return ret; + } + + ret = drm_agp_info(dev, &info); + if (ret) { + DRM_ERROR("Unable to get AGP info: %d\n", ret); + return ret; + } + + mode.mode = info.mode; + + agp_status = (RADEON_READ(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; + is_v3 = !!(agp_status & RADEON_AGPv3_MODE); + + if (is_v3) { + default_mode = (agp_status & RADEON_AGPv3_8X_MODE) ? 8 : 4; + } else { + if (agp_status & RADEON_AGP_4X_MODE) default_mode = 4; + else if (agp_status & RADEON_AGP_2X_MODE) default_mode = 2; + else default_mode = 1; + } + + if (radeon_agpmode > 0) { + if ((radeon_agpmode < (is_v3 ? 4 : 1)) || + (radeon_agpmode > (is_v3 ? 8 : 4)) || + (radeon_agpmode & (radeon_agpmode - 1))) { + DRM_ERROR("Illegal AGP Mode: %d (valid %s), leaving at %d\n", + radeon_agpmode, is_v3 ? "4, 8" : "1, 2, 4", + default_mode); + radeon_agpmode = default_mode; + } + else + DRM_INFO("AGP mode requested: %d\n", radeon_agpmode); + } else + radeon_agpmode = default_mode; + + mode.mode &= ~RADEON_AGP_MODE_MASK; + if (is_v3) { + switch(radeon_agpmode) { + case 8: + mode.mode |= RADEON_AGPv3_8X_MODE; + break; + case 4: + default: + mode.mode |= RADEON_AGPv3_4X_MODE; + break; + } + } else { + switch(radeon_agpmode) { + case 4: mode.mode |= RADEON_AGP_4X_MODE; + case 2: mode.mode |= RADEON_AGP_2X_MODE; + case 1: + default: + mode.mode |= RADEON_AGP_1X_MODE; + break; + } + } + + mode.mode &= ~RADEON_AGP_FW_MODE; /* disable fw */ + + ret = drm_agp_enable(dev, mode); + if (ret) { + DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode); + return ret; + } + + /* workaround some hw issues */ + if (dev_priv->chip_family <= CHIP_R200) { + RADEON_WRITE(RADEON_AGP_CNTL, RADEON_READ(RADEON_AGP_CNTL) | 0x000e0000); + } + return 0; +} +#endif + int radeon_modeset_cp_init(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -2389,6 +2477,11 @@ int radeon_modeset_cp_init(struct drm_device *dev) dev_priv->new_memmap = true; r300_init_reg_flags(dev); + +#if __OS_HAS_AGP + if (dev_priv->flags & RADEON_IS_AGP) + radeon_modeset_agp_init(dev); +#endif return radeon_modeset_cp_resume(dev); } @@ -2478,6 +2571,7 @@ int radeon_static_clocks_init(struct drm_device *dev) } } radeon_force_some_clocks(dev); + return 0; } int radeon_driver_load(struct drm_device *dev, unsigned long flags) @@ -2523,6 +2617,12 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) DRM_DEBUG("%s card detected\n", ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); + if ((dev_priv->flags & RADEON_IS_AGP) && (radeon_agpmode == -1)) { + DRM_INFO("Forcing AGP to PCI mode\n"); + dev_priv->flags &= ~RADEON_IS_AGP; + } + + ret = drm_addmap(dev, drm_get_resource_start(dev, 2), drm_get_resource_len(dev, 2), _DRM_REGISTERS, _DRM_DRIVER | _DRM_READ_ONLY, &dev_priv->mmio); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index c37f23d6..a6ce129d 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -459,6 +459,7 @@ extern int radeon_dynclks; extern int radeon_r4xx_atom; extern struct drm_ioctl_desc radeon_ioctls[]; extern int radeon_max_ioctl; +extern int radeon_agpmode; /* Check whether the given hardware address is inside the framebuffer or the * GART area. -- cgit v1.2.3 From 6df7b0719fe92b718e486c2b87e2f883cfa41efa Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 12 Jun 2008 23:22:26 -0700 Subject: intel: Protect bufmgr objects with a pthread mutex. We want to be able to use the bufmgr from multiple threads for GL, and thus we need to protect the internal structures. The pthread-stubs package is used so that programs not linked against pthreads get weak symbols to stubs and don't eat most of the cost. --- configure.ac | 4 ++ libdrm/Makefile.am | 4 +- libdrm/intel/Makefile.am | 1 + libdrm/intel/intel_bufmgr_fake.c | 112 +++++++++++++++++++++++++++++++++------ libdrm/intel/intel_bufmgr_gem.c | 65 ++++++++++++++++++----- 5 files changed, 155 insertions(+), 31 deletions(-) diff --git a/configure.ac b/configure.ac index 0cf09744..92507cb5 100644 --- a/configure.ac +++ b/configure.ac @@ -32,6 +32,10 @@ AC_PROG_CC AC_HEADER_STDC AC_SYS_LARGEFILE +PKG_CHECK_MODULES(PTHREADSTUBS, pthread-stubs) +AC_SUBST(PTHREADSTUBS_CFLAGS) +AC_SUBST(PTHREADSTUBS_LIBS) + pkgconfigdir=${libdir}/pkgconfig AC_SUBST(pkgconfigdir) AC_ARG_ENABLE(udev, AS_HELP_STRING([--enable-udev], diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index 532ca138..8e1c0ee4 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -26,8 +26,8 @@ libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined AM_CFLAGS = -I$(top_srcdir)/shared-core libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c \ - xf86drmMode.c -libdrm_la_LIBADD = intel/libdrm_intel.la + xf86drmMode.c libdrm_lists.h +libdrm_la_LIBADD = intel/libdrm_intel.la @PTHREADSTUBS_LIBS@ libdrmincludedir = ${includedir} libdrminclude_HEADERS = xf86drm.h xf86drmMode.h diff --git a/libdrm/intel/Makefile.am b/libdrm/intel/Makefile.am index 607c4765..92388c24 100644 --- a/libdrm/intel/Makefile.am +++ b/libdrm/intel/Makefile.am @@ -26,6 +26,7 @@ AM_CFLAGS = \ $(WARN_CFLAGS) \ -I$(top_srcdir)/libdrm \ -I$(top_srcdir)/libdrm/intel \ + $(PTHREADSTUBS_CFLAGS) \ -I$(top_srcdir)/shared-core libdrm_intel_la_LTLIBRARIES = libdrm_intel.la diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index c88e1cb0..4c281467 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "intel_bufmgr.h" #include "intel_bufmgr_priv.h" #include "drm.h" @@ -112,6 +113,8 @@ struct block { typedef struct _bufmgr_fake { dri_bufmgr bufmgr; + pthread_mutex_t lock; + unsigned long low_offset; unsigned long size; void *virtual; @@ -716,10 +719,16 @@ dri_fake_bo_wait_rendering(dri_bo *bo) dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; - if (bo_fake->block == NULL || !bo_fake->block->fenced) + pthread_mutex_lock(&bufmgr_fake->lock); + + if (bo_fake->block == NULL || !bo_fake->block->fenced) { + pthread_mutex_unlock(&bufmgr_fake->lock); return; + } _fence_wait_internal(bufmgr_fake, bo_fake->block->fence); + + pthread_mutex_unlock(&bufmgr_fake->lock); } /* Specifically ignore texture memory sharing. @@ -732,6 +741,8 @@ intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr) dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; struct block *block, *tmp; + pthread_mutex_lock(&bufmgr_fake->lock); + bufmgr_fake->need_fence = 1; bufmgr_fake->fail = 0; @@ -751,6 +762,8 @@ intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr) assert(_fence_test(bufmgr_fake, block->fence)); set_dirty(block->bo); } + + pthread_mutex_unlock(&bufmgr_fake->lock); } static dri_bo * @@ -825,21 +838,29 @@ intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name, static void dri_fake_bo_reference(dri_bo *bo) { + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; + pthread_mutex_lock(&bufmgr_fake->lock); bo_fake->refcount++; + pthread_mutex_unlock(&bufmgr_fake->lock); } static void -dri_fake_bo_unreference(dri_bo *bo) +dri_fake_bo_reference_locked(dri_bo *bo) +{ + dri_bo_fake *bo_fake = (dri_bo_fake *)bo; + + bo_fake->refcount++; +} + +static void +dri_fake_bo_unreference_locked(dri_bo *bo) { dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; int i; - if (!bo) - return; - if (--bo_fake->refcount == 0) { assert(bo_fake->map_count == 0); /* No remaining references, so free it */ @@ -848,17 +869,25 @@ dri_fake_bo_unreference(dri_bo *bo) free_backing_store(bo); for (i = 0; i < bo_fake->nr_relocs; i++) - dri_bo_unreference(bo_fake->relocs[i].target_buf); + dri_fake_bo_unreference_locked(bo_fake->relocs[i].target_buf); DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id, bo_fake->name); free(bo_fake->relocs); free(bo); - - return; } } +static void +dri_fake_bo_unreference(dri_bo *bo) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; + + pthread_mutex_lock(&bufmgr_fake->lock); + dri_fake_bo_unreference_locked(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); +} + /** * Set the buffer as not requiring backing store, and instead get the callback * invoked whenever it would be set dirty. @@ -871,6 +900,8 @@ void intel_bo_fake_disable_backing_store(dri_bo *bo, dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; + pthread_mutex_lock(&bufmgr_fake->lock); + if (bo_fake->backing_store) free_backing_store(bo); @@ -887,6 +918,8 @@ void intel_bo_fake_disable_backing_store(dri_bo *bo, */ if (invalidate_cb != NULL) invalidate_cb(bo, ptr); + + pthread_mutex_unlock(&bufmgr_fake->lock); } /** @@ -894,7 +927,7 @@ void intel_bo_fake_disable_backing_store(dri_bo *bo, * BM_NO_BACKING_STORE or BM_PINNED) or backing store, as necessary. */ static int -dri_fake_bo_map(dri_bo *bo, int write_enable) +dri_fake_bo_map_locked(dri_bo *bo, int write_enable) { dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; @@ -952,7 +985,20 @@ dri_fake_bo_map(dri_bo *bo, int write_enable) } static int -dri_fake_bo_unmap(dri_bo *bo) +dri_fake_bo_map(dri_bo *bo, int write_enable) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; + int ret; + + pthread_mutex_lock(&bufmgr_fake->lock); + ret = dri_fake_bo_map_locked(bo, write_enable); + pthread_mutex_unlock(&bufmgr_fake->lock); + + return ret; +} + +static int +dri_fake_bo_unmap_locked(dri_bo *bo) { dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; @@ -973,11 +1019,26 @@ dri_fake_bo_unmap(dri_bo *bo) return 0; } +static int +dri_fake_bo_unmap(dri_bo *bo) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; + int ret; + + pthread_mutex_lock(&bufmgr_fake->lock); + ret = dri_fake_bo_unmap_locked(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); + + return ret; +} + static void dri_fake_kick_all(dri_bufmgr_fake *bufmgr_fake) { struct block *block, *tmp; + pthread_mutex_lock(&bufmgr_fake->lock); + bufmgr_fake->performed_rendering = 0; /* okay for ever BO that is on the HW kick it off. seriously not afraid of the POLICE right now */ @@ -991,6 +1052,8 @@ dri_fake_kick_all(dri_bufmgr_fake *bufmgr_fake) if (!(bo_fake->flags & BM_NO_BACKING_STORE)) bo_fake->dirty = 1; } + + pthread_mutex_unlock(&bufmgr_fake->lock); } static int @@ -999,9 +1062,6 @@ dri_fake_bo_validate(dri_bo *bo) dri_bufmgr_fake *bufmgr_fake; dri_bo_fake *bo_fake = (dri_bo_fake *)bo; - /* XXX: Sanity-check whether we've already validated this one under - * different flags. See drmAddValidateItem(). - */ bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; DBG("drm_bo_validate: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, @@ -1084,6 +1144,7 @@ dri_fake_destroy(dri_bufmgr *bufmgr) { dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; + pthread_mutex_destroy(&bufmgr_fake->lock); mmDestroy(bufmgr_fake->heap); free(bufmgr); } @@ -1099,6 +1160,8 @@ dri_fake_emit_reloc(dri_bo *reloc_buf, dri_bo_fake *target_fake = (dri_bo_fake *)target_buf; int i; + pthread_mutex_lock(&bufmgr_fake->lock); + assert(reloc_buf); assert(target_buf); @@ -1111,7 +1174,7 @@ dri_fake_emit_reloc(dri_bo *reloc_buf, assert(reloc_fake->nr_relocs <= MAX_RELOCS); - dri_bo_reference(target_buf); + dri_fake_bo_reference_locked(target_buf); if (!target_fake->is_static) reloc_fake->child_size += ALIGN(target_buf->size, target_fake->alignment); @@ -1132,6 +1195,8 @@ dri_fake_emit_reloc(dri_bo *reloc_buf, } } + pthread_mutex_unlock(&bufmgr_fake->lock); + return 0; } @@ -1178,7 +1243,7 @@ dri_fake_reloc_and_validate_buffer(dri_bo *bo) ret = dri_fake_reloc_and_validate_buffer(r->target_buf); if (ret != 0) { if (bo->virtual != NULL) - dri_bo_unmap(bo); + dri_fake_bo_unmap_locked(bo); return ret; } } @@ -1188,7 +1253,7 @@ dri_fake_reloc_and_validate_buffer(dri_bo *bo) reloc_data = r->target_buf->offset + r->delta; if (bo->virtual == NULL) - dri_bo_map(bo, 1); + dri_fake_bo_map_locked(bo, 1); *(uint32_t *)((uint8_t *)bo->virtual + r->offset) = reloc_data; @@ -1197,7 +1262,7 @@ dri_fake_reloc_and_validate_buffer(dri_bo *bo) } if (bo->virtual != NULL) - dri_bo_unmap(bo); + dri_fake_bo_unmap_locked(bo); if (bo_fake->write_domain != 0) { if (!(bo_fake->flags & (BM_NO_BACKING_STORE|BM_PINNED))) { @@ -1261,6 +1326,8 @@ dri_fake_bo_exec(dri_bo *bo, int used, int ret; int retry_count = 0; + pthread_mutex_lock(&bufmgr_fake->lock); + bufmgr_fake->performed_rendering = 0; dri_fake_calculate_domains(bo); @@ -1305,6 +1372,8 @@ dri_fake_bo_exec(dri_bo *bo, int used, dri_bo_fake_post_submit(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); + return 0; } @@ -1357,6 +1426,8 @@ intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr) dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; struct block *block, *tmp; + pthread_mutex_lock(&bufmgr_fake->lock); + bufmgr_fake->need_fence = 1; bufmgr_fake->fail = 0; @@ -1376,6 +1447,8 @@ intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr) /* Releases the memory, and memcpys dirty contents out if necessary. */ free_block(bufmgr_fake, block); } + + pthread_mutex_unlock(&bufmgr_fake->lock); } void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr, volatile unsigned int *last_dispatch) @@ -1395,6 +1468,11 @@ intel_bufmgr_fake_init(int fd, bufmgr_fake = calloc(1, sizeof(*bufmgr_fake)); + if (pthread_mutex_init(&bufmgr_fake->lock, NULL) != 0) { + free(bufmgr_fake); + return NULL; + } + /* Initialize allocator */ DRMINITLISTHEAD(&bufmgr_fake->fenced); DRMINITLISTHEAD(&bufmgr_fake->on_hardware); diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 70cdca74..af58ad8f 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,8 @@ typedef struct _dri_bufmgr_gem { int max_relocs; + pthread_mutex_t lock; + struct drm_i915_gem_exec_object *exec_objects; dri_bo **exec_bos; int exec_size; @@ -133,6 +136,8 @@ struct _dri_bo_gem { dri_bo_gem *next; }; +static void dri_gem_bo_reference_locked(dri_bo *bo); + static int logbase2(int n) { @@ -237,7 +242,7 @@ intel_add_validate_buffer(dri_bo *bo) bufmgr_gem->exec_objects[index].alignment = 0; bufmgr_gem->exec_objects[index].offset = 0; bufmgr_gem->exec_bos[index] = bo; - dri_bo_reference(bo); + dri_gem_bo_reference_locked(bo); bufmgr_gem->exec_count++; } @@ -285,6 +290,7 @@ dri_gem_bo_alloc(dri_bufmgr *bufmgr, const char *name, bo_size = page_size; } + pthread_mutex_lock(&bufmgr_gem->lock); /* Get a buffer out of the cache if available */ if (bucket != NULL && bucket->num_entries > 0) { struct drm_i915_gem_busy busy; @@ -302,6 +308,7 @@ dri_gem_bo_alloc(dri_bufmgr *bufmgr, const char *name, bucket->num_entries--; } } + pthread_mutex_unlock(&bufmgr_gem->lock); if (!alloc_from_cache) { struct drm_i915_gem_create create; @@ -379,6 +386,17 @@ intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name, static void dri_gem_bo_reference(dri_bo *bo) +{ + dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; + dri_bo_gem *bo_gem = (dri_bo_gem *)bo; + + pthread_mutex_lock(&bufmgr_gem->lock); + bo_gem->refcount++; + pthread_mutex_unlock(&bufmgr_gem->lock); +} + +static void +dri_gem_bo_reference_locked(dri_bo *bo) { dri_bo_gem *bo_gem = (dri_bo_gem *)bo; @@ -408,14 +426,11 @@ dri_gem_bo_free(dri_bo *bo) } static void -dri_gem_bo_unreference(dri_bo *bo) +dri_gem_bo_unreference_locked(dri_bo *bo) { dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; dri_bo_gem *bo_gem = (dri_bo_gem *)bo; - if (!bo) - return; - if (--bo_gem->refcount == 0) { struct dri_gem_bo_bucket *bucket; @@ -424,7 +439,7 @@ dri_gem_bo_unreference(dri_bo *bo) /* Unreference all the target buffers */ for (i = 0; i < bo_gem->reloc_count; i++) - dri_bo_unreference(bo_gem->reloc_target_bo[i]); + dri_gem_bo_unreference_locked(bo_gem->reloc_target_bo[i]); free(bo_gem->reloc_target_bo); free(bo_gem->relocs); } @@ -452,20 +467,28 @@ dri_gem_bo_unreference(dri_bo *bo) } else { dri_gem_bo_free(bo); } - - return; } } +static void +dri_gem_bo_unreference(dri_bo *bo) +{ + dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; + + pthread_mutex_lock(&bufmgr_gem->lock); + dri_gem_bo_unreference_locked(bo); + pthread_mutex_unlock(&bufmgr_gem->lock); +} + static int dri_gem_bo_map(dri_bo *bo, int write_enable) { - dri_bufmgr_gem *bufmgr_gem; + dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; dri_bo_gem *bo_gem = (dri_bo_gem *)bo; struct drm_i915_gem_set_domain set_domain; int ret; - bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; + pthread_mutex_lock(&bufmgr_gem->lock); /* Allow recursive mapping. Mesa may recursively map buffers with * nested display loops. @@ -515,6 +538,8 @@ dri_gem_bo_map(dri_bo *bo, int write_enable) bo_gem->swrast = 1; } + pthread_mutex_unlock(&bufmgr_gem->lock); + return 0; } @@ -531,6 +556,7 @@ dri_gem_bo_unmap(dri_bo *bo) assert(bo_gem->mapped); + pthread_mutex_lock(&bufmgr_gem->lock); if (bo_gem->swrast) { sw_finish.handle = bo_gem->gem_handle; do { @@ -539,6 +565,7 @@ dri_gem_bo_unmap(dri_bo *bo) } while (ret == -1 && errno == EINTR); bo_gem->swrast = 0; } + pthread_mutex_unlock(&bufmgr_gem->lock); return 0; } @@ -623,6 +650,8 @@ dri_bufmgr_gem_destroy(dri_bufmgr *bufmgr) free(bufmgr_gem->exec_objects); free(bufmgr_gem->exec_bos); + pthread_mutex_destroy(&bufmgr_gem->lock); + /* Free any cached buffer objects we were going to reuse */ for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++) { struct dri_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i]; @@ -658,6 +687,8 @@ dri_gem_bo_emit_reloc(dri_bo *bo, uint32_t read_domains, uint32_t write_domain, dri_bo_gem *bo_gem = (dri_bo_gem *)bo; dri_bo_gem *target_bo_gem = (dri_bo_gem *)target_bo; + pthread_mutex_lock(&bufmgr_gem->lock); + /* Create a new relocation list if needed */ if (bo_gem->relocs == NULL) intel_setup_reloc_list(bo); @@ -678,9 +709,12 @@ dri_gem_bo_emit_reloc(dri_bo *bo, uint32_t read_domains, uint32_t write_domain, bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset; bo_gem->reloc_target_bo[bo_gem->reloc_count] = target_bo; - dri_bo_reference(target_bo); + dri_gem_bo_reference_locked(target_bo); bo_gem->reloc_count++; + + pthread_mutex_unlock(&bufmgr_gem->lock); + return 0; } @@ -737,6 +771,7 @@ dri_gem_bo_exec(dri_bo *bo, int used, struct drm_i915_gem_execbuffer execbuf; int ret, i; + pthread_mutex_lock(&bufmgr_gem->lock); /* Update indices and set up the validate list. */ dri_gem_bo_process_reloc(bo); @@ -772,10 +807,11 @@ dri_gem_bo_exec(dri_bo *bo, int used, /* Disconnect the buffer from the validate list */ bo_gem->validate_index = -1; - dri_bo_unreference(bo); + dri_gem_bo_unreference_locked(bo); bufmgr_gem->exec_bos[i] = NULL; } bufmgr_gem->exec_count = 0; + pthread_mutex_unlock(&bufmgr_gem->lock); return 0; } @@ -900,6 +936,11 @@ intel_bufmgr_gem_init(int fd, int batch_size) bufmgr_gem = calloc(1, sizeof(*bufmgr_gem)); bufmgr_gem->fd = fd; + if (pthread_mutex_init(&bufmgr_gem->lock, NULL) != 0) { + free(bufmgr_gem); + return NULL; + } + /* Let's go with one relocation per every 2 dwords (but round down a bit * since a power of two will mean an extra page allocation for the reloc * buffer). -- cgit v1.2.3 From 9dda3a8f63331cb55f4669fd8edb600f2e07ec86 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 13 Oct 2008 07:16:33 +1000 Subject: libdrm: don't depend or link to libdrm_intel --- libdrm/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index 8e1c0ee4..8fd985bd 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -27,7 +27,7 @@ libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined AM_CFLAGS = -I$(top_srcdir)/shared-core libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c \ xf86drmMode.c libdrm_lists.h -libdrm_la_LIBADD = intel/libdrm_intel.la @PTHREADSTUBS_LIBS@ +libdrm_la_LIBADD = @PTHREADSTUBS_LIBS@ libdrmincludedir = ${includedir} libdrminclude_HEADERS = xf86drm.h xf86drmMode.h -- cgit v1.2.3 From 4c8aeb6fc7fa9f0aa9df4fd855696afe4bf6c0b4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 17 Oct 2008 06:40:38 +1000 Subject: link libdrm_intel properly libdrm_intel needs symbols from libdrm, so link against it. (cherry picked from commit d9c2f65dd8e50736a33e97a55c257ef6843e1ce7) Conflicts: libdrm/Makefile.am --- libdrm/Makefile.am | 4 ++-- libdrm/intel/Makefile.am | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index 8fd985bd..c3619a6d 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -18,7 +18,7 @@ # 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. -SUBDIRS = intel +SUBDIRS = . intel libdrm_la_LTLIBRARIES = libdrm.la libdrm_ladir = $(libdir) @@ -27,7 +27,7 @@ libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined AM_CFLAGS = -I$(top_srcdir)/shared-core libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c \ xf86drmMode.c libdrm_lists.h -libdrm_la_LIBADD = @PTHREADSTUBS_LIBS@ + libdrm_lists.h libdrmincludedir = ${includedir} libdrminclude_HEADERS = xf86drm.h xf86drmMode.h diff --git a/libdrm/intel/Makefile.am b/libdrm/intel/Makefile.am index 92388c24..5e3dee06 100644 --- a/libdrm/intel/Makefile.am +++ b/libdrm/intel/Makefile.am @@ -32,6 +32,7 @@ AM_CFLAGS = \ libdrm_intel_la_LTLIBRARIES = libdrm_intel.la libdrm_intel_ladir = $(libdir) libdrm_intel_la_LDFLAGS = -version-number 1:0:0 -no-undefined +libdrm_intel_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ libdrm_intel_la_SOURCES = \ intel_bufmgr.c \ -- cgit v1.2.3 From 0796bf8c6b983de7fbb188bd5d84d4ea54f81525 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 24 Oct 2008 18:23:39 +0200 Subject: mode: Indent defines --- shared-core/drm_mode.h | 94 +++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h index 678dc230..01e6c7e7 100644 --- a/shared-core/drm_mode.h +++ b/shared-core/drm_mode.h @@ -33,10 +33,10 @@ #include #endif -#define DRM_DISPLAY_INFO_LEN 32 -#define DRM_CONNECTOR_NAME_LEN 32 -#define DRM_DISPLAY_MODE_LEN 32 -#define DRM_PROP_NAME_LEN 32 +#define DRM_DISPLAY_INFO_LEN 32 +#define DRM_CONNECTOR_NAME_LEN 32 +#define DRM_DISPLAY_MODE_LEN 32 +#define DRM_PROP_NAME_LEN 32 #define DRM_MODE_TYPE_BUILTIN (1<<0) #define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) @@ -65,20 +65,20 @@ /* DPMS flags */ /* bit compatible with the xorg definitions. */ -#define DRM_MODE_DPMS_ON 0 -#define DRM_MODE_DPMS_STANDBY 1 -#define DRM_MODE_DPMS_SUSPEND 2 -#define DRM_MODE_DPMS_OFF 3 +#define DRM_MODE_DPMS_ON 0 +#define DRM_MODE_DPMS_STANDBY 1 +#define DRM_MODE_DPMS_SUSPEND 2 +#define DRM_MODE_DPMS_OFF 3 /* Scaling mode options */ -#define DRM_MODE_SCALE_NON_GPU 0 -#define DRM_MODE_SCALE_FULLSCREEN 1 -#define DRM_MODE_SCALE_NO_SCALE 2 -#define DRM_MODE_SCALE_ASPECT 3 +#define DRM_MODE_SCALE_NON_GPU 0 +#define DRM_MODE_SCALE_FULLSCREEN 1 +#define DRM_MODE_SCALE_NO_SCALE 2 +#define DRM_MODE_SCALE_ASPECT 3 /* Dithering mode options */ -#define DRM_MODE_DITHERING_OFF 0 -#define DRM_MODE_DITHERING_ON 1 +#define DRM_MODE_DITHERING_OFF 0 +#define DRM_MODE_DITHERING_ON 1 struct drm_mode_modeinfo { unsigned int clock; @@ -119,11 +119,11 @@ struct drm_mode_crtc { struct drm_mode_modeinfo mode; }; -#define DRM_MODE_ENCODER_NONE 0 -#define DRM_MODE_ENCODER_DAC 1 -#define DRM_MODE_ENCODER_TMDS 2 -#define DRM_MODE_ENCODER_LVDS 3 -#define DRM_MODE_ENCODER_TVDAC 4 +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 struct drm_mode_get_encoder { @@ -138,27 +138,27 @@ struct drm_mode_get_encoder { /* This is for connectors with multiple signal types. */ /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ -#define DRM_MODE_SUBCONNECTOR_Automatic 0 -#define DRM_MODE_SUBCONNECTOR_Unknown 0 -#define DRM_MODE_SUBCONNECTOR_DVID 3 -#define DRM_MODE_SUBCONNECTOR_DVIA 4 -#define DRM_MODE_SUBCONNECTOR_Composite 5 -#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 -#define DRM_MODE_SUBCONNECTOR_Component 8 - -#define DRM_MODE_CONNECTOR_Unknown 0 -#define DRM_MODE_CONNECTOR_VGA 1 -#define DRM_MODE_CONNECTOR_DVII 2 -#define DRM_MODE_CONNECTOR_DVID 3 -#define DRM_MODE_CONNECTOR_DVIA 4 -#define DRM_MODE_CONNECTOR_Composite 5 -#define DRM_MODE_CONNECTOR_SVIDEO 6 -#define DRM_MODE_CONNECTOR_LVDS 7 -#define DRM_MODE_CONNECTOR_Component 8 -#define DRM_MODE_CONNECTOR_9PinDIN 9 -#define DRM_MODE_CONNECTOR_DisplayPort 10 -#define DRM_MODE_CONNECTOR_HDMIA 11 -#define DRM_MODE_CONNECTOR_HDMIB 12 +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 3 +#define DRM_MODE_SUBCONNECTOR_DVIA 4 +#define DRM_MODE_SUBCONNECTOR_Composite 5 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +#define DRM_MODE_SUBCONNECTOR_Component 8 + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 struct drm_mode_get_connector { @@ -181,11 +181,11 @@ struct drm_mode_get_connector { unsigned int subpixel; }; -#define DRM_MODE_PROP_PENDING (1<<0) -#define DRM_MODE_PROP_RANGE (1<<1) -#define DRM_MODE_PROP_IMMUTABLE (1<<2) -#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */ -#define DRM_MODE_PROP_BLOB (1<<4) +#define DRM_MODE_PROP_PENDING (1<<0) +#define DRM_MODE_PROP_RANGE (1<<1) +#define DRM_MODE_PROP_IMMUTABLE (1<<2) +#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */ +#define DRM_MODE_PROP_BLOB (1<<4) struct drm_mode_property_enum { uint64_t value; @@ -230,8 +230,8 @@ struct drm_mode_mode_cmd { struct drm_mode_modeinfo mode; }; -#define DRM_MODE_CURSOR_BO 0x01 -#define DRM_MODE_CURSOR_MOVE 0x02 +#define DRM_MODE_CURSOR_BO (1<<0) +#define DRM_MODE_CURSOR_MOVE (1<<1) /* * depending on the value in flags diffrent members are used. -- cgit v1.2.3 From 34a3ebffc369575412a4ff2c05c50264e83c6d3e Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 24 Oct 2008 18:43:55 +0200 Subject: mode: Try to settle on a standard for struct fields --- libdrm/xf86drmMode.c | 4 +-- linux-core/drm_crtc.c | 4 +-- shared-core/drm_mode.h | 78 +++++++++++++++++++++++++------------------------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index c3921ee9..a25b11bb 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -308,7 +308,7 @@ int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width struct drm_mode_cursor arg; arg.flags = DRM_MODE_CURSOR_BO; - arg.crtc = crtcId; + arg.crtc_id = crtcId; arg.width = width; arg.height = height; arg.handle = bo_handle; @@ -321,7 +321,7 @@ int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) struct drm_mode_cursor arg; arg.flags = DRM_MODE_CURSOR_MOVE; - arg.crtc = crtcId; + arg.crtc_id = crtcId; arg.x = x; arg.y = y; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 2fefd1d2..2f80ec07 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1448,9 +1448,9 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, } mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, req->crtc, DRM_MODE_OBJECT_CRTC); + obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { - DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc); + DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc_id); ret = -EINVAL; goto out; } diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h index 01e6c7e7..e6daa7ca 100644 --- a/shared-core/drm_mode.h +++ b/shared-core/drm_mode.h @@ -81,14 +81,14 @@ #define DRM_MODE_DITHERING_ON 1 struct drm_mode_modeinfo { - unsigned int clock; - unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; - unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan; + uint32_t clock; + uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; + uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; - unsigned int vrefresh; /* vertical refresh * 1000 */ + uint32_t vrefresh; /* vertical refresh * 1000 */ - unsigned int flags; - unsigned int type; + uint32_t flags; + uint32_t type; char name[DRM_DISPLAY_MODE_LEN]; }; @@ -97,25 +97,25 @@ struct drm_mode_card_res { uint64_t crtc_id_ptr; uint64_t connector_id_ptr; uint64_t encoder_id_ptr; - int count_fbs; - int count_crtcs; - int count_connectors; - int count_encoders; - int min_width, max_width; - int min_height, max_height; + uint32_t count_fbs; + uint32_t count_crtcs; + uint32_t count_connectors; + uint32_t count_encoders; + uint32_t min_width, max_width; + uint32_t min_height, max_height; }; struct drm_mode_crtc { uint64_t set_connectors_ptr; - int count_connectors; + uint32_t count_connectors; unsigned int crtc_id; /**< Id */ unsigned int fb_id; /**< Id of framebuffer */ - int x, y; /**< Position on the frameuffer */ + uint32_t x, y; /**< Position on the frameuffer */ uint32_t gamma_size; - int mode_valid; + uint32_t mode_valid; struct drm_mode_modeinfo mode; }; @@ -126,12 +126,11 @@ struct drm_mode_crtc { #define DRM_MODE_ENCODER_TVDAC 4 struct drm_mode_get_encoder { - - unsigned int encoder_type; unsigned int encoder_id; - unsigned int crtc_id; /**< Id of crtc */ + uint32_t encoder_type; + uint32_t possible_crtcs; uint32_t possible_clones; }; @@ -167,18 +166,18 @@ struct drm_mode_get_connector { uint64_t props_ptr; uint64_t prop_values_ptr; - int count_modes; - int count_props; - int count_encoders; + uint32_t count_modes; + uint32_t count_props; + uint32_t count_encoders; unsigned int encoder_id; /**< Current Encoder */ unsigned int connector_id; /**< Id */ unsigned int connector_type; unsigned int connector_type_id; - unsigned int connection; - unsigned int mm_width, mm_height; /**< HxW in millimeters */ - unsigned int subpixel; + uint32_t connection; + uint32_t mm_width, mm_height; /**< HxW in millimeters */ + uint32_t subpixel; }; #define DRM_MODE_PROP_PENDING (1<<0) @@ -197,11 +196,11 @@ struct drm_mode_get_property { uint64_t enum_blob_ptr; /* enum and blob id ptrs */ unsigned int prop_id; - unsigned int flags; + uint32_t flags; unsigned char name[DRM_PROP_NAME_LEN]; - int count_values; - int count_enum_blobs; + uint32_t count_values; + uint32_t count_enum_blobs; }; struct drm_mode_connector_set_property { @@ -218,11 +217,12 @@ struct drm_mode_get_blob { struct drm_mode_fb_cmd { unsigned int buffer_id; - unsigned int width, height; - unsigned int pitch; - unsigned int bpp; - unsigned int handle; - unsigned int depth; + uint32_t width, height; + uint32_t pitch; + uint32_t bpp; + uint32_t depth; + + uint64_t handle; }; struct drm_mode_mode_cmd { @@ -248,13 +248,14 @@ struct drm_mode_mode_cmd { * y */ struct drm_mode_cursor { - unsigned int flags; - unsigned int crtc; - int x; - int y; + uint32_t flags; + unsigned int crtc_id; + int32_t x; + int32_t y; uint32_t width; uint32_t height; - unsigned int handle; + /* driver specific handle */ + uint64_t handle; }; /* @@ -265,8 +266,7 @@ struct drm_mode_hotplug { }; struct drm_mode_crtc_lut { - - uint32_t crtc_id; + unsigned int crtc_id; uint32_t gamma_size; /* pointers to arrays */ -- cgit v1.2.3 From 389b7617b5b88b6270af5b3824fe73519900c87f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 27 Oct 2008 17:06:23 +1000 Subject: drm: make handles 32-bits again not sure why they changed --- shared-core/drm_mode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h index e6daa7ca..0c378f44 100644 --- a/shared-core/drm_mode.h +++ b/shared-core/drm_mode.h @@ -220,9 +220,9 @@ struct drm_mode_fb_cmd { uint32_t width, height; uint32_t pitch; uint32_t bpp; + uint32_t handle; uint32_t depth; - uint64_t handle; }; struct drm_mode_mode_cmd { @@ -255,7 +255,7 @@ struct drm_mode_cursor { uint32_t width; uint32_t height; /* driver specific handle */ - uint64_t handle; + uint32_t handle; }; /* -- cgit v1.2.3 From 7617d1fef7b743349b470e4a62388174bbffb56b Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 27 Oct 2008 19:27:15 +0100 Subject: radeon: radeon util library --- configure.ac | 1 + libdrm/Makefile.am | 2 +- libdrm/radeon/Makefile.am | 43 ++++++++++ libdrm/radeon/radeon_bo.h | 102 +++++++++++++++++++++++ libdrm/radeon/radeon_bo_gem.c | 186 ++++++++++++++++++++++++++++++++++++++++++ libdrm/radeon/radeon_bo_gem.h | 38 +++++++++ libdrm/radeon/radeon_cs.h | 144 ++++++++++++++++++++++++++++++++ 7 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 libdrm/radeon/Makefile.am create mode 100644 libdrm/radeon/radeon_bo.h create mode 100644 libdrm/radeon/radeon_bo_gem.c create mode 100644 libdrm/radeon/radeon_bo_gem.h create mode 100644 libdrm/radeon/radeon_cs.h diff --git a/configure.ac b/configure.ac index 92507cb5..a6fbff73 100644 --- a/configure.ac +++ b/configure.ac @@ -117,6 +117,7 @@ AC_OUTPUT([ Makefile libdrm/Makefile libdrm/intel/Makefile + libdrm/radeon/Makefile shared-core/Makefile tests/Makefile libdrm.pc]) diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index c3619a6d..ded86308 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -18,7 +18,7 @@ # 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. -SUBDIRS = . intel +SUBDIRS = . intel radeon libdrm_la_LTLIBRARIES = libdrm.la libdrm_ladir = $(libdir) diff --git a/libdrm/radeon/Makefile.am b/libdrm/radeon/Makefile.am new file mode 100644 index 00000000..6af06a7f --- /dev/null +++ b/libdrm/radeon/Makefile.am @@ -0,0 +1,43 @@ +# Copyright © 2008 Jérôme Glisse +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# Authors: +# Jérôme Glisse + +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + -I$(top_srcdir)/libdrm \ + -I$(top_srcdir)/libdrm/radeon \ + $(PTHREADSTUBS_CFLAGS) \ + -I$(top_srcdir)/shared-core + +libdrm_radeon_la_LTLIBRARIES = libdrm_radeon.la +libdrm_radeon_ladir = $(libdir) +libdrm_radeon_la_LDFLAGS = -version-number 1:0:0 -no-undefined +libdrm_radeon_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ + +libdrm_radeon_la_SOURCES = \ + radeon_bo_gem.c + +libdrm_radeonincludedir = ${includedir} +libdrm_radeoninclude_HEADERS = \ + radeon_bo.h \ + radeon_cs.h diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h new file mode 100644 index 00000000..67c75262 --- /dev/null +++ b/libdrm/radeon/radeon_bo.h @@ -0,0 +1,102 @@ +/* + * Copyright © 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse + */ +#ifndef RADEON_BO_H +#define RADEON_BO_H + +#include + +/* bo object */ +#define RADEON_BO_FLAGS_MACRO_TILE 1 +#define RADEON_BO_FLAGS_MICRO_TILE 2 + +struct radeon_bo_manager; + +struct radeon_bo { + uint32_t alignment; + uint32_t handle; + uint32_t size; + uint32_t flags; + void *ptr; + struct radeon_bo_manager *bom; +}; + +/* bo functions */ +struct radeon_bo_funcs { + struct radeon_bo *(*bo_open)(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t flags); + void (*bo_close)(struct radeon_bo *bo); + void (*bo_pin)(struct radeon_bo *bo); + void (*bo_unpin)(struct radeon_bo *bo); + int (*bo_map)(struct radeon_bo *bo, unsigned int flags); + int (*bo_unmap)(struct radeon_bo *bo); +}; + +struct radeon_bo_manager { + struct radeon_bo_funcs *funcs; + int fd; +}; + +static inline struct radeon_bo *radeon_bo_open(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t flags) +{ + return bom->funcs->bo_open(bom, handle, size, alignment, flags); +} + +static inline void radeon_bo_close(struct radeon_bo *bo) +{ + return bo->bom->funcs->bo_close(bo); +} + +static inline void radeon_bo_pin(struct radeon_bo *bo) +{ + return bo->bom->funcs->bo_pin(bo); +} + +static inline void radeon_bo_unpin(struct radeon_bo *bo) +{ + return bo->bom->funcs->bo_unpin(bo); +} + +static inline int radeon_bo_map(struct radeon_bo *bo, unsigned int flags) +{ + return bo->bom->funcs->bo_map(bo, flags); +} + +static inline int radeon_bo_unmap(struct radeon_bo *bo) +{ + return bo->bom->funcs->bo_unmap(bo); +} + +#endif diff --git a/libdrm/radeon/radeon_bo_gem.c b/libdrm/radeon/radeon_bo_gem.c new file mode 100644 index 00000000..21fe41f9 --- /dev/null +++ b/libdrm/radeon/radeon_bo_gem.c @@ -0,0 +1,186 @@ +/* + * Copyright © 2008 Dave Airlie + * Copyright © 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie + * Jérôme Glisse + */ +#include +#include +#include +#include +#include +#include +#include "xf86drm.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_bo.h" +#include "radeon_bo_gem.h" + +struct radeon_bo_gem { + struct radeon_bo base; + int ref_count; + int map_count; +}; + +static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t flags) +{ + struct radeon_bo_gem *bo; + int r; + + bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem)); + if (bo == NULL) { + return NULL; + } + + bo->base.bom = bom; + bo->base.handle = 0; + bo->base.size = size; + bo->base.alignment = alignment; + bo->base.flags = flags; + bo->base.ptr = NULL; + bo->ref_count = 0; + bo->map_count = 0; + + if (handle) { + struct drm_gem_open open_arg; + + memset(&open_arg, 0, sizeof(open_arg)); + open_arg.name = handle; + r = ioctl(bom->fd, DRM_IOCTL_GEM_OPEN, &open_arg); + if (r != 0) { + fprintf(stderr, "GEM open failed: %d (%s)\n",r,strerror(r)); + free(bo); + return NULL; + } + bo->base.handle = handle; + } else { + struct drm_radeon_gem_create args; + + args.size = size; + args.alignment = alignment; + args.initial_domain = RADEON_GEM_DOMAIN_CPU; + args.no_backing_store = 0; + r = drmCommandWriteRead(bom->fd, DRM_RADEON_GEM_CREATE, + &args, sizeof(args)); + bo->base.handle = args.handle; + if (r) { + free(bo); + return NULL; + } + } + return (struct radeon_bo*)bo; +} + +static void bo_close(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + struct drm_gem_close args; + + if (bo == NULL) { + return; + } + if (bo_gem->ref_count) { + /* FIXME: what to do ? */ + } + + if (bo_gem->map_count) { + munmap(bo->ptr, bo->size); + } + + /* close object */ + args.handle = bo->handle; + ioctl(bo->bom->fd, DRM_IOCTL_GEM_CLOSE, &args); + free(bo_gem); +} + +static void bo_pin(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + + bo_gem->ref_count++; +} + +static void bo_unpin(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + + bo_gem->ref_count--; +} + +static int bo_map(struct radeon_bo *bo, unsigned int flags) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + struct drm_radeon_gem_mmap args; + int r; + + if (bo_gem->map_count++ != 0) { + return 0; + } + args.handle = bo->handle; + args.offset = 0; + args.size = bo->size; + + r = drmCommandWriteRead(bo->bom->fd, + DRM_RADEON_GEM_MMAP, + &args, + sizeof(args)); + if (!r) { + bo->ptr = (void *)(unsigned long)args.addr_ptr; + } + return r; +} + +static int bo_unmap(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + + if (--bo_gem->map_count > 0) { + return 0; + } + + munmap(bo->ptr, bo->size); + bo->ptr = NULL; + return 0; +} + +static struct radeon_bo_funcs bo_gem_funcs = { + bo_open, + bo_close, + bo_pin, + bo_unpin, + bo_map, + bo_unmap +}; + +struct radeon_bo_funcs *radeon_bo_gem_initialize(int fd) +{ + return &bo_gem_funcs; +} diff --git a/libdrm/radeon/radeon_bo_gem.h b/libdrm/radeon/radeon_bo_gem.h new file mode 100644 index 00000000..e0ed61fb --- /dev/null +++ b/libdrm/radeon/radeon_bo_gem.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2008 Dave Airlie + * Copyright © 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie + * Jérôme Glisse + */ +#ifndef RADEON_BO_GEM_H +#define RADEON_BO_GEM_H + +#include "radeon_bo.h" + +struct radeon_bo_funcs *radeon_bo_gem_initialize(int fd); + +#endif diff --git a/libdrm/radeon/radeon_cs.h b/libdrm/radeon/radeon_cs.h new file mode 100644 index 00000000..71b2839f --- /dev/null +++ b/libdrm/radeon/radeon_cs.h @@ -0,0 +1,144 @@ +/* + * Copyright © 2008 Nicolai Haehnle + * Copyright © 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Aapo Tahkola + * Nicolai Haehnle + * Jérôme Glisse + */ +#ifndef RADEON_CS_H +#define RADEON_CS_H + +#include +#include "radeon_bo.h" + +struct radeon_cs_reloc { + struct radeon_bo *bo; + uint32_t soffset; + uint32_t eoffset; + uint32_t size; + uint32_t domains; +}; + +struct radeon_cs_manager; + +struct radeon_cs { + struct radeon_cs_manager *csm; + struct radeon_cs_reloc *relocs; + uint32_t *packets; + unsigned crelocs; + unsigned cdw; + unsigned ndw; + int section; + unsigned section_ndw; + unsigned section_cdw; + const char *section_file; + const char *section_func; + int section_line; +}; + +/* cs functions */ +struct radeon_cs_funcs { + struct radeon_cs *(*cs_create)(struct radeon_cs_manager *csm, + uint32_t ndw); + int (*cs_write_dword)(struct radeon_cs *cs, uint32_t dword); + int (*cs_write_reloc)(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t soffset, + uint32_t eoffset, + uint32_t domains); + int (*cs_begin)(struct radeon_cs *cs, + uint32_t ndw, + const char *file, + const char *func, + int line); + int (*cs_end)(struct radeon_cs *cs, + const char *file, + const char *func, + int line); + int (*cs_emit)(struct radeon_cs *cs); + int (*cs_destroy)(struct radeon_cs *cs); + int (*cs_erase)(struct radeon_cs *cs); +}; + +struct radeon_cs_manager { + struct radeon_cs_funcs *funcs; + int fd; +}; + +static inline struct radeon_cs *radeon_cs_create(struct radeon_cs_manager *csm, + uint32_t ndw) +{ + return csm->funcs->cs_create(csm, ndw); +} + +static inline int radeon_cs_write_dword(struct radeon_cs *cs, uint32_t dword) +{ + return cs->csm->funcs->cs_write_dword(cs, dword); +} + +static inline int radeon_cs_write_reloc(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t soffset, + uint32_t eoffset, + uint32_t domains) +{ + return cs->csm->funcs->cs_write_reloc(cs, bo, soffset, eoffset, domains); +} + +static inline int radeon_cs_begin(struct radeon_cs *cs, + uint32_t ndw, + const char *file, + const char *func, + int line) +{ + return cs->csm->funcs->cs_begin(cs, ndw, file, func, line); +} + +static inline int radeon_cs_end(struct radeon_cs *cs, + const char *file, + const char *func, + int line) +{ + return cs->csm->funcs->cs_end(cs, file, func, line); +} + +static inline int radeon_cs_emit(struct radeon_cs *cs) +{ + return cs->csm->funcs->cs_emit(cs); +} + +static inline int radeon_cs_destroy(struct radeon_cs *cs) +{ + return cs->csm->funcs->cs_destroy(cs); +} + +static inline int radeon_cs_erase(struct radeon_cs *cs) +{ + return cs->csm->funcs->cs_erase(cs); +} + +#endif -- cgit v1.2.3 From af118cd186407cd8e72ccd63f6deca56f1ffd905 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 27 Oct 2008 23:26:15 +0100 Subject: radeon: reloc are backend dependant --- libdrm/radeon/radeon_cs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdrm/radeon/radeon_cs.h b/libdrm/radeon/radeon_cs.h index 71b2839f..6d560748 100644 --- a/libdrm/radeon/radeon_cs.h +++ b/libdrm/radeon/radeon_cs.h @@ -47,7 +47,7 @@ struct radeon_cs_manager; struct radeon_cs { struct radeon_cs_manager *csm; - struct radeon_cs_reloc *relocs; + void *relocs; uint32_t *packets; unsigned crelocs; unsigned cdw; -- cgit v1.2.3 From 1db35ba58353b862ca04a190d46c6f074a21f223 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 29 Oct 2008 12:17:39 -0700 Subject: libdrm: fix ABI change in drm_mode_get_encoder The encoder_type field should be at the top to match the kernel. --- shared-core/drm_mode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h index 0c378f44..bd3d257e 100644 --- a/shared-core/drm_mode.h +++ b/shared-core/drm_mode.h @@ -126,10 +126,10 @@ struct drm_mode_crtc { #define DRM_MODE_ENCODER_TVDAC 4 struct drm_mode_get_encoder { + unsigned int encoder_type; unsigned int encoder_id; - unsigned int crtc_id; /**< Id of crtc */ - uint32_t encoder_type; + unsigned int crtc_id; /**< Id of crtc */ uint32_t possible_crtcs; uint32_t possible_clones; -- cgit v1.2.3 From 5d861951b3714d13292d18f3731294c83e209b3a Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 29 Oct 2008 23:40:20 +0100 Subject: radeon: libdrm_radeon updates bo & cs interfaces --- libdrm/radeon/radeon_bo.h | 93 ++++++++++++++++++++++++++++++++++++----------- libdrm/radeon/radeon_cs.h | 7 ++++ 2 files changed, 78 insertions(+), 22 deletions(-) diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index 67c75262..00dd521b 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -29,6 +29,7 @@ #ifndef RADEON_BO_H #define RADEON_BO_H +#include #include /* bo object */ @@ -42,6 +43,7 @@ struct radeon_bo { uint32_t handle; uint32_t size; uint32_t flags; + unsigned cref; void *ptr; struct radeon_bo_manager *bom; }; @@ -53,10 +55,9 @@ struct radeon_bo_funcs { uint32_t size, uint32_t alignment, uint32_t flags); - void (*bo_close)(struct radeon_bo *bo); - void (*bo_pin)(struct radeon_bo *bo); - void (*bo_unpin)(struct radeon_bo *bo); - int (*bo_map)(struct radeon_bo *bo, unsigned int flags); + void (*bo_ref)(struct radeon_bo *bo); + void (*bo_unref)(struct radeon_bo *bo); + int (*bo_map)(struct radeon_bo *bo, int write); int (*bo_unmap)(struct radeon_bo *bo); }; @@ -65,38 +66,86 @@ struct radeon_bo_manager { int fd; }; -static inline struct radeon_bo *radeon_bo_open(struct radeon_bo_manager *bom, - uint32_t handle, - uint32_t size, - uint32_t alignment, - uint32_t flags) +static inline struct radeon_bo *_radeon_bo_open(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t flags, + const char *file, + const char *func, + int line) { - return bom->funcs->bo_open(bom, handle, size, alignment, flags); -} - -static inline void radeon_bo_close(struct radeon_bo *bo) -{ - return bo->bom->funcs->bo_close(bo); + struct radeon_bo *bo; + bo = bom->funcs->bo_open(bom, handle, size, alignment, flags); +#ifdef RADEON_BO_TRACK_OPEN + if (bo) { + fprintf(stderr, "+open (%p, %d, %d) at (%s, %s, %d)\n", + bo, bo->size, bo->cref, file, func, line); + } +#endif + return bo; } -static inline void radeon_bo_pin(struct radeon_bo *bo) +static inline void _radeon_bo_ref(struct radeon_bo *bo, + const char *file, + const char *func, + int line) { - return bo->bom->funcs->bo_pin(bo); + bo->cref++; +#ifdef RADEON_BO_TRACK_REF + fprintf(stderr, "+ref (%p, %d, %d) at (%s, %s, %d)\n", + bo, bo->size, bo->cref, file, func, line); +#endif + bo->bom->funcs->bo_ref(bo); } -static inline void radeon_bo_unpin(struct radeon_bo *bo) +static inline void _radeon_bo_unref(struct radeon_bo *bo, + const char *file, + const char *func, + int line) { - return bo->bom->funcs->bo_unpin(bo); + bo->cref--; +#ifdef RADEON_BO_TRACK_REF + fprintf(stderr, "-unref(%p, %d, %d) at (%s, %s, %d)\n", + bo, bo->size, bo->cref, file, func, line); +#endif + bo->bom->funcs->bo_unref(bo); } -static inline int radeon_bo_map(struct radeon_bo *bo, unsigned int flags) +static inline int _radeon_bo_map(struct radeon_bo *bo, + int write, + const char *file, + const char *func, + int line) { - return bo->bom->funcs->bo_map(bo, flags); +#ifdef RADEON_BO_TRACK_MAP + fprintf(stderr, "+map (%p, %d, %d) at (%s, %s, %d)\n", + bo, bo->size, bo->cref, file, func, line); +#endif + return bo->bom->funcs->bo_map(bo, write); } -static inline int radeon_bo_unmap(struct radeon_bo *bo) +static inline int _radeon_bo_unmap(struct radeon_bo *bo, + const char *file, + const char *func, + int line) { +#ifdef RADEON_BO_TRACK_MAP + fprintf(stderr, "-unmap(%p, %d, %d) at (%s, %s, %d)\n", + bo, bo->size, bo->cref, file, func, line); +#endif return bo->bom->funcs->bo_unmap(bo); } +#define radeon_bo_open(bom, h, s, a, f)\ + _radeon_bo_open(bom, h, s, a, f, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_ref(bo)\ + _radeon_bo_ref(bo, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_unref(bo)\ + _radeon_bo_unref(bo, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_map(bo, w)\ + _radeon_bo_map(bo, w, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_unmap(bo)\ + _radeon_bo_unmap(bo, __FILE__, __FUNCTION__, __LINE__) + #endif diff --git a/libdrm/radeon/radeon_cs.h b/libdrm/radeon/radeon_cs.h index 6d560748..347e9f35 100644 --- a/libdrm/radeon/radeon_cs.h +++ b/libdrm/radeon/radeon_cs.h @@ -50,6 +50,7 @@ struct radeon_cs { void *relocs; uint32_t *packets; unsigned crelocs; + unsigned relocs_total_size; unsigned cdw; unsigned ndw; int section; @@ -82,6 +83,7 @@ struct radeon_cs_funcs { int (*cs_emit)(struct radeon_cs *cs); int (*cs_destroy)(struct radeon_cs *cs); int (*cs_erase)(struct radeon_cs *cs); + int (*cs_need_flush)(struct radeon_cs *cs); }; struct radeon_cs_manager { @@ -141,4 +143,9 @@ static inline int radeon_cs_erase(struct radeon_cs *cs) return cs->csm->funcs->cs_erase(cs); } +static inline int radeon_cs_need_flush(struct radeon_cs *cs) +{ + return cs->csm->funcs->cs_need_flush(cs); +} + #endif -- cgit v1.2.3 From 7651b4c424aa6c6ac6c47b2d07c8f65d0b9d0191 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 2 Nov 2008 16:00:06 +0100 Subject: radeon: debug bo --- libdrm/radeon/radeon_bo.h | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index 00dd521b..68adc3e9 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -65,6 +65,16 @@ struct radeon_bo_manager { struct radeon_bo_funcs *funcs; int fd; }; + +static inline void _radeon_bo_debug(struct radeon_bo *bo, + int opcode, + const char *file, + const char *func, + int line) +{ + fprintf(stderr, "%02d %p 0x%08X 0x%08X [%s %s %d]\n", + opcode, bo, bo->size, bo->cref, file, func, line); +} static inline struct radeon_bo *_radeon_bo_open(struct radeon_bo_manager *bom, uint32_t handle, @@ -79,8 +89,7 @@ static inline struct radeon_bo *_radeon_bo_open(struct radeon_bo_manager *bom, bo = bom->funcs->bo_open(bom, handle, size, alignment, flags); #ifdef RADEON_BO_TRACK_OPEN if (bo) { - fprintf(stderr, "+open (%p, %d, %d) at (%s, %s, %d)\n", - bo, bo->size, bo->cref, file, func, line); + _radeon_bo_debug(bo, 1, file, func, line); } #endif return bo; @@ -93,8 +102,7 @@ static inline void _radeon_bo_ref(struct radeon_bo *bo, { bo->cref++; #ifdef RADEON_BO_TRACK_REF - fprintf(stderr, "+ref (%p, %d, %d) at (%s, %s, %d)\n", - bo, bo->size, bo->cref, file, func, line); + _radeon_bo_debug(bo, 2, file, func, line); #endif bo->bom->funcs->bo_ref(bo); } @@ -106,8 +114,7 @@ static inline void _radeon_bo_unref(struct radeon_bo *bo, { bo->cref--; #ifdef RADEON_BO_TRACK_REF - fprintf(stderr, "-unref(%p, %d, %d) at (%s, %s, %d)\n", - bo, bo->size, bo->cref, file, func, line); + _radeon_bo_debug(bo, 3, file, func, line); #endif bo->bom->funcs->bo_unref(bo); } @@ -119,8 +126,7 @@ static inline int _radeon_bo_map(struct radeon_bo *bo, int line) { #ifdef RADEON_BO_TRACK_MAP - fprintf(stderr, "+map (%p, %d, %d) at (%s, %s, %d)\n", - bo, bo->size, bo->cref, file, func, line); + _radeon_bo_debug(bo, 4, file, func, line); #endif return bo->bom->funcs->bo_map(bo, write); } @@ -131,8 +137,7 @@ static inline int _radeon_bo_unmap(struct radeon_bo *bo, int line) { #ifdef RADEON_BO_TRACK_MAP - fprintf(stderr, "-unmap(%p, %d, %d) at (%s, %s, %d)\n", - bo, bo->size, bo->cref, file, func, line); + _radeon_bo_debug(bo, 5, file, func, line); #endif return bo->bom->funcs->bo_unmap(bo); } @@ -147,5 +152,7 @@ static inline int _radeon_bo_unmap(struct radeon_bo *bo, _radeon_bo_map(bo, w, __FILE__, __FUNCTION__, __LINE__) #define radeon_bo_unmap(bo)\ _radeon_bo_unmap(bo, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_debug(bo, opcode)\ + _radeon_bo_debug(bo, opcode, __FILE__, __FUNCTION__, __LINE__) #endif -- cgit v1.2.3 From b09cb93e2d188228e26135149786ee231cd9b11d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:23:19 +1000 Subject: radeon: add some more r100 support to test AGP --- shared-core/r300_cmdbuf.c | 3 +++ shared-core/radeon_cs.c | 27 ++------------------------- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index b15e8928..f39a7afd 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -356,6 +356,9 @@ void r300_init_reg_flags(struct drm_device *dev) } else { + ADD_RANGE(RADEON_SE_COORD_FMT, 1); + ADD_RANGE(RADEON_SE_CNTL_STATUS, 1); + ADD_RANGE(RADEON_PP_TXFILTER_0, 1); ADD_RANGE(RADEON_PP_TXFORMAT_0, 1); ADD_RANGE(RADEON_PP_TEX_SIZE_0, 1); diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index f9147136..3e47ad12 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -122,7 +122,7 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct /* this is too strict we may want to expand the length in the future and have old kernels ignore it. */ if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { - DRM_ERROR("Packet 3 was %x should have been %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16)); + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16), reg); return -EINVAL; } @@ -195,30 +195,6 @@ static int radeon_cs_relocate_packet3(struct drm_device *dev, struct drm_file *f return 0; } -static __inline__ int radeon_cs_check_offset(struct drm_device *dev, - uint32_t reg, uint32_t val) -{ - uint32_t offset; - - switch(reg) { - case RADEON_DST_PITCH_OFFSET: - case RADEON_SRC_PITCH_OFFSET: - offset = val & ((1 << 22) - 1); - offset <<= 10; - break; - case R300_RB3D_COLOROFFSET0: - case R300_ZB_DEPTHOFFSET: - offset = val; - break; - case R300_TX_OFFSET_0: - case R300_TX_OFFSET_0+4: - offset = val & 0xffffffe0; - break; - } - - return 0; -} - int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv, uint32_t *packets, uint32_t offset_dw) { @@ -308,6 +284,7 @@ int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv, DRM_ERROR("need relocate packet 3 for %x\n", reg); break; + case RADEON_3D_DRAW_IMMD: /* triggers drawing using in-packet vertex data */ case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ -- cgit v1.2.3 From f74721fc2553d81acfe4d4a670833405dd52092b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:24:13 +1000 Subject: radeon: fix unused agp functionality --- shared-core/radeon_cp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 190b1432..d5889e61 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -120,7 +120,7 @@ void radeon_read_agp_location(drm_radeon_private_t *dev_priv, u32 *agp_lo, u32 * *agp_lo = RADEON_READ(R600_MC_VM_AGP_BOT); *agp_hi = RADEON_READ(R600_MC_VM_AGP_TOP); } else if (dev_priv->chip_family == CHIP_RV515) { - *agp_lo = radeon_read_mc_reg(dev_priv, RV515_MC_FB_LOCATION); + *agp_lo = radeon_read_mc_reg(dev_priv, RV515_MC_AGP_LOCATION); *agp_hi = 0; } else if (dev_priv->chip_family == CHIP_RS600) { *agp_lo = 0; @@ -133,7 +133,7 @@ void radeon_read_agp_location(drm_radeon_private_t *dev_priv, u32 *agp_lo, u32 * *agp_lo = radeon_read_mc_reg(dev_priv, R520_MC_AGP_LOCATION); *agp_hi = 0; } else { - *agp_lo = RADEON_READ(RADEON_MC_FB_LOCATION); + *agp_lo = RADEON_READ(RADEON_MC_AGP_LOCATION); *agp_hi = 0; } } -- cgit v1.2.3 From 48f222751643a349924ba3e6c26890310822f89c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:25:32 +1000 Subject: radeon: export radeon_modeset --- shared-core/radeon_drv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index a6ce129d..3be99eb3 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -460,6 +460,7 @@ extern int radeon_r4xx_atom; extern struct drm_ioctl_desc radeon_ioctls[]; extern int radeon_max_ioctl; extern int radeon_agpmode; +extern int radeon_modeset; /* Check whether the given hardware address is inside the framebuffer or the * GART area. -- cgit v1.2.3 From d275f99c9a7d915473034e6abd575f35bea5db9c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:26:00 +1000 Subject: radeon: don't enable dynclks on rs48x --- shared-core/radeon_cp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index d5889e61..ded6f676 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2562,6 +2562,10 @@ int radeon_static_clocks_init(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; + if (dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) + radeon_dynclks = 0; + if ((dev_priv->flags & RADEON_IS_MOBILITY) && !radeon_is_avivo(dev_priv)) { radeon_set_dynamic_clock(dev, radeon_dynclks); } else if (radeon_is_avivo(dev_priv)) { -- cgit v1.2.3 From a8f07db596532912e354bb7a2b3acdfc11a8d150 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:26:32 +1000 Subject: radeon: workaround failure to parse some rs48x edid --- linux-core/radeon_connectors.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c index f217fe77..8de21997 100644 --- a/linux-core/radeon_connectors.c +++ b/linux-core/radeon_connectors.c @@ -87,19 +87,23 @@ static int radeon_lvds_get_modes(struct drm_connector *connector) if (radeon_connector->ddc_bus) { radeon_i2c_do_lock(radeon_connector, 1); - edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); + edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); radeon_i2c_do_lock(radeon_connector, 0); if (edid) { drm_mode_connector_update_edid_property(&radeon_connector->base, edid); ret = drm_add_edid_modes(&radeon_connector->base, edid); kfree(edid); + if (ret == 0) + goto native; return ret; } } +native: encoder = radeon_best_single_encoder(connector); if (!encoder) - return connector_status_disconnected; + return 0; + /* we have no EDID modes */ mode = radeon_fp_native_mode(encoder); if (mode) { -- cgit v1.2.3 From 52ef9d87db8d3b7e0e9114f987263292e8e12d6a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:27:00 +1000 Subject: radeon: fix small typo in agp code --- shared-core/radeon_cp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index ded6f676..ae3a69b6 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2439,7 +2439,7 @@ int radeon_modeset_agp_init(struct drm_device *dev) } /* workaround some hw issues */ - if (dev_priv->chip_family <= CHIP_R200) { + if (dev_priv->chip_family < CHIP_R200) { RADEON_WRITE(RADEON_AGP_CNTL, RADEON_READ(RADEON_AGP_CNTL) | 0x000e0000); } return 0; -- cgit v1.2.3 From 0dbe3436ee6e3f2a4d6d252ef5e31b7bb7e36764 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:28:36 +1000 Subject: radeon: fix some warnings --- linux-core/ati_pcigart.c | 10 +++++----- linux-core/drm_bufs.c | 1 - linux-core/radeon_buffer.c | 2 -- shared-core/r300_reg.h | 2 +- shared-core/radeon_cp.c | 7 ++----- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 50e990f1..6b0d8947 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -39,7 +39,7 @@ #define ATI_PCIE_WRITE 0x4 #define ATI_PCIE_READ 0x8 -static __inline__ void gart_insert_page_into_table(struct drm_ati_pcigart_info *gart_info, dma_addr_t addr, u32 *pci_gart) +static __inline__ void gart_insert_page_into_table(struct drm_ati_pcigart_info *gart_info, dma_addr_t addr, volatile u32 *pci_gart) { u32 page_base; @@ -61,7 +61,7 @@ static __inline__ void gart_insert_page_into_table(struct drm_ati_pcigart_info * *pci_gart = cpu_to_le32(page_base); } -static __inline__ dma_addr_t gart_get_page_from_table(struct drm_ati_pcigart_info *gart_info, u32 *pci_gart) +static __inline__ dma_addr_t gart_get_page_from_table(struct drm_ati_pcigart_info *gart_info, volatile u32 *pci_gart) { dma_addr_t retval; switch(gart_info->gart_reg_if) { @@ -93,7 +93,7 @@ int drm_ati_alloc_pcigart_table(struct drm_device *dev, #ifdef CONFIG_X86 /* IGPs only exist on x86 in any case */ if (gart_info->gart_reg_if == DRM_ATI_GART_IGP) - set_memory_uc(gart_info->table_handle->vaddr, gart_info->table_size >> PAGE_SHIFT); + set_memory_uc((unsigned long)gart_info->table_handle->vaddr, gart_info->table_size >> PAGE_SHIFT); #endif memset(gart_info->table_handle->vaddr, 0, gart_info->table_size); @@ -107,7 +107,7 @@ static void drm_ati_free_pcigart_table(struct drm_device *dev, #ifdef CONFIG_X86 /* IGPs only exist on x86 in any case */ if (gart_info->gart_reg_if == DRM_ATI_GART_IGP) - set_memory_wb(gart_info->table_handle->vaddr, gart_info->table_size >> PAGE_SHIFT); + set_memory_wb((unsigned long)gart_info->table_handle->vaddr, gart_info->table_size >> PAGE_SHIFT); #endif drm_pci_free(dev, gart_info->table_handle); gart_info->table_handle = NULL; @@ -260,7 +260,7 @@ static int ati_pcigart_bind_ttm(struct drm_ttm_backend *backend, j = offset; while (j < (offset + atipci_be->num_pages)) { - if (gart_get_page_from_table(info, pci_gart+j)) + if (gart_get_page_from_table(info, pci_gart + j)) return -EBUSY; j++; } diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index c966badc..15c426cb 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -1544,7 +1544,6 @@ int drm_mapbufs(struct drm_device *dev, void *data, goto done; } down_write(¤t->mm->mmap_sem); - DRM_DEBUG("%x %d\n", token, map->size); virtual = do_mmap(file_priv->filp, 0, map->size, PROT_READ | PROT_WRITE, MAP_SHARED, diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index e5a90892..e88378a4 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -350,7 +350,6 @@ static int radeon_move_vram(struct drm_buffer_object * bo, struct drm_bo_mem_reg tmp_mem; struct drm_bo_mem_reg *old_mem = &bo->mem; int ret; - bool was_local = false; /* old - LOCAL memory node bo->mem tmp - TT type memory node @@ -398,7 +397,6 @@ int radeon_move(struct drm_buffer_object * bo, int evict, int no_wait, struct drm_bo_mem_reg *new_mem) { struct drm_device *dev = bo->dev; - struct drm_bo_mem_reg *old_mem = &bo->mem; drm_radeon_private_t *dev_priv = dev->dev_private; if (!dev_priv->cp_running) diff --git a/shared-core/r300_reg.h b/shared-core/r300_reg.h index 9e9cb526..1e4631db 100644 --- a/shared-core/r300_reg.h +++ b/shared-core/r300_reg.h @@ -1353,7 +1353,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #define R300_RB3D_COLORPITCH2 0x4E40 /* GUESS */ #define R300_RB3D_COLORPITCH3 0x4E44 /* GUESS */ -#define R300_RB3D_AARESOLVE_CTL 0x4E88 +//#define R300_RB3D_AARESOLVE_CTL 0x4E88 /* gap */ /* Guess by Vladimir. diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index ae3a69b6..f579e01a 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2434,7 +2434,7 @@ int radeon_modeset_agp_init(struct drm_device *dev) ret = drm_agp_enable(dev, mode); if (ret) { - DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode); + DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); return ret; } @@ -2457,7 +2457,7 @@ int radeon_modeset_cp_init(struct drm_device *dev) dev_priv->writeback_works = 0; if (dev_priv->chip_family > CHIP_R600) - return; + return 0; dev_priv->usec_timeout = RADEON_DEFAULT_CP_TIMEOUT; dev_priv->ring.size = RADEON_DEFAULT_RING_SIZE; @@ -2713,7 +2713,6 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master) void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) { struct drm_radeon_master_private *master_priv = master->driver_priv; - struct drm_radeon_private *dev_priv = dev->dev_private; if (!master_priv) return; @@ -2735,8 +2734,6 @@ void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) */ int radeon_driver_firstopen(struct drm_device *dev) { - int ret; - drm_local_map_t *map; drm_radeon_private_t *dev_priv = dev->dev_private; dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; -- cgit v1.2.3 From a066a5f908af0e82b1a0c7099b73d4a63585c69d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:28:56 +1000 Subject: radeon: make writeback work again --- shared-core/radeon_cp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index f579e01a..0200797a 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -825,7 +825,7 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, static void radeon_test_writeback(drm_radeon_private_t * dev_priv) { - u32 tmp; + u32 tmp, scratch1_store; void *ring_read_ptr; if (dev_priv->mm.ring_read.bo) @@ -833,6 +833,7 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv) else ring_read_ptr = dev_priv->ring_rptr->handle; + scratch1_store = RADEON_READ(RADEON_SCRATCH_REG1); /* Writeback doesn't seem to work everywhere, test it here and possibly * enable it if it appears to work */ @@ -858,6 +859,9 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv) DRM_INFO("writeback forced off\n"); } + /* write back previous value */ + RADEON_WRITE(RADEON_SCRATCH_REG1, scratch1_store); + if (!dev_priv->writeback_works) { /* Disable writeback to avoid unnecessary bus master transfers */ RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) | RADEON_RB_NO_UPDATE); @@ -2353,6 +2357,8 @@ int radeon_modeset_cp_resume(struct drm_device *dev) radeon_do_engine_reset(dev); + radeon_test_writeback(dev_priv); + radeon_do_cp_start(dev_priv); return 0; } -- cgit v1.2.3 From 3fd0e1483ebe640b69da888e286ea85d11539b46 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:29:22 +1000 Subject: radeon: fixup scratch register interactions properly --- shared-core/radeon_cp.c | 14 +++++++++++++- shared-core/radeon_cs.c | 4 ++-- shared-core/radeon_drv.h | 12 ++++++------ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 0200797a..71d1a61b 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -791,7 +791,10 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, dev_priv->ring_rptr->handle + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); - RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); + if (dev_priv->chip_family > CHIP_R300) + RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x3f); + else + RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x1f); /* Turn on bus mastering */ tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; @@ -806,6 +809,15 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, dev_priv->scratch[2] = 0; RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0); + dev_priv->scratch[3] = 0; + RADEON_WRITE(RADEON_LAST_SWI_REG, 0); + + dev_priv->scratch[4] = 0; + RADEON_WRITE(RADEON_SCRATCH_REG4, 0); + + dev_priv->scratch[6] = 0; + RADEON_WRITE(RADEON_SCRATCH_REG6, 0); + radeon_do_wait_for_idle(dev_priv); /* Sync everything up */ diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 3e47ad12..b5982894 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -365,14 +365,14 @@ uint32_t r100_cs_id_last_get(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; - return RADEON_READ(RADEON_SCRATCH_REG4); + return GET_SCRATCH(4); } uint32_t r300_cs_id_last_get(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; - return RADEON_READ(RADEON_SCRATCH_REG6); + return GET_SCRATCH(6); } int radeon_cs_init(struct drm_device *dev) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 3be99eb3..2d592e45 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -733,11 +733,11 @@ int radeon_resume(struct drm_device *dev); #define RADEON_SCRATCHOFF( x ) (RADEON_SCRATCH_REG_OFFSET + 4*(x)) -#define GET_SCRATCH( x ) (dev_priv->writeback_works ? \ - (dev_priv->mm.ring_read.bo ? \ - readl(dev_priv->mm.ring_read.kmap.virtual + RADEON_SCRATCHOFF(x)) : \ - DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(x))) : \ - RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x))) +#define GET_SCRATCH( x ) (dev_priv->writeback_works ? \ + (dev_priv->mm.ring_read.bo ? \ + readl(dev_priv->mm.ring_read.kmap.virtual + RADEON_SCRATCHOFF(x)) : \ + DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(x))) : \ + RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x))) #define RADEON_CRTC_CRNT_FRAME 0x0214 #define RADEON_CRTC2_CRNT_FRAME 0x0314 @@ -1607,7 +1607,7 @@ extern uint64_t radeon_evict_flags(struct drm_buffer_object *bo); #define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) /* Breadcrumb - swi irq */ -#define READ_BREADCRUMB(dev_priv) RADEON_READ(RADEON_LAST_SWI_REG) +#define READ_BREADCRUMB(dev_priv) GET_SCRATCH(3) static inline int radeon_update_breadcrumb(struct drm_device *dev) { -- cgit v1.2.3 From b4803991c8ad8596786f8cf1cffc6417c8ce446a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:30:48 +1000 Subject: radeon: update proper chip family --- shared-core/radeon_cp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 71d1a61b..4f5c538c 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -791,8 +791,8 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, dev_priv->ring_rptr->handle + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); - if (dev_priv->chip_family > CHIP_R300) - RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x3f); + if (dev_priv->chip_family >= CHIP_R300) + RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7f); else RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x1f); -- cgit v1.2.3 From 653b16f2dd32b5fdbd5f97277edc1c6df66755a9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:31:17 +1000 Subject: radeon: fix accessible VRAM sizing --- linux-core/radeon_gem.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 5e2ad98b..5ecd8c55 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -585,6 +585,9 @@ void radeon_vram_setup(struct drm_device *dev) if (accessible > bar_size) accessible = bar_size; + if (accessible > vram) + accessible = vram; + DRM_INFO("Detected VRAM RAM=%dK, accessible=%uK, BAR=%uK\n", vram, accessible, bar_size); -- cgit v1.2.3 From 1c817cc3fc09abe93539413130de3875e4c7eafe Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:32:39 +1000 Subject: radeon: pull bus master enable into its own function --- linux-core/radeon_pm.c | 6 +----- shared-core/radeon_cp.c | 22 ++++++++++++++++++---- shared-core/radeon_drv.h | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index 6b1e6f84..db8f44c4 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -93,7 +93,6 @@ int radeon_resume(struct drm_device *dev) struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_framebuffer *fb; int i; - u32 tmp; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return 0; @@ -104,10 +103,7 @@ int radeon_resume(struct drm_device *dev) return -1; /* Turn on bus mastering -todo fix properly */ - if (dev_priv->chip_family < CHIP_RV380) { - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; - RADEON_WRITE(RADEON_BUS_CNTL, tmp); - } + radeon_enable_bm(dev_priv); DRM_ERROR("\n"); /* on atom cards re init the whole card diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 4f5c538c..b6207c7d 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -194,6 +194,23 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) } } +void radeon_enable_bm(struct drm_radeon_private *dev_priv) +{ + u32 tmp; + /* Turn on bus mastering */ + if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) { + /* rs400, rs690/rs740 */ + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS400_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); + } else if (!(((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) || + ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R423))) { + /* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */ + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); + } /* PCIE cards appears to not need this */ +} void radeon_pll_errata_after_index(struct drm_radeon_private *dev_priv) { @@ -686,7 +703,6 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, drm_radeon_private_t * dev_priv) { u32 ring_start, cur_read_ptr; - u32 tmp; /* Initialize the memory controller. With new memory map, the fb location * is not changed, it should have been properly initialized already. Part @@ -796,9 +812,7 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, else RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x1f); - /* Turn on bus mastering */ - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; - RADEON_WRITE(RADEON_BUS_CNTL, tmp); + radeon_enable_bm(dev_priv); dev_priv->scratch[0] = 0; RADEON_WRITE(RADEON_LAST_FRAME_REG, 0); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 2d592e45..0d5f762b 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1691,7 +1691,7 @@ extern int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file * extern int radeon_cs_init(struct drm_device *dev); void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master); void radeon_init_memory_map(struct drm_device *dev); - +void radeon_enable_bm(struct drm_radeon_private *dev_priv); #define MARK_SAFE 1 #define MARK_CHECK_OFFSET 2 -- cgit v1.2.3 From 624da91277ee33936ea3cfaf20e7f6775293deb2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:33:12 +1000 Subject: radeon: add r423 bits to modesetting --- linux-core/radeon_gem.c | 2 ++ linux-core/radeon_legacy_encoders.c | 3 +++ shared-core/radeon_drv.h | 1 + 3 files changed, 6 insertions(+) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 5ecd8c55..4b15fac3 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -525,6 +525,7 @@ static uint32_t radeon_get_accessible_vram(struct drm_device *dev) dev_priv->chip_family == CHIP_RV350 || dev_priv->chip_family == CHIP_RV380 || dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_R423 || dev_priv->chip_family == CHIP_RV410 || radeon_is_avivo(dev_priv)) { uint32_t temp = RADEON_READ(RADEON_HOST_PATH_CNTL); @@ -963,6 +964,7 @@ void radeon_init_memory_map(struct drm_device *dev) dev_priv->chip_family == CHIP_RV350 || dev_priv->chip_family == CHIP_RV380 || dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_R423 || dev_priv->chip_family == CHIP_RV410) aper0_base &= ~(mem_size - 1); diff --git a/linux-core/radeon_legacy_encoders.c b/linux-core/radeon_legacy_encoders.c index 261501d1..3df89d30 100644 --- a/linux-core/radeon_legacy_encoders.c +++ b/linux-core/radeon_legacy_encoders.c @@ -1070,6 +1070,7 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; //tv_master_cntl |= RADEON_TV_ON; if (dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_R423 || dev_priv->chip_family == CHIP_RV410) tv_dac_cntl &= ~(R420_TV_DAC_RDACPD | R420_TV_DAC_GDACPD | @@ -1095,6 +1096,7 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; //tv_master_cntl &= ~RADEON_TV_ON; if (dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_R423 || dev_priv->chip_family == CHIP_RV410) tv_dac_cntl |= (R420_TV_DAC_RDACPD | R420_TV_DAC_GDACPD | @@ -1158,6 +1160,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, if (dev_priv->chip_family != CHIP_R200) { tv_dac_cntl = RADEON_READ(RADEON_TV_DAC_CNTL); if (dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_R423 || dev_priv->chip_family == CHIP_RV410) { tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK | RADEON_TV_DAC_BGADJ_MASK | diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 0d5f762b..17c0c297 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1644,6 +1644,7 @@ static inline int radeon_update_breadcrumb(struct drm_device *dev) (dev_priv->chip_family == CHIP_R350) || \ (dev_priv->chip_family == CHIP_RV380) || \ (dev_priv->chip_family == CHIP_R420) || \ + (dev_priv->chip_family == CHIP_R423) || \ (dev_priv->chip_family == CHIP_RV410) || \ (dev_priv->chip_family == CHIP_RS400) || \ (dev_priv->chip_family == CHIP_RS480)) -- cgit v1.2.3 From fd9e05b3f4f464ddf08097817a3af824f54a97ca Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:33:32 +1000 Subject: radeon: release agp on module unload --- shared-core/radeon_cp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index b6207c7d..8e97f034 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2476,6 +2476,12 @@ int radeon_modeset_agp_init(struct drm_device *dev) } return 0; } + +void radeon_modeset_agp_destroy(struct drm_device *dev) +{ + if (dev->agp->acquired) + drm_agp_release(dev); +} #endif int radeon_modeset_cp_init(struct drm_device *dev) @@ -2790,6 +2796,10 @@ int radeon_driver_unload(struct drm_device *dev) drm_irq_uninstall(dev); radeon_modeset_cleanup(dev); radeon_gem_mm_fini(dev); +#if __OS_HAS_AGP + if (dev_priv->flags & RADEON_IS_AGP) + radeon_modeset_agp_destroy(dev); +#endif } drm_bo_driver_finish(dev); -- cgit v1.2.3 From 563e7e5930a8d628b33cb1f7a9aaea251f2fc50b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:36:03 +1000 Subject: radeon/drm: fixup ref counting in on fb objs --- linux-core/atombios_crtc.c | 2 +- linux-core/drm_crtc.h | 1 - linux-core/drm_crtc_helper.c | 4 +--- linux-core/drm_crtc_helper.h | 3 +-- linux-core/radeon_display.c | 23 ++++++++++++++--------- linux-core/radeon_fb.c | 2 +- linux-core/radeon_legacy_crtc.c | 4 ++-- linux-core/radeon_mode.h | 3 ++- linux-core/radeon_pm.c | 8 ++++---- 9 files changed, 26 insertions(+), 24 deletions(-) diff --git a/linux-core/atombios_crtc.c b/linux-core/atombios_crtc.c index 3856f8ca..2e144c90 100644 --- a/linux-core/atombios_crtc.c +++ b/linux-core/atombios_crtc.c @@ -276,7 +276,7 @@ void atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y) radeon_fb = to_radeon_framebuffer(crtc->fb); - obj = radeon_fb->base.mm_private; + obj = radeon_fb->obj; obj_priv = obj->driver_private; fb_location = obj_priv->bo->offset + dev_priv->fb_location; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 6a73a71b..13fba4f2 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -240,7 +240,6 @@ struct drm_framebuffer { void *fbdev; u32 pseudo_palette[17]; struct list_head filp_head; - void *mm_private; }; struct drm_property_blob { diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index b334f5b5..776a98e1 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -771,15 +771,13 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev) EXPORT_SYMBOL(drm_helper_hotplug_stage_two); int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd *mode_cmd, - void *mm_private) + struct drm_mode_fb_cmd *mode_cmd) { fb->width = mode_cmd->width; fb->height = mode_cmd->height; fb->pitch = mode_cmd->pitch; fb->bits_per_pixel = mode_cmd->bpp; fb->depth = mode_cmd->depth; - fb->mm_private = mm_private; return 0; } diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index 01b14239..c0719157 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -75,8 +75,7 @@ extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_m extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd *mode_cmd, - void *mm_private); + struct drm_mode_fb_cmd *mode_cmd); static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) { diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index ddc933cc..679244a9 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -601,17 +601,18 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) if (fb->fbdev) radeonfb_remove(dev, fb); + drm_gem_object_unreference(radeon_fb->obj); drm_framebuffer_cleanup(fb); kfree(radeon_fb); } static int radeon_user_framebuffer_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, - unsigned int *handle) + struct drm_file *file_priv, + unsigned int *handle) { - struct drm_gem_object *object = fb->mm_private; + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); - return drm_gem_handle_create(file_priv, object, handle); + return drm_gem_handle_create(file_priv, radeon_fb->obj, handle); } static const struct drm_framebuffer_funcs radeon_fb_funcs = { @@ -622,7 +623,7 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = { struct drm_framebuffer * radeon_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd *mode_cmd, - void *mm_private) + struct drm_gem_object *obj) { struct radeon_framebuffer *radeon_fb; @@ -631,7 +632,10 @@ radeon_framebuffer_create(struct drm_device *dev, return NULL; drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs); - drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd, mm_private); + drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd); + + radeon_fb->obj = obj; + return &radeon_fb->base; } @@ -641,10 +645,11 @@ radeon_user_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd *mode_cmd) { struct radeon_framebuffer *radeon_fb; - void *mm_private; + struct drm_gem_object *obj; + + obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); - mm_private = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); - return radeon_framebuffer_create(dev, mode_cmd, mm_private); + return radeon_framebuffer_create(dev, mode_cmd, obj); } static const struct drm_mode_config_funcs radeon_mode_funcs = { diff --git a/linux-core/radeon_fb.c b/linux-core/radeon_fb.c index 8d4181e8..405f1da9 100644 --- a/linux-core/radeon_fb.c +++ b/linux-core/radeon_fb.c @@ -1148,7 +1148,7 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) unregister_framebuffer(info); drm_bo_kunmap(&radeon_fb->kmap_obj); mutex_lock(&dev->struct_mutex); - drm_gem_object_unreference(fb->mm_private); + drm_gem_object_unreference(radeon_fb->obj); mutex_unlock(&dev->struct_mutex); framebuffer_release(info); } diff --git a/linux-core/radeon_legacy_crtc.c b/linux-core/radeon_legacy_crtc.c index 820bd548..c0a3c0fa 100644 --- a/linux-core/radeon_legacy_crtc.c +++ b/linux-core/radeon_legacy_crtc.c @@ -231,7 +231,7 @@ static bool radeon_set_crtc1_base(struct drm_crtc *crtc, int x, int y) radeon_fb = to_radeon_framebuffer(crtc->fb); - obj = radeon_fb->base.mm_private; + obj = radeon_fb->obj; obj_priv = obj->driver_private; crtc_offset = obj_priv->bo->offset; @@ -654,7 +654,7 @@ static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y) radeon_fb = to_radeon_framebuffer(crtc->fb); - obj = radeon_fb->base.mm_private; + obj = radeon_fb->obj; obj_priv = obj->driver_private; crtc2_offset = obj_priv->bo->offset; diff --git a/linux-core/radeon_mode.h b/linux-core/radeon_mode.h index 64608e35..23de1088 100644 --- a/linux-core/radeon_mode.h +++ b/linux-core/radeon_mode.h @@ -255,6 +255,7 @@ struct radeon_connector { struct radeon_framebuffer { struct drm_framebuffer base; struct drm_bo_kmap_obj kmap_obj; + struct drm_gem_object *obj; }; extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, @@ -323,7 +324,7 @@ extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); struct drm_framebuffer *radeon_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd *mode_cmd, - void *mm_private); + struct drm_gem_object *obj); int radeonfb_probe(struct drm_device *dev); diff --git a/linux-core/radeon_pm.c b/linux-core/radeon_pm.c index db8f44c4..259d42da 100644 --- a/linux-core/radeon_pm.c +++ b/linux-core/radeon_pm.c @@ -54,10 +54,10 @@ int radeon_suspend(struct drm_device *dev, pm_message_t state) if (!radeon_fb) continue; - if (!radeon_fb->base.mm_private) + if (!radeon_fb->obj) continue; - radeon_gem_object_unpin(radeon_fb->base.mm_private); + radeon_gem_object_unpin(radeon_fb->obj); } if (!(dev_priv->flags & RADEON_IS_IGP)) @@ -175,10 +175,10 @@ int radeon_resume(struct drm_device *dev) if (!radeon_fb) continue; - if (!radeon_fb->base.mm_private) + if (!radeon_fb->obj) continue; - radeon_gem_object_pin(radeon_fb->base.mm_private, + radeon_gem_object_pin(radeon_fb->obj, PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); } /* blat the mode back in */ -- cgit v1.2.3 From 8b2925468d326ab6fa31a312e845a3bc71343106 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:39:53 +1000 Subject: radeon: make new CS2 command submission interface port older interface to this --- linux-core/radeon_gem.c | 25 +++-- shared-core/radeon_cs.c | 257 ++++++++++++++++++++++++++++++++++++++------- shared-core/radeon_drm.h | 19 +++- shared-core/radeon_drv.h | 31 ++++-- shared-core/radeon_state.c | 1 + 5 files changed, 273 insertions(+), 60 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 4b15fac3..7899490f 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1148,11 +1148,11 @@ int radeon_gem_object_unpin(struct drm_gem_object *obj) #define RADEON_NUM_IB (RADEON_IB_MEMORY / RADEON_IB_SIZE) -int radeon_gem_ib_get(struct drm_device *dev, void **ib, uint32_t dwords, uint32_t *card_offset) +int radeon_gem_ib_get(struct drm_radeon_cs_parser *parser, uint32_t *card_offset) { int i, index = -1; int ret; - drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_private_t *dev_priv = parser->dev->dev_private; for (i = 0; i < RADEON_NUM_IB; i++) { if (!(dev_priv->ib_alloc_bitmap & (1 << i))){ @@ -1178,12 +1178,12 @@ int radeon_gem_ib_get(struct drm_device *dev, void **ib, uint32_t dwords, uint32 } if (index == -1) { - DRM_ERROR("Major case fail to allocate IB from freelist %x\n", dev_priv->ib_alloc_bitmap); + DRM_ERROR("Major case fail to allocate IB from freelist %llx\n", dev_priv->ib_alloc_bitmap); return -EINVAL; } - if (dwords > RADEON_IB_SIZE / sizeof(uint32_t)) + if (parser->chunks[parser->ib_index].length_dw > RADEON_IB_SIZE / sizeof(uint32_t)) return -EINVAL; ret = drm_bo_do_validate(dev_priv->ib_objs[index]->bo, 0, @@ -1195,25 +1195,24 @@ int radeon_gem_ib_get(struct drm_device *dev, void **ib, uint32_t dwords, uint32 } *card_offset = dev_priv->gart_vm_start + dev_priv->ib_objs[index]->bo->offset; - *ib = dev_priv->ib_objs[index]->kmap.virtual; + parser->ib = dev_priv->ib_objs[index]->kmap.virtual; dev_priv->ib_alloc_bitmap |= (1 << i); return 0; } -static void radeon_gem_ib_free(struct drm_device *dev, void *ib, uint32_t dwords) +static void radeon_gem_ib_free(struct drm_radeon_cs_parser *parser) { + struct drm_device *dev = parser->dev; drm_radeon_private_t *dev_priv = dev->dev_private; struct drm_fence_object *fence; int ret; int i; for (i = 0; i < RADEON_NUM_IB; i++) { - - if (dev_priv->ib_objs[i]->kmap.virtual == ib) { + if (dev_priv->ib_objs[i]->kmap.virtual == parser->ib) { /* emit a fence object */ ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); if (ret) { - drm_putback_buffer_objects(dev); } /* dereference the fence object */ @@ -1243,19 +1242,19 @@ static int radeon_gem_ib_destroy(struct drm_device *dev) return 0; } -static int radeon_gem_relocate(struct drm_device *dev, struct drm_file *file_priv, - uint32_t *reloc, uint32_t *offset) +static int radeon_gem_relocate(struct drm_radeon_cs_parser *parser, + uint32_t *reloc, uint32_t *offset) { + struct drm_device *dev = parser->dev; drm_radeon_private_t *dev_priv = dev->dev_private; /* relocate the handle */ uint32_t read_domains = reloc[2]; uint32_t write_domain = reloc[3]; struct drm_gem_object *obj; int flags = 0; - int ret; struct drm_radeon_gem_object *obj_priv; - obj = drm_gem_object_lookup(dev, file_priv, reloc[1]); + obj = drm_gem_object_lookup(dev, parser->file_priv, reloc[1]); if (!obj) return -EINVAL; diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index b5982894..452f04b4 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -29,16 +29,163 @@ #include "radeon_drv.h" #include "r300_reg.h" +int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) +{ + struct drm_radeon_cs_parser parser; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_radeon_cs2 *cs = data; + uint32_t cs_id; + struct drm_radeon_cs_chunk __user **chunk_ptr = NULL; + uint64_t *chunk_array; + uint64_t *chunk_array_ptr; + uint32_t card_offset; + long size; + int r, i; + RING_LOCALS; + + /* set command stream id to 0 which is fake id */ + cs_id = 0; + DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); + + if (dev_priv == NULL) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + if (!cs->num_chunks) { + return 0; + } + + + chunk_array = drm_calloc(cs->num_chunks, sizeof(uint64_t), DRM_MEM_DRIVER); + if (!chunk_array) { + return -ENOMEM; + } + + chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks); + + if (DRM_COPY_FROM_USER(chunk_array, chunk_array_ptr, sizeof(uint64_t)*cs->num_chunks)) { + r = -EFAULT; + goto out; + } + + parser.reloc_index = -1; + parser.ib_index = -1; + parser.num_chunks = cs->num_chunks; + /* copy out the chunk headers */ + parser.chunks = drm_calloc(parser.num_chunks, sizeof(struct drm_radeon_kernel_chunk), DRM_MEM_DRIVER); + if (!parser.chunks) { + return -ENOMEM; + } + + for (i = 0; i < parser.num_chunks; i++) { + struct drm_radeon_cs_chunk user_chunk; + + chunk_ptr = (void __user *)(unsigned long)chunk_array[i]; + + if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr, sizeof(struct drm_radeon_cs_chunk))){ + r = -EFAULT; + goto out; + } + parser.chunks[i].chunk_id = user_chunk.chunk_id; + + if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) + parser.reloc_index = i; + + if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_IB) + parser.ib_index = i; + + if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_OLD) { + parser.ib_index = i; + parser.reloc_index = -1; + } + + parser.chunks[i].length_dw = user_chunk.length_dw; + parser.chunks[i].chunk_data = (uint32_t *)(unsigned long)user_chunk.chunk_data; + + parser.chunks[i].kdata = NULL; + + switch(parser.chunks[i].chunk_id) { + case RADEON_CHUNK_ID_RELOCS: + case RADEON_CHUNK_ID_IB: + case RADEON_CHUNK_ID_OLD: { + /* copy from user the relocs chunk */ + int size = parser.chunks[i].length_dw * sizeof(uint32_t); + parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER); + if (!parser.chunks[i].kdata) { + r = -ENOMEM; + goto out; + } + + if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) { + r = -EFAULT; + goto out; + } + } + break; + default: + break; + } + DRM_DEBUG("chunk %d %d %d %p\n", i, parser.chunks[i].chunk_id, parser.chunks[i].length_dw, + parser.chunks[i].chunk_data); + } + + + if (parser.chunks[parser.ib_index].length_dw > (16 * 1024)) { + DRM_ERROR("cs->dwords too big: %d\n", parser.chunks[parser.ib_index].length_dw); + r = -EINVAL; + goto out; + } + + /* get ib */ + r = dev_priv->cs.ib_get(&parser, &card_offset); + if (r) { + DRM_ERROR("ib_get failed\n"); + goto out; + } + + /* now parse command stream */ + r = dev_priv->cs.parse(&parser); + if (r) { + goto out; + } + + BEGIN_RING(4); + OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); + OUT_RING(card_offset); + OUT_RING(parser.chunks[parser.ib_index].length_dw); + OUT_RING(CP_PACKET2()); + ADVANCE_RING(); + + /* emit cs id sequence */ + dev_priv->cs.id_emit(dev, &cs_id); + COMMIT_RING(); + + DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); +out: + dev_priv->cs.ib_free(&parser); + + for (i = 0; i < parser.num_chunks; i++) { + if (parser.chunks[i].kdata) + drm_free(parser.chunks[i].kdata, parser.chunks[i].length_dw * sizeof(uint32_t), DRM_MEM_DRIVER); + } + + drm_free(parser.chunks, sizeof(struct drm_radeon_kernel_chunk)*parser.num_chunks, DRM_MEM_DRIVER); + drm_free(chunk_array, sizeof(uint64_t)*parser.num_chunks, DRM_MEM_DRIVER); + + return r; +} + int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) { + struct drm_radeon_cs_parser parser; struct drm_radeon_private *dev_priv = dev->dev_private; struct drm_radeon_cs *cs = data; uint32_t *packets = NULL; uint32_t cs_id; uint32_t card_offset; - void *ib = NULL; long size; int r; + struct drm_radeon_kernel_chunk chunk_fake[1]; RING_LOCALS; /* set command stream id to 0 which is fake id */ @@ -69,14 +216,26 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) r = -EFAULT; goto out; } + + chunk_fake[0].chunk_id = RADEON_CHUNK_ID_OLD; + chunk_fake[0].length_dw = cs->dwords; + chunk_fake[0].kdata = packets; + + parser.dev = dev; + parser.file_priv = fpriv; + parser.num_chunks = 1; + parser.chunks = chunk_fake; + parser.ib_index = 0; + parser.reloc_index = -1; + /* get ib */ - r = dev_priv->cs.ib_get(dev, &ib, cs->dwords, &card_offset); + r = dev_priv->cs.ib_get(&parser, &card_offset); if (r) { goto out; } /* now parse command stream */ - r = dev_priv->cs.parse(dev, fpriv, ib, packets, cs->dwords); + r = dev_priv->cs.parse(&parser); if (r) { goto out; } @@ -94,13 +253,13 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); out: - dev_priv->cs.ib_free(dev, ib, cs->dwords); + dev_priv->cs.ib_free(&parser); drm_free(packets, size, DRM_MEM_DRIVER); return r; } /* for non-mm */ -static int radeon_nomm_relocate(struct drm_device *dev, struct drm_file *file_priv, uint32_t *reloc, uint32_t *offset) +static int radeon_nomm_relocate(struct drm_radeon_cs_parser *parser, uint32_t *reloc, uint32_t *offset) { *offset = reloc[1]; return 0; @@ -108,17 +267,24 @@ static int radeon_nomm_relocate(struct drm_device *dev, struct drm_file *file_pr #define RELOC_SIZE 2 #define RADEON_2D_OFFSET_MASK 0x3fffff -static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct drm_file *file_priv, - uint32_t *packets, uint32_t offset_dw) +static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) { + struct drm_device *dev = parser->dev; drm_radeon_private_t *dev_priv = dev->dev_private; - uint32_t hdr = packets[offset_dw]; - uint32_t reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; - uint32_t val = packets[offset_dw + 1]; - uint32_t packet3_hdr = packets[offset_dw+2]; + uint32_t hdr, reg, val, packet3_hdr; uint32_t tmp, offset; + struct drm_radeon_kernel_chunk *ib_chunk; int ret; + ib_chunk = &parser->chunks[parser->ib_index]; +// if (parser->reloc_index == -1) +// is_old = 1; + + hdr = ib_chunk->kdata[offset_dw]; + reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + val = ib_chunk->kdata[offset_dw + 1]; + packet3_hdr = ib_chunk->kdata[offset_dw + 2]; + /* this is too strict we may want to expand the length in the future and have old kernels ignore it. */ if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { @@ -130,7 +296,7 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct case RADEON_DST_PITCH_OFFSET: case RADEON_SRC_PITCH_OFFSET: /* pass in the start of the reloc */ - ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset); + ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + 2, &offset); if (ret) return ret; tmp = (val & RADEON_2D_OFFSET_MASK) << 10; @@ -148,7 +314,7 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct case R200_PP_TXOFFSET_1: case RADEON_PP_TXOFFSET_0: case RADEON_PP_TXOFFSET_1: - ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset); + ret = dev_priv->cs.relocate(parser. ib_chunk->kdata + offset_dw + 2, &offset); if (ret) return ret; @@ -159,25 +325,32 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct break; } - packets[offset_dw + 1] = val; + ib_chunk->kdata[offset_dw + 1] = val; return 0; } -static int radeon_cs_relocate_packet3(struct drm_device *dev, struct drm_file *file_priv, - uint32_t *packets, uint32_t offset_dw) +static int radeon_cs_relocate_packet3(struct drm_radeon_cs_parser *parser, + uint32_t offset_dw) { - drm_radeon_private_t *dev_priv = dev->dev_private; - uint32_t hdr = packets[offset_dw]; - int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16; - uint32_t reg = hdr & 0xff00; + drm_radeon_private_t *dev_priv = parser->dev->dev_private; + uint32_t hdr, num_dw, reg; uint32_t offset, val, tmp; int ret; + struct drm_radeon_kernel_chunk *ib_chunk; + + ib_chunk = &parser->chunks[parser->ib_index]; +// if (parser->reloc_index == -1) +// is_old = 1; + + hdr = ib_chunk->kdata[offset_dw]; + num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16; + reg = hdr & 0xff00; switch(reg) { case RADEON_CNTL_HOSTDATA_BLT: { - val = packets[offset_dw + 2]; - ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + num_dw + 2, &offset); + val = ib_chunk->kdata[offset_dw + 2]; + ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + num_dw + 2, &offset); if (ret) return ret; @@ -187,7 +360,7 @@ static int radeon_cs_relocate_packet3(struct drm_device *dev, struct drm_file *f offset >>= 10; val |= offset; - packets[offset_dw + 2] = val; + ib_chunk->kdata[offset_dw + 2] = val; } default: return -EINVAL; @@ -195,17 +368,18 @@ static int radeon_cs_relocate_packet3(struct drm_device *dev, struct drm_file *f return 0; } -int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv, - uint32_t *packets, uint32_t offset_dw) +int radeon_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) { - drm_radeon_private_t *dev_priv = dev->dev_private; - uint32_t hdr = packets[offset_dw]; - int num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; + drm_radeon_private_t *dev_priv = parser->dev->dev_private; + uint32_t hdr, num_dw, reg; int need_reloc = 0; - int reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; int count_dw = 1; int ret; + hdr = parser->chunks[parser->ib_index].kdata[offset_dw]; + num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; + reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + while (count_dw < num_dw) { /* need to have something like the r300 validation here - list of allowed registers */ @@ -226,7 +400,7 @@ int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv, return -EINVAL; } - ret = radeon_cs_relocate_packet0(dev, file_priv, packets, offset_dw); + ret = radeon_cs_relocate_packet0(parser, offset_dw); if (ret) return ret; DRM_DEBUG("need to relocate %x %d\n", reg, flags); @@ -245,24 +419,27 @@ int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv, return 0; } -int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv, - void *ib, uint32_t *packets, uint32_t dwords) +int radeon_cs_parse(struct drm_radeon_cs_parser *parser) { - drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_device *dev = parser->dev; + drm_radeon_private_t *dev_priv = parser->dev->dev_private; volatile int rb; - int size_dw = dwords; + struct drm_radeon_kernel_chunk *ib_chunk; /* scan the packet for various things */ - int count_dw = 0; + int count_dw = 0, size_dw; int ret = 0; + ib_chunk = &parser->chunks[parser->ib_index]; + size_dw = ib_chunk->length_dw; + while (count_dw < size_dw && ret == 0) { - int hdr = packets[count_dw]; + int hdr = ib_chunk->kdata[count_dw]; int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16; int reg; switch (hdr & RADEON_CP_PACKET_MASK) { case RADEON_CP_PACKET0: - ret = radeon_cs_packet0(dev, file_priv, packets, count_dw); + ret = radeon_cs_packet0(parser, count_dw); break; case RADEON_CP_PACKET1: case RADEON_CP_PACKET2: @@ -275,7 +452,7 @@ int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv, switch(reg) { case RADEON_CNTL_HOSTDATA_BLT: - radeon_cs_relocate_packet3(dev, file_priv, packets, count_dw); + radeon_cs_relocate_packet3(parser, count_dw); break; case RADEON_CNTL_BITBLT_MULTI: @@ -306,10 +483,10 @@ int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv, /* copy the packet into the IB */ - memcpy(ib, packets, dwords * sizeof(uint32_t)); + memcpy(parser->ib, ib_chunk->kdata, ib_chunk->length_dw * sizeof(uint32_t)); /* read back last byte to flush WC buffers */ - rb = readl((ib + (dwords-1) * sizeof(uint32_t))); + rb = readl((parser->ib + (ib_chunk->length_dw-1) * sizeof(uint32_t))); return 0; } diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index c924c689..bc2eb45a 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -514,6 +514,7 @@ typedef struct { #define DRM_RADEON_GEM_INDIRECT 0x24 // temporary for X server #define DRM_RADEON_CS 0x25 +#define DRM_RADEON_CS2 0x26 #define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t) #define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START) @@ -554,6 +555,7 @@ typedef struct { #define DRM_IOCTL_RADEON_GEM_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INDIRECT, struct drm_radeon_gem_indirect) #define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs) +#define DRM_IOCTL_RADEON_CS2 DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS2, struct drm_radeon_cs2) typedef struct drm_radeon_init { @@ -874,11 +876,26 @@ struct drm_radeon_gem_indirect { struct drm_radeon_cs { -// uint32_t __user *packets; uint32_t dwords; uint32_t cs_id; uint64_t packets; +}; + +#define RADEON_CHUNK_ID_RELOCS 0x01 +#define RADEON_CHUNK_ID_IB 0x02 +#define RADEON_CHUNK_ID_OLD 0xff + +struct drm_radeon_cs_chunk { + uint32_t chunk_id; + uint32_t length_dw; + uint64_t chunk_data; +}; +struct drm_radeon_cs2 { + uint32_t num_chunks; + uint32_t cs_id; + uint64_t chunks; /* this points to uint64_t * which point to + cs chunks */ }; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 17c0c297..b741953b 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -294,6 +294,23 @@ struct drm_radeon_master_private { #define RADEON_FLUSH_EMITED (1 < 0) #define RADEON_PURGE_EMITED (1 < 1) +struct drm_radeon_kernel_chunk { + uint32_t chunk_id; + uint32_t length_dw; + uint32_t __user *chunk_data; + uint32_t *kdata; +}; + +struct drm_radeon_cs_parser { + struct drm_device *dev; + struct drm_file *file_priv; + uint32_t num_chunks; + struct drm_radeon_kernel_chunk *chunks; + int ib_index; + int reloc_index; + void *ib; +}; + /* command submission struct */ struct drm_radeon_cs_priv { uint32_t id_wcnt; @@ -301,21 +318,22 @@ struct drm_radeon_cs_priv { uint32_t id_last_wcnt; uint32_t id_last_scnt; - int (*parse)(struct drm_device *dev, struct drm_file *file_priv, - void *ib, uint32_t *packets, uint32_t dwords); + int (*parse)(struct drm_radeon_cs_parser *parser); void (*id_emit)(struct drm_device *dev, uint32_t *id); uint32_t (*id_last_get)(struct drm_device *dev); /* this ib handling callback are for hidding memory manager drm * from memory manager less drm, free have to emit ib discard * sequence into the ring */ - int (*ib_get)(struct drm_device *dev, void **ib, uint32_t dwords, uint32_t *card_offset); + int (*ib_get)(struct drm_radeon_cs_parser *parser, uint32_t *card_offset); uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib); - void (*ib_free)(struct drm_device *dev, void *ib, uint32_t dwords); + void (*ib_free)(struct drm_radeon_cs_parser *parser); /* do a relocation either MM or non-MM */ - int (*relocate)(struct drm_device *dev, struct drm_file *file_priv, - uint32_t *reloc, uint32_t *offset); + int (*relocate)(struct drm_radeon_cs_parser *parser, + uint32_t *reloc, uint32_t *offset); }; + + struct radeon_pm_regs { uint32_t crtc_ext_cntl; uint32_t bios_scratch[8]; @@ -1689,6 +1707,7 @@ extern int radeon_master_create(struct drm_device *dev, struct drm_master *maste extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master); extern void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master); extern int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv); +extern int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv); extern int radeon_cs_init(struct drm_device *dev); void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master); void radeon_init_memory_map(struct drm_device *dev); diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 7262b2aa..f0cd6f89 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3290,6 +3290,7 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_GEM_INDIRECT, radeon_gem_indirect_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CS2, radeon_cs2_ioctl, DRM_AUTH), }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); -- cgit v1.2.3 From 35f080559287ebf30f417337fa124d827709503b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:40:24 +1000 Subject: radeon: don't copy to user the cs ids --- shared-core/radeon_cs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 452f04b4..14f3dcd9 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -45,7 +45,7 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) /* set command stream id to 0 which is fake id */ cs_id = 0; - DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); + cs->cs_id = cs_id; if (dev_priv == NULL) { DRM_ERROR("called with no initialization\n"); @@ -160,7 +160,8 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) dev_priv->cs.id_emit(dev, &cs_id); COMMIT_RING(); - DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); + cs->cs_id = cs_id; + out: dev_priv->cs.ib_free(&parser); @@ -190,7 +191,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) /* set command stream id to 0 which is fake id */ cs_id = 0; - DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); + cs->cs_id = cs_id; if (dev_priv == NULL) { DRM_ERROR("called with no initialization\n"); @@ -251,7 +252,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) dev_priv->cs.id_emit(dev, &cs_id); COMMIT_RING(); - DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t)); + cs->cs_id = cs_id; out: dev_priv->cs.ib_free(&parser); drm_free(packets, size, DRM_MEM_DRIVER); -- cgit v1.2.3 From 6000fa686294019e93f815433a1a9b44db511a69 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:40:52 +1000 Subject: radeon: CS2 make it all work with new relocs style --- linux-core/radeon_gem.c | 47 +++++++++++++++++++++++++++++++++++++++----- shared-core/radeon_cs.c | 52 ++++++++++++++++++++++++++++++------------------- 2 files changed, 74 insertions(+), 25 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 7899490f..851a95d3 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1242,21 +1242,58 @@ static int radeon_gem_ib_destroy(struct drm_device *dev) return 0; } +static int radeon_gem_find_reloc(struct drm_radeon_cs_parser *parser, + uint32_t offset, uint32_t *handle, + uint32_t *read_domains, uint32_t *write_domain) +{ + struct drm_device *dev = parser->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_kernel_chunk *reloc_chunk = &parser->chunks[parser->reloc_index]; + + if (!reloc_chunk->kdata) + return -EINVAL; + + if (offset > reloc_chunk->length_dw){ + DRM_ERROR("Offset larger than chunk %d %d\n", offset, reloc_chunk->length_dw); + return -EINVAL; + } + + *handle = reloc_chunk->kdata[offset]; + *read_domains = reloc_chunk->kdata[offset + 1]; + *write_domain = reloc_chunk->kdata[offset + 2]; + return 0; +} + static int radeon_gem_relocate(struct drm_radeon_cs_parser *parser, uint32_t *reloc, uint32_t *offset) { struct drm_device *dev = parser->dev; drm_radeon_private_t *dev_priv = dev->dev_private; /* relocate the handle */ - uint32_t read_domains = reloc[2]; - uint32_t write_domain = reloc[3]; + uint32_t read_domains, write_domain; struct drm_gem_object *obj; int flags = 0; + int ret; struct drm_radeon_gem_object *obj_priv; - obj = drm_gem_object_lookup(dev, parser->file_priv, reloc[1]); - if (!obj) - return -EINVAL; + if (parser->reloc_index == -1) { + obj = drm_gem_object_lookup(dev, parser->file_priv, reloc[1]); + if (!obj) + return -EINVAL; + read_domains = reloc[2]; + write_domain = reloc[3]; + } else { + uint32_t handle; + + /* have to lookup handle in other chunk */ + ret = radeon_gem_find_reloc(parser, reloc[1], &handle, &read_domains, &write_domain); + if (ret < 0) + return ret; + + obj = drm_gem_object_lookup(dev, parser->file_priv, handle); + if (!obj) + return -EINVAL; + } obj_priv = obj->driver_private; radeon_gem_set_domain(obj, read_domains, write_domain, &flags, false); diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 14f3dcd9..31cd53db 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -68,6 +68,8 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) goto out; } + parser.dev = dev; + parser.file_priv = fpriv; parser.reloc_index = -1; parser.ib_index = -1; parser.num_chunks = cs->num_chunks; @@ -103,24 +105,29 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) parser.chunks[i].chunk_data = (uint32_t *)(unsigned long)user_chunk.chunk_data; parser.chunks[i].kdata = NULL; + size = parser.chunks[i].length_dw * sizeof(uint32_t); switch(parser.chunks[i].chunk_id) { - case RADEON_CHUNK_ID_RELOCS: case RADEON_CHUNK_ID_IB: - case RADEON_CHUNK_ID_OLD: { - /* copy from user the relocs chunk */ - int size = parser.chunks[i].length_dw * sizeof(uint32_t); - parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER); - if (!parser.chunks[i].kdata) { - r = -ENOMEM; + case RADEON_CHUNK_ID_OLD: + if (size == 0) { + r = -EINVAL; goto out; } - - if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) { - r = -EFAULT; - goto out; - } - } + case RADEON_CHUNK_ID_RELOCS: + if (size) { + parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER); + if (!parser.chunks[i].kdata) { + r = -ENOMEM; + goto out; + } + + if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) { + r = -EFAULT; + goto out; + } + } else + parser.chunks[i].kdata = NULL; break; default: break; @@ -266,6 +273,7 @@ static int radeon_nomm_relocate(struct drm_radeon_cs_parser *parser, uint32_t *r return 0; } #define RELOC_SIZE 2 +#define RELOC_SIZE_NEW 0 #define RADEON_2D_OFFSET_MASK 0x3fffff static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) @@ -288,9 +296,17 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *pa /* this is too strict we may want to expand the length in the future and have old kernels ignore it. */ - if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { - DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16), reg); - return -EINVAL; + if (parser->reloc_index == -1) { + if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16), reg); + return -EINVAL; + } + } else { + if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16))) { + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16), reg); + return -EINVAL; + + } } switch(reg) { @@ -371,9 +387,7 @@ static int radeon_cs_relocate_packet3(struct drm_radeon_cs_parser *parser, int radeon_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) { - drm_radeon_private_t *dev_priv = parser->dev->dev_private; uint32_t hdr, num_dw, reg; - int need_reloc = 0; int count_dw = 1; int ret; @@ -422,8 +436,6 @@ int radeon_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) int radeon_cs_parse(struct drm_radeon_cs_parser *parser) { - struct drm_device *dev = parser->dev; - drm_radeon_private_t *dev_priv = parser->dev->dev_private; volatile int rb; struct drm_radeon_kernel_chunk *ib_chunk; /* scan the packet for various things */ -- cgit v1.2.3 From e57072b5ee521ec799d0aa0ef84a7d01d8479202 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:41:12 +1000 Subject: radeon: fix free after refcount --- linux-core/radeon_display.c | 6 +++++- linux-core/radeon_fb.c | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index 679244a9..f16288ef 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -601,7 +601,11 @@ static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) if (fb->fbdev) radeonfb_remove(dev, fb); - drm_gem_object_unreference(radeon_fb->obj); + if (radeon_fb->obj) { + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(radeon_fb->obj); + mutex_unlock(&dev->struct_mutex); + } drm_framebuffer_cleanup(fb); kfree(radeon_fb); } diff --git a/linux-core/radeon_fb.c b/linux-core/radeon_fb.c index 405f1da9..d3722c37 100644 --- a/linux-core/radeon_fb.c +++ b/linux-core/radeon_fb.c @@ -1149,6 +1149,7 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) drm_bo_kunmap(&radeon_fb->kmap_obj); mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(radeon_fb->obj); + radeon_fb->obj = NULL; mutex_unlock(&dev->struct_mutex); framebuffer_release(info); } -- cgit v1.2.3 From f5e6dbef797cff18953e4f3271e1c74a0b24b715 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:41:30 +1000 Subject: radeon: fix some warnings --- linux-core/radeon_gem.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 851a95d3..6c62620a 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -126,7 +126,6 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_radeon_gem_object *obj_priv; struct drm_gem_object *obj; int ret = 0; - uint32_t flags; int handle; /* create a gem object to contain this object in */ @@ -157,8 +156,6 @@ fail: int radeon_gem_set_domain(struct drm_gem_object *obj, uint32_t read_domains, uint32_t write_domain, uint32_t *flags_p, bool unfenced) { - struct drm_device *dev = obj->dev; - drm_radeon_private_t *dev_priv = dev->dev_private; struct drm_radeon_gem_object *obj_priv; uint32_t flags = 0; int ret; @@ -616,7 +613,7 @@ static int radeon_gart_init(struct drm_device *dev) base = dev->agp->base; if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location && base < (dev_priv->fb_location + dev_priv->fb_size - 1)) { - DRM_INFO("Can't use agp base @0x%08xlx, won't fit\n", + DRM_INFO("Can't use agp base @0x%08lx, won't fit\n", dev->agp->base); base = 0; } @@ -732,7 +729,7 @@ int radeon_alloc_gart_objects(struct drm_device *dev) return -EINVAL; } - DRM_DEBUG("Ring ptr %p mapped at %d %p, read ptr %p maped at %d %p\n", + DRM_DEBUG("Ring ptr %p mapped at %ld %p, read ptr %p maped at %ld %p\n", dev_priv->mm.ring.bo, dev_priv->mm.ring.bo->offset, dev_priv->mm.ring.kmap.virtual, dev_priv->mm.ring_read.bo, dev_priv->mm.ring_read.bo->offset, dev_priv->mm.ring_read.kmap.virtual); @@ -829,7 +826,6 @@ static void radeon_wait_for_vsync(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; uint32_t crtc_gen_cntl; - int ret; crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL); if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) || @@ -848,7 +844,6 @@ static void radeon_wait_for_vsync2(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; uint32_t crtc2_gen_cntl; - struct timeval timeout; crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) || @@ -917,7 +912,6 @@ void radeon_init_memory_map(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; u32 mem_size, aper_size; - u32 tmp; dev_priv->mc_fb_location = radeon_read_fb_location(dev_priv); radeon_read_agp_location(dev_priv, &dev_priv->mc_agp_loc_lo, &dev_priv->mc_agp_loc_hi); @@ -1581,7 +1575,7 @@ static int radeon_gem_dma_bufs_init(struct drm_device *dev) DRM_DEBUG("\n"); radeon_gem_addbufs(dev); - DRM_DEBUG("%x %d\n", dev_priv->mm.dma_bufs.bo->map_list.hash.key, size); + DRM_DEBUG("%lx %d\n", dev_priv->mm.dma_bufs.bo->map_list.hash.key, size); dev->agp_buffer_token = dev_priv->mm.dma_bufs.bo->map_list.hash.key << PAGE_SHIFT; dev_priv->mm.fake_agp_map.handle = dev_priv->mm.dma_bufs.kmap.virtual; dev_priv->mm.fake_agp_map.size = size; -- cgit v1.2.3 From 4ccec67a239517458bace47bf08f6770393abb37 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:42:01 +1000 Subject: radeon: remove unused gem indirect ioctl --- linux-core/radeon_gem.c | 75 ---------------------------------------------- shared-core/radeon_drm.h | 6 ---- shared-core/radeon_drv.h | 2 -- shared-core/radeon_state.c | 1 - 4 files changed, 84 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 6c62620a..ce33979e 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -424,81 +424,6 @@ int radeon_gem_execbuffer(struct drm_device *dev, void *data, } -int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_radeon_gem_indirect *args = data; - struct drm_radeon_private *dev_priv = dev->dev_private; - struct drm_gem_object *obj; - struct drm_radeon_gem_object *obj_priv; - uint32_t start, end; - int ret; - RING_LOCALS; - - obj = drm_gem_object_lookup(dev, file_priv, args->handle); - if (obj == NULL) - return -EINVAL; - - obj_priv = obj->driver_private; - - DRM_DEBUG("got here %p %d\n", obj, args->used); - //RING_SPACE_TEST_WITH_RETURN(dev_priv); - //VB_AGE_TEST_WITH_RETURN(dev_priv); - - ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, - 0 , 0); - if (ret) - return ret; - - /* Wait for the 3D stream to idle before the indirect buffer - * containing 2D acceleration commands is processed. - */ - BEGIN_RING(2); - - RADEON_WAIT_UNTIL_3D_IDLE(); - - ADVANCE_RING(); - - start = 0; - end = args->used; - - if (start != end) { - int offset = (dev_priv->gart_vm_start + - + obj_priv->bo->offset + start); - int dwords = (end - start + 3) / sizeof(u32); - - /* Fire off the indirect buffer */ - BEGIN_RING(3); - - OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); - OUT_RING(offset); - OUT_RING(dwords); - - ADVANCE_RING(); - } - - COMMIT_RING(); - - /* we need to fence the buffer */ - ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &obj_priv->fence); - if (ret) { - - drm_putback_buffer_objects(dev); - ret = 0; - goto fail; - } - - /* dereference he fence object */ - drm_fence_usage_deref_unlocked(&obj_priv->fence); - - mutex_lock(&dev->struct_mutex); - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - ret = 0; - fail: - return ret; -} - /* * Depending on card genertation, chipset bugs, etc... the amount of vram * accessible to the CPU can vary. This function is our best shot at figuring diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index bc2eb45a..0780eb7f 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -511,7 +511,6 @@ typedef struct { #define DRM_RADEON_GEM_PREAD 0x21 #define DRM_RADEON_GEM_PWRITE 0x22 #define DRM_RADEON_GEM_SET_DOMAIN 0x23 -#define DRM_RADEON_GEM_INDIRECT 0x24 // temporary for X server #define DRM_RADEON_CS 0x25 #define DRM_RADEON_CS2 0x26 @@ -552,7 +551,6 @@ typedef struct { #define DRM_IOCTL_RADEON_GEM_PREAD DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PREAD, struct drm_radeon_gem_pread) #define DRM_IOCTL_RADEON_GEM_PWRITE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PWRITE, struct drm_radeon_gem_pwrite) #define DRM_IOCTL_RADEON_GEM_SET_DOMAIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_DOMAIN, struct drm_radeon_gem_set_domain) -#define DRM_IOCTL_RADEON_GEM_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INDIRECT, struct drm_radeon_gem_indirect) #define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs) #define DRM_IOCTL_RADEON_CS2 DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS2, struct drm_radeon_cs2) @@ -866,10 +864,6 @@ struct drm_radeon_gem_pwrite { uint64_t data_ptr; /* void *, but pointers are not 32/64 compatible */ }; -struct drm_radeon_gem_indirect { - uint32_t handle; - uint32_t used; -}; /* New interface which obsolete all previous interface. */ diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index b741953b..73e5a261 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1688,8 +1688,6 @@ extern int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment, uint32_t pin_domain); int radeon_gem_object_unpin(struct drm_gem_object *obj); -int radeon_gem_indirect_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index f0cd6f89..40ecf1c4 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3288,7 +3288,6 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_GEM_INDIRECT, radeon_gem_indirect_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_CS2, radeon_cs2_ioctl, DRM_AUTH), }; -- cgit v1.2.3 From fc25c81eab2d847c854e0a44cae29f8c2213bba6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:43:29 +1000 Subject: radeon: rs480 fixes for bus mastering --- shared-core/radeon_cp.c | 15 ++++++++------- shared-core/radeon_drv.h | 5 +++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 8e97f034..942ccc51 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -198,15 +198,16 @@ void radeon_enable_bm(struct drm_radeon_private *dev_priv) { u32 tmp; /* Turn on bus mastering */ - if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) || - ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || + if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) { - /* rs400, rs690/rs740 */ - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS400_BUS_MASTER_DIS; + /* rs600/rs690/rs740 */ + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS; RADEON_WRITE(RADEON_BUS_CNTL, tmp); - } else if (!(((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) || - ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R423))) { - /* r1xx, r2xx, r300, r(v)350, r420/r481, rs480 */ + } else if (((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV350) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R420) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) { + /* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */ tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; RADEON_WRITE(RADEON_BUS_CNTL, tmp); } /* PCIE cards appears to not need this */ diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 73e5a261..85a22e9f 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -591,7 +591,11 @@ int radeon_resume(struct drm_device *dev); # define RADEON_SCISSOR_2_ENABLE (1 << 30) #define RADEON_BUS_CNTL 0x0030 +/* r1xx, r2xx, r300, r(v)350, r420/r481, rs400/rs480 */ # define RADEON_BUS_MASTER_DIS (1 << 6) +/* rs600/rs690/rs740 */ +# define RS600_BUS_MASTER_DIS (1 << 14) +# define RS600_MSI_REARM (1 << 20) #define RADEON_CLOCK_CNTL_DATA 0x000c # define RADEON_PLL_WR_EN (1 << 7) @@ -1053,6 +1057,7 @@ int radeon_resume(struct drm_device *dev); #define RADEON_AIC_CNTL 0x01d0 # define RADEON_PCIGART_TRANSLATE_EN (1 << 0) +# define RS400_MSI_REARM (1 << 3) #define RADEON_AIC_STAT 0x01d4 #define RADEON_AIC_PT_BASE 0x01d8 #define RADEON_AIC_LO_ADDR 0x01dc -- cgit v1.2.3 From 31f8d4218c0f6455751d8bbc788172912359b0df Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:44:03 +1000 Subject: radeon: add wait rendering API --- linux-core/radeon_gem.c | 25 ++++++++++++++++++++++--- shared-core/radeon_drm.h | 6 ++++-- shared-core/radeon_drv.h | 2 ++ shared-core/radeon_state.c | 1 + 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index ce33979e..f5d6b94a 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -416,14 +416,33 @@ int radeon_gem_busy(struct drm_device *dev, void *data, return 0; } -int radeon_gem_execbuffer(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int radeon_gem_wait_rendering(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - return -ENOSYS; + struct drm_radeon_gem_wait_rendering *args = data; + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + int ret; + + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + obj_priv = obj->driver_private; + mutex_lock(&obj_priv->bo->mutex); + ret = drm_bo_wait(obj_priv->bo, 0, 1, 1, 0); + mutex_unlock(&obj_priv->bo->mutex); + + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + return ret; } + + /* * Depending on card genertation, chipset bugs, etc... the amount of vram * accessible to the CPU can vary. This function is our best shot at figuring diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h index 0780eb7f..002e4004 100644 --- a/shared-core/radeon_drm.h +++ b/shared-core/radeon_drm.h @@ -511,6 +511,7 @@ typedef struct { #define DRM_RADEON_GEM_PREAD 0x21 #define DRM_RADEON_GEM_PWRITE 0x22 #define DRM_RADEON_GEM_SET_DOMAIN 0x23 +#define DRM_RADEON_GEM_WAIT_RENDERING 0x24 #define DRM_RADEON_CS 0x25 #define DRM_RADEON_CS2 0x26 @@ -551,7 +552,7 @@ typedef struct { #define DRM_IOCTL_RADEON_GEM_PREAD DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PREAD, struct drm_radeon_gem_pread) #define DRM_IOCTL_RADEON_GEM_PWRITE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PWRITE, struct drm_radeon_gem_pwrite) #define DRM_IOCTL_RADEON_GEM_SET_DOMAIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_DOMAIN, struct drm_radeon_gem_set_domain) - +#define DRM_IOCTL_RADEON_GEM_WAIT_RENDERING DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_GEM_WAIT_RENDERING, struct drm_radeon_gem_wait_rendering) #define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs) #define DRM_IOCTL_RADEON_CS2 DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS2, struct drm_radeon_cs2) @@ -820,7 +821,8 @@ struct drm_radeon_gem_set_domain { uint32_t write_domain; }; -struct drm_radeon_gem_exec_buffer { +struct drm_radeon_gem_wait_rendering { + uint32_t handle; }; struct drm_radeon_gem_pin { diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 85a22e9f..aa178d4d 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1695,6 +1695,8 @@ int radeon_gem_object_pin(struct drm_gem_object *obj, int radeon_gem_object_unpin(struct drm_gem_object *obj); int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int radeon_gem_wait_rendering(struct drm_device *dev, void *data, + struct drm_file *file_priv); struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, int initial_domain, bool discardable); int radeon_modeset_init(struct drm_device *dev); diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 40ecf1c4..ada91362 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -3288,6 +3288,7 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_RENDERING, radeon_gem_wait_rendering, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_CS2, radeon_cs2_ioctl, DRM_AUTH), }; -- cgit v1.2.3 From be3dac976e07fbfd727a2d0216ea9ba3247db348 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:44:32 +1000 Subject: radeon: only enable dynclks if asked for --- linux-core/radeon_drv.c | 2 +- shared-core/radeon_cp.c | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index f1fe3012..daa335b9 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -37,7 +37,7 @@ #include "drm_pciids.h" int radeon_no_wb; -int radeon_dynclks = 1; +int radeon_dynclks = -1; int radeon_r4xx_atom = 0; int radeon_agpmode = 0; diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 942ccc51..3f8f0c94 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2601,19 +2601,23 @@ int radeon_static_clocks_init(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; - if (dev_priv->chip_family == CHIP_RS400 || - dev_priv->chip_family == CHIP_RS480) - radeon_dynclks = 0; - - if ((dev_priv->flags & RADEON_IS_MOBILITY) && !radeon_is_avivo(dev_priv)) { - radeon_set_dynamic_clock(dev, radeon_dynclks); - } else if (radeon_is_avivo(dev_priv)) { - if (radeon_dynclks) { - radeon_atom_static_pwrmgt_setup(dev, 1); - radeon_atom_dyn_clk_setup(dev, 1); + if (radeon_dynclks != -1) { + + if (dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) + radeon_dynclks = 0; + + if ((dev_priv->flags & RADEON_IS_MOBILITY) && !radeon_is_avivo(dev_priv)) { + radeon_set_dynamic_clock(dev, radeon_dynclks); + } else if (radeon_is_avivo(dev_priv)) { + if (radeon_dynclks) { + radeon_atom_static_pwrmgt_setup(dev, 1); + radeon_atom_dyn_clk_setup(dev, 1); + } } } - radeon_force_some_clocks(dev); + if (radeon_is_r300(dev_priv) || radeon_is_rv100(dev_priv)) + radeon_force_some_clocks(dev); return 0; } -- cgit v1.2.3 From 4ef8ace9a96bd6bb4040ef5c4c3ea5572d7129e1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:45:43 +1000 Subject: radeon: add proc debugging for interrupts/ring --- linux-core/Makefile.kernel | 2 +- linux-core/radeon_drv.c | 2 + linux-core/radeon_gem_proc.c | 143 +++++++++++++++++++++++++++++++++++++++++++ shared-core/radeon_drv.h | 3 + shared-core/radeon_irq.c | 1 + 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 linux-core/radeon_gem_proc.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 392abaf9..98616e4b 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -44,7 +44,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_gem.o \ radeon_buffer.o radeon_fence.o atom.o radeon_display.o radeon_atombios.o radeon_i2c.o radeon_connectors.o radeon_cs.o \ atombios_crtc.o radeon_encoders.o radeon_fb.o radeon_combios.o radeon_legacy_crtc.o radeon_legacy_encoders.o \ - radeon_cursor.o radeon_pm.o + radeon_cursor.o radeon_pm.o radeon_gem_proc.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_bci.o savage_state.o diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index daa335b9..3bc0c057 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -122,6 +122,8 @@ static struct drm_driver driver = { .dma_ioctl = radeon_cp_buffers, .master_create = radeon_master_create, .master_destroy = radeon_master_destroy, + .proc_init = radeon_gem_proc_init, + .proc_cleanup = radeon_gem_proc_cleanup, .fops = { .owner = THIS_MODULE, .open = drm_open, diff --git a/linux-core/radeon_gem_proc.c b/linux-core/radeon_gem_proc.c new file mode 100644 index 00000000..d3b467b1 --- /dev/null +++ b/linux-core/radeon_gem_proc.c @@ -0,0 +1,143 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Keith Packard + * + */ + +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + + +static int radeon_ring_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data) +{ + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + int len = 0; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + DRM_PROC_PRINT("RADEON_CP_RB_WPTR %08x\n", + RADEON_READ(RADEON_CP_RB_WPTR)); + + DRM_PROC_PRINT("RADEON_CP_RB_RPTR %08x\n", + RADEON_READ(RADEON_CP_RB_RPTR)); + + + if (len > request + offset) + return request; + *eof = 1; + return len - offset; +} + +static int radeon_interrupt_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data) +{ + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + int len = 0; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + DRM_PROC_PRINT("Interrupt enable: %08x\n", + RADEON_READ(RADEON_GEN_INT_CNTL)); + + if (dev_priv->chip_family >= CHIP_RS690) { + DRM_PROC_PRINT("DxMODE_INT_MASK: %08x\n", + RADEON_READ(R500_DxMODE_INT_MASK)); + } + DRM_PROC_PRINT("Interrupts received: %d\n", + atomic_read(&dev_priv->irq_received)); + DRM_PROC_PRINT("Current sequence: %d\n", + READ_BREADCRUMB(dev_priv)); + DRM_PROC_PRINT("Counter sequence: %d\n", + dev_priv->counter); + + + if (len > request + offset) + return request; + *eof = 1; + return len - offset; +} + +static struct drm_proc_list { + /** file name */ + const char *name; + /** proc callback*/ + int (*f) (char *, char **, off_t, int, int *, void *); +} radeon_gem_proc_list[] = { + {"radeon_gem_interrupt", radeon_interrupt_info}, + {"radeon_gem_ring", radeon_ring_info}, +}; + + +#define RADEON_GEM_PROC_ENTRIES ARRAY_SIZE(radeon_gem_proc_list) + +int radeon_gem_proc_init(struct drm_minor *minor) +{ + struct proc_dir_entry *ent; + int i, j; + + for (i = 0; i < RADEON_GEM_PROC_ENTRIES; i++) { + ent = create_proc_entry(radeon_gem_proc_list[i].name, + S_IFREG | S_IRUGO, minor->dev_root); + if (!ent) { + DRM_ERROR("Cannot create /proc/dri/.../%s\n", + radeon_gem_proc_list[i].name); + for (j = 0; j < i; j++) + remove_proc_entry(radeon_gem_proc_list[i].name, + minor->dev_root); + return -1; + } + ent->read_proc = radeon_gem_proc_list[i].f; + ent->data = minor; + } + return 0; +} + +void radeon_gem_proc_cleanup(struct drm_minor *minor) +{ + int i; + + if (!minor->dev_root) + return; + + for (i = 0; i < RADEON_GEM_PROC_ENTRIES; i++) + remove_proc_entry(radeon_gem_proc_list[i].name, minor->dev_root); +} diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index aa178d4d..8f77c850 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -459,6 +459,7 @@ typedef struct drm_radeon_private { struct drm_radeon_cs_priv cs; struct radeon_pm_regs pmregs; + atomic_t irq_received; } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { @@ -1718,6 +1719,8 @@ void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master void radeon_init_memory_map(struct drm_device *dev); void radeon_enable_bm(struct drm_radeon_private *dev_priv); +extern int radeon_gem_proc_init(struct drm_minor *minor); +extern void radeon_gem_proc_cleanup(struct drm_minor *minor); #define MARK_SAFE 1 #define MARK_CHECK_OFFSET 2 #define MARK_CHECK_SCISSOR 3 diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index dcf58e43..311901c0 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -195,6 +195,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) if (!stat) return IRQ_NONE; + atomic_inc(&dev_priv->irq_received); stat &= dev_priv->irq_enable_reg; /* SW interrupt */ -- cgit v1.2.3 From ce2cd141c36f330da7e9fb9a281e51abab88e0d1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:46:07 +1000 Subject: radeon: fix race in sysfs --- linux-core/radeon_drv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 3bc0c057..f7881720 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -60,8 +60,12 @@ module_param_named(agpmode, radeon_agpmode, int, 0444); static int dri_library_name(struct drm_device * dev, char * buf) { drm_radeon_private_t *dev_priv = dev->dev_private; - int family = dev_priv->flags & RADEON_FAMILY_MASK; + int family; + if (!dev_priv) + return 0; + + family = dev_priv->flags & RADEON_FAMILY_MASK; return snprintf(buf, PAGE_SIZE, "%s\n", (family < CHIP_R200) ? "radeon" : ((family < CHIP_R300) ? "r200" : -- cgit v1.2.3 From 31b8a640db9b55638bf9967f0d78ec665fa8839f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:46:54 +1000 Subject: radeon: overhaul ring interactions emit in 16-dword blocks, emit irqs at same time as everything else --- linux-core/radeon_buffer.c | 10 ++++-- linux-core/radeon_fence.c | 1 - linux-core/radeon_gem.c | 5 +-- shared-core/radeon_cs.c | 84 ++++++++++++++++++++++++++++------------------ shared-core/radeon_drv.h | 6 ++-- shared-core/radeon_irq.c | 16 +++++---- 6 files changed, 77 insertions(+), 45 deletions(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index e88378a4..571a0b9c 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -170,10 +170,12 @@ void radeon_emit_copy_blit(struct drm_device * dev, ADVANCE_RING(); } - BEGIN_RING(4); + BEGIN_RING(6); OUT_RING(CP_PACKET0(RADEON_RB2D_DSTCACHE_CTLSTAT, 0)); OUT_RING(RADEON_RB2D_DC_FLUSH_ALL); RADEON_WAIT_UNTIL_2D_IDLE(); + OUT_RING(CP_PACKET2()); + OUT_RING(CP_PACKET2()); ADVANCE_RING(); COMMIT_RING(); @@ -265,10 +267,14 @@ void radeon_emit_solid_fill(struct drm_device * dev, ADVANCE_RING(); } - BEGIN_RING(4); + BEGIN_RING(8); OUT_RING(CP_PACKET0(RADEON_RB2D_DSTCACHE_CTLSTAT, 0)); OUT_RING(RADEON_RB2D_DC_FLUSH_ALL); RADEON_WAIT_UNTIL_2D_IDLE(); + OUT_RING(CP_PACKET2()); + OUT_RING(CP_PACKET2()); + OUT_RING(CP_PACKET2()); + OUT_RING(CP_PACKET2()); ADVANCE_RING(); COMMIT_RING(); diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c index 591ad53b..b662da21 100644 --- a/linux-core/radeon_fence.c +++ b/linux-core/radeon_fence.c @@ -39,7 +39,6 @@ int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, uint32_t *native_type) { struct drm_radeon_private *dev_priv = (struct drm_radeon_private *) dev->dev_private; - RING_LOCALS; if (!dev_priv) return -EINVAL; diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index f5d6b94a..a785041e 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1086,7 +1086,7 @@ int radeon_gem_object_unpin(struct drm_gem_object *obj) #define RADEON_NUM_IB (RADEON_IB_MEMORY / RADEON_IB_SIZE) -int radeon_gem_ib_get(struct drm_radeon_cs_parser *parser, uint32_t *card_offset) +int radeon_gem_ib_get(struct drm_radeon_cs_parser *parser) { int i, index = -1; int ret; @@ -1132,8 +1132,8 @@ int radeon_gem_ib_get(struct drm_radeon_cs_parser *parser, uint32_t *card_offset return -EINVAL; } - *card_offset = dev_priv->gart_vm_start + dev_priv->ib_objs[index]->bo->offset; parser->ib = dev_priv->ib_objs[index]->kmap.virtual; + parser->card_offset = dev_priv->gart_vm_start + dev_priv->ib_objs[index]->bo->offset; dev_priv->ib_alloc_bitmap |= (1 << i); return 0; } @@ -1150,6 +1150,7 @@ static void radeon_gem_ib_free(struct drm_radeon_cs_parser *parser) if (dev_priv->ib_objs[i]->kmap.virtual == parser->ib) { /* emit a fence object */ ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence); + dev_priv->irq_emitted = 0; if (ret) { drm_putback_buffer_objects(dev); } diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 31cd53db..4a231962 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -38,10 +38,8 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) struct drm_radeon_cs_chunk __user **chunk_ptr = NULL; uint64_t *chunk_array; uint64_t *chunk_array_ptr; - uint32_t card_offset; long size; int r, i; - RING_LOCALS; /* set command stream id to 0 which is fake id */ cs_id = 0; @@ -144,7 +142,7 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) } /* get ib */ - r = dev_priv->cs.ib_get(&parser, &card_offset); + r = dev_priv->cs.ib_get(&parser); if (r) { DRM_ERROR("ib_get failed\n"); goto out; @@ -156,16 +154,8 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) goto out; } - BEGIN_RING(4); - OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); - OUT_RING(card_offset); - OUT_RING(parser.chunks[parser.ib_index].length_dw); - OUT_RING(CP_PACKET2()); - ADVANCE_RING(); - /* emit cs id sequence */ - dev_priv->cs.id_emit(dev, &cs_id); - COMMIT_RING(); + dev_priv->cs.id_emit(&parser, &cs_id); cs->cs_id = cs_id; @@ -194,7 +184,6 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) long size; int r; struct drm_radeon_kernel_chunk chunk_fake[1]; - RING_LOCALS; /* set command stream id to 0 which is fake id */ cs_id = 0; @@ -237,7 +226,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) parser.reloc_index = -1; /* get ib */ - r = dev_priv->cs.ib_get(&parser, &card_offset); + r = dev_priv->cs.ib_get(&parser); if (r) { goto out; } @@ -248,15 +237,8 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) goto out; } - BEGIN_RING(4); - OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); - OUT_RING(card_offset); - OUT_RING(cs->dwords); - OUT_RING(CP_PACKET2()); - ADVANCE_RING(); - /* emit cs id sequence */ - dev_priv->cs.id_emit(dev, &cs_id); + dev_priv->cs.id_emit(&parser, &cs_id); COMMIT_RING(); cs->cs_id = cs_id; @@ -518,37 +500,75 @@ uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon) return (radeon->cs.id_scnt | radeon->cs.id_wcnt); } -void r100_cs_id_emit(struct drm_device *dev, uint32_t *id) +void r100_cs_id_emit(struct drm_radeon_cs_parser *parser, uint32_t *id) { - drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_private_t *dev_priv = parser->dev->dev_private; RING_LOCALS; + dev_priv->irq_emitted = radeon_update_breadcrumb(parser->dev); /* ISYNC_CNTL should have CPSCRACTH bit set */ *id = radeon_cs_id_get(dev_priv); /* emit id in SCRATCH4 (not used yet in old drm) */ - BEGIN_RING(2); + BEGIN_RING(10); + OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); + OUT_RING(parser->card_offset); + OUT_RING(parser->chunks[parser->ib_index].length_dw); + OUT_RING(CP_PACKET2()); OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG4, 0)); OUT_RING(*id); + OUT_RING_REG(RADEON_LAST_SWI_REG, dev_priv->irq_emitted); + OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); ADVANCE_RING(); + COMMIT_RING(); + } -void r300_cs_id_emit(struct drm_device *dev, uint32_t *id) +void r300_cs_id_emit(struct drm_radeon_cs_parser *parser, uint32_t *id) { - drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_private_t *dev_priv = parser->dev->dev_private; + int i; RING_LOCALS; + dev_priv->irq_emitted = radeon_update_breadcrumb(parser->dev); + /* ISYNC_CNTL should not have CPSCRACTH bit set */ *id = radeon_cs_id_get(dev_priv); + /* emit id in SCRATCH6 */ - BEGIN_RING(8); - OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 0)); + BEGIN_RING(16); + OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); + OUT_RING(parser->card_offset); + OUT_RING(parser->chunks[parser->ib_index].length_dw); + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(0); + for (i = 0; i < 11; i++) /* emit fillers like fglrx */ + OUT_RING(CP_PACKET2()); + ADVANCE_RING(); + COMMIT_RING(); + + BEGIN_RING(16); + OUT_RING_REG(R300_RB3D_DSTCACHE_CTLSTAT, R300_RB3D_DC_FLUSH); + OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 1)); OUT_RING(6); - OUT_RING(CP_PACKET0(R300_CP_RESYNC_DATA, 0)); OUT_RING(*id); - OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); - OUT_RING(R300_RB3D_DC_FINISH); + OUT_RING_REG(R300_RB3D_DSTCACHE_CTLSTAT, R300_RB3D_DC_FINISH|R300_RB3D_DC_FLUSH); + /* emit inline breadcrumb for TTM fencing */ +#if 1 RADEON_WAIT_UNTIL_3D_IDLE(); + OUT_RING_REG(RADEON_LAST_SWI_REG, dev_priv->irq_emitted); +#else + OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 1)); + OUT_RING(3); /* breadcrumb register */ + OUT_RING(dev_priv->irq_emitted); + OUT_RING(CP_PACKET2()); +#endif + OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); + OUT_RING(CP_PACKET2()); + OUT_RING(CP_PACKET2()); + OUT_RING(CP_PACKET2()); ADVANCE_RING(); + COMMIT_RING(); + } uint32_t r100_cs_id_last_get(struct drm_device *dev) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 8f77c850..83478a27 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -308,6 +308,7 @@ struct drm_radeon_cs_parser { struct drm_radeon_kernel_chunk *chunks; int ib_index; int reloc_index; + uint32_t card_offset; void *ib; }; @@ -319,12 +320,12 @@ struct drm_radeon_cs_priv { uint32_t id_last_scnt; int (*parse)(struct drm_radeon_cs_parser *parser); - void (*id_emit)(struct drm_device *dev, uint32_t *id); + void (*id_emit)(struct drm_radeon_cs_parser *parser, uint32_t *id); uint32_t (*id_last_get)(struct drm_device *dev); /* this ib handling callback are for hidding memory manager drm * from memory manager less drm, free have to emit ib discard * sequence into the ring */ - int (*ib_get)(struct drm_radeon_cs_parser *parser, uint32_t *card_offset); + int (*ib_get)(struct drm_radeon_cs_parser *parser); uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib); void (*ib_free)(struct drm_radeon_cs_parser *parser); /* do a relocation either MM or non-MM */ @@ -459,6 +460,7 @@ typedef struct drm_radeon_private { struct drm_radeon_cs_priv cs; struct radeon_pm_regs pmregs; + int irq_emitted; atomic_t irq_received; } drm_radeon_private_t; diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index 311901c0..46a27943 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -223,15 +223,19 @@ int radeon_emit_irq(struct drm_device * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; unsigned int ret; + int i; RING_LOCALS; - ret = radeon_update_breadcrumb(dev); + if (!dev_priv->irq_emitted) { + ret = radeon_update_breadcrumb(dev); - BEGIN_RING(4); - OUT_RING_REG(RADEON_LAST_SWI_REG, ret); - OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); - ADVANCE_RING(); - COMMIT_RING(); + BEGIN_RING(4); + OUT_RING_REG(RADEON_LAST_SWI_REG, ret); + OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); + ADVANCE_RING(); + COMMIT_RING(); + } else + ret = dev_priv->irq_emitted; return ret; } -- cgit v1.2.3 From 13d9acd3110a32d94434311821362900a9463cf4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:47:14 +1000 Subject: radeon: add more debugging --- linux-core/radeon_gem_proc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_gem_proc.c b/linux-core/radeon_gem_proc.c index d3b467b1..04f5a5fc 100644 --- a/linux-core/radeon_gem_proc.c +++ b/linux-core/radeon_gem_proc.c @@ -84,10 +84,13 @@ static int radeon_interrupt_info(char *buf, char **start, off_t offset, } DRM_PROC_PRINT("Interrupts received: %d\n", atomic_read(&dev_priv->irq_received)); - DRM_PROC_PRINT("Current sequence: %d\n", - READ_BREADCRUMB(dev_priv)); + DRM_PROC_PRINT("Current sequence: %d %d\n", + READ_BREADCRUMB(dev_priv), RADEON_READ(RADEON_SCRATCH_REG3)); DRM_PROC_PRINT("Counter sequence: %d\n", dev_priv->counter); + if (dev_priv->chip_family >= CHIP_R300) + DRM_PROC_PRINT("CS: %d\n", + GET_SCRATCH(6)); if (len > request + offset) -- cgit v1.2.3 From e829d5b6bc9f5887c82653c007641c3c37f7ae67 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:47:49 +1000 Subject: radeon: setup isync cntl properly --- shared-core/radeon_cp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 3f8f0c94..1c187b15 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -591,10 +591,15 @@ static void radeon_do_cp_start(drm_radeon_private_t * dev_priv) BEGIN_RING(8); /* isync can only be written through cp on r5xx write it here */ OUT_RING(CP_PACKET0(RADEON_ISYNC_CNTL, 0)); + if (dev_priv->chip_family > CHIP_RV280) + OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI | + dev_priv->mm_enabled ? 0 : RADEON_ISYNC_CPSCRATCH_IDLEGUI); + else OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D | RADEON_ISYNC_ANY3D_IDLE2D | - RADEON_ISYNC_WAIT_IDLEGUI | - RADEON_ISYNC_CPSCRATCH_IDLEGUI); + RADEON_ISYNC_WAIT_IDLEGUI); RADEON_PURGE_CACHE(); RADEON_PURGE_ZCACHE(); RADEON_WAIT_UNTIL_IDLE(); -- cgit v1.2.3 From cdddff835510eca179ac289f41a1771093939901 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:48:10 +1000 Subject: radeon: enable DVI-D + HDMI connectors. This allows the rs690 to work on DVI --- linux-core/radeon_connectors.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c index 8de21997..18873f0f 100644 --- a/linux-core/radeon_connectors.c +++ b/linux-core/radeon_connectors.c @@ -305,8 +305,11 @@ static struct connector_funcs { { CONNECTOR_LVDS, &radeon_lvds_connector_funcs, &radeon_lvds_connector_helper_funcs, DRM_MODE_CONNECTOR_LVDS, "LVDS" }, { CONNECTOR_DVI_A, &radeon_vga_connector_funcs, &radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_DVIA, "DVI" }, { CONNECTOR_DVI_I, &radeon_dvi_connector_funcs, &radeon_dvi_connector_helper_funcs, DRM_MODE_CONNECTOR_DVII, "DVI" }, - + { CONNECTOR_DVI_D, &radeon_dvi_connector_funcs, &radeon_dvi_connector_helper_funcs, DRM_MODE_CONNECTOR_DVID, "DVI" }, + { CONNECTOR_HDMI_TYPE_A, &radeon_dvi_connector_funcs, &radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_HDMIA, "HDMI" }, + { CONNECTOR_HDMI_TYPE_B, &radeon_dvi_connector_funcs, &radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_HDMIB, "HDMI" }, #if 0 + { CONNECTOR_HDMI_TYPE_A, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, { CONNECTOR_DVI_D, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, { CONNECTOR_STV, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, @@ -314,7 +317,6 @@ static struct connector_funcs { { CONNECTOR_DIGITAL, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, { CONNECTOR_SCART, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, - { CONNECTOR_HDMI_TYPE_A, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, { CONNECTOR_HDMI_TYPE_B, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, { CONNECTOR_HDMI_TYPE_B, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, { CONNECTOR_HDMI_TYPE_B, radeon_vga_connector_funcs, radeon_vga_connector_helper_funcs, DRM_MODE_CONNECTOR_VGA }, -- cgit v1.2.3 From 49551f87fcd21e10a4485b3e00af47f0b9f94a0f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:49:41 +1000 Subject: radeon: set dma bufs bo type to a kernel type --- linux-core/radeon_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index a785041e..f39e8b47 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1502,7 +1502,7 @@ static int radeon_gem_dma_bufs_init(struct drm_device *dev) if (ret < 0) return ret; - ret = drm_buffer_object_create(dev, size, drm_bo_type_device, + ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MAPPABLE, 0, 0, 0, &dev_priv->mm.dma_bufs.bo); -- cgit v1.2.3 From c153a86af7e4e782e55565f882ef2c8618650150 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:49:59 +1000 Subject: radeon: add more HDMI bits --- linux-core/radeon_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_display.c b/linux-core/radeon_display.c index f16288ef..0b9467fd 100644 --- a/linux-core/radeon_display.c +++ b/linux-core/radeon_display.c @@ -263,7 +263,9 @@ bool radeon_setup_enc_conn(struct drm_device *dev) /* TMDS on DVI */ if ((mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_I) || - (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D)) { + (mode_info->bios_connector[i].connector_type == CONNECTOR_DVI_D) || + (mode_info->bios_connector[i].connector_type == CONNECTOR_HDMI_TYPE_A) || + (mode_info->bios_connector[i].connector_type == CONNECTOR_HDMI_TYPE_B)) { if (radeon_is_avivo(dev_priv) || radeon_r4xx_atom) encoder = radeon_encoder_atom_tmds_add(dev, i, mode_info->bios_connector[i].tmds_type); else { -- cgit v1.2.3 From 28c9eb7b7493ee2478df66476c742432525f1efa Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:50:46 +1000 Subject: radeon: commit ring after emitting the buffer discards --- shared-core/radeon_state.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index ada91362..e0a00f02 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -1884,10 +1884,11 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev, OUT_RING((image->width << 16) | height); RADEON_WAIT_UNTIL_2D_IDLE(); ADVANCE_RING(); - COMMIT_RING(); radeon_cp_discard_buffer(dev, file_priv->master, buf); + COMMIT_RING(); + /* Update the input parameters for next time */ image->y += height; image->height -= height; -- cgit v1.2.3 From d3aa052f6174ea37136574b68ed55d7cb82c5017 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:51:33 +1000 Subject: radeon: disable debugging message --- shared-core/radeon_mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_mem.c b/shared-core/radeon_mem.c index dbd73c50..2622cf3c 100644 --- a/shared-core/radeon_mem.c +++ b/shared-core/radeon_mem.c @@ -294,7 +294,7 @@ int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *fi return -EFAULT; if (*heap) { - DRM_ERROR("heap already initialized?"); + DRM_DEBUG("heap already initialized?"); return -EFAULT; } -- cgit v1.2.3 From 2b9a7d5381534122858dc6e407794e8cd5c04d3e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:51:57 +1000 Subject: radeon: disable AGP for certain chips if not specified until we figure it out --- shared-core/radeon_cp.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 1c187b15..71914782 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2669,9 +2669,16 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) DRM_DEBUG("%s card detected\n", ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); - if ((dev_priv->flags & RADEON_IS_AGP) && (radeon_agpmode == -1)) { - DRM_INFO("Forcing AGP to PCI mode\n"); - dev_priv->flags &= ~RADEON_IS_AGP; + if (dev_priv->flags & RADEON_IS_AGP) { + + /* disable AGP for any chips after RV280 if not specified */ + if ((dev_priv->chip_family > CHIP_RV280) && (radeon_agpmode == 0)) + radeon_agpmode = -1; + + if (radeon_agpmode == -1) { + DRM_INFO("Forcing AGP to PCI mode\n"); + dev_priv->flags &= ~RADEON_IS_AGP; + } } -- cgit v1.2.3 From 0e1df6216e7ce3a69d4311e4685613e57129285f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:52:25 +1000 Subject: radeon: add mtrr support for VRAM aperture. --- linux-core/radeon_gem.c | 6 ++++++ shared-core/radeon_drv.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index f39e8b47..2e20de3c 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -947,6 +947,10 @@ void radeon_init_memory_map(struct drm_device *dev) - dev_priv->fb_location; } + /* add an MTRR for the VRAM */ + dev_priv->aper_size = aper_size; + dev_priv->vram_mtrr = mtrr_add(dev_priv->fb_aper_offset, dev_priv->aper_size, MTRR_TYPE_WRCOMB, 1); + } /* init memory manager - start with all of VRAM and a 32MB GART aperture for now */ @@ -1037,6 +1041,8 @@ void radeon_gem_mm_fini(struct drm_device *dev) DRM_DEBUG("delaying takedown of VRAM memory\n"); } + if (dev_priv->vram_mtrr) + mtrr_del(dev_priv->vram_mtrr, dev_priv->fb_aper_offset, dev_priv->aper_size); mutex_unlock(&dev->struct_mutex); drm_bo_driver_finish(dev); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 83478a27..c6ebf9b6 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -462,6 +462,9 @@ typedef struct drm_radeon_private { struct radeon_pm_regs pmregs; int irq_emitted; atomic_t irq_received; + + uint32_t aper_size; + int vram_mtrr; } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { -- cgit v1.2.3 From b7108445c9ebb37d06fcc7821e984124fda928f3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:52:40 +1000 Subject: radeon: fix ROP values for the paint ROP --- linux-core/radeon_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_buffer.c b/linux-core/radeon_buffer.c index 571a0b9c..f047b1ac 100644 --- a/linux-core/radeon_buffer.c +++ b/linux-core/radeon_buffer.c @@ -254,7 +254,8 @@ void radeon_emit_solid_fill(struct drm_device * dev, RADEON_GMC_DST_CLIPPING | RADEON_GMC_BRUSH_SOLID_COLOR | (format << 8) | - RADEON_ROP3_S | + RADEON_ROP3_P | + RADEON_CLR_CMP_SRC_SOURCE | RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS); OUT_RING((pitch << 22) | (dst_offset >> 10)); // PITCH OUT_RING(0); // SC_TOP_LEFT // DST CLIPPING -- cgit v1.2.3 From 68fcb7770efc20b9e27b1724e2fb5ac112a5330e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:58:12 +1000 Subject: radeon: make build again --- linux-core/radeon_drv.c | 2 +- shared-core/radeon_cp.c | 9 --------- shared-core/radeon_cs.c | 2 +- shared-core/radeon_drv.h | 1 + 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index f7881720..f4194688 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -44,7 +44,7 @@ int radeon_agpmode = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers\n"); module_param_named(no_wb, radeon_no_wb, int, 0444); -unsigned int radeon_modeset = 0; +int radeon_modeset = 0; module_param_named(modeset, radeon_modeset, int, 0400); MODULE_PARM_DESC(dynclks, "Disable/Enable dynamic clocks"); diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 71914782..9a1e0e02 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2793,15 +2793,6 @@ int radeon_driver_firstopen(struct drm_device *dev) dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - radeon_gem_mm_init(dev); - - ret = drm_addmap(dev, dev_priv->fb_aper_offset, - drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER, - _DRM_WRITE_COMBINING, &map); - if (ret != 0) - return ret; - return 0; } diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 4a231962..3dde321d 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -313,7 +313,7 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *pa case R200_PP_TXOFFSET_1: case RADEON_PP_TXOFFSET_0: case RADEON_PP_TXOFFSET_1: - ret = dev_priv->cs.relocate(parser. ib_chunk->kdata + offset_dw + 2, &offset); + ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + 2, &offset); if (ret) return ret; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index c6ebf9b6..a95ab152 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -124,6 +124,7 @@ enum radeon_family { CHIP_RV350, CHIP_RV380, CHIP_R420, + CHIP_R423, CHIP_RV410, CHIP_RS400, CHIP_RS480, -- cgit v1.2.3 From 2d822542c74c9a38d18724f568642397b5a4d13d Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 5 Nov 2008 16:00:04 +0100 Subject: radeon: libdrm_radeon add handle to debug string --- libdrm/radeon/radeon_bo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index 68adc3e9..c1f25fa1 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -72,8 +72,8 @@ static inline void _radeon_bo_debug(struct radeon_bo *bo, const char *func, int line) { - fprintf(stderr, "%02d %p 0x%08X 0x%08X [%s %s %d]\n", - opcode, bo, bo->size, bo->cref, file, func, line); + fprintf(stderr, "%02d %p 0x%08X 0x%08X 0x%08X [%s %s %d]\n", + opcode, bo, bo->handle, bo->size, bo->cref, file, func, line); } static inline struct radeon_bo *_radeon_bo_open(struct radeon_bo_manager *bom, -- cgit v1.2.3 From 273cc1a69887df2bccfab96120f992c506c9035e Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Thu, 6 Nov 2008 00:40:06 +0100 Subject: radeon: lib radeon add bo & cs gem backend --- libdrm/radeon/Makefile.am | 9 +- libdrm/radeon/radeon_bo.h | 9 +- libdrm/radeon/radeon_bo_gem.c | 76 +++++++----- libdrm/radeon/radeon_bo_gem.h | 3 +- libdrm/radeon/radeon_cs_gem.c | 266 ++++++++++++++++++++++++++++++++++++++++++ libdrm/radeon/radeon_cs_gem.h | 40 +++++++ linux-core/drm_gem.c | 3 +- 7 files changed, 367 insertions(+), 39 deletions(-) create mode 100644 libdrm/radeon/radeon_cs_gem.c create mode 100644 libdrm/radeon/radeon_cs_gem.h diff --git a/libdrm/radeon/Makefile.am b/libdrm/radeon/Makefile.am index 6af06a7f..cc4951a9 100644 --- a/libdrm/radeon/Makefile.am +++ b/libdrm/radeon/Makefile.am @@ -35,9 +35,12 @@ libdrm_radeon_la_LDFLAGS = -version-number 1:0:0 -no-undefined libdrm_radeon_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ libdrm_radeon_la_SOURCES = \ - radeon_bo_gem.c + radeon_bo_gem.c \ + radeon_cs_gem.c -libdrm_radeonincludedir = ${includedir} +libdrm_radeonincludedir = ${includedir}/drm libdrm_radeoninclude_HEADERS = \ radeon_bo.h \ - radeon_cs.h + radeon_cs.h \ + radeon_bo_gem.h \ + radeon_cs_gem.h diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index c1f25fa1..a0739265 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -42,6 +42,7 @@ struct radeon_bo { uint32_t alignment; uint32_t handle; uint32_t size; + uint32_t domains; uint32_t flags; unsigned cref; void *ptr; @@ -54,6 +55,7 @@ struct radeon_bo_funcs { uint32_t handle, uint32_t size, uint32_t alignment, + uint32_t domains, uint32_t flags); void (*bo_ref)(struct radeon_bo *bo); void (*bo_unref)(struct radeon_bo *bo); @@ -80,13 +82,14 @@ static inline struct radeon_bo *_radeon_bo_open(struct radeon_bo_manager *bom, uint32_t handle, uint32_t size, uint32_t alignment, + uint32_t domains, uint32_t flags, const char *file, const char *func, int line) { struct radeon_bo *bo; - bo = bom->funcs->bo_open(bom, handle, size, alignment, flags); + bo = bom->funcs->bo_open(bom, handle, size, alignment, domains, flags); #ifdef RADEON_BO_TRACK_OPEN if (bo) { _radeon_bo_debug(bo, 1, file, func, line); @@ -142,8 +145,8 @@ static inline int _radeon_bo_unmap(struct radeon_bo *bo, return bo->bom->funcs->bo_unmap(bo); } -#define radeon_bo_open(bom, h, s, a, f)\ - _radeon_bo_open(bom, h, s, a, f, __FILE__, __FUNCTION__, __LINE__) +#define radeon_bo_open(bom, h, s, a, d, f)\ + _radeon_bo_open(bom, h, s, a, d, f, __FILE__, __FUNCTION__, __LINE__) #define radeon_bo_ref(bo)\ _radeon_bo_ref(bo, __FILE__, __FUNCTION__, __LINE__) #define radeon_bo_unref(bo)\ diff --git a/libdrm/radeon/radeon_bo_gem.c b/libdrm/radeon/radeon_bo_gem.c index 21fe41f9..04e36c59 100644 --- a/libdrm/radeon/radeon_bo_gem.c +++ b/libdrm/radeon/radeon_bo_gem.c @@ -42,14 +42,19 @@ struct radeon_bo_gem { struct radeon_bo base; - int ref_count; + uint32_t name; int map_count; }; +struct bo_manager_gem { + struct radeon_bo_manager base; +}; + static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, uint32_t handle, uint32_t size, uint32_t alignment, + uint32_t domains, uint32_t flags) { struct radeon_bo_gem *bo; @@ -64,11 +69,10 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, bo->base.handle = 0; bo->base.size = size; bo->base.alignment = alignment; + bo->base.domains = domains; bo->base.flags = flags; bo->base.ptr = NULL; - bo->ref_count = 0; bo->map_count = 0; - if (handle) { struct drm_gem_open open_arg; @@ -80,13 +84,15 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, free(bo); return NULL; } - bo->base.handle = handle; + bo->base.handle = open_arg.handle; + bo->base.size = open_arg.size; + bo->name = handle; } else { struct drm_radeon_gem_create args; args.size = size; args.alignment = alignment; - args.initial_domain = RADEON_GEM_DOMAIN_CPU; + args.initial_domain = bo->base.domains; args.no_backing_store = 0; r = drmCommandWriteRead(bom->fd, DRM_RADEON_GEM_CREATE, &args, sizeof(args)); @@ -99,7 +105,11 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, return (struct radeon_bo*)bo; } -static void bo_close(struct radeon_bo *bo) +static void bo_ref(struct radeon_bo *bo) +{ +} + +static void bo_unref(struct radeon_bo *bo) { struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; struct drm_gem_close args; @@ -107,10 +117,10 @@ static void bo_close(struct radeon_bo *bo) if (bo == NULL) { return; } - if (bo_gem->ref_count) { + if (bo->cref) { /* FIXME: what to do ? */ + return; } - if (bo_gem->map_count) { munmap(bo->ptr, bo->size); } @@ -121,33 +131,20 @@ static void bo_close(struct radeon_bo *bo) free(bo_gem); } -static void bo_pin(struct radeon_bo *bo) -{ - struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; - - bo_gem->ref_count++; -} - -static void bo_unpin(struct radeon_bo *bo) -{ - struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; - - bo_gem->ref_count--; -} - -static int bo_map(struct radeon_bo *bo, unsigned int flags) +static int bo_map(struct radeon_bo *bo, int write) { struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; struct drm_radeon_gem_mmap args; int r; + uint8_t *tt; if (bo_gem->map_count++ != 0) { return 0; } + bo->ptr = NULL; args.handle = bo->handle; args.offset = 0; - args.size = bo->size; - + args.size = (uint64_t)bo->size; r = drmCommandWriteRead(bo->bom->fd, DRM_RADEON_GEM_MMAP, &args, @@ -155,6 +152,7 @@ static int bo_map(struct radeon_bo *bo, unsigned int flags) if (!r) { bo->ptr = (void *)(unsigned long)args.addr_ptr; } + tt = bo->ptr; return r; } @@ -165,7 +163,6 @@ static int bo_unmap(struct radeon_bo *bo) if (--bo_gem->map_count > 0) { return 0; } - munmap(bo->ptr, bo->size); bo->ptr = NULL; return 0; @@ -173,14 +170,31 @@ static int bo_unmap(struct radeon_bo *bo) static struct radeon_bo_funcs bo_gem_funcs = { bo_open, - bo_close, - bo_pin, - bo_unpin, + bo_ref, + bo_unref, bo_map, bo_unmap }; -struct radeon_bo_funcs *radeon_bo_gem_initialize(int fd) +struct radeon_bo_manager *radeon_bo_manager_gem(int fd) { - return &bo_gem_funcs; + struct bo_manager_gem *bomg; + + bomg = (struct bo_manager_gem*)calloc(1, sizeof(struct bo_manager_gem)); + if (bomg == NULL) { + return NULL; + } + bomg->base.funcs = &bo_gem_funcs; + bomg->base.fd = fd; + return (struct radeon_bo_manager*)bomg; +} + +void radeon_bo_manager_gem_shutdown(struct radeon_bo_manager *bom) +{ + struct bo_manager_gem *bomg = (struct bo_manager_gem*)bom; + + if (bom == NULL) { + return; + } + free(bomg); } diff --git a/libdrm/radeon/radeon_bo_gem.h b/libdrm/radeon/radeon_bo_gem.h index e0ed61fb..d0997614 100644 --- a/libdrm/radeon/radeon_bo_gem.h +++ b/libdrm/radeon/radeon_bo_gem.h @@ -33,6 +33,7 @@ #include "radeon_bo.h" -struct radeon_bo_funcs *radeon_bo_gem_initialize(int fd); +struct radeon_bo_manager *radeon_bo_manager_gem(int fd); +void radeon_bo_manager_gem_shutdown(struct radeon_bo_manager *bom); #endif diff --git a/libdrm/radeon/radeon_cs_gem.c b/libdrm/radeon/radeon_cs_gem.c new file mode 100644 index 00000000..7ed5780b --- /dev/null +++ b/libdrm/radeon/radeon_cs_gem.c @@ -0,0 +1,266 @@ +/* + * Copyright © 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse + */ +#include +#include +#include "radeon_cs.h" +#include "radeon_cs_gem.h" +#include "radeon_bo_gem.h" +#include "drm.h" +#include "radeon_drm.h" + +#pragma pack(1) +struct cs_reloc_gem { + uint32_t handle; + uint32_t domains; + uint32_t soffset; + uint32_t eoffset; +}; +#pragma pack() + +struct cs_gem { + struct radeon_cs base; + struct drm_radeon_cs2 cs; + struct drm_radeon_cs_chunk chunks[2]; + unsigned nrelocs; + uint32_t *relocs; +}; + +static struct radeon_cs *cs_create(struct radeon_cs_manager *csm, + uint32_t ndw) +{ + struct cs_gem *csg; + + /* max cmd buffer size is 64Kb */ + if (ndw > (64 * 1024 / 4)) { + return NULL; + } + csg = (struct cs_gem*)calloc(1, sizeof(struct cs_gem)); + if (csg == NULL) { + return NULL; + } + csg->base.csm = csm; + csg->base.ndw = 64 * 1024 / 4; + csg->base.packets = (uint32_t*)calloc(1, 64 * 1024); + if (csg->base.packets == NULL) { + free(csg); + return NULL; + } + csg->base.relocs_total_size = 0; + csg->base.crelocs = 0; + csg->nrelocs = 4096 / (4 * 4) ; + csg->base.relocs = csg->relocs = (uint32_t*)calloc(1, 4096); + if (csg->relocs == NULL) { + free(csg->base.packets); + free(csg); + return NULL; + } + csg->chunks[0].chunk_id = RADEON_CHUNK_ID_IB; + csg->chunks[0].length_dw = 0; + csg->chunks[0].chunk_data = (uint64_t)(intptr_t)csg->base.packets; + csg->chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS; + csg->chunks[1].length_dw = 0; + csg->chunks[1].chunk_data = (uint64_t)(intptr_t)csg->relocs; + return (struct radeon_cs*)csg; +} + +static int cs_write_dword(struct radeon_cs *cs, uint32_t dword) +{ + if (cs->cdw >= cs->ndw) { + uint32_t tmp, *ptr; + tmp = (cs->cdw + 1 + 0x3FF) & (~0x3FF); + ptr = (uint32_t*)realloc(cs->packets, 4 * tmp); + if (ptr == NULL) { + return -ENOMEM; + } + cs->packets = ptr; + cs->ndw = tmp; + } + cs->packets[cs->cdw++] = dword; + if (cs->section) { + cs->section_cdw++; + } + return 0; +} + +static int cs_write_reloc(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t soffset, + uint32_t eoffset, + uint32_t domains) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + struct cs_reloc_gem *reloc; + unsigned i; + + /* check reloc window */ + if (eoffset > bo->size) { + return -EINVAL; + } + if (soffset > eoffset) { + return -EINVAL; + } + /* check if bo is already referenced */ + for(i = 0; i < cs->crelocs; i++) { + reloc = (struct cs_reloc_gem*)&csg->relocs[i * 4]; + + if (reloc->handle == bo->handle) { + /* update start offset and size */ + if (eoffset > reloc->eoffset) { + reloc->eoffset = eoffset; + } + if (soffset < reloc->soffset) { + reloc->soffset = soffset; + } + reloc->domains |= domains; + return 0; + } + } + /* add bo */ + if (csg->base.crelocs >= csg->nrelocs) { + uint32_t *tmp, size; + size = (csg->nrelocs * 4 * 4) + (4096 / (4 * 4)); + tmp = (uint32_t*)realloc(csg->relocs, size); + if (tmp == NULL) { + return -ENOMEM; + } + cs->relocs = csg->relocs = tmp; + csg->nrelocs = size / (4 * 4); + } + reloc = (struct cs_reloc_gem*)&csg->relocs[csg->base.crelocs * 4]; + reloc->handle = bo->handle; + reloc->soffset = soffset; + reloc->eoffset = eoffset; + reloc->domains = domains; + cs->crelocs++; + radeon_bo_ref(bo); + return 0; +} + +static int cs_begin(struct radeon_cs *cs, + uint32_t ndw, + const char *file, + const char *func, + int line) +{ + if (cs->section) { + fprintf(stderr, "CS already in a section(%s,%s,%d)\n", + cs->section_file, cs->section_func, cs->section_line); + fprintf(stderr, "CS can't start section(%s,%s,%d)\n", + file, func, line); + return -EPIPE; + } + cs->section = 1; + cs->section_ndw = ndw; + cs->section_cdw = 0; + cs->section_file = file; + cs->section_func = func; + cs->section_line = line; + return 0; +} + +static int cs_end(struct radeon_cs *cs, + const char *file, + const char *func, + int line) + +{ + if (!cs->section) { + fprintf(stderr, "CS no section to end at (%s,%s,%d)\n", + file, func, line); + return -EPIPE; + } + cs->section = 0; + if (cs->section_ndw != cs->section_cdw) { + fprintf(stderr, "CS section size missmatch start at (%s,%s,%d)\n", + cs->section_file, cs->section_func, cs->section_line); + fprintf(stderr, "CS section end at (%s,%s,%d)\n", + file, func, line); + return -EPIPE; + } + return 0; +} + +static int cs_emit(struct radeon_cs *cs) +{ + return 0; +} + +static int cs_destroy(struct radeon_cs *cs) +{ + free(cs->relocs); + free(cs->packets); + free(cs); + return 0; +} + +static int cs_erase(struct radeon_cs *cs) +{ + cs->relocs_total_size = 0; + cs->relocs = NULL; + cs->crelocs = 0; + cs->cdw = 0; + cs->section = 0; + return 0; +} + +static int cs_need_flush(struct radeon_cs *cs) +{ + return (cs->relocs_total_size > (7*1024*1024)); +} + +struct radeon_cs_funcs radeon_cs_funcs = { + cs_create, + cs_write_dword, + cs_write_reloc, + cs_begin, + cs_end, + cs_emit, + cs_destroy, + cs_erase, + cs_need_flush +}; + +struct radeon_cs_manager *radeon_cs_manager_gem(int fd) +{ + struct radeon_cs_manager *csm; + + csm = (struct radeon_cs_manager*)calloc(1, + sizeof(struct radeon_cs_manager)); + if (csm == NULL) { + return NULL; + } + csm->funcs = &radeon_cs_funcs; + csm->fd = fd; + return csm; +} + +void radeon_cs_manager_gem_shutdown(struct radeon_cs_manager *csm) +{ + free(csm); +} diff --git a/libdrm/radeon/radeon_cs_gem.h b/libdrm/radeon/radeon_cs_gem.h new file mode 100644 index 00000000..a032a8cc --- /dev/null +++ b/libdrm/radeon/radeon_cs_gem.h @@ -0,0 +1,40 @@ +/* + * Copyright © 2008 Nicolai Haehnle + * Copyright © 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Aapo Tahkola + * Nicolai Haehnle + * Jérôme Glisse + */ +#ifndef RADEON_CS_GEM_H +#define RADEON_CS_GEM_H + +#include "radeon_cs.h" + +struct radeon_cs_manager *radeon_cs_manager_gem(int fd); +void radeon_cs_manager_gem_shutdown(struct radeon_cs_manager *csm); + +#endif diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 0cbf9cab..607c8b67 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -263,8 +263,9 @@ again: spin_lock(&dev->object_name_lock); if (obj->name) { + args->name = (uint64_t) obj->name; spin_unlock(&dev->object_name_lock); - return -EEXIST; + return 0; } ret = idr_get_new_above(&dev->object_name_idr, obj, 1, &obj->name); -- cgit v1.2.3 From 751d024dd5c91831a8141810c0f40ecdb235e7ca Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 9 Nov 2008 18:45:43 +0100 Subject: libdrm-radeon: update libdrm-radeon to match current CS relocation structures --- libdrm/radeon/radeon_bo.h | 17 ++--- libdrm/radeon/radeon_bo_gem.c | 19 ++--- libdrm/radeon/radeon_bo_gem.h | 17 ++--- libdrm/radeon/radeon_cs_gem.c | 162 +++++++++++++++++++++++++++--------------- libdrm/radeon/radeon_cs_gem.h | 17 ++--- 5 files changed, 143 insertions(+), 89 deletions(-) diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index a0739265..f884e0fa 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -2,20 +2,21 @@ * Copyright © 2008 Jérôme Glisse * All Rights Reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * The above copyright notice and this permission notice (including the diff --git a/libdrm/radeon/radeon_bo_gem.c b/libdrm/radeon/radeon_bo_gem.c index 04e36c59..fc198711 100644 --- a/libdrm/radeon/radeon_bo_gem.c +++ b/libdrm/radeon/radeon_bo_gem.c @@ -3,20 +3,21 @@ * Copyright © 2008 Jérôme Glisse * All Rights Reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * The above copyright notice and this permission notice (including the @@ -102,6 +103,7 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, return NULL; } } + radeon_bo_ref(bo); return (struct radeon_bo*)bo; } @@ -118,7 +120,6 @@ static void bo_unref(struct radeon_bo *bo) return; } if (bo->cref) { - /* FIXME: what to do ? */ return; } if (bo_gem->map_count) { diff --git a/libdrm/radeon/radeon_bo_gem.h b/libdrm/radeon/radeon_bo_gem.h index d0997614..aaefd8c3 100644 --- a/libdrm/radeon/radeon_bo_gem.h +++ b/libdrm/radeon/radeon_bo_gem.h @@ -3,20 +3,21 @@ * Copyright © 2008 Jérôme Glisse * All Rights Reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * The above copyright notice and this permission notice (including the diff --git a/libdrm/radeon/radeon_cs_gem.c b/libdrm/radeon/radeon_cs_gem.c index 7ed5780b..00aa9086 100644 --- a/libdrm/radeon/radeon_cs_gem.c +++ b/libdrm/radeon/radeon_cs_gem.c @@ -2,20 +2,21 @@ * Copyright © 2008 Jérôme Glisse * All Rights Reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * The above copyright notice and this permission notice (including the @@ -24,22 +25,27 @@ */ /* * Authors: + * Aapo Tahkola + * Nicolai Haehnle * Jérôme Glisse */ #include #include +#include +#include #include "radeon_cs.h" #include "radeon_cs_gem.h" #include "radeon_bo_gem.h" #include "drm.h" +#include "xf86drm.h" #include "radeon_drm.h" #pragma pack(1) struct cs_reloc_gem { uint32_t handle; - uint32_t domains; - uint32_t soffset; - uint32_t eoffset; + uint32_t rdomain; + uint32_t wdomain; + uint32_t cnt; }; #pragma pack() @@ -49,6 +55,7 @@ struct cs_gem { struct drm_radeon_cs_chunk chunks[2]; unsigned nrelocs; uint32_t *relocs; + struct radeon_bo **relocs_bo; }; static struct radeon_cs *cs_create(struct radeon_cs_manager *csm, @@ -74,8 +81,16 @@ static struct radeon_cs *cs_create(struct radeon_cs_manager *csm, csg->base.relocs_total_size = 0; csg->base.crelocs = 0; csg->nrelocs = 4096 / (4 * 4) ; + csg->relocs_bo = (struct radeon_bo**)calloc(1, + csg->nrelocs*sizeof(void*)); + if (csg->relocs_bo == NULL) { + free(csg->base.packets); + free(csg); + return NULL; + } csg->base.relocs = csg->relocs = (uint32_t*)calloc(1, 4096); if (csg->relocs == NULL) { + free(csg->relocs_bo); free(csg->base.packets); free(csg); return NULL; @@ -91,6 +106,7 @@ static struct radeon_cs *cs_create(struct radeon_cs_manager *csm, static int cs_write_dword(struct radeon_cs *cs, uint32_t dword) { + struct cs_gem *csg = (struct cs_gem*)cs; if (cs->cdw >= cs->ndw) { uint32_t tmp, *ptr; tmp = (cs->cdw + 1 + 0x3FF) & (~0x3FF); @@ -100,11 +116,10 @@ static int cs_write_dword(struct radeon_cs *cs, uint32_t dword) } cs->packets = ptr; cs->ndw = tmp; + csg->chunks[0].chunk_data = (uint64_t)(intptr_t)csg->base.packets; } cs->packets[cs->cdw++] = dword; - if (cs->section) { - cs->section_cdw++; - } + csg->chunks[0].length_dw += 1; return 0; } @@ -116,6 +131,7 @@ static int cs_write_reloc(struct radeon_cs *cs, { struct cs_gem *csg = (struct cs_gem*)cs; struct cs_reloc_gem *reloc; + uint32_t idx; unsigned i; /* check reloc window */ @@ -127,38 +143,73 @@ static int cs_write_reloc(struct radeon_cs *cs, } /* check if bo is already referenced */ for(i = 0; i < cs->crelocs; i++) { - reloc = (struct cs_reloc_gem*)&csg->relocs[i * 4]; + idx = i * 4; + reloc = (struct cs_reloc_gem*)&csg->relocs[idx]; if (reloc->handle == bo->handle) { /* update start offset and size */ - if (eoffset > reloc->eoffset) { - reloc->eoffset = eoffset; + switch (bo->domains) { + case RADEON_GEM_DOMAIN_VRAM: + reloc->rdomain = 0; + reloc->wdomain = RADEON_GEM_DOMAIN_VRAM; + break; + case RADEON_GEM_DOMAIN_GTT: + reloc->rdomain = RADEON_GEM_DOMAIN_GTT; + reloc->wdomain = 0; + break; + default: + exit(0); + break; } - if (soffset < reloc->soffset) { - reloc->soffset = soffset; - } - reloc->domains |= domains; + reloc->cnt++; + cs_write_dword(cs, 0xc0001000); + cs_write_dword(cs, idx); return 0; } } /* add bo */ if (csg->base.crelocs >= csg->nrelocs) { uint32_t *tmp, size; - size = (csg->nrelocs * 4 * 4) + (4096 / (4 * 4)); + size = ((csg->nrelocs + 1) * sizeof(struct radeon_bo*)); + tmp = (uint32_t*)realloc(csg->relocs_bo, size); + if (tmp == NULL) { + return -ENOMEM; + } + csg->relocs_bo = (struct radeon_bo**)tmp; + size = ((csg->nrelocs + 1) * 4 * 4); tmp = (uint32_t*)realloc(csg->relocs, size); if (tmp == NULL) { return -ENOMEM; } cs->relocs = csg->relocs = tmp; - csg->nrelocs = size / (4 * 4); + csg->nrelocs += 1; + csg->chunks[1].chunk_data = (uint64_t)(intptr_t)csg->relocs; } - reloc = (struct cs_reloc_gem*)&csg->relocs[csg->base.crelocs * 4]; + csg->relocs_bo[csg->base.crelocs] = bo; + idx = (csg->base.crelocs++) * 4; + reloc = (struct cs_reloc_gem*)&csg->relocs[idx]; reloc->handle = bo->handle; - reloc->soffset = soffset; - reloc->eoffset = eoffset; - reloc->domains = domains; - cs->crelocs++; + reloc->rdomain = bo->domains; + reloc->wdomain = bo->domains; + switch (bo->domains) { + case RADEON_GEM_DOMAIN_VRAM: + reloc->rdomain = 0; + reloc->wdomain = RADEON_GEM_DOMAIN_VRAM; + break; + case RADEON_GEM_DOMAIN_GTT: + reloc->rdomain = RADEON_GEM_DOMAIN_GTT; + reloc->wdomain = 0; + break; + default: + exit(0); + break; + } + reloc->cnt = 1; + csg->chunks[1].length_dw += 4; radeon_bo_ref(bo); + cs->relocs_total_size += bo->size; + cs_write_dword(cs, 0xc0001000); + cs_write_dword(cs, idx); return 0; } @@ -168,19 +219,6 @@ static int cs_begin(struct radeon_cs *cs, const char *func, int line) { - if (cs->section) { - fprintf(stderr, "CS already in a section(%s,%s,%d)\n", - cs->section_file, cs->section_func, cs->section_line); - fprintf(stderr, "CS can't start section(%s,%s,%d)\n", - file, func, line); - return -EPIPE; - } - cs->section = 1; - cs->section_ndw = ndw; - cs->section_cdw = 0; - cs->section_file = file; - cs->section_func = func; - cs->section_line = line; return 0; } @@ -190,29 +228,38 @@ static int cs_end(struct radeon_cs *cs, int line) { - if (!cs->section) { - fprintf(stderr, "CS no section to end at (%s,%s,%d)\n", - file, func, line); - return -EPIPE; - } cs->section = 0; - if (cs->section_ndw != cs->section_cdw) { - fprintf(stderr, "CS section size missmatch start at (%s,%s,%d)\n", - cs->section_file, cs->section_func, cs->section_line); - fprintf(stderr, "CS section end at (%s,%s,%d)\n", - file, func, line); - return -EPIPE; - } return 0; } static int cs_emit(struct radeon_cs *cs) { + struct cs_gem *csg = (struct cs_gem*)cs; + uint64_t chunk_array[2]; + int r; + + chunk_array[0] = (uint64_t)(intptr_t)&csg->chunks[0]; + chunk_array[1] = (uint64_t)(intptr_t)&csg->chunks[1]; + + csg->cs.num_chunks = 2; + csg->cs.chunks = (uint64_t)(intptr_t)chunk_array; + + r = drmCommandWriteRead(cs->csm->fd, DRM_RADEON_CS2, + &csg->cs, sizeof(struct drm_radeon_cs2)); + if (r) { + return r; + } + for(i = 0; i < cs->crelocs; i++) { + radeon_bo_unref(csg->relocs_bo[i]); + } return 0; } static int cs_destroy(struct radeon_cs *cs) { + struct cs_gem *csg = (struct cs_gem*)cs; + + free(csg->relocs_bo); free(cs->relocs); free(cs->packets); free(cs); @@ -221,17 +268,20 @@ static int cs_destroy(struct radeon_cs *cs) static int cs_erase(struct radeon_cs *cs) { + struct cs_gem *csg = (struct cs_gem*)cs; + cs->relocs_total_size = 0; - cs->relocs = NULL; - cs->crelocs = 0; cs->cdw = 0; cs->section = 0; + cs->crelocs = 0; + csg->chunks[0].length_dw = 0; + csg->chunks[1].length_dw = 0; return 0; } static int cs_need_flush(struct radeon_cs *cs) { - return (cs->relocs_total_size > (7*1024*1024)); + return (cs->relocs_total_size > (16*1024*1024)); } struct radeon_cs_funcs radeon_cs_funcs = { diff --git a/libdrm/radeon/radeon_cs_gem.h b/libdrm/radeon/radeon_cs_gem.h index a032a8cc..f50c5e84 100644 --- a/libdrm/radeon/radeon_cs_gem.h +++ b/libdrm/radeon/radeon_cs_gem.h @@ -3,20 +3,21 @@ * Copyright © 2008 Jérôme Glisse * All Rights Reserved. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * The above copyright notice and this permission notice (including the -- cgit v1.2.3 From 7abb8416a7fd8d69f1f2317cdac2baa8e640671e Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 9 Nov 2008 18:48:46 +0100 Subject: radeon: add more packet3 relocations handling --- shared-core/radeon_cs.c | 99 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 21 deletions(-) diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 3dde321d..56f6cbac 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -180,7 +180,6 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) struct drm_radeon_cs *cs = data; uint32_t *packets = NULL; uint32_t cs_id; - uint32_t card_offset; long size; int r; struct drm_radeon_kernel_chunk chunk_fake[1]; @@ -280,12 +279,11 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *pa old kernels ignore it. */ if (parser->reloc_index == -1) { if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { - DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16), reg); + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x at %d\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16), reg, offset_dw); return -EINVAL; } - } else { if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16))) { - DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16), reg); + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x at %d\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16), reg, offset_dw); return -EINVAL; } @@ -295,9 +293,11 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *pa case RADEON_DST_PITCH_OFFSET: case RADEON_SRC_PITCH_OFFSET: /* pass in the start of the reloc */ - ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + 2, &offset); - if (ret) + ret = dev_priv->cs.relocate(parser, + ib_chunk->kdata + offset_dw + 2, &offset); + if (ret) { return ret; + } tmp = (val & RADEON_2D_OFFSET_MASK) << 10; val &= ~RADEON_2D_OFFSET_MASK; offset += tmp; @@ -313,9 +313,12 @@ static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *pa case R200_PP_TXOFFSET_1: case RADEON_PP_TXOFFSET_0: case RADEON_PP_TXOFFSET_1: - ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + 2, &offset); - if (ret) + ret = dev_priv->cs.relocate(parser, + ib_chunk->kdata + offset_dw + 2, &offset); + if (ret) { + DRM_ERROR("Failed to relocate %d\n", offset_dw); return ret; + } offset &= 0xffffffe0; val += offset; @@ -332,8 +335,9 @@ static int radeon_cs_relocate_packet3(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) { drm_radeon_private_t *dev_priv = parser->dev->dev_private; - uint32_t hdr, num_dw, reg; - uint32_t offset, val, tmp; + uint32_t hdr, num_dw, reg, i; + uint32_t offset, val, tmp, nptr, cptr; + uint32_t *reloc; int ret; struct drm_radeon_kernel_chunk *ib_chunk; @@ -347,11 +351,13 @@ static int radeon_cs_relocate_packet3(struct drm_radeon_cs_parser *parser, switch(reg) { case RADEON_CNTL_HOSTDATA_BLT: - { val = ib_chunk->kdata[offset_dw + 2]; - ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + num_dw + 2, &offset); - if (ret) + ret = dev_priv->cs.relocate(parser, + ib_chunk->kdata + offset_dw + num_dw + 2, + &offset); + if (ret) { return ret; + } tmp = (val & RADEON_2D_OFFSET_MASK) << 10; val &= ~RADEON_2D_OFFSET_MASK; @@ -360,8 +366,48 @@ static int radeon_cs_relocate_packet3(struct drm_radeon_cs_parser *parser, val |= offset; ib_chunk->kdata[offset_dw + 2] = val; - } + break; + case RADEON_3D_LOAD_VBPNTR: + nptr = ib_chunk->kdata[offset_dw + 1]; + cptr = offset_dw + 3; + for (i = 0; i < (nptr & ~1); i+= 2) { + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + reloc += ((i + 0) * 2); + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[cptr] += offset; + cptr += 1; + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + reloc += ((i + 1) * 2); + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[cptr] += offset; + cptr += 2; + } + if (nptr & 1) { + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + reloc += ((nptr - 1) * 2); + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[cptr] += offset; + } + break; + case RADEON_CP_INDX_BUFFER: + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[offset_dw + 2] += offset; + break; default: + DRM_ERROR("Unknown packet3 0x%08X\n", hdr); return -EINVAL; } return 0; @@ -377,6 +423,12 @@ int radeon_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + if (hdr & (1 << 15)) { + if (reg == 0x2208) { + return 0; + } + } + while (count_dw < num_dw) { /* need to have something like the r300 validation here - list of allowed registers */ @@ -405,7 +457,8 @@ int radeon_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) } else if (flags == MARK_CHECK_SCISSOR) { DRM_DEBUG("need to validate scissor %x %d\n", reg, flags); } else { - DRM_DEBUG("illegal register %x %d\n", reg, flags); + + DRM_ERROR("illegal register 0x%x %d at %d\n", reg, flags, offset_dw); return -EINVAL; } break; @@ -435,6 +488,8 @@ int radeon_cs_parse(struct drm_radeon_cs_parser *parser) switch (hdr & RADEON_CP_PACKET_MASK) { case RADEON_CP_PACKET0: ret = radeon_cs_packet0(parser, count_dw); + if (ret) + return ret; break; case RADEON_CP_PACKET1: case RADEON_CP_PACKET2: @@ -446,14 +501,17 @@ int radeon_cs_parse(struct drm_radeon_cs_parser *parser) reg = hdr & 0xff00; switch(reg) { + case RADEON_3D_LOAD_VBPNTR: + case RADEON_CP_INDX_BUFFER: case RADEON_CNTL_HOSTDATA_BLT: - radeon_cs_relocate_packet3(parser, count_dw); + ret =radeon_cs_relocate_packet3(parser, + count_dw); + if (ret) + return ret; break; case RADEON_CNTL_BITBLT_MULTI: - case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */ - case RADEON_CP_INDX_BUFFER: - DRM_ERROR("need relocate packet 3 for %x\n", reg); + DRM_ERROR("need relocate packet 3 for %x %d\n", reg, count_dw); break; case RADEON_3D_DRAW_IMMD: /* triggers drawing using in-packet vertex data */ @@ -464,12 +522,11 @@ int radeon_cs_parse(struct drm_radeon_cs_parser *parser) case RADEON_CP_NOP: break; default: - DRM_ERROR("unknown packet 3 %x\n", reg); + DRM_ERROR("unknown packet 3 %x at %d\n", reg, count_dw); ret = -EINVAL; } break; } - count_dw += num_dw+2; } -- cgit v1.2.3 From 31b0c4cd20d0eb843268a6307b7c32dbc07e42a0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:13:08 +1000 Subject: radeon: fixup vram visible calculation to take a/c pinned objects for now --- linux-core/radeon_fb.c | 5 +++++ linux-core/radeon_gem.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/linux-core/radeon_fb.c b/linux-core/radeon_fb.c index d3722c37..9d30d1f7 100644 --- a/linux-core/radeon_fb.c +++ b/linux-core/radeon_fb.c @@ -707,6 +707,7 @@ int radeonfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_heigh uint32_t surface_width, uint32_t surface_height, struct radeon_framebuffer **radeon_fb_p) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct fb_info *info; struct radeonfb_par *par; struct drm_framebuffer *fb; @@ -743,6 +744,8 @@ int radeonfb_create(struct drm_device *dev, uint32_t fb_width, uint32_t fb_heigh goto out_unref; } + dev_priv->mm.vram_visible -= aligned_size; + mutex_lock(&dev->struct_mutex); fb = radeon_framebuffer_create(dev, &mode_cmd, fbo); if (!fb) { @@ -1136,6 +1139,7 @@ EXPORT_SYMBOL(radeonfb_probe); int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) { + struct drm_radeon_private *dev_priv = dev->dev_private; struct fb_info *info; struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); @@ -1147,6 +1151,7 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) if (info) { unregister_framebuffer(info); drm_bo_kunmap(&radeon_fb->kmap_obj); + dev_priv->mm.vram_visible += radeon_fb->obj->size; mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(radeon_fb->obj); radeon_fb->obj = NULL; diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 2e20de3c..85185232 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -586,6 +586,9 @@ static int radeon_gart_init(struct drm_device *dev) if (ret) return -EINVAL; + /* subtract from VRAM value reporting to userspace */ + dev_priv->mm.vram_visible -= RADEON_PCIGART_TABLE_SIZE; + dev_priv->mm.pcie_table_backup = kzalloc(RADEON_PCIGART_TABLE_SIZE, GFP_KERNEL); if (!dev_priv->mm.pcie_table_backup) return -EINVAL; -- cgit v1.2.3 From 08ef5b5e677579892a454d44a96a12dc771b56ac Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:24:42 +1000 Subject: radeon: force all ring writes to 16-dword alignment. --- shared-core/radeon_cp.c | 37 ++++++++++++++++++++++++++++++++----- shared-core/radeon_drv.h | 21 +++++++++------------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 9a1e0e02..73192d03 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1313,9 +1313,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, dev_priv->ring.rptr_update = /* init->rptr_update */ 4096; dev_priv->ring.rptr_update_l2qw = drm_order( /* init->rptr_update */ 4096 / 8); - dev_priv->ring.fetch_size = /* init->fetch_size */ 32; - dev_priv->ring.fetch_size_l2ow = drm_order( /* init->fetch_size */ 32 / 16); - + dev_priv->ring.fetch_size_l2ow = 2; dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; @@ -2513,8 +2511,7 @@ int radeon_modeset_cp_init(struct drm_device *dev) dev_priv->ring.size_l2qw = drm_order(dev_priv->ring.size / 8); dev_priv->ring.rptr_update = 4096; dev_priv->ring.rptr_update_l2qw = drm_order(4096 / 8); - dev_priv->ring.fetch_size = 32; - dev_priv->ring.fetch_size_l2ow = drm_order(32 / 16); + dev_priv->ring.fetch_size_l2ow = 2; /* do what tcore does */ dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; @@ -2841,3 +2838,33 @@ void radeon_gart_flush(struct drm_device *dev) } } + +void radeon_commit_ring(drm_radeon_private_t *dev_priv) +{ + int i; + u32 *ring; + int tail_aligned; + + /* check if the ring is padded out to 16-dword alignment */ + + tail_aligned = dev_priv->ring.tail & 0xf; + if (tail_aligned) { + int num_p2 = 16 - tail_aligned; + + ring = dev_priv->ring.start; + /* pad with some CP_PACKET2 */ + for (i = 0; i < num_p2; i++) + ring[dev_priv->ring.tail + i] = CP_PACKET2(); + + dev_priv->ring.tail += i; + + dev_priv->ring.space -= num_p2 * sizeof(u32); + } + + DRM_MEMORYBARRIER(); + GET_RING_HEAD( dev_priv ); + + RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); + /* read from PCI bus to ensure correct posting */ + RADEON_READ( RADEON_CP_RB_RPTR ); +} diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index a95ab152..828ad3f9 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -219,7 +219,6 @@ typedef struct drm_radeon_ring_buffer { int rptr_update; /* Double Words */ int rptr_update_l2qw; /* log2 Quad Words */ - int fetch_size; /* Double Words */ int fetch_size_l2ow; /* log2 Oct Words */ u32 tail; @@ -1515,15 +1514,16 @@ do { \ #define RADEON_VERBOSE 0 -#define RING_LOCALS int write, _nr; unsigned int mask; u32 *ring; +#define RING_LOCALS int write, _nr, _align_nr; unsigned int mask; u32 *ring; #define BEGIN_RING( n ) do { \ if ( RADEON_VERBOSE ) { \ DRM_INFO( "BEGIN_RING( %d )\n", (n)); \ } \ - if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ + _align_nr = (n + 0xf) & ~0xf; \ + if (dev_priv->ring.space <= (_align_nr * sizeof(u32))) { \ COMMIT_RING(); \ - radeon_wait_ring( dev_priv, (n) * sizeof(u32) ); \ + radeon_wait_ring(dev_priv, _align_nr * sizeof(u32)); \ } \ _nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \ ring = dev_priv->ring.start; \ @@ -1540,19 +1540,14 @@ do { \ DRM_ERROR( \ "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \ ((dev_priv->ring.tail + _nr) & mask), \ - write, __LINE__); \ + write, __LINE__); \ } else \ dev_priv->ring.tail = write; \ } while (0) #define COMMIT_RING() do { \ - /* Flush writes to ring */ \ - DRM_MEMORYBARRIER(); \ - GET_RING_HEAD( dev_priv ); \ - RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); \ - /* read from PCI bus to ensure correct posting */ \ - RADEON_READ( RADEON_CP_RB_RPTR ); \ -} while (0) + radeon_commit_ring(dev_priv); \ + } while(0) #define OUT_RING( x ) do { \ if ( RADEON_VERBOSE ) { \ @@ -1731,6 +1726,8 @@ extern void radeon_gem_proc_cleanup(struct drm_minor *minor); #define MARK_CHECK_OFFSET 2 #define MARK_CHECK_SCISSOR 3 +extern void radeon_commit_ring(drm_radeon_private_t *dev_priv); + extern int r300_check_range(unsigned reg, int count); extern int r300_get_reg_flags(unsigned reg); #endif /* __RADEON_DRV_H__ */ -- cgit v1.2.3 From 758376e6eb2155605ad502d0dc5147c74f3c47a6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:25:12 +1000 Subject: radeon: disable HDP read cache for now --- shared-core/radeon_cp.c | 3 +++ shared-core/radeon_drv.h | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 73192d03..a087829e 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2519,6 +2519,9 @@ int radeon_modeset_cp_init(struct drm_device *dev) r300_init_reg_flags(dev); + /* turn off HDP read cache for now */ + RADEON_WRITE(RADEON_HOST_PATH_CNTL, RADEON_READ(RADEON_HOST_PATH_CNTL) | RADEON_HP_LIN_RD_CACHE_DIS); + #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) radeon_modeset_agp_init(dev); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 828ad3f9..cd683795 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -791,8 +791,10 @@ int radeon_resume(struct drm_device *dev); # define R500_DISPLAY_INT_STATUS (1 << 0) #define RADEON_HOST_PATH_CNTL 0x0130 -# define RADEON_HDP_SOFT_RESET (1 << 26) # define RADEON_HDP_APER_CNTL (1 << 23) +# define RADEON_HP_LIN_RD_CACHE_DIS (1 << 24) +# define RADEON_HDP_SOFT_RESET (1 << 26) +# define RADEON_HDP_READ_BUFFER_INVALIDATED (1 << 27) #define RADEON_NB_TOM 0x15c -- cgit v1.2.3 From 994f2405030f7f595c4ec6bee524f7c06f27cd7b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:25:27 +1000 Subject: radeon: fix ring tail overflow issue since alignment --- shared-core/radeon_cp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index a087829e..285bd4d7 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -2863,6 +2863,8 @@ void radeon_commit_ring(drm_radeon_private_t *dev_priv) dev_priv->ring.space -= num_p2 * sizeof(u32); } + + dev_priv->ring.tail &= dev_priv->ring.tail_mask; DRM_MEMORYBARRIER(); GET_RING_HEAD( dev_priv ); -- cgit v1.2.3 From 241a9b64141b2dd09449e581017b5ca0c0cc2357 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:30:21 +1000 Subject: drm/radeon: add uncached allocator to drm ttm code. --- linux-core/Makefile.kernel | 2 +- linux-core/drm_bo.c | 3 + linux-core/drm_objects.h | 13 +++++ linux-core/drm_ttm.c | 29 +++++++--- linux-core/drm_uncached.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ linux-core/radeon_gem.c | 3 + 6 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 linux-core/drm_uncached.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 98616e4b..9ef9890d 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -15,7 +15,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_hashtab.o drm_mm.o drm_compat.o \ drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o \ drm_crtc.o drm_edid.o drm_modes.o drm_crtc_helper.o \ - drm_regman.o drm_vm_nopage_compat.o drm_gem.o + drm_regman.o drm_vm_nopage_compat.o drm_gem.o drm_uncached.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 36af51c2..9cf23f21 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1850,6 +1850,7 @@ int drm_bo_driver_finish(struct drm_device *dev) __free_page(bm->dummy_read_page); } + drm_uncached_fini(); out: mutex_unlock(&dev->struct_mutex); return ret; @@ -1869,6 +1870,8 @@ int drm_bo_driver_init(struct drm_device *dev) struct drm_buffer_manager *bm = &dev->bm; int ret = -EINVAL; + drm_uncached_init(); + bm->dummy_read_page = NULL; mutex_lock(&dev->struct_mutex); if (!driver) diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index 0c8ffe92..012123bf 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -661,6 +661,9 @@ struct drm_bo_lock { #define _DRM_FLAG_MEMTYPE_CMA 0x00000010 /* Can't map aperture */ #define _DRM_FLAG_MEMTYPE_CSELECT 0x00000020 /* Select caching */ +#define _DRM_BM_ALLOCATOR_CACHED 0x0 +#define _DRM_BM_ALLOCATOR_UNCACHED 0x1 + struct drm_buffer_manager { struct drm_bo_lock bm_lock; struct mutex evict_mutex; @@ -679,6 +682,7 @@ struct drm_buffer_manager { unsigned long cur_pages; atomic_t count; struct page *dummy_read_page; + int allocator_type; }; struct drm_bo_driver { @@ -894,6 +898,15 @@ extern int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg * m void **virtual); extern void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg * mem, void *virtual); + +/* + * drm_uncached.c + */ +extern int drm_uncached_init(void); +extern void drm_uncached_fini(void); +extern struct page *drm_get_uncached_page(void); +extern void drm_put_uncached_page(struct page *page); + #ifdef CONFIG_DEBUG_MUTEXES #define DRM_ASSERT_LOCKED(_mutex) \ BUG_ON(!mutex_is_locked(_mutex) || \ diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 054a7ce8..4067b9e1 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -120,14 +120,18 @@ static void drm_ttm_free_page_directory(struct drm_ttm *ttm) ttm->pages = NULL; } -static struct page *drm_ttm_alloc_page(void) +static struct page *drm_ttm_alloc_page(struct drm_ttm *ttm) { struct page *page; if (drm_alloc_memctl(PAGE_SIZE)) return NULL; - page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32); + if (ttm->dev->bm.allocator_type == _DRM_BM_ALLOCATOR_UNCACHED) + page = drm_get_uncached_page(); + else + page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32); + if (!page) { drm_free_memctl(PAGE_SIZE); return NULL; @@ -149,6 +153,9 @@ static int drm_ttm_set_caching(struct drm_ttm *ttm, int noncached) struct page **cur_page; int do_tlbflush = 0; + if (ttm->dev->bm.allocator_type == _DRM_BM_ALLOCATOR_UNCACHED) + return 0; + if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached) return 0; @@ -215,14 +222,18 @@ static void drm_ttm_free_alloced_pages(struct drm_ttm *ttm) for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages + i; if (*cur_page) { + if (ttm->dev->bm.allocator_type == _DRM_BM_ALLOCATOR_UNCACHED) + drm_put_uncached_page(*cur_page); + else { #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) - ClearPageReserved(*cur_page); + ClearPageReserved(*cur_page); #endif - if (page_count(*cur_page) != 1) - DRM_ERROR("Erroneous page count. Leaking pages.\n"); - if (page_mapped(*cur_page)) - DRM_ERROR("Erroneous map count. Leaking page mappings.\n"); - __free_page(*cur_page); + if (page_count(*cur_page) != 1) + DRM_ERROR("Erroneous page count. Leaking pages.\n"); + if (page_mapped(*cur_page)) + DRM_ERROR("Erroneous map count. Leaking page mappings.\n"); + __free_page(*cur_page); + } drm_free_memctl(PAGE_SIZE); --bm->cur_pages; } @@ -268,7 +279,7 @@ struct page *drm_ttm_get_page(struct drm_ttm *ttm, int index) struct drm_buffer_manager *bm = &ttm->dev->bm; while(NULL == (p = ttm->pages[index])) { - p = drm_ttm_alloc_page(); + p = drm_ttm_alloc_page(ttm); if (!p) return NULL; diff --git a/linux-core/drm_uncached.c b/linux-core/drm_uncached.c new file mode 100644 index 00000000..9c7183b0 --- /dev/null +++ b/linux-core/drm_uncached.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) Red Hat Inc. + + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + */ + +/* simple list based uncached page allocator + * - Add chunks of 1MB to the allocator at a time. + * - Use page->lru to keep a free list + * - doesn't track currently in use pages + * + * TODO: Add shrinker support + */ + +#include "drmP.h" +#include + +static struct list_head uncached_free_list; + +static struct mutex uncached_mutex; +static int uncached_inited; +static int total_uncached_pages; + +/* add 1MB at a time */ +#define NUM_PAGES_TO_ADD 256 + +static void drm_uncached_page_put(struct page *page) +{ + unmap_page_from_agp(page); + put_page(page); + __free_page(page); +} + +int drm_uncached_add_pages_locked(int num_pages) +{ + struct page *page; + int i; + + DRM_DEBUG("adding uncached memory %ld\n", num_pages * PAGE_SIZE); + for (i = 0; i < num_pages; i++) { + + page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32); + if (!page) { + DRM_ERROR("unable to get page %d\n", i); + return i; + } + + get_page(page); +#ifdef CONFIG_X86 + set_memory_wc((unsigned long)page_address(page), 1); +#else + map_page_into_agp(page); +#endif + + list_add(&page->lru, &uncached_free_list); + total_uncached_pages++; + } + return i; +} + +struct page *drm_get_uncached_page(void) +{ + struct page *page = NULL; + int ret; + + mutex_lock(&uncached_mutex); + if (list_empty(&uncached_free_list)) { + ret = drm_uncached_add_pages_locked(NUM_PAGES_TO_ADD); + if (ret == 0) + return NULL; + } + + page = list_first_entry(&uncached_free_list, struct page, lru); + list_del(&page->lru); + + mutex_unlock(&uncached_mutex); + return page; +} + +void drm_put_uncached_page(struct page *page) +{ + mutex_lock(&uncached_mutex); + list_add(&page->lru, &uncached_free_list); + mutex_unlock(&uncached_mutex); +} + +void drm_uncached_release_all_pages(void) +{ + struct page *page, *tmp; + + list_for_each_entry_safe(page, tmp, &uncached_free_list, lru) { + list_del(&page->lru); + drm_uncached_page_put(page); + } +} + +int drm_uncached_init(void) +{ + + if (uncached_inited) + return 0; + + INIT_LIST_HEAD(&uncached_free_list); + + mutex_init(&uncached_mutex); + uncached_inited = 1; + return 0; + +} + +void drm_uncached_fini(void) +{ + if (!uncached_inited) + return; + + uncached_inited = 0; + drm_uncached_release_all_pages(); +} + diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 85185232..f338e64c 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -966,6 +966,9 @@ int radeon_gem_mm_init(struct drm_device *dev) /* init TTM underneath */ drm_bo_driver_init(dev); + /* use the uncached allocator */ + dev->bm.allocator_type = _DRM_BM_ALLOCATOR_UNCACHED; + /* size the mappable VRAM memory for now */ radeon_vram_setup(dev); -- cgit v1.2.3 From b1cf46378a54230291ba9fdb4dbbd4bc4befe049 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:35:16 +1000 Subject: modesetting: set the crtc x,y after the mode base change --- linux-core/drm_crtc_helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 776a98e1..58163e51 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -683,6 +683,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) if (set->crtc->fb != set->fb) set->crtc->fb = set->fb; crtc_funcs->mode_set_base(set->crtc, set->x, set->y); + set->crtc->x = set->x; + set->crtc->y = set->y; } kfree(save_encoders); -- cgit v1.2.3 From 327631c8b50a90c8f694ffd9ebd0e5c618e99dff Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:35:34 +1000 Subject: radeon: avivo cursors are across the full surface. fixes cursor on second head --- linux-core/radeon_cursor.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-core/radeon_cursor.c b/linux-core/radeon_cursor.c index d352d10f..fbd4143c 100644 --- a/linux-core/radeon_cursor.c +++ b/linux-core/radeon_cursor.c @@ -204,6 +204,10 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, radeon_lock_cursor(crtc, true); if (radeon_is_avivo(dev_priv)) { + /* avivo cursor are offset into the total surface */ + x += crtc->x; + y += crtc->y; + DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); RADEON_WRITE(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, ((xorigin ? 0: x) << 16) | (yorigin ? 0 : y)); -- cgit v1.2.3 From 195cc0d817f99e25a1e961deeabbb15a40b789ed Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:37:16 +1000 Subject: drm/radeon: add dpms connector functions --- linux-core/drm_crtc.c | 2 +- linux-core/drm_crtc_helper.c | 27 +++++++++++++++++++++++++++ linux-core/drm_crtc_helper.h | 2 ++ linux-core/radeon_connectors.c | 19 +++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 2f80ec07..bc385dce 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1423,7 +1423,7 @@ int drm_mode_setcrtc(struct drm_device *dev, set.mode = mode; set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; - set.fb =fb; + set.fb = fb; ret = crtc->funcs->set_config(&set); out: diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 58163e51..ebb44794 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -804,3 +804,30 @@ int drm_helper_resume_force_mode(struct drm_device *dev) return 0; } EXPORT_SYMBOL(drm_helper_resume_force_mode); + +void drm_helper_set_connector_dpms(struct drm_connector *connector, + int dpms_mode) +{ + int i = 0; + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_mode_object *obj; + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, + connector->encoder_ids[i], + DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; + + encoder = obj_to_encoder(obj); + encoder_funcs = encoder->helper_private; + if (encoder_funcs->dpms) + encoder_funcs->dpms(encoder, dpms_mode); + + } +} +EXPORT_SYMBOL(drm_helper_set_connector_dpms); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h index c0719157..a0dd6675 100644 --- a/linux-core/drm_crtc_helper.h +++ b/linux-core/drm_crtc_helper.h @@ -93,4 +93,6 @@ static inline void drm_connector_helper_add(struct drm_connector *connector, con } extern int drm_helper_resume_force_mode(struct drm_device *dev); +extern void drm_helper_set_connector_dpms(struct drm_connector *connector, + int dpms_mode); #endif diff --git a/linux-core/radeon_connectors.c b/linux-core/radeon_connectors.c index 18873f0f..be1dbae1 100644 --- a/linux-core/radeon_connectors.c +++ b/linux-core/radeon_connectors.c @@ -77,6 +77,22 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode return mode; } +int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = connector->dev; + + if (property == dev->mode_config.dpms_property) { + if (val > 3) + return -EINVAL; + + drm_helper_set_connector_dpms(connector, val); + + } + return 0; +} + + static int radeon_lvds_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -146,6 +162,7 @@ struct drm_connector_funcs radeon_lvds_connector_funcs = { .detect = radeon_lvds_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = radeon_connector_destroy, + .set_property = radeon_connector_set_property, }; static int radeon_vga_get_modes(struct drm_connector *connector) @@ -197,6 +214,7 @@ struct drm_connector_funcs radeon_vga_connector_funcs = { .detect = radeon_vga_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = radeon_connector_destroy, + .set_property = radeon_connector_set_property, }; @@ -289,6 +307,7 @@ struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = { struct drm_connector_funcs radeon_dvi_connector_funcs = { .detect = radeon_dvi_detect, .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = radeon_connector_set_property, .destroy = radeon_connector_destroy, }; -- cgit v1.2.3 From 213a71f31b174dcae2ef5b3d8b124c1fb62d1866 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:37:36 +1000 Subject: radeon: fix fence race condition hopefully For some reason reading the SCRATCH reg from RAM causes some race to occur. Hopefully fix this. --- linux-core/radeon_fence.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c index b662da21..13af804b 100644 --- a/linux-core/radeon_fence.c +++ b/linux-core/radeon_fence.c @@ -57,14 +57,15 @@ static void radeon_fence_poll(struct drm_device *dev, uint32_t fence_class, { struct drm_radeon_private *dev_priv = (struct drm_radeon_private *) dev->dev_private; uint32_t sequence; - if (waiting_types & DRM_FENCE_TYPE_EXE) { - sequence = READ_BREADCRUMB(dev_priv); + sequence = RADEON_READ(RADEON_SCRATCH_REG3); + /* this used to be READ_BREADCRUMB(dev_priv); but it caused + * a race somewhere in the fencing irq + */ - DRM_DEBUG("polling %d\n", sequence); - drm_fence_handler(dev, 0, sequence, - DRM_FENCE_TYPE_EXE, 0); - } + DRM_DEBUG("polling %d\n", sequence); + drm_fence_handler(dev, 0, sequence, + DRM_FENCE_TYPE_EXE, 0); } void radeon_fence_handler(struct drm_device * dev) -- cgit v1.2.3 From 532c63cddd273bffab715e3d387268abe164f148 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:37:51 +1000 Subject: radeon: upgrade atom headers --- linux-core/ObjectID.h | 36 ++- linux-core/atombios.h | 803 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 700 insertions(+), 139 deletions(-) diff --git a/linux-core/ObjectID.h b/linux-core/ObjectID.h index 4b106cf6..f1f18a48 100644 --- a/linux-core/ObjectID.h +++ b/linux-core/ObjectID.h @@ -78,6 +78,10 @@ #define ENCODER_OBJECT_ID_DP_DP501 0x1D #define ENCODER_OBJECT_ID_INTERNAL_UNIPHY 0x1E #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA 0x1F +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 0x20 +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 0x21 + +#define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO 0xFF /****************************************************/ /* Connector Object ID Definition */ @@ -118,6 +122,8 @@ #define GRAPH_OBJECT_ENUM_ID2 0x02 #define GRAPH_OBJECT_ENUM_ID3 0x03 #define GRAPH_OBJECT_ENUM_ID4 0x04 +#define GRAPH_OBJECT_ENUM_ID5 0x05 +#define GRAPH_OBJECT_ENUM_ID6 0x06 /****************************************************/ /* Graphics Object ID Bit definition */ @@ -173,7 +179,7 @@ #define ENCODER_SI178_ENUM_ID1 0x2117 #define ENCODER_MVPU_FPGA_ENUM_ID1 0x2118 #define ENCODER_INTERNAL_DDI_ENUM_ID1 0x2119 -#define ENCODER_VT1625_ENUM_ID1 0x211A +#define ENCODER_VT1625_ENUM_ID1 0x211A #define ENCODER_HDMI_SI1932_ENUM_ID1 0x211B #define ENCODER_ENCODER_DP_AN9801_ENUM_ID1 0x211C #define ENCODER_DP_DP501_ENUM_ID1 0x211D @@ -323,6 +329,26 @@ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA << OBJECT_ID_SHIFT) +#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT) + +#define ENCODER_GENERAL_EXTERNAL_DVO_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT) + /****************************************************/ /* Connector Object ID definition - Shared with BIOS */ /****************************************************/ @@ -453,6 +479,14 @@ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) +#define CONNECTOR_DISPLAYPORT_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + /****************************************************/ /* Router Object ID definition - Shared with BIOS */ /****************************************************/ diff --git a/linux-core/atombios.h b/linux-core/atombios.h index 2e7dc6c2..9932b096 100644 --- a/linux-core/atombios.h +++ b/linux-core/atombios.h @@ -266,7 +266,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ USHORT SetCRTC_UsingDTDTiming; //Atomic Table, directly used by various SW components,latest version 1.1 USHORT ExternalEncoderControl; //Atomic Table, directly used by various SW components,latest version 2.1 USHORT LVTMAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 - USHORT VRAM_BlockDetectionByStrap; + USHORT VRAM_BlockDetectionByStrap; //Atomic Table, used only by Bios USHORT MemoryCleanUp; //Atomic Table, only used by Bios USHORT ProcessI2cChannelTransaction; //Function Table,only used by Bios USHORT WriteOneByteToHWAssistedI2C; //Function Table,indirectly used by various SW components @@ -276,9 +276,9 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ USHORT MC_Synchronization; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock USHORT ComputeMemoryEnginePLL; //Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock USHORT MemoryRefreshConversion; //Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock - USHORT VRAM_GetCurrentInfoBlock; + USHORT VRAM_GetCurrentInfoBlock; //Atomic Table, used only by Bios USHORT DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock - USHORT MemoryTraining; + USHORT MemoryTraining; //Atomic Table, used only by Bios USHORT EnableSpreadSpectrumOnPPLL; //Atomic Table, directly used by various SW components,latest version 1.2 USHORT TMDSAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 USHORT SetVoltage; //Function Table,directly and/or indirectly used by various SW components,latest version 1.1 @@ -296,11 +296,12 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ USHORT DPEncoderService; //Function Table,only used by Bios }ATOM_MASTER_LIST_OF_COMMAND_TABLES; +// For backward compatible #define ReadEDIDFromHWAssistedI2C ProcessI2cChannelTransaction - #define UNIPHYTransmitterControl DIG1TransmitterControl #define LVTMATransmitterControl DIG2TransmitterControl -#define SetCRTC_DPM_State GetConditionalGoldenSetting +#define SetCRTC_DPM_State GetConditionalGoldenSetting +#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange typedef struct _ATOM_MASTER_COMMAND_TABLE { @@ -308,6 +309,9 @@ typedef struct _ATOM_MASTER_COMMAND_TABLE ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables; }ATOM_MASTER_COMMAND_TABLE; +/****************************************************************************/ +// Structures used in every command table +/****************************************************************************/ typedef struct _ATOM_TABLE_ATTRIBUTE { #if ATOM_BIG_ENDIAN @@ -327,23 +331,20 @@ typedef union _ATOM_TABLE_ATTRIBUTE_ACCESS USHORT susAccess; }ATOM_TABLE_ATTRIBUTE_ACCESS; +/****************************************************************************/ // Common header for all command tables. -//Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header. -//And the pointer actually points to this header. - +// Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header. +// And the pointer actually points to this header. +/****************************************************************************/ typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER { ATOM_COMMON_TABLE_HEADER CommonHeader; ATOM_TABLE_ATTRIBUTE TableAttribute; }ATOM_COMMON_ROM_COMMAND_TABLE_HEADER; - -typedef struct _ASIC_INIT_PARAMETERS -{ - ULONG ulDefaultEngineClock; //In 10Khz unit - ULONG ulDefaultMemoryClock; //In 10Khz unit -}ASIC_INIT_PARAMETERS; - +/****************************************************************************/ +// Structures used by ComputeMemoryEnginePLLTable +/****************************************************************************/ #define COMPUTE_MEMORY_PLL_PARAM 1 #define COMPUTE_ENGINE_PLL_PARAM 2 @@ -380,6 +381,57 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 #define b3FIRST_TIME_CHANGE_CLOCK 0x08 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup #define b3SKIP_SW_PROGRAM_PLL 0x10 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL +typedef struct _ATOM_COMPUTE_CLOCK_FREQ +{ +#if ATOM_BIG_ENDIAN + ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM + ULONG ulClockFreq:24; // in unit of 10kHz +#else + ULONG ulClockFreq:24; // in unit of 10kHz + ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM +#endif +}ATOM_COMPUTE_CLOCK_FREQ; + +typedef struct _ATOM_S_MPLL_FB_DIVIDER +{ + USHORT usFbDivFrac; + USHORT usFbDiv; +}ATOM_S_MPLL_FB_DIVIDER; + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 +{ + union + { + ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter + ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter + }; + UCHAR ucRefDiv; //Output Parameter + UCHAR ucPostDiv; //Output Parameter + UCHAR ucCntlFlag; //Output Parameter + UCHAR ucReserved; +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3; + +// ucCntlFlag +#define ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN 1 +#define ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE 2 +#define ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE 4 + +typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER +{ + ATOM_COMPUTE_CLOCK_FREQ ulClock; + ULONG ulReserved[2]; +}DYNAMICE_MEMORY_SETTINGS_PARAMETER; + +typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER +{ + ATOM_COMPUTE_CLOCK_FREQ ulClock; + ULONG ulMemoryClock; + ULONG ulReserved; +}DYNAMICE_ENGINE_SETTINGS_PARAMETER; + +/****************************************************************************/ +// Structures used by SetEngineClockTable +/****************************************************************************/ typedef struct _SET_ENGINE_CLOCK_PARAMETERS { ULONG ulTargetEngineClock; //In 10Khz unit @@ -391,7 +443,9 @@ typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; }SET_ENGINE_CLOCK_PS_ALLOCATION; - +/****************************************************************************/ +// Structures used by SetMemoryClockTable +/****************************************************************************/ typedef struct _SET_MEMORY_CLOCK_PARAMETERS { ULONG ulTargetMemoryClock; //In 10Khz unit @@ -403,13 +457,24 @@ typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; }SET_MEMORY_CLOCK_PS_ALLOCATION; +/****************************************************************************/ +// Structures used by ASIC_Init.ctb +/****************************************************************************/ +typedef struct _ASIC_INIT_PARAMETERS +{ + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit +}ASIC_INIT_PARAMETERS; + typedef struct _ASIC_INIT_PS_ALLOCATION { ASIC_INIT_PARAMETERS sASICInitClocks; SET_ENGINE_CLOCK_PS_ALLOCATION sReserved; //Caller doesn't need to init this structure }ASIC_INIT_PS_ALLOCATION; - +/****************************************************************************/ +// Structure used by DynamicClockGatingTable.ctb +/****************************************************************************/ typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS { UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE @@ -417,7 +482,9 @@ typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS }DYNAMIC_CLOCK_GATING_PARAMETERS; #define DYNAMIC_CLOCK_GATING_PS_ALLOCATION DYNAMIC_CLOCK_GATING_PARAMETERS - +/****************************************************************************/ +// Structure used by EnableASIC_StaticPwrMgtTable.ctb +/****************************************************************************/ typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS { UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE @@ -425,7 +492,9 @@ typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS }ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS; #define ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS - +/****************************************************************************/ +// Structures used by DAC_LoadDetectionTable.ctb +/****************************************************************************/ typedef struct _DAC_LOAD_DETECTION_PARAMETERS { USHORT usDeviceID; //{ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT} @@ -436,14 +505,15 @@ typedef struct _DAC_LOAD_DETECTION_PARAMETERS // DAC_LOAD_DETECTION_PARAMETERS.ucMisc #define DAC_LOAD_MISC_YPrPb 0x01 - typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION { DAC_LOAD_DETECTION_PARAMETERS sDacload; ULONG Reserved[2];// Don't set this one, allocation for EXT DAC }DAC_LOAD_DETECTION_PS_ALLOCATION; - +/****************************************************************************/ +// Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb +/****************************************************************************/ typedef struct _DAC_ENCODER_CONTROL_PARAMETERS { USHORT usPixelClock; // in 10KHz; for bios convenient @@ -455,14 +525,11 @@ typedef struct _DAC_ENCODER_CONTROL_PARAMETERS #define DAC_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PARAMETERS -typedef struct _TV_ENCODER_CONTROL_PARAMETERS -{ - USHORT usPixelClock; // in 10KHz; for bios convenient - UCHAR ucTvStandard; // See definition "ATOM_TV_NTSC ..." - UCHAR ucAction; // 0: turn off encoder - // 1: setup and turn on encoder -}TV_ENCODER_CONTROL_PARAMETERS; - +/****************************************************************************/ +// Structures used by DIG1EncoderControlTable +// DIG2EncoderControlTable +// ExternalEncoderControlTable +/****************************************************************************/ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS { USHORT usPixelClock; // in 10KHz; for bios convenient @@ -487,7 +554,6 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS }DIG_ENCODER_CONTROL_PARAMETERS; #define DIG_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PARAMETERS #define EXTERNAL_ENCODER_CONTROL_PARAMETER DIG_ENCODER_CONTROL_PARAMETERS -#define EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PS_ALLOCATION //ucConfig #define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01 @@ -518,6 +584,56 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS #define ATOM_ENCODER_MODE_CV 14 #define ATOM_ENCODER_MODE_CRT 15 +typedef struct _ATOM_DIG_ENCODER_CONFIG_V2 +{ +#if ATOM_BIG_ENDIAN + UCHAR ucReserved1:2; + UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF + UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F + UCHAR ucReserved:1; + UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz +#else + UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz + UCHAR ucReserved:1; + UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F + UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF + UCHAR ucReserved1:2; +#endif +}ATOM_DIG_ENCODER_CONFIG_V2; + + +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + ATOM_DIG_ENCODER_CONFIG_V2 acConfig; + UCHAR ucAction; + UCHAR ucEncoderMode; + // =0: DP encoder + // =1: LVDS encoder + // =2: DVI encoder + // =3: HDMI encoder + // =4: SDVO encoder + UCHAR ucLaneNum; // how many lanes to enable + UCHAR ucReserved[2]; +}DIG_ENCODER_CONTROL_PARAMETERS_V2; + +//ucConfig +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_MASK 0x01 +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_V2_LINK_SEL_MASK 0x04 +#define ATOM_ENCODER_CONFIG_V2_LINKA 0x00 +#define ATOM_ENCODER_CONFIG_V2_LINKB 0x04 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER_SEL_MASK 0x18 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER1 0x00 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER2 0x08 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER3 0x10 + +/****************************************************************************/ +// Structures used by UNIPHYTransmitterControlTable +// LVTMATransmitterControlTable +// DVOOutputControlTable +/****************************************************************************/ typedef struct _ATOM_DP_VS_MODE { UCHAR ucLaneSel; @@ -595,7 +711,82 @@ typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS #define ATOM_TRANSMITTER_ACTION_SETUP 10 #define ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH 11 -/****************************Device Output Control Command Table Definitions**********************/ + +// Following are used for DigTransmitterControlTable ver1.2 +typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V2 +{ +#if ATOM_BIG_ENDIAN + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) + UCHAR ucReserved:1; + UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector +#else + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) + UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector + UCHAR ucReserved:1; + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) +#endif +}ATOM_DIG_TRANSMITTER_CONFIG_V2; + +//ucConfig +//Bit0 +#define ATOM_TRANSMITTER_CONFIG_V2_DUAL_LINK_CONNECTOR 0x01 + +//Bit1 +#define ATOM_TRANSMITTER_CONFIG_V2_COHERENT 0x02 + +//Bit2 +#define ATOM_TRANSMITTER_CONFIG_V2_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_V2_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_V2_LINKB 0x04 + +// Bit3 +#define ATOM_TRANSMITTER_CONFIG_V2_ENCODER_SEL_MASK 0x08 +#define ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER 0x00 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP +#define ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER 0x08 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP + +// Bit4 +#define ATOM_TRASMITTER_CONFIG_V2_DP_CONNECTOR 0x10 + +// Bit7:6 +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER_SEL_MASK 0xC0 +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1 0x00 //AB +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2 0x40 //CD +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3 0x80 //EF + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 +{ + union + { + USHORT usPixelClock; // in 10KHz; for bios convenient + USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h + ATOM_DP_VS_MODE asMode; // DP Voltage swing mode + }; + ATOM_DIG_TRANSMITTER_CONFIG_V2 acConfig; + UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX + UCHAR ucReserved[4]; +}DIG_TRANSMITTER_CONTROL_PARAMETERS_V2; + + +/****************************************************************************/ +// Structures used by DAC1OuputControlTable +// DAC2OuputControlTable +// LVTMAOutputControlTable (Before DEC30) +// TMDSAOutputControlTable (Before DEC30) +/****************************************************************************/ typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS { UCHAR ucAction; // Possible input:ATOM_ENABLE||ATOMDISABLE @@ -634,7 +825,9 @@ typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS #define DVO_OUTPUT_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PS_ALLOCATION #define DVO_OUTPUT_CONTROL_PARAMETERS_V3 DIG_TRANSMITTER_CONTROL_PARAMETERS -/**************************************************************************/ +/****************************************************************************/ +// Structures used by BlankCRTCTable +/****************************************************************************/ typedef struct _BLANK_CRTC_PARAMETERS { UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 @@ -645,7 +838,11 @@ typedef struct _BLANK_CRTC_PARAMETERS }BLANK_CRTC_PARAMETERS; #define BLANK_CRTC_PS_ALLOCATION BLANK_CRTC_PARAMETERS - +/****************************************************************************/ +// Structures used by EnableCRTCTable +// EnableCRTCMemReqTable +// UpdateCRTC_DoubleBufferRegistersTable +/****************************************************************************/ typedef struct _ENABLE_CRTC_PARAMETERS { UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 @@ -654,7 +851,9 @@ typedef struct _ENABLE_CRTC_PARAMETERS }ENABLE_CRTC_PARAMETERS; #define ENABLE_CRTC_PS_ALLOCATION ENABLE_CRTC_PARAMETERS - +/****************************************************************************/ +// Structures used by SetCRTC_OverScanTable +/****************************************************************************/ typedef struct _SET_CRTC_OVERSCAN_PARAMETERS { USHORT usOverscanRight; // right @@ -666,7 +865,9 @@ typedef struct _SET_CRTC_OVERSCAN_PARAMETERS }SET_CRTC_OVERSCAN_PARAMETERS; #define SET_CRTC_OVERSCAN_PS_ALLOCATION SET_CRTC_OVERSCAN_PARAMETERS - +/****************************************************************************/ +// Structures used by SetCRTC_ReplicationTable +/****************************************************************************/ typedef struct _SET_CRTC_REPLICATION_PARAMETERS { UCHAR ucH_Replication; // horizontal replication @@ -676,7 +877,9 @@ typedef struct _SET_CRTC_REPLICATION_PARAMETERS }SET_CRTC_REPLICATION_PARAMETERS; #define SET_CRTC_REPLICATION_PS_ALLOCATION SET_CRTC_REPLICATION_PARAMETERS - +/****************************************************************************/ +// Structures used by SelectCRTC_SourceTable +/****************************************************************************/ typedef struct _SELECT_CRTC_SOURCE_PARAMETERS { UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 @@ -713,6 +916,10 @@ typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2 //#define ATOM_ENCODER_MODE_CV 14 //#define ATOM_ENCODER_MODE_CRT 15 +/****************************************************************************/ +// Structures used by SetPixelClockTable +// GetPixelClockTable +/****************************************************************************/ //Major revision=1., Minor revision=1 typedef struct _PIXEL_CLOCK_PARAMETERS { @@ -728,7 +935,6 @@ typedef struct _PIXEL_CLOCK_PARAMETERS UCHAR ucPadding; }PIXEL_CLOCK_PARAMETERS; - //Major revision=1., Minor revision=2, add ucMiscIfno //ucMiscInfo: #define MISC_FORCE_REPROG_PIXEL_CLOCK 0x1 @@ -799,6 +1005,9 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V3 #define PIXEL_CLOCK_PARAMETERS_LAST PIXEL_CLOCK_PARAMETERS_V2 #define GET_PIXEL_CLOCK_PS_ALLOCATION PIXEL_CLOCK_PARAMETERS_LAST +/****************************************************************************/ +// Structures used by AdjustDisplayPllTable +/****************************************************************************/ typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS { USHORT usPixelClock; @@ -816,6 +1025,9 @@ typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS #define ADJUST_DISPLAY_PLL_PS_ALLOCATION ADJUST_DISPLAY_PLL_PARAMETERS +/****************************************************************************/ +// Structures used by EnableYUVTable +/****************************************************************************/ typedef struct _ENABLE_YUV_PARAMETERS { UCHAR ucEnable; // ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB) @@ -824,20 +1036,27 @@ typedef struct _ENABLE_YUV_PARAMETERS }ENABLE_YUV_PARAMETERS; #define ENABLE_YUV_PS_ALLOCATION ENABLE_YUV_PARAMETERS +/****************************************************************************/ +// Structures used by GetMemoryClockTable +/****************************************************************************/ typedef struct _GET_MEMORY_CLOCK_PARAMETERS { ULONG ulReturnMemoryClock; // current memory speed in 10KHz unit } GET_MEMORY_CLOCK_PARAMETERS; #define GET_MEMORY_CLOCK_PS_ALLOCATION GET_MEMORY_CLOCK_PARAMETERS - +/****************************************************************************/ +// Structures used by GetEngineClockTable +/****************************************************************************/ typedef struct _GET_ENGINE_CLOCK_PARAMETERS { ULONG ulReturnEngineClock; // current engine speed in 10KHz unit } GET_ENGINE_CLOCK_PARAMETERS; #define GET_ENGINE_CLOCK_PS_ALLOCATION GET_ENGINE_CLOCK_PARAMETERS - +/****************************************************************************/ +// Following Structures and constant may be obsolete +/****************************************************************************/ //Maxium 8 bytes,the data read in will be placed in the parameter space. //Read operaion successeful when the paramter space is non-zero, otherwise read operation failed typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS @@ -887,6 +1106,9 @@ typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS /**************************************************************************/ #define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS +/****************************************************************************/ +// Structures used by PowerConnectorDetectionTable +/****************************************************************************/ typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS { UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected @@ -903,6 +1125,10 @@ typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION }POWER_CONNECTOR_DETECTION_PS_ALLOCATION; /****************************LVDS SS Command Table Definitions**********************/ + +/****************************************************************************/ +// Structures used by EnableSpreadSpectrumOnPPLLTable +/****************************************************************************/ typedef struct _ENABLE_LVDS_SS_PARAMETERS { USHORT usSpreadSpectrumPercentage; @@ -948,6 +1174,9 @@ typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION #define ENABLE_VGA_RENDER_PS_ALLOCATION SET_PIXEL_CLOCK_PS_ALLOCATION +/****************************************************************************/ +// Structures used by ### +/****************************************************************************/ typedef struct _MEMORY_TRAINING_PARAMETERS { ULONG ulTargetMemoryClock; //In 10Khz unit @@ -955,8 +1184,14 @@ typedef struct _MEMORY_TRAINING_PARAMETERS #define MEMORY_TRAINING_PS_ALLOCATION MEMORY_TRAINING_PARAMETERS - /****************************LVDS and other encoder command table definitions **********************/ + + +/****************************************************************************/ +// Structures used by LVDSEncoderControlTable (Before DCE30) +// LVTMAEncoderControlTable (Before DCE30) +// TMDSAEncoderControlTable (Before DCE30) +/****************************************************************************/ typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS { USHORT usPixelClock; // in 10KHz; for bios convenient @@ -976,19 +1211,6 @@ typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS #define TMDS2_ENCODER_CONTROL_PARAMETERS TMDS1_ENCODER_CONTROL_PARAMETERS #define TMDS2_ENCODER_CONTROL_PS_ALLOCATION TMDS2_ENCODER_CONTROL_PARAMETERS -typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS -{ - UCHAR ucEnable; // Enable or Disable External TMDS encoder - UCHAR ucMisc; // Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB} - UCHAR ucPadding[2]; -}ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS; - -typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION -{ - ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder; - WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion -}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION; - //ucTableFormatRevision=1,ucTableContentRevision=2 typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 @@ -1028,6 +1250,32 @@ typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 #define TMDS2_ENCODER_CONTROL_PARAMETERS_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 #define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS2_ENCODER_CONTROL_PARAMETERS_V2 + +#define LVDS_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS1_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3 + +/****************************************************************************/ +// Structures used by ### +/****************************************************************************/ +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS +{ + UCHAR ucEnable; // Enable or Disable External TMDS encoder + UCHAR ucMisc; // Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB} + UCHAR ucPadding[2]; +}ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS; + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION +{ + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION; + #define ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2 @@ -1036,7 +1284,15 @@ typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2 WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion }ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2; +typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION +{ + DIG_ENCODER_CONTROL_PARAMETERS sDigEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION; +/****************************************************************************/ +// Structures used by DVOEncoderControlTable +/****************************************************************************/ //ucTableFormatRevision=1,ucTableContentRevision=3 //ucDVOConfig: @@ -1062,15 +1318,6 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 // bit1=0: non-coherent mode // =1: coherent mode -#define LVDS_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V2 -#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 - -#define TMDS1_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 -#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS1_ENCODER_CONTROL_PARAMETERS_V3 - -#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 -#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3 - //========================================================================================== //Only change is here next time when changing encoder parameter definitions again! #define LVDS_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 @@ -1114,20 +1361,23 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 #define PANEL_ENCODER_75FRC_E 0x00 #define PANEL_ENCODER_75FRC_F 0x80 -/**************************************************************************/ - +/****************************************************************************/ +// Structures used by SetVoltageTable +/****************************************************************************/ #define SET_VOLTAGE_TYPE_ASIC_VDDC 1 #define SET_VOLTAGE_TYPE_ASIC_MVDDC 2 #define SET_VOLTAGE_TYPE_ASIC_MVDDQ 3 #define SET_VOLTAGE_TYPE_ASIC_VDDCI 4 +#define SET_VOLTAGE_INIT_MODE 5 +#define SET_VOLTAGE_GET_MAX_VOLTAGE 6 //Gets the Max. voltage for the soldered Asic #define SET_ASIC_VOLTAGE_MODE_ALL_SOURCE 0x1 #define SET_ASIC_VOLTAGE_MODE_SOURCE_A 0x2 #define SET_ASIC_VOLTAGE_MODE_SOURCE_B 0x4 -#define SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE 0x0 -#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1 -#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2 +#define SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE 0x0 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2 typedef struct _SET_VOLTAGE_PARAMETERS { @@ -1137,7 +1387,6 @@ typedef struct _SET_VOLTAGE_PARAMETERS UCHAR ucReserved; }SET_VOLTAGE_PARAMETERS; - typedef struct _SET_VOLTAGE_PARAMETERS_V2 { UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ @@ -1145,13 +1394,23 @@ typedef struct _SET_VOLTAGE_PARAMETERS_V2 USHORT usVoltageLevel; // real voltage level }SET_VOLTAGE_PARAMETERS_V2; - typedef struct _SET_VOLTAGE_PS_ALLOCATION { SET_VOLTAGE_PARAMETERS sASICSetVoltage; WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; }SET_VOLTAGE_PS_ALLOCATION; +/****************************************************************************/ +// Structures used by TVEncoderControlTable +/****************************************************************************/ +typedef struct _TV_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucTvStandard; // See definition "ATOM_TV_NTSC ..." + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder +}TV_ENCODER_CONTROL_PARAMETERS; + typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION { TV_ENCODER_CONTROL_PARAMETERS sTVEncoder; @@ -1165,6 +1424,9 @@ typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION #define USHORT void* #endif +/****************************************************************************/ +// Structure used in Data.mtb +/****************************************************************************/ typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES { USHORT UtilityPipeLine; // Offest for the utility to get parser info,Don't change this position! @@ -1207,14 +1469,15 @@ typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES #define USHORT UTEMP #endif - typedef struct _ATOM_MASTER_DATA_TABLE { ATOM_COMMON_TABLE_HEADER sHeader; ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables; }ATOM_MASTER_DATA_TABLE; - +/****************************************************************************/ +// Structure used in MultimediaCapabilityInfoTable +/****************************************************************************/ typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO { ATOM_COMMON_TABLE_HEADER sHeader; @@ -1225,7 +1488,9 @@ typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO UCHAR ucHostPortInfo; // Provides host port configuration information }ATOM_MULTIMEDIA_CAPABILITY_INFO; - +/****************************************************************************/ +// Structure used in MultimediaConfigInfoTable +/****************************************************************************/ typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO { ATOM_COMMON_TABLE_HEADER sHeader; @@ -1244,7 +1509,9 @@ typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) }ATOM_MULTIMEDIA_CONFIG_INFO; -/****************************Firmware Info Table Definitions**********************/ +/****************************************************************************/ +// Structures used in FirmwareInfoTable +/****************************************************************************/ // usBIOSCapability Defintion: // Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; @@ -1459,6 +1726,9 @@ typedef struct _ATOM_FIRMWARE_INFO_V1_4 #define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V1_4 +/****************************************************************************/ +// Structures used in IntegratedSystemInfoTable +/****************************************************************************/ #define IGP_CAP_FLAG_DYNAMIC_CLOCK_EN 0x2 #define IGP_CAP_FLAG_AC_CARD 0x4 #define IGP_CAP_FLAG_SDVO_CARD 0x8 @@ -1540,11 +1810,11 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 { ATOM_COMMON_TABLE_HEADER sHeader; ULONG ulBootUpEngineClock; //in 10kHz unit - ULONG ulReserved1[2]; //must be 0x0 for the reserved + ULONG ulReserved1[2]; //must be 0x0 for the reserved ULONG ulBootUpUMAClock; //in 10kHz unit ULONG ulBootUpSidePortClock; //in 10kHz unit ULONG ulMinSidePortClock; //in 10kHz unit - ULONG ulReserved2[6]; //must be 0x0 for the reserved + ULONG ulReserved2[6]; //must be 0x0 for the reserved ULONG ulSystemConfig; //see explanation below ULONG ulBootUpReqDisplayVector; ULONG ulOtherDisplayMisc; @@ -1567,7 +1837,13 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 USHORT usUMADataReturnTime; USHORT usLinkStatusZeroTime; USHORT usReserved; - ULONG ulReserved3[101]; //must be 0x0 + ULONG ulHighVoltageHTLinkFreq; // in 10Khz + ULONG ulLowVoltageHTLinkFreq; // in 10Khz + USHORT usMaxUpStreamHTLinkWidth; + USHORT usMaxDownStreamHTLinkWidth; + USHORT usMinUpStreamHTLinkWidth; + USHORT usMinDownStreamHTLinkWidth; + ULONG ulReserved3[97]; //must be 0x0 }ATOM_INTEGRATED_SYSTEM_INFO_V2; /* @@ -1576,8 +1852,20 @@ ulBootUpUMAClock: Boot-up UMA Clock in 10Khz; it must be 0x0 when UMA is no ulBootUpSidePortClock: Boot-up SidePort Clock in 10Khz; it must be 0x0 when SidePort Memory is not present,this could be equal to or less than maximum supported Sideport memory clock ulSystemConfig: -Bit[0]: =1 PowerExpress mode =0 Non-PowerExpress mode; -Bit[1]=1: system is running at overdrived engine clock =0:system is not running at overdrived engine clock +Bit[0]=1: PowerExpress mode =0 Non-PowerExpress mode; +Bit[1]=1: system boots up at AMD overdrived state or user customized mode. In this case, driver will just stick to this boot-up mode. No other PowerPlay state + =0: system boots up at driver control state. Power state depends on PowerPlay table. +Bit[2]=1: PWM method is used on NB voltage control. =0: GPIO method is used. +Bit[3]=1: Only one power state(Performance) will be supported. + =0: Multiple power states supported from PowerPlay table. +Bit[4]=1: CLMC is supported and enabled on current system. + =0: CLMC is not supported or enabled on current system. SBIOS need to support HT link/freq change through ATIF interface. +Bit[5]=1: Enable CDLW for all driver control power states. Max HT width is from SBIOS, while Min HT width is determined by display requirement. + =0: CDLW is disabled. If CLMC is enabled case, Min HT width will be set equal to Max HT width. If CLMC disabled case, Max HT width will be applied. +Bit[6]=1: High Voltage requested for all power states. In this case, voltage will be forced at 1.1v and powerplay table voltage drop/throttling request will be ignored. + =0: Voltage settings is determined by powerplay table. +Bit[7]=1: Enable CLMC as hybrid Mode. CDLD and CILR will be disabled in this case and we're using legacy C1E. This is workaround for CPU(Griffin) performance issue. + =0: Enable CLMC as regular mode, CDLD and CILR will be enabled. ulBootUpReqDisplayVector: This dword is a bit vector indicates what display devices are requested during boot-up. Refer to ATOM_DEVICE_xxx_SUPPORT for the bit vector definitions. @@ -1606,16 +1894,21 @@ ucDockingPinBit: which bit in this register to read the pin status; ucDockingPinPolarity:Polarity of the pin when docked; ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0 - + usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%. -usMaxNBVoltage:Voltage regulator dependent PWM value.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. -usMinNBVoltage:Voltage regulator dependent PWM value.Set this one to 0x00 if VC without PWM or no VC at all. +usMaxNBVoltage:Max. voltage control value in either PWM or GPIO mode. +usMinNBVoltage:Min. voltage control value in either PWM or GPIO mode. + GPIO mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=0 + PWM mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=1 + GPU SW don't control mode: usMaxNBVoltage & usMinNBVoltage=0 and no care about ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE usBootUpNBVoltage:Boot-up voltage regulator dependent PWM value. +ulHTLinkFreq: Bootup HT link Frequency in 10Khz. +usMinHTLinkWidth: Bootup minimum HT link width. If CDLW disabled, this is equal to usMaxHTLinkWidth. + If CDLW enabled, both upstream and downstream width should be the same during bootup. +usMaxHTLinkWidth: Bootup maximum HT link width. If CDLW disabled, this is equal to usMinHTLinkWidth. + If CDLW enabled, both upstream and downstream width should be the same during bootup. -ulHTLinkFreq: Current HT link Frequency in 10Khz. -usMinHTLinkWidth: -usMaxHTLinkWidth: usUMASyncStartDelay: Memory access latency, required for watermark calculation usUMADataReturnTime: Memory access latency, required for watermark calculation usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us @@ -1624,10 +1917,27 @@ for Griffin or Greyhound. SBIOS needs to convert to actual time by: if T0Ttime [5:4]=01b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.5us (0.0 to 7.5us) if T0Ttime [5:4]=10b, then usLinkStatusZeroTime=T0Ttime [3:0]*2.0us (0.0 to 30us) if T0Ttime [5:4]=11b, and T0Ttime [3:0]=0x0 to 0xa, then usLinkStatusZeroTime=T0Ttime [3:0]*20us (0.0 to 200us) + +ulHighVoltageHTLinkFreq: HT link frequency for power state with low voltage. If boot up runs in HT1, this must be 0. + This must be less than or equal to ulHTLinkFreq(bootup frequency). +ulLowVoltageHTLinkFreq: HT link frequency for power state with low voltage or voltage scaling 1.0v~1.1v. If boot up runs in HT1, this must be 0. + This must be less than or equal to ulHighVoltageHTLinkFreq. + +usMaxUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMaxHTLinkWidth. Not used for now. +usMaxDownStreamHTLinkWidth: same as above. +usMinUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMinHTLinkWidth. Not used for now. +usMinDownStreamHTLinkWidth: same as above. */ + #define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001 #define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002 +#define SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE 0x00000004 +#define SYSTEM_CONFIG_PERFORMANCE_POWERSTATE_ONLY 0x00000008 +#define SYSTEM_CONFIG_CLMC_ENABLED 0x00000010 +#define SYSTEM_CONFIG_CDLW_ENABLED 0x00000020 +#define SYSTEM_CONFIG_HIGH_VOLTAGE_REQUESTED 0x00000040 +#define SYSTEM_CONFIG_CLMC_HYBRID_MODE_ENABLED 0x00000080 #define IGP_DDI_SLOT_LANE_CONFIG_MASK 0x000000FF @@ -1683,14 +1993,16 @@ for Griffin or Greyhound. SBIOS needs to convert to actual time by: #define ATOM_DEVICE_DFP2_INDEX 0x00000007 #define ATOM_DEVICE_CV_INDEX 0x00000008 #define ATOM_DEVICE_DFP3_INDEX 0x00000009 -#define ATOM_DEVICE_RESERVEDA_INDEX 0x0000000A -#define ATOM_DEVICE_RESERVEDB_INDEX 0x0000000B +#define ATOM_DEVICE_DFP4_INDEX 0x0000000A +#define ATOM_DEVICE_DFP5_INDEX 0x0000000B #define ATOM_DEVICE_RESERVEDC_INDEX 0x0000000C #define ATOM_DEVICE_RESERVEDD_INDEX 0x0000000D #define ATOM_DEVICE_RESERVEDE_INDEX 0x0000000E #define ATOM_DEVICE_RESERVEDF_INDEX 0x0000000F -#define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_CV_INDEX+2) +#define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_DFP3_INDEX+1) #define ATOM_MAX_SUPPORTED_DEVICE_INFO_2 ATOM_MAX_SUPPORTED_DEVICE_INFO +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_3 (ATOM_DEVICE_DFP5_INDEX + 1 ) + #define ATOM_MAX_SUPPORTED_DEVICE (ATOM_DEVICE_RESERVEDF_INDEX+1) #define ATOM_DEVICE_CRT1_SUPPORT (0x1L << ATOM_DEVICE_CRT1_INDEX ) @@ -1703,9 +2015,11 @@ for Griffin or Greyhound. SBIOS needs to convert to actual time by: #define ATOM_DEVICE_DFP2_SUPPORT (0x1L << ATOM_DEVICE_DFP2_INDEX) #define ATOM_DEVICE_CV_SUPPORT (0x1L << ATOM_DEVICE_CV_INDEX ) #define ATOM_DEVICE_DFP3_SUPPORT (0x1L << ATOM_DEVICE_DFP3_INDEX ) +#define ATOM_DEVICE_DFP4_SUPPORT (0x1L << ATOM_DEVICE_DFP4_INDEX ) +#define ATOM_DEVICE_DFP5_SUPPORT (0x1L << ATOM_DEVICE_DFP5_INDEX ) #define ATOM_DEVICE_CRT_SUPPORT ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT -#define ATOM_DEVICE_DFP_SUPPORT ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT +#define ATOM_DEVICE_DFP_SUPPORT ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT | ATOM_DEVICE_DFP4_SUPPORT | ATOM_DEVICE_DFP5_SUPPORT #define ATOM_DEVICE_TV_SUPPORT ATOM_DEVICE_TV1_SUPPORT | ATOM_DEVICE_TV2_SUPPORT #define ATOM_DEVICE_LCD_SUPPORT ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT @@ -1776,7 +2090,6 @@ for Griffin or Greyhound. SBIOS needs to convert to actual time by: // = 3-7 Reserved for future I2C engines // [3-0] - I2C_LINE_MUX = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C - typedef struct _ATOM_I2C_ID_CONFIG { #if ATOM_BIG_ENDIAN @@ -1797,6 +2110,9 @@ typedef union _ATOM_I2C_ID_CONFIG_ACCESS }ATOM_I2C_ID_CONFIG_ACCESS; +/****************************************************************************/ +// Structure used in GPIO_I2C_InfoTable +/****************************************************************************/ typedef struct _ATOM_GPIO_I2C_ASSIGMENT { USHORT usClkMaskRegisterIndex; @@ -1826,6 +2142,9 @@ typedef struct _ATOM_GPIO_I2C_INFO ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE]; }ATOM_GPIO_I2C_INFO; +/****************************************************************************/ +// Common Structure used in other structures +/****************************************************************************/ #ifndef _H2INC @@ -1908,7 +2227,9 @@ typedef union _ATOM_MODE_MISC_INFO_ACCESS // VESA_HSYNC_WIDTH = VESA_HSYNC_TIME = EDID_HSPW // VESA_BORDER = EDID_BORDER - +/****************************************************************************/ +// Structure used in SetCRTC_UsingDTDTimingTable +/****************************************************************************/ typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS { USHORT usH_Size; @@ -1926,6 +2247,9 @@ typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS UCHAR ucPadding[3]; }SET_CRTC_USING_DTD_TIMING_PARAMETERS; +/****************************************************************************/ +// Structure used in SetCRTC_TimingTable +/****************************************************************************/ typedef struct _SET_CRTC_TIMING_PARAMETERS { USHORT usH_Total; // horizontal total @@ -1946,7 +2270,11 @@ typedef struct _SET_CRTC_TIMING_PARAMETERS }SET_CRTC_TIMING_PARAMETERS; #define SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION SET_CRTC_TIMING_PARAMETERS - +/****************************************************************************/ +// Structure used in StandardVESA_TimingTable +// AnalogTV_InfoTable +// ComponentVideoInfoTable +/****************************************************************************/ typedef struct _ATOM_MODE_TIMING { USHORT usCRTC_H_Total; @@ -1968,7 +2296,6 @@ typedef struct _ATOM_MODE_TIMING UCHAR ucRefreshRate; }ATOM_MODE_TIMING; - typedef struct _ATOM_DTD_FORMAT { USHORT usPixClk; @@ -1989,12 +2316,19 @@ typedef struct _ATOM_DTD_FORMAT UCHAR ucRefreshRate; }ATOM_DTD_FORMAT; +/****************************************************************************/ +// Structure used in LVDS_InfoTable +// * Need a document to describe this table +/****************************************************************************/ #define SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004 #define SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008 #define SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010 #define SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020 -/****************************LVDS Info Table Definitions **********************/ +//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12. +//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL +#define LCDPANEL_CAP_READ_EDID 0x1 + //ucTableFormatRevision=1 //ucTableContentRevision=1 typedef struct _ATOM_LVDS_INFO @@ -2123,9 +2457,9 @@ typedef struct _ATOM_SPREAD_SPECTRUM_INFO ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY]; }ATOM_SPREAD_SPECTRUM_INFO; - - - +/****************************************************************************/ +// Structure used in AnalogTV_InfoTable (Top level) +/****************************************************************************/ //ucTVBootUpDefaultStd definiton: //ATOM_TV_NTSC 1 @@ -2137,7 +2471,6 @@ typedef struct _ATOM_SPREAD_SPECTRUM_INFO //ATOM_TV_PAL60 7 //ATOM_TV_SECAM 8 - //ucTVSuppportedStd definition: #define NTSC_SUPPORT 0x1 #define NTSCJ_SUPPORT 0x2 @@ -2227,7 +2560,15 @@ typedef struct _ATOM_ANALOG_TV_INFO #define ATOM_DFP3_DTD_MODE_TBL_ADDR (ATOM_DFP3_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) #define ATOM_DFP3_STD_MODE_TBL_ADDR (ATOM_DFP3_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) -#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP3_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP4_EDID_ADDR (ATOM_DFP3_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP4_DTD_MODE_TBL_ADDR (ATOM_DFP4_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP4_STD_MODE_TBL_ADDR (ATOM_DFP4_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP5_EDID_ADDR (ATOM_DFP4_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE) #define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR+256) #define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START+512 @@ -2240,6 +2581,15 @@ typedef struct _ATOM_ANALOG_TV_INFO #define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 #define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0 +/***********************************************************************************/ +// Structure used in VRAM_UsageByFirmwareTable +// Note1: This table is filled by SetBiosReservationStartInFB in CoreCommSubs.asm +// at running time. +// note2: From RV770, the memory is more than 32bit addressable, so we will change +// ucTableFormatRevision=1,ucTableContentRevision=4, the strcuture remains +// exactly same as 1.1 and 1.2 (1.3 is never in use), but ulStartAddrUsedByFirmware +// (in offset to start of memory address) is KB aligned instead of byte aligend. +/***********************************************************************************/ #define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO 1 typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO @@ -2255,8 +2605,9 @@ typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE ATOM_FIRMWARE_VRAM_RESERVE_INFO asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO]; }ATOM_VRAM_USAGE_BY_FIRMWARE; -/**************************************************************************/ -//GPIO Pin lut table definition +/****************************************************************************/ +// Structure used in GPIO_Pin_LUTTable +/****************************************************************************/ typedef struct _ATOM_GPIO_PIN_ASSIGNMENT { USHORT usGpioPin_AIndex; @@ -2270,9 +2621,9 @@ typedef struct _ATOM_GPIO_PIN_LUT ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1]; }ATOM_GPIO_PIN_LUT; -/**************************************************************************/ - - +/****************************************************************************/ +// Structure used in ComponentVideoInfoTable +/****************************************************************************/ #define GPIO_PIN_ACTIVE_HIGH 0x1 #define MAX_SUPPORTED_CV_STANDARDS 5 @@ -2362,8 +2713,9 @@ typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21 #define ATOM_COMPONENT_VIDEO_INFO_LAST ATOM_COMPONENT_VIDEO_INFO_V21 -/**************************************************************************/ -//Object table starts here +/****************************************************************************/ +// Structure used in object_InfoTable +/****************************************************************************/ typedef struct _ATOM_OBJECT_HEADER { ATOM_COMMON_TABLE_HEADER sHeader; @@ -2608,9 +2960,9 @@ typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD #define ATOM_ROUTER_MUX_PIN_STATE_MASK 0x0f #define ATOM_ROUTER_MUX_PIN_SINGLE_STATE_COMPLEMENT 0x01 -/**************************************************************************/ -//ASIC voltage data table starts here - +/****************************************************************************/ +// ASIC voltage data table +/****************************************************************************/ typedef struct _ATOM_VOLTAGE_INFO_HEADER { USHORT usVDDCBaseLevel; //In number of 50mv unit @@ -2836,13 +3188,16 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S0_CV_DIN 0x00002000L #define ATOM_S0_CV_MASK (ATOM_S0_CV+ATOM_S0_CV_DIN) - #define ATOM_S0_DFP1 0x00010000L #define ATOM_S0_DFP2 0x00020000L #define ATOM_S0_LCD1 0x00040000L #define ATOM_S0_LCD2 0x00080000L #define ATOM_S0_TV2 0x00100000L #define ATOM_S0_DFP3 0x00200000L +#define ATOM_S0_DFP4 0x00400000L +#define ATOM_S0_DFP5 0x00800000L + +#define ATOM_S0_DFP_MASK ATOM_S0_DFP1 | ATOM_S0_DFP2 | ATOM_S0_DFP3 | ATOM_S0_DFP4 | ATOM_S0_DFP5 #define ATOM_S0_FAD_REGISTER_BUG 0x02000000L // If set, indicates we are running a PCIE asic with // the FAD/HDP reg access bug. Bit is read by DAL @@ -2900,7 +3255,6 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S1_ROM_LOCATION_MASK 0x0000FFFFL #define ATOM_S1_PCI_BUS_DEV_MASK 0xFFFF0000L - // BIOS_2_SCRATCH Definition #define ATOM_S2_TV1_STANDARD_MASK 0x0000000FL #define ATOM_S2_CURRENT_BL_LEVEL_MASK 0x0000FF00L @@ -2916,12 +3270,14 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S2_DFP2_DPMS_STATE 0x00800000L #define ATOM_S2_CV_DPMS_STATE 0x01000000L #define ATOM_S2_DFP3_DPMS_STATE 0x02000000L +#define ATOM_S2_DFP4_DPMS_STATE 0x04000000L +#define ATOM_S2_DFP5_DPMS_STATE 0x08000000L -#define ATOM_S2_DEVICE_DPMS_STATE (ATOM_S2_CRT1_DPMS_STATE+ATOM_S2_LCD1_DPMS_STATE+ATOM_S2_TV1_DPMS_STATE+\ - ATOM_S2_DFP1I_DPMS_STATE+ATOM_S2_CRT2_DPMS_STATE+ATOM_S2_LCD2_DPMS_STATE+\ - ATOM_S2_TV2_DPMS_STATE+ATOM_S2_DFP1X_DPMS_STATE+ATOM_S2_CV_DPMS_STATE+\ - ATOM_S2_DFP3_DPMS_STATE) +#define ATOM_S2_DFP_DPM_STATE ATOM_S2_DFP1_DPMS_STATE | ATOM_S2_DFP2_DPMS_STATE | ATOM_S2_DFP3_DPMS_STATE | ATOM_S2_DFP4_DPMS_STATE | ATOM_S2_DFP5_DPMS_STATE +#define ATOM_S2_DEVICE_DPMS_STATE (ATOM_S2_CRT1_DPMS_STATE+ATOM_S2_LCD1_DPMS_STATE+ATOM_S2_TV1_DPMS_STATE+\ + ATOM_S2_DFP_DPMS_STATE+ATOM_S2_CRT2_DPMS_STATE+ATOM_S2_LCD2_DPMS_STATE+\ + ATOM_S2_TV2_DPMS_STATE+ATOM_S2_CV_DPMS_STATE #define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK 0x0C000000L #define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK_SHIFT 26 @@ -2950,6 +3306,8 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S2_DFP2_DPMS_STATEb2 0x80 #define ATOM_S2_CV_DPMS_STATEb3 0x01 #define ATOM_S2_DFP3_DPMS_STATEb3 0x02 +#define ATOM_S2_DFP4_DPMS_STATEb3 0x04 +#define ATOM_S2_DFP5_DPMS_STATEb3 0x08 #define ATOM_S2_DEVICE_DPMS_MASKw1 0x3FF #define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASKb3 0x0C @@ -2969,6 +3327,8 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S3_DFP2_ACTIVE 0x00000080L #define ATOM_S3_CV_ACTIVE 0x00000100L #define ATOM_S3_DFP3_ACTIVE 0x00000200L +#define ATOM_S3_DFP4_ACTIVE 0x00000400L +#define ATOM_S3_DFP5_ACTIVE 0x00000800L #define ATOM_S3_DEVICE_ACTIVE_MASK 0x000003FFL @@ -2985,8 +3345,10 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S3_DFP2_CRTC_ACTIVE 0x00800000L #define ATOM_S3_CV_CRTC_ACTIVE 0x01000000L #define ATOM_S3_DFP3_CRTC_ACTIVE 0x02000000L +#define ATOM_S3_DFP4_CRTC_ACTIVE 0x04000000L +#define ATOM_S3_DFP5_CRTC_ACTIVE 0x08000000L -#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x03FF0000L +#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x0FFF0000L #define ATOM_S3_ASIC_GUI_ENGINE_HUNG 0x20000000L #define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L #define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L @@ -3002,8 +3364,10 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S3_DFP2_ACTIVEb0 0x80 #define ATOM_S3_CV_ACTIVEb1 0x01 #define ATOM_S3_DFP3_ACTIVEb1 0x02 +#define ATOM_S3_DFP4_ACTIVEb1 0x04 +#define ATOM_S3_DFP5_ACTIVEb1 0x08 -#define ATOM_S3_ACTIVE_CRTC1w0 0x3FF +#define ATOM_S3_ACTIVE_CRTC1w0 0xFFF #define ATOM_S3_CRT1_CRTC_ACTIVEb2 0x01 #define ATOM_S3_LCD1_CRTC_ACTIVEb2 0x02 @@ -3015,8 +3379,10 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S3_DFP2_CRTC_ACTIVEb2 0x80 #define ATOM_S3_CV_CRTC_ACTIVEb3 0x01 #define ATOM_S3_DFP3_CRTC_ACTIVEb3 0x02 +#define ATOM_S3_DFP4_CRTC_ACTIVEb3 0x04 +#define ATOM_S3_DFP5_CRTC_ACTIVEb3 0x08 -#define ATOM_S3_ACTIVE_CRTC2w1 0x3FF +#define ATOM_S3_ACTIVE_CRTC2w1 0xFFF #define ATOM_S3_ASIC_GUI_ENGINE_HUNGb3 0x20 #define ATOM_S3_ALLOW_FAST_PWR_SWITCHb3 0x40 @@ -3027,13 +3393,11 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L #define ATOM_S4_LCD1_REFRESH_SHIFT 8 - //Byte aligned defintion for BIOS usage #define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF #define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0 #define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0 - // BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!! #define ATOM_S5_DOS_REQ_CRT1b0 0x01 #define ATOM_S5_DOS_REQ_LCD1b0 0x02 @@ -3045,6 +3409,8 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S5_DOS_REQ_DFP2b0 0x80 #define ATOM_S5_DOS_REQ_CVb1 0x01 #define ATOM_S5_DOS_REQ_DFP3b1 0x02 +#define ATOM_S5_DOS_REQ_DFP4b1 0x04 +#define ATOM_S5_DOS_REQ_DFP5b1 0x08 #define ATOM_S5_DOS_REQ_DEVICEw0 0x03FF @@ -3058,6 +3424,8 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S5_DOS_REQ_DFP2 0x0080 #define ATOM_S5_DOS_REQ_CV 0x0100 #define ATOM_S5_DOS_REQ_DFP3 0x0200 +#define ATOM_S5_DOS_REQ_DFP4 0x0400 +#define ATOM_S5_DOS_REQ_DFP5 0x0800 #define ATOM_S5_DOS_FORCE_CRT1b2 ATOM_S5_DOS_REQ_CRT1b0 #define ATOM_S5_DOS_FORCE_TV1b2 ATOM_S5_DOS_REQ_TV1b0 @@ -3085,7 +3453,6 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S6_DISPLAY_STATE_CHANGE 0x00004000L //This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion #define ATOM_S6_I2C_STATE_CHANGE 0x00008000L //This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion - #define ATOM_S6_ACC_REQ_CRT1 0x00010000L #define ATOM_S6_ACC_REQ_LCD1 0x00020000L #define ATOM_S6_ACC_REQ_TV1 0x00040000L @@ -3096,8 +3463,10 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S6_ACC_REQ_DFP2 0x00800000L #define ATOM_S6_ACC_REQ_CV 0x01000000L #define ATOM_S6_ACC_REQ_DFP3 0x02000000L +#define ATOM_S6_ACC_REQ_DFP4 0x04000000L +#define ATOM_S6_ACC_REQ_DFP5 0x08000000L -#define ATOM_S6_ACC_REQ_MASK 0x03FF0000L +#define ATOM_S6_ACC_REQ_MASK 0x0FFF0000L #define ATOM_S6_SYSTEM_POWER_MODE_CHANGE 0x10000000L #define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH 0x20000000L #define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L @@ -3129,6 +3498,8 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ #define ATOM_S6_ACC_REQ_DFP2b2 0x80 #define ATOM_S6_ACC_REQ_CVb3 0x01 #define ATOM_S6_ACC_REQ_DFP3b3 0x02 +#define ATOM_S6_ACC_REQ_DFP4b3 0x04 +#define ATOM_S6_ACC_REQ_DFP5b3 0x08 #define ATOM_S6_ACC_REQ_DEVICEw1 ATOM_S5_DOS_REQ_DEVICEw0 #define ATOM_S6_SYSTEM_POWER_MODE_CHANGEb3 0x10 @@ -3403,7 +3774,7 @@ typedef struct _ATOM_TV_MODE_SCALER_PTR typedef struct _ATOM_STANDARD_VESA_TIMING { ATOM_COMMON_TABLE_HEADER sHeader; - ATOM_MODE_TIMING aModeTimings[16]; // 16 is not the real array number, just for initial allocation + ATOM_DTD_FORMAT aModeTimings[16]; // 16 is not the real array number, just for initial allocation }ATOM_STANDARD_VESA_TIMING; @@ -3482,6 +3853,11 @@ typedef struct _ATOM_INIT_REG_BLOCK{ #define VALUE_SAME_AS_ABOVE 0 #define VALUE_MASK_DWORD 0x84 +#define INDEX_ACCESS_RANGE_BEGIN (VALUE_DWORD + 1) +#define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1) +#define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1) + + typedef struct _ATOM_MC_INIT_PARAM_TABLE { ATOM_COMMON_TABLE_HEADER sHeader; @@ -3520,6 +3896,28 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE #define QIMONDA INFINEON #define PROMOS MOSEL +/////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// + +#define UCODE_ROM_START_ADDRESS 0x1c000 +#define UCODE_SIGNATURE 0x4375434d // 'MCuC' - MC uCode + +//uCode block header for reference + +typedef struct _MCuCodeHeader +{ + ULONG ulSignature; + UCHAR ucRevision; + UCHAR ucChecksum; + UCHAR ucReserved1; + UCHAR ucReserved2; + USHORT usParametersLength; + USHORT usUCodeLength; + USHORT usReserved1; + USHORT usReserved2; +} MCuCodeHeader; + +////////////////////////////////////////////////////////////////////////////////// + #define ATOM_MAX_NUMBER_OF_VRAM_MODULE 16 #define ATOM_VRAM_MODULE_MEMORY_VENDOR_ID_MASK 0xF @@ -3574,6 +3972,42 @@ typedef struct _ATOM_VRAM_MODULE_V2 typedef struct _ATOM_MEMORY_TIMING_FORMAT +{ + ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing + union{ + USHORT usMRS; // mode register + USHORT usDDR3_MR0; + }; + union{ + USHORT usEMRS; // extended mode register + USHORT usDDR3_MR1; + }; + UCHAR ucCL; // CAS latency + UCHAR ucWL; // WRITE Latency + UCHAR uctRAS; // tRAS + UCHAR uctRC; // tRC + UCHAR uctRFC; // tRFC + UCHAR uctRCDR; // tRCDR + UCHAR uctRCDW; // tRCDW + UCHAR uctRP; // tRP + UCHAR uctRRD; // tRRD + UCHAR uctWR; // tWR + UCHAR uctWTR; // tWTR + UCHAR uctPDIX; // tPDIX + UCHAR uctFAW; // tFAW + UCHAR uctAOND; // tAOND + union + { + struct { + UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon + UCHAR ucReserved; + }; + USHORT usDDR3_MR2; + }; +}ATOM_MEMORY_TIMING_FORMAT; + + +typedef struct _ATOM_MEMORY_TIMING_FORMAT_V1 { ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing USHORT usMRS; // mode register @@ -3593,16 +4027,31 @@ typedef struct _ATOM_MEMORY_TIMING_FORMAT UCHAR uctFAW; // tFAW UCHAR uctAOND; // tAOND UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon - UCHAR ucReserved; // -}ATOM_MEMORY_TIMING_FORMAT; +////////////////////////////////////GDDR parameters/////////////////////////////////// + UCHAR uctCCDL; // + UCHAR uctCRCRL; // + UCHAR uctCRCWL; // + UCHAR uctCKE; // + UCHAR uctCKRSE; // + UCHAR uctCKRSX; // + UCHAR uctFAW32; // + UCHAR ucReserved1; // + UCHAR ucReserved2; // + UCHAR ucTerminator; +}ATOM_MEMORY_TIMING_FORMAT_V1; -#define MEM_TIMING_FLAG_APP_MODE 0x01 // =0 mid clock range =1 high clock range typedef struct _ATOM_MEMORY_FORMAT { ULONG ulDllDisClock; // memory DLL will be disable when target memory clock is below this clock - USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type - USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + union{ + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_Reserved; // Not used for DDR3 memory + }; + union{ + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_MR3; // Used for DDR3 memory + }; UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed UCHAR ucRow; // Number of Row,in power of 2; @@ -3641,6 +4090,79 @@ typedef struct _ATOM_VRAM_MODULE_V3 #define ATOM_VRAM_MODULE ATOM_VRAM_MODULE_V3 +typedef struct _ATOM_VRAM_MODULE_V4 +{ + ULONG ulChannelMapCfg; // board dependent parameter: Channel combination + USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE + USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; + UCHAR ucChannelNum; // Number of channels present in this module config + UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucFlag; // To enable/disable functionalities based on memory type + UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 + UCHAR ucVREFI; // board dependent parameter + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros + UCHAR ucReserved[3]; + +//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level + union{ + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_Reserved; + }; + union{ + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_MR3; // Used for DDR3 memory + }; + UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed + UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) + UCHAR ucReserved2[2]; + ATOM_MEMORY_TIMING_FORMAT asMemTiming[5];//Memory Timing block sort from lower clock to higher clock +}ATOM_VRAM_MODULE_V4; + +#define VRAM_MODULE_V4_MISC_RANK_MASK 0x3 +#define VRAM_MODULE_V4_MISC_DUAL_RANK 0x1 +#define VRAM_MODULE_V4_MISC_BL_MASK 0x4 +#define VRAM_MODULE_V4_MISC_BL8 0x4 +#define VRAM_MODULE_V4_MISC_DUAL_CS 0x10 + +typedef struct _ATOM_VRAM_MODULE_V5 +{ + ULONG ulChannelMapCfg; // board dependent parameter: Channel combination + USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE + USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; + UCHAR ucChannelNum; // Number of channels present in this module config + UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucFlag; // To enable/disable functionalities based on memory type + UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 + UCHAR ucVREFI; // board dependent parameter + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros + UCHAR ucReserved[3]; + +//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed + UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) + UCHAR ucFIFODepth; // FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth + UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth + ATOM_MEMORY_TIMING_FORMAT_V1 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock +}ATOM_VRAM_MODULE_V5; + typedef struct _ATOM_VRAM_INFO_V2 { ATOM_COMMON_TABLE_HEADER sHeader; @@ -3663,6 +4185,21 @@ typedef struct _ATOM_VRAM_INFO_V3 #define ATOM_VRAM_INFO_LAST ATOM_VRAM_INFO_V3 +typedef struct _ATOM_VRAM_INFO_V4 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting + USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting + USHORT usRerseved; + UCHAR ucMemDQ7_0ByteRemap; // DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3 + ULONG ulMemDQ7_0BitRemap; // each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21] + UCHAR ucReservde[4]; + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE_V4 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; + ATOM_INIT_REG_BLOCK asMemPatch; // for allocation + // ATOM_INIT_REG_BLOCK aMemAdjust; +}ATOM_VRAM_INFO_V4; + typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO { ATOM_COMMON_TABLE_HEADER sHeader; @@ -3966,6 +4503,7 @@ typedef struct _DP_ENCODER_SERVICE_PARAMETERS #define ATOM_DP_ACTION_TRAINING_PATTERN_SEL 0x04 #define ATOM_DP_ACTION_SET_VSWING_PREEMP 0x05 #define ATOM_DP_ACTION_GET_VSWING_PREEMP 0x06 +#define ATOM_DP_ACTION_BLANKING 0x07 // ucConfig #define ATOM_DP_CONFIG_ENCODER_SEL_MASK 0x03 @@ -4481,17 +5019,6 @@ typedef struct _ATOM_POWERPLAY_INFO_V3 #define ENABLE_LVDS_SS_PARAMETERS_V3 ENABLE_SPREAD_SPECTRUM_ON_PPLL /*********************************************************************************/ -#define ATOM_S3_SCALER2_ACTIVE_H 0x00004000L -#define ATOM_S3_SCALER2_ACTIVE_V 0x00008000L -#define ATOM_S6_REQ_SCALER2_H 0x00004000L -#define ATOM_S6_REQ_SCALER2_V 0x00008000L - -#define ATOM_S3_SCALER1_ACTIVE_H ATOM_S3_LCD_FULLEXPANSION_ACTIVE -#define ATOM_S3_SCALER1_ACTIVE_V ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE - -#define ATOM_S6_REQ_SCALER1_H ATOM_S6_REQ_LCD_EXPANSION_FULL -#define ATOM_S6_REQ_SCALER1_V ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO -//========================================================================================== #pragma pack() // BIOS data must use byte aligment -- cgit v1.2.3 From 15464f5181538d01e8fc016211daa1a824b89531 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:38:32 +1000 Subject: radeon: add gart useable size to report to userspace --- linux-core/radeon_gem.c | 7 ++++++- shared-core/radeon_drv.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index f338e64c..2ed9bfc1 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -68,7 +68,7 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, args->vram_visible = dev_priv->mm.vram_visible; args->gart_start = dev_priv->mm.gart_start; - args->gart_size = dev_priv->mm.gart_size; + args->gart_size = dev_priv->mm.gart_useable; return 0; } @@ -680,6 +680,8 @@ int radeon_alloc_gart_objects(struct drm_device *dev) dev_priv->mm.ring.bo, dev_priv->mm.ring.bo->offset, dev_priv->mm.ring.kmap.virtual, dev_priv->mm.ring_read.bo, dev_priv->mm.ring_read.bo->offset, dev_priv->mm.ring_read.kmap.virtual); + dev_priv->mm.gart_useable -= RADEON_DEFAULT_RING_SIZE + PAGE_SIZE; + /* init the indirect buffers */ radeon_gem_ib_init(dev); radeon_gem_dma_bufs_init(dev); @@ -989,6 +991,7 @@ int radeon_gem_mm_init(struct drm_device *dev) dev_priv->mm.gart_size = (32 * 1024 * 1024); dev_priv->mm.gart_start = 0; + dev_priv->mm.gart_useable = dev_priv->mm.gart_size; ret = radeon_gart_init(dev); if (ret) return -EINVAL; @@ -1293,6 +1296,7 @@ static int radeon_gem_ib_init(struct drm_device *dev) goto free_all; } + dev_priv->mm.gart_useable -= RADEON_IB_SIZE * RADEON_NUM_IB; dev_priv->ib_alloc_bitmap = 0; dev_priv->cs.ib_get = radeon_gem_ib_get; @@ -1529,6 +1533,7 @@ static int radeon_gem_dma_bufs_init(struct drm_device *dev) DRM_ERROR("Failed to mmap DMA buffers\n"); return -ENOMEM; } + dev_priv->mm.gart_useable -= size; DRM_DEBUG("\n"); radeon_gem_addbufs(dev); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index cd683795..cf3084e1 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -274,6 +274,8 @@ struct radeon_mm_info { uint64_t gart_start; uint64_t gart_size; + uint64_t gart_useable; + void *pcie_table_backup; struct radeon_mm_obj pcie_table; -- cgit v1.2.3 From 72997fb3726b99b99c44e96e59abd8c70abbd8be Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 10 Nov 2008 22:18:22 +0100 Subject: libdrm-radeon: be verbose on bo failure and cleanup cs a bit --- libdrm/radeon/radeon_bo_gem.c | 11 +++++-- libdrm/radeon/radeon_cs_gem.c | 75 +++++++++++++++++++++---------------------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/libdrm/radeon/radeon_bo_gem.c b/libdrm/radeon/radeon_bo_gem.c index fc198711..8ce82919 100644 --- a/libdrm/radeon/radeon_bo_gem.c +++ b/libdrm/radeon/radeon_bo_gem.c @@ -99,11 +99,15 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, &args, sizeof(args)); bo->base.handle = args.handle; if (r) { + fprintf(stderr, "Failed to allocate :\n"); + fprintf(stderr, " size : %d bytes\n", size); + fprintf(stderr, " alignment : %d bytes\n", alignment); + fprintf(stderr, " domains : %d\n", bo->base.domains); free(bo); return NULL; } } - radeon_bo_ref(bo); + radeon_bo_ref((struct radeon_bo*)bo); return (struct radeon_bo*)bo; } @@ -137,7 +141,6 @@ static int bo_map(struct radeon_bo *bo, int write) struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; struct drm_radeon_gem_mmap args; int r; - uint8_t *tt; if (bo_gem->map_count++ != 0) { return 0; @@ -152,8 +155,10 @@ static int bo_map(struct radeon_bo *bo, int write) sizeof(args)); if (!r) { bo->ptr = (void *)(unsigned long)args.addr_ptr; + } else { + fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n", + bo, bo->handle, r); } - tt = bo->ptr; return r; } diff --git a/libdrm/radeon/radeon_cs_gem.c b/libdrm/radeon/radeon_cs_gem.c index 00aa9086..6be1728f 100644 --- a/libdrm/radeon/radeon_cs_gem.c +++ b/libdrm/radeon/radeon_cs_gem.c @@ -58,8 +58,8 @@ struct cs_gem { struct radeon_bo **relocs_bo; }; -static struct radeon_cs *cs_create(struct radeon_cs_manager *csm, - uint32_t ndw) +static struct radeon_cs *cs_gem_create(struct radeon_cs_manager *csm, + uint32_t ndw) { struct cs_gem *csg; @@ -104,7 +104,7 @@ static struct radeon_cs *cs_create(struct radeon_cs_manager *csm, return (struct radeon_cs*)csg; } -static int cs_write_dword(struct radeon_cs *cs, uint32_t dword) +static int cs_gem_write_dword(struct radeon_cs *cs, uint32_t dword) { struct cs_gem *csg = (struct cs_gem*)cs; if (cs->cdw >= cs->ndw) { @@ -123,11 +123,11 @@ static int cs_write_dword(struct radeon_cs *cs, uint32_t dword) return 0; } -static int cs_write_reloc(struct radeon_cs *cs, - struct radeon_bo *bo, - uint32_t soffset, - uint32_t eoffset, - uint32_t domains) +static int cs_gem_write_reloc(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t soffset, + uint32_t eoffset, + uint32_t domains) { struct cs_gem *csg = (struct cs_gem*)cs; struct cs_reloc_gem *reloc; @@ -162,8 +162,8 @@ static int cs_write_reloc(struct radeon_cs *cs, break; } reloc->cnt++; - cs_write_dword(cs, 0xc0001000); - cs_write_dword(cs, idx); + cs_gem_write_dword(cs, 0xc0001000); + cs_gem_write_dword(cs, idx); return 0; } } @@ -208,31 +208,31 @@ static int cs_write_reloc(struct radeon_cs *cs, csg->chunks[1].length_dw += 4; radeon_bo_ref(bo); cs->relocs_total_size += bo->size; - cs_write_dword(cs, 0xc0001000); - cs_write_dword(cs, idx); + cs_gem_write_dword(cs, 0xc0001000); + cs_gem_write_dword(cs, idx); return 0; } -static int cs_begin(struct radeon_cs *cs, - uint32_t ndw, - const char *file, - const char *func, - int line) +static int cs_gem_begin(struct radeon_cs *cs, + uint32_t ndw, + const char *file, + const char *func, + int line) { return 0; } -static int cs_end(struct radeon_cs *cs, - const char *file, - const char *func, - int line) +static int cs_gem_end(struct radeon_cs *cs, + const char *file, + const char *func, + int line) { cs->section = 0; return 0; } -static int cs_emit(struct radeon_cs *cs) +static int cs_gem_emit(struct radeon_cs *cs) { struct cs_gem *csg = (struct cs_gem*)cs; uint64_t chunk_array[2]; @@ -249,13 +249,10 @@ static int cs_emit(struct radeon_cs *cs) if (r) { return r; } - for(i = 0; i < cs->crelocs; i++) { - radeon_bo_unref(csg->relocs_bo[i]); - } return 0; } -static int cs_destroy(struct radeon_cs *cs) +static int cs_gem_destroy(struct radeon_cs *cs) { struct cs_gem *csg = (struct cs_gem*)cs; @@ -266,7 +263,7 @@ static int cs_destroy(struct radeon_cs *cs) return 0; } -static int cs_erase(struct radeon_cs *cs) +static int cs_gem_erase(struct radeon_cs *cs) { struct cs_gem *csg = (struct cs_gem*)cs; @@ -279,21 +276,21 @@ static int cs_erase(struct radeon_cs *cs) return 0; } -static int cs_need_flush(struct radeon_cs *cs) +static int cs_gem_need_flush(struct radeon_cs *cs) { return (cs->relocs_total_size > (16*1024*1024)); } -struct radeon_cs_funcs radeon_cs_funcs = { - cs_create, - cs_write_dword, - cs_write_reloc, - cs_begin, - cs_end, - cs_emit, - cs_destroy, - cs_erase, - cs_need_flush +static struct radeon_cs_funcs radeon_cs_gem_funcs = { + cs_gem_create, + cs_gem_write_dword, + cs_gem_write_reloc, + cs_gem_begin, + cs_gem_end, + cs_gem_emit, + cs_gem_destroy, + cs_gem_erase, + cs_gem_need_flush }; struct radeon_cs_manager *radeon_cs_manager_gem(int fd) @@ -305,7 +302,7 @@ struct radeon_cs_manager *radeon_cs_manager_gem(int fd) if (csm == NULL) { return NULL; } - csm->funcs = &radeon_cs_funcs; + csm->funcs = &radeon_cs_gem_funcs; csm->fd = fd; return csm; } -- cgit v1.2.3 From a7457915f5775137436f3b16a640eb8bd6424ca6 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Wed, 12 Nov 2008 15:56:40 +0100 Subject: radeon+libdrm-radeon: change relocation informations Relocation now consist of the following informations (in this order) : handle buffer object handle identifier start_offset start offset of first data of the buffer object used by the cs end_offset end offset of last data of the buffer object used by the cs read_domain read domain (either VRAM, or GTT as GPU is invalid for CS) write_domain write domain (either VRAM, or GTT as GPU is invalid for CS) flags flags used for further optimization (like discard previous buffer content or forget buffer content after cs which can help in avoiding moving content in or out) --- libdrm/radeon/Makefile.am | 2 +- libdrm/radeon/radeon_cs.h | 33 +++++++++----- libdrm/radeon/radeon_cs_gem.c | 103 ++++++++++++++++++++++++------------------ linux-core/radeon_gem.c | 4 +- 4 files changed, 84 insertions(+), 58 deletions(-) diff --git a/libdrm/radeon/Makefile.am b/libdrm/radeon/Makefile.am index cc4951a9..d15a266b 100644 --- a/libdrm/radeon/Makefile.am +++ b/libdrm/radeon/Makefile.am @@ -29,7 +29,7 @@ AM_CFLAGS = \ $(PTHREADSTUBS_CFLAGS) \ -I$(top_srcdir)/shared-core -libdrm_radeon_la_LTLIBRARIES = libdrm_radeon.la +libdrm_radeon_la_LTLIBRARIES = libdrm-radeon.la libdrm_radeon_ladir = $(libdir) libdrm_radeon_la_LDFLAGS = -version-number 1:0:0 -no-undefined libdrm_radeon_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ diff --git a/libdrm/radeon/radeon_cs.h b/libdrm/radeon/radeon_cs.h index 347e9f35..63f104b6 100644 --- a/libdrm/radeon/radeon_cs.h +++ b/libdrm/radeon/radeon_cs.h @@ -37,10 +37,11 @@ struct radeon_cs_reloc { struct radeon_bo *bo; - uint32_t soffset; - uint32_t eoffset; - uint32_t size; - uint32_t domains; + uint32_t start_offset; + uint32_t end_offset; + uint32_t read_domain; + uint32_t write_domain; + uint32_t flags; }; struct radeon_cs_manager; @@ -68,9 +69,11 @@ struct radeon_cs_funcs { int (*cs_write_dword)(struct radeon_cs *cs, uint32_t dword); int (*cs_write_reloc)(struct radeon_cs *cs, struct radeon_bo *bo, - uint32_t soffset, - uint32_t eoffset, - uint32_t domains); + uint32_t start_offset, + uint32_t end_offset, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags); int (*cs_begin)(struct radeon_cs *cs, uint32_t ndw, const char *file, @@ -104,11 +107,19 @@ static inline int radeon_cs_write_dword(struct radeon_cs *cs, uint32_t dword) static inline int radeon_cs_write_reloc(struct radeon_cs *cs, struct radeon_bo *bo, - uint32_t soffset, - uint32_t eoffset, - uint32_t domains) + uint32_t start_offset, + uint32_t end_offset, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags) { - return cs->csm->funcs->cs_write_reloc(cs, bo, soffset, eoffset, domains); + return cs->csm->funcs->cs_write_reloc(cs, + bo, + start_offset, + end_offset, + read_domain, + write_domain, + flags); } static inline int radeon_cs_begin(struct radeon_cs *cs, diff --git a/libdrm/radeon/radeon_cs_gem.c b/libdrm/radeon/radeon_cs_gem.c index 6be1728f..f9c9fabb 100644 --- a/libdrm/radeon/radeon_cs_gem.c +++ b/libdrm/radeon/radeon_cs_gem.c @@ -43,9 +43,11 @@ #pragma pack(1) struct cs_reloc_gem { uint32_t handle; - uint32_t rdomain; - uint32_t wdomain; - uint32_t cnt; + uint32_t start_offset; + uint32_t end_offset; + uint32_t read_domain; + uint32_t write_domain; + uint32_t flags; }; #pragma pack() @@ -125,50 +127,74 @@ static int cs_gem_write_dword(struct radeon_cs *cs, uint32_t dword) static int cs_gem_write_reloc(struct radeon_cs *cs, struct radeon_bo *bo, - uint32_t soffset, - uint32_t eoffset, - uint32_t domains) + uint32_t start_offset, + uint32_t end_offset, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags) { struct cs_gem *csg = (struct cs_gem*)cs; struct cs_reloc_gem *reloc; uint32_t idx; unsigned i; + /* check domains */ + if ((read_domain && write_domain) || (!read_domain && !write_domain)) { + /* in one CS a bo can only be in read or write domain but not + * in read & write domain at the same sime + */ + return -EINVAL; + } + if (read_domain == RADEON_GEM_DOMAIN_CPU) { + return -EINVAL; + } + if (write_domain == RADEON_GEM_DOMAIN_CPU) { + return -EINVAL; + } /* check reloc window */ - if (eoffset > bo->size) { + if (end_offset > bo->size) { return -EINVAL; } - if (soffset > eoffset) { + if (start_offset > end_offset) { return -EINVAL; } /* check if bo is already referenced */ for(i = 0; i < cs->crelocs; i++) { - idx = i * 4; + idx = i * 6; reloc = (struct cs_reloc_gem*)&csg->relocs[idx]; - if (reloc->handle == bo->handle) { - /* update start offset and size */ - switch (bo->domains) { - case RADEON_GEM_DOMAIN_VRAM: - reloc->rdomain = 0; - reloc->wdomain = RADEON_GEM_DOMAIN_VRAM; - break; - case RADEON_GEM_DOMAIN_GTT: - reloc->rdomain = RADEON_GEM_DOMAIN_GTT; - reloc->wdomain = 0; - break; - default: - exit(0); - break; + /* Check domains must be in read or write. As we check already + * checked that in argument one of the read or write domain was + * set we only need to check that if previous reloc as the read + * domain set then the read_domain should also be set for this + * new relocation. + */ + if (reloc->read_domain && !read_domain) { + return -EINVAL; + } + if (reloc->write_domain && !write_domain) { + return -EINVAL; + } + reloc->read_domain |= read_domain; + reloc->write_domain |= write_domain; + /* update start and end offset */ + if (start_offset < reloc->start_offset) { + reloc->start_offset = start_offset; } - reloc->cnt++; + if (end_offset > reloc->end_offset) { + reloc->end_offset = end_offset; + } + /* update flags */ + reloc->flags |= (flags & reloc->flags); + /* write relocation packet */ cs_gem_write_dword(cs, 0xc0001000); cs_gem_write_dword(cs, idx); return 0; } } - /* add bo */ + /* new relocation */ if (csg->base.crelocs >= csg->nrelocs) { + /* allocate more memory (TODO: should use a slab allocatore maybe) */ uint32_t *tmp, size; size = ((csg->nrelocs + 1) * sizeof(struct radeon_bo*)); tmp = (uint32_t*)realloc(csg->relocs_bo, size); @@ -176,7 +202,7 @@ static int cs_gem_write_reloc(struct radeon_cs *cs, return -ENOMEM; } csg->relocs_bo = (struct radeon_bo**)tmp; - size = ((csg->nrelocs + 1) * 4 * 4); + size = ((csg->nrelocs + 1) * 6 * 4); tmp = (uint32_t*)realloc(csg->relocs, size); if (tmp == NULL) { return -ENOMEM; @@ -186,26 +212,15 @@ static int cs_gem_write_reloc(struct radeon_cs *cs, csg->chunks[1].chunk_data = (uint64_t)(intptr_t)csg->relocs; } csg->relocs_bo[csg->base.crelocs] = bo; - idx = (csg->base.crelocs++) * 4; + idx = (csg->base.crelocs++) * 6; reloc = (struct cs_reloc_gem*)&csg->relocs[idx]; reloc->handle = bo->handle; - reloc->rdomain = bo->domains; - reloc->wdomain = bo->domains; - switch (bo->domains) { - case RADEON_GEM_DOMAIN_VRAM: - reloc->rdomain = 0; - reloc->wdomain = RADEON_GEM_DOMAIN_VRAM; - break; - case RADEON_GEM_DOMAIN_GTT: - reloc->rdomain = RADEON_GEM_DOMAIN_GTT; - reloc->wdomain = 0; - break; - default: - exit(0); - break; - } - reloc->cnt = 1; - csg->chunks[1].length_dw += 4; + reloc->start_offset = start_offset; + reloc->end_offset = end_offset; + reloc->read_domain = read_domain; + reloc->write_domain = write_domain; + reloc->flags = flags; + csg->chunks[1].length_dw += 6; radeon_bo_ref(bo); cs->relocs_total_size += bo->size; cs_gem_write_dword(cs, 0xc0001000); diff --git a/linux-core/radeon_gem.c b/linux-core/radeon_gem.c index 2ed9bfc1..b2e1d7fe 100644 --- a/linux-core/radeon_gem.c +++ b/linux-core/radeon_gem.c @@ -1213,8 +1213,8 @@ static int radeon_gem_find_reloc(struct drm_radeon_cs_parser *parser, } *handle = reloc_chunk->kdata[offset]; - *read_domains = reloc_chunk->kdata[offset + 1]; - *write_domain = reloc_chunk->kdata[offset + 2]; + *read_domains = reloc_chunk->kdata[offset + 3]; + *write_domain = reloc_chunk->kdata[offset + 4]; return 0; } -- cgit v1.2.3 From 13948c635d83285909e25ffd5285165789a598b2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 12 Nov 2008 18:16:38 +0100 Subject: mode: Unify types for ids and strings --- shared-core/drm_mode.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h index bd3d257e..f44c9a0d 100644 --- a/shared-core/drm_mode.h +++ b/shared-core/drm_mode.h @@ -109,8 +109,8 @@ struct drm_mode_crtc { uint64_t set_connectors_ptr; uint32_t count_connectors; - unsigned int crtc_id; /**< Id */ - unsigned int fb_id; /**< Id of framebuffer */ + uint32_t crtc_id; /**< Id */ + uint32_t fb_id; /**< Id of framebuffer */ uint32_t x, y; /**< Position on the frameuffer */ @@ -126,10 +126,10 @@ struct drm_mode_crtc { #define DRM_MODE_ENCODER_TVDAC 4 struct drm_mode_get_encoder { - unsigned int encoder_type; - unsigned int encoder_id; + uint32_t encoder_type; + uint32_t encoder_id; - unsigned int crtc_id; /**< Id of crtc */ + uint32_t crtc_id; /**< Id of crtc */ uint32_t possible_crtcs; uint32_t possible_clones; @@ -170,10 +170,10 @@ struct drm_mode_get_connector { uint32_t count_props; uint32_t count_encoders; - unsigned int encoder_id; /**< Current Encoder */ - unsigned int connector_id; /**< Id */ - unsigned int connector_type; - unsigned int connector_type_id; + uint32_t encoder_id; /**< Current Encoder */ + uint32_t connector_id; /**< Id */ + uint32_t connector_type; + uint32_t connector_type_id; uint32_t connection; uint32_t mm_width, mm_height; /**< HxW in millimeters */ @@ -188,16 +188,16 @@ struct drm_mode_get_connector { struct drm_mode_property_enum { uint64_t value; - unsigned char name[DRM_PROP_NAME_LEN]; + char name[DRM_PROP_NAME_LEN]; }; struct drm_mode_get_property { uint64_t values_ptr; /* values and blob lengths */ uint64_t enum_blob_ptr; /* enum and blob id ptrs */ - unsigned int prop_id; + uint32_t prop_id; uint32_t flags; - unsigned char name[DRM_PROP_NAME_LEN]; + char name[DRM_PROP_NAME_LEN]; uint32_t count_values; uint32_t count_enum_blobs; @@ -205,8 +205,8 @@ struct drm_mode_get_property { struct drm_mode_connector_set_property { uint64_t value; - unsigned int prop_id; - unsigned int connector_id; + uint32_t prop_id; + uint32_t connector_id; }; struct drm_mode_get_blob { @@ -216,7 +216,7 @@ struct drm_mode_get_blob { }; struct drm_mode_fb_cmd { - unsigned int buffer_id; + uint32_t buffer_id; uint32_t width, height; uint32_t pitch; uint32_t bpp; @@ -226,7 +226,7 @@ struct drm_mode_fb_cmd { }; struct drm_mode_mode_cmd { - unsigned int connector_id; + uint32_t connector_id; struct drm_mode_modeinfo mode; }; @@ -249,7 +249,7 @@ struct drm_mode_mode_cmd { */ struct drm_mode_cursor { uint32_t flags; - unsigned int crtc_id; + uint32_t crtc_id; int32_t x; int32_t y; uint32_t width; @@ -266,7 +266,7 @@ struct drm_mode_hotplug { }; struct drm_mode_crtc_lut { - unsigned int crtc_id; + uint32_t crtc_id; uint32_t gamma_size; /* pointers to arrays */ -- cgit v1.2.3 From 1ead45c8f02e7c51cfe977383726d20479385688 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 12 Nov 2008 18:40:04 +0100 Subject: mode: Remove hotplug support from ioctl interface --- libdrm/xf86drmMode.c | 9 --------- libdrm/xf86drmMode.h | 5 ----- linux-core/drm_crtc.c | 10 ---------- linux-core/drm_drv.c | 2 -- linux-core/drm_irq.c | 52 -------------------------------------------------- shared-core/drm.h | 33 -------------------------------- shared-core/drm_mode.h | 7 ------- 7 files changed, 118 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index a25b11bb..38fdbc11 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -183,15 +183,6 @@ err_allocs: return r; } -uint32_t drmModeGetHotplug(int fd) -{ - struct drm_mode_hotplug arg; - arg.counter = 0; - - ioctl(fd, DRM_IOCTL_MODE_HOTPLUG, &arg); - return arg.counter; -} - int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 59612a94..ee45717b 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -158,11 +158,6 @@ extern void drmModeFreeEncoder( drmModeEncoderPtr ptr ); */ extern drmModeResPtr drmModeGetResources(int fd); -/** - * Retrives the hotplug counter - */ -extern uint32_t drmModeGetHotplug(int fd); - /* * FrameBuffer manipulation. */ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index bc385dce..255cc8c2 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -844,16 +844,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_cleanup); -int drm_mode_hotplug_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_hotplug *arg = data; - - arg->counter = dev->mode_config.hotplug_counter; - - return 0; -} - /** * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo * @out: drm_mode_modeinfo struct to return to the user diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 11044bff..a8b17f1d 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -138,8 +138,6 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_HOTPLUG, drm_mode_hotplug_ioctl, DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_WAIT_HOTPLUG, drm_wait_hotplug, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_REPLACEFB, drm_mode_replacefb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW), diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index b317d863..103f3e2b 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -192,58 +192,6 @@ err: } EXPORT_SYMBOL(drm_vblank_init); -int drm_wait_hotplug(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - union drm_wait_hotplug *hotplugwait = data; - struct timeval now; - int ret = 0; - unsigned int flags; - - if ((!dev->irq) || (!dev->irq_enabled)) - return -EINVAL; - - flags = hotplugwait->request.type; - - if (flags & _DRM_HOTPLUG_SIGNAL) { - unsigned long irqflags; - struct list_head *hotplug_sigs = dev->hotplug_sigs; - struct drm_hotplug_sig *hotplug_sig; - - hotplug_sig = drm_calloc(1, sizeof(struct drm_hotplug_sig), - DRM_MEM_DRIVER); - if (!hotplug_sig) - return -ENOMEM; - - atomic_inc(&dev->hotplug_signal_pending); - - hotplug_sig->info.si_signo = hotplugwait->request.signal; - hotplug_sig->task = current; - hotplug_sig->counter = - hotplugwait->reply.counter = - dev->mode_config.hotplug_counter; - - spin_lock_irqsave(&dev->hotplug_lock, irqflags); - - list_add_tail(&hotplug_sig->head, hotplug_sigs); - - spin_unlock_irqrestore(&dev->hotplug_lock, irqflags); - } else { - int cur_hotplug = dev->mode_config.hotplug_counter; - - DRM_WAIT_ON(ret, dev->hotplug_queue, 3 * DRM_HZ, - dev->mode_config.hotplug_counter > cur_hotplug); - - do_gettimeofday(&now); - - hotplugwait->reply.tval_sec = now.tv_sec; - hotplugwait->reply.tval_usec = now.tv_usec; - hotplugwait->reply.counter = dev->mode_config.hotplug_counter; - } - - return ret; -} - static void drm_hotplug_cleanup(struct drm_device *dev) { if (dev->hotplug_sigs) diff --git a/shared-core/drm.h b/shared-core/drm.h index 42dad492..cc6aead4 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -555,37 +555,6 @@ union drm_wait_vblank { struct drm_wait_vblank_reply reply; }; -/* Handle monitor hotplug. - * - * May want to extend this later to pass reply information which - * details the connectors which generated the hotplug event. - * Some chipsets can't determine that though, and we'd need to leave - * it to the higher levels to determine exactly what changed. - */ -enum drm_hotplug_seq_type { - _DRM_HOTPLUG_SIGNAL = 0x00000001, /**< Send signal instead of blocking */ -}; -struct drm_wait_hotplug_request { - enum drm_hotplug_seq_type type; - unsigned long signal; -}; - -struct drm_wait_hotplug_reply { - enum drm_hotplug_seq_type type; - unsigned int counter; - long tval_sec; - long tval_usec; -}; - -/** - * DRM_IOCTL_WAIT_HOTPLUG ioctl argument type. - * - * \sa drmWaitHotplug(). - */ -union drm_wait_hotplug { - struct drm_wait_hotplug_request request; - struct drm_wait_hotplug_reply reply; -}; enum drm_modeset_ctl_cmd { _DRM_PRE_MODESET = 1, @@ -792,8 +761,6 @@ struct drm_gem_open { #define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property) #define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xAC, struct drm_mode_cursor) -#define DRM_IOCTL_MODE_HOTPLUG DRM_IOWR(0xAD, struct drm_mode_hotplug) -#define DRM_IOCTL_WAIT_HOTPLUG DRM_IOWR(0xAE, union drm_wait_hotplug) #define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xAF, struct drm_mode_fb_cmd) #define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xB0, struct drm_mode_get_encoder) diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h index f44c9a0d..6b1abd5b 100644 --- a/shared-core/drm_mode.h +++ b/shared-core/drm_mode.h @@ -258,13 +258,6 @@ struct drm_mode_cursor { uint32_t handle; }; -/* - * oh so ugly hotplug - */ -struct drm_mode_hotplug { - uint32_t counter; -}; - struct drm_mode_crtc_lut { uint32_t crtc_id; uint32_t gamma_size; -- cgit v1.2.3 From ea849d7ca6aaedd3aba6ec7239f01426521d8604 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 12 Nov 2008 18:49:46 +0100 Subject: mode: Unify userspace API to uint_t --- libdrm/xf86drmMode.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index ee45717b..b68d1469 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -77,8 +77,8 @@ typedef struct _drmModePropertyBlob { } drmModePropertyBlobRes, *drmModePropertyBlobPtr; typedef struct _drmModeProperty { - unsigned int prop_id; - unsigned int flags; + uint32_t prop_id; + uint32_t flags; char name[DRM_PROP_NAME_LEN]; int count_values; uint64_t *values; // store the blob lengths @@ -89,8 +89,8 @@ typedef struct _drmModeProperty { } drmModePropertyRes, *drmModePropertyPtr; typedef struct _drmModeCrtc { - unsigned int crtc_id; - unsigned int buffer_id; /**< FB id to connect to 0 = disconnect */ + uint32_t crtc_id; + uint32_t buffer_id; /**< FB id to connect to 0 = disconnect */ uint32_t x, y; /**< Position on the framebuffer */ uint32_t width, height; @@ -102,9 +102,9 @@ typedef struct _drmModeCrtc { } drmModeCrtc, *drmModeCrtcPtr; typedef struct _drmModeEncoder { - unsigned int encoder_id; - unsigned int encoder_type; - unsigned int crtc_id; + uint32_t encoder_id; + uint32_t encoder_type; + uint32_t crtc_id; uint32_t possible_crtcs; uint32_t possible_clones; } drmModeEncoder, *drmModeEncoderPtr; @@ -125,10 +125,10 @@ typedef enum { } drmModeSubPixel; typedef struct _drmModeConnector { - unsigned int connector_id; - unsigned int encoder_id; /**< Encoder currently connected to */ - unsigned int connector_type; - unsigned int connector_type_id; + uint32_t connector_id; + uint32_t encoder_id; /**< Encoder currently connected to */ + uint32_t connector_type; + uint32_t connector_type_id; drmModeConnection connection; uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ drmModeSubPixel subpixel; -- cgit v1.2.3 From 17789a409d3e83cad9f5cf06c2bb7123b78746b2 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 12 Nov 2008 19:10:50 +0100 Subject: mode: Reorder the ioctls and numbering This is to fill in the gaps left by the removal of the hotplug ioctls. And they also look better :) --- shared-core/drm.h | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index cc6aead4..7419ad6e 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -747,25 +747,26 @@ struct drm_gem_open { #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) + #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) -#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA2, struct drm_mode_get_connector) -#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA3, struct drm_mode_crtc) -#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xA4, struct drm_mode_fb_cmd) -#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xA5, unsigned int) -#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xA6, struct drm_mode_fb_cmd) - -#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xA7, struct drm_mode_connector_set_property) -#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xA8, struct drm_mode_get_blob) -#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) -#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xAA, struct drm_mode_mode_cmd) - -#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAB, struct drm_mode_get_property) -#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xAC, struct drm_mode_cursor) - -#define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xAF, struct drm_mode_fb_cmd) -#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xB0, struct drm_mode_get_encoder) -#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xB1, struct drm_mode_crtc_lut) -#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xB2, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA2, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xA3, struct drm_mode_cursor) +#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xA4, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xA5, struct drm_mode_crtc_lut) + +#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xA6, struct drm_mode_get_encoder) + +#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA7, struct drm_mode_get_connector) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAA, struct drm_mode_get_property) +#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_connector_set_property) +#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xAC, struct drm_mode_get_blob) + +#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, uint32_t) +#define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xB0, struct drm_mode_fb_cmd) /*@}*/ -- cgit v1.2.3 From 9a4cb7eab4f74747cc777a3fef31dbb46e1191e5 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 12 Nov 2008 19:17:18 +0100 Subject: mode: Minor reodering and renaming --- libdrm/xf86drmMode.c | 8 ++++---- linux-core/drm_crtc.c | 6 +++--- shared-core/drm_mode.h | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index 38fdbc11..a0a164de 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -200,7 +200,7 @@ int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, if ((ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f))) return ret; - *buf_id = f.buffer_id; + *buf_id = f.fb_id; return 0; } @@ -216,7 +216,7 @@ drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) struct drm_mode_fb_cmd info; drmModeFBPtr r; - info.buffer_id = buf; + info.fb_id = buf; if (ioctl(fd, DRM_IOCTL_MODE_GETFB, &info)) return NULL; @@ -224,7 +224,7 @@ drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) if (!(r = drmMalloc(sizeof(*r)))) return NULL; - r->buffer_id = info.buffer_id; + r->fb_id = info.fb_id; r->width = info.width; r->height = info.height; r->pitch = info.pitch; @@ -639,7 +639,7 @@ int drmModeReplaceFB(int fd, uint32_t buffer_id, f.bpp = bpp; f.depth = depth; f.handle = bo_handle; - f.buffer_id = buffer_id; + f.fb_id = buffer_id; if ((ret = ioctl(fd, DRM_IOCTL_MODE_REPLACEFB, &f))) return ret; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 255cc8c2..aa0c4a95 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1517,7 +1517,7 @@ int drm_mode_addfb(struct drm_device *dev, goto out; } - r->buffer_id = fb->base.id; + r->fb_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); out: @@ -1609,7 +1609,7 @@ int drm_mode_getfb(struct drm_device *dev, int ret = 0; mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, r->buffer_id, DRM_MODE_OBJECT_FB); + obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { DRM_ERROR("invalid framebuffer id\n"); ret = -EINVAL; @@ -2212,7 +2212,7 @@ int drm_mode_replacefb(struct drm_device *dev, /* right replace the current bo attached to this fb with a new bo */ mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, r->buffer_id, DRM_MODE_OBJECT_FB); + obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { ret = -EINVAL; goto out; diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h index 6b1abd5b..601d2bd8 100644 --- a/shared-core/drm_mode.h +++ b/shared-core/drm_mode.h @@ -126,8 +126,8 @@ struct drm_mode_crtc { #define DRM_MODE_ENCODER_TVDAC 4 struct drm_mode_get_encoder { - uint32_t encoder_type; uint32_t encoder_id; + uint32_t encoder_type; uint32_t crtc_id; /**< Id of crtc */ @@ -216,13 +216,13 @@ struct drm_mode_get_blob { }; struct drm_mode_fb_cmd { - uint32_t buffer_id; + uint32_t fb_id; uint32_t width, height; uint32_t pitch; uint32_t bpp; - uint32_t handle; uint32_t depth; - + /* driver specific handle */ + uint32_t handle; }; struct drm_mode_mode_cmd { -- cgit v1.2.3 From bfbecc5c42d9669fceaab683d1464dd353be9492 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 14 Nov 2008 12:08:27 +0100 Subject: libdrm-radeon: new tracker tools To keep record of bo activities and print them when necessary, should help in tracking unbalanced ref/unref calls. --- libdrm/radeon/Makefile.am | 6 +- libdrm/radeon/radeon_bo.h | 29 +++++---- libdrm/radeon/radeon_track.c | 139 +++++++++++++++++++++++++++++++++++++++++++ libdrm/radeon/radeon_track.h | 64 ++++++++++++++++++++ 4 files changed, 224 insertions(+), 14 deletions(-) create mode 100644 libdrm/radeon/radeon_track.c create mode 100644 libdrm/radeon/radeon_track.h diff --git a/libdrm/radeon/Makefile.am b/libdrm/radeon/Makefile.am index d15a266b..39ee021f 100644 --- a/libdrm/radeon/Makefile.am +++ b/libdrm/radeon/Makefile.am @@ -36,11 +36,13 @@ libdrm_radeon_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ libdrm_radeon_la_SOURCES = \ radeon_bo_gem.c \ - radeon_cs_gem.c + radeon_cs_gem.c \ + radeon_track.c libdrm_radeonincludedir = ${includedir}/drm libdrm_radeoninclude_HEADERS = \ radeon_bo.h \ radeon_cs.h \ radeon_bo_gem.h \ - radeon_cs_gem.h + radeon_cs_gem.h \ + radeon_track.h diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index f884e0fa..ed785034 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -32,6 +32,7 @@ #include #include +#include "radeon_track.h" /* bo object */ #define RADEON_BO_FLAGS_MACRO_TILE 1 @@ -46,6 +47,9 @@ struct radeon_bo { uint32_t domains; uint32_t flags; unsigned cref; +#ifdef RADEON_BO_TRACK + struct radeon_track *track; +#endif void *ptr; struct radeon_bo_manager *bom; }; @@ -67,6 +71,7 @@ struct radeon_bo_funcs { struct radeon_bo_manager { struct radeon_bo_funcs *funcs; int fd; + struct radeon_tracker tracker; }; static inline void _radeon_bo_debug(struct radeon_bo *bo, @@ -90,10 +95,12 @@ static inline struct radeon_bo *_radeon_bo_open(struct radeon_bo_manager *bom, int line) { struct radeon_bo *bo; + bo = bom->funcs->bo_open(bom, handle, size, alignment, domains, flags); -#ifdef RADEON_BO_TRACK_OPEN +#ifdef RADEON_BO_TRACK if (bo) { - _radeon_bo_debug(bo, 1, file, func, line); + bo->track = radeon_tracker_add_track(&bom->tracker, bo->handle); + radeon_track_add_event(bo->track, file, func, "open", line); } #endif return bo; @@ -105,8 +112,8 @@ static inline void _radeon_bo_ref(struct radeon_bo *bo, int line) { bo->cref++; -#ifdef RADEON_BO_TRACK_REF - _radeon_bo_debug(bo, 2, file, func, line); +#ifdef RADEON_BO_TRACK + radeon_track_add_event(bo->track, file, func, "ref", line); #endif bo->bom->funcs->bo_ref(bo); } @@ -117,8 +124,12 @@ static inline void _radeon_bo_unref(struct radeon_bo *bo, int line) { bo->cref--; -#ifdef RADEON_BO_TRACK_REF - _radeon_bo_debug(bo, 3, file, func, line); +#ifdef RADEON_BO_TRACK + radeon_track_add_event(bo->track, file, func, "unref", line); + if (bo->cref <= 0) { + radeon_tracker_remove_track(&bo->bom->tracker, bo->track); + bo->track = NULL; + } #endif bo->bom->funcs->bo_unref(bo); } @@ -129,9 +140,6 @@ static inline int _radeon_bo_map(struct radeon_bo *bo, const char *func, int line) { -#ifdef RADEON_BO_TRACK_MAP - _radeon_bo_debug(bo, 4, file, func, line); -#endif return bo->bom->funcs->bo_map(bo, write); } @@ -140,9 +148,6 @@ static inline int _radeon_bo_unmap(struct radeon_bo *bo, const char *func, int line) { -#ifdef RADEON_BO_TRACK_MAP - _radeon_bo_debug(bo, 5, file, func, line); -#endif return bo->bom->funcs->bo_unmap(bo); } diff --git a/libdrm/radeon/radeon_track.c b/libdrm/radeon/radeon_track.c new file mode 100644 index 00000000..c0c6f850 --- /dev/null +++ b/libdrm/radeon/radeon_track.c @@ -0,0 +1,139 @@ +/* + * Copyright © 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse + */ +#include +#include +#include +#include "radeon_track.h" + +void radeon_track_add_event(struct radeon_track *track, + const char *file, + const char *func, + const char *op, + unsigned line) +{ + struct radeon_track_event *event; + + if (track == NULL) { + return; + } + event = (void*)calloc(1,sizeof(struct radeon_track_event)); + if (event == NULL) { + return; + } + event->line = line; + event->file = strdup(file); + event->func = strdup(func); + event->op = strdup(op); + if (event->file == NULL || event->func == NULL || event->op == NULL) { + free(event->file); + free(event->func); + free(event->op); + free(event); + return; + } + event->next = track->events; + track->events = event; +} + +struct radeon_track *radeon_tracker_add_track(struct radeon_tracker *tracker, + unsigned key) +{ + struct radeon_track *track; + + track = (struct radeon_track*)calloc(1, sizeof(struct radeon_track)); + if (track) { + track->next = tracker->tracks.next; + track->prev = &tracker->tracks; + tracker->tracks.next = track; + if (track->next) { + track->next->prev = track; + } + track->key = key; + track->events = NULL; + } + return track; +} + +void radeon_tracker_remove_track(struct radeon_tracker *tracker, + struct radeon_track *track) +{ + struct radeon_track_event *event; + void *tmp; + + if (track == NULL) { + return; + } + track->prev->next = track->next; + if (track->next) { + track->next->prev = track->prev; + } + event = track->events; + while (event) { + tmp = event; + free(event->file); + free(event->func); + free(event->op); + event = event->next; + free(tmp); + } + track->events = NULL; + free(track); +} + +void radeon_tracker_print(struct radeon_tracker *tracker, FILE *file) +{ + struct radeon_track *track; + struct radeon_track_event *event; + void *tmp; + + track = tracker->tracks.next; + while (track) { + event = track->events; + fprintf(file, "[0x%08X] :\n", track->key); + while (event) { + tmp = event; + fprintf(file, " [0x%08X:%s](%s:%s:%d)\n", + track->key, event->op, event->file, + event->func, event->line); + free(event->file); + free(event->func); + free(event->op); + event->file = NULL; + event->func = NULL; + event->op = NULL; + event = event->next; + free(tmp); + } + track->events = NULL; + tmp = track; + track = track->next; + free(tmp); + } +} diff --git a/libdrm/radeon/radeon_track.h b/libdrm/radeon/radeon_track.h new file mode 100644 index 00000000..838d1f38 --- /dev/null +++ b/libdrm/radeon/radeon_track.h @@ -0,0 +1,64 @@ +/* + * Copyright © 2008 Jérôme Glisse + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS + * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse + */ +#ifndef RADEON_TRACK_H +#define RADEON_TRACK_H + +struct radeon_track_event { + struct radeon_track_event *next; + char *file; + char *func; + char *op; + unsigned line; +}; + +struct radeon_track { + struct radeon_track *next; + struct radeon_track *prev; + unsigned key; + struct radeon_track_event *events; +}; + +struct radeon_tracker { + struct radeon_track tracks; +}; + +void radeon_track_add_event(struct radeon_track *track, + const char *file, + const char *func, + const char *op, + unsigned line); +struct radeon_track *radeon_tracker_add_track(struct radeon_tracker *tracker, + unsigned key); +void radeon_tracker_remove_track(struct radeon_tracker *tracker, + struct radeon_track *track); +void radeon_tracker_print(struct radeon_tracker *tracker, + FILE *file); + +#endif -- cgit v1.2.3 From 080a45624b2b0ac9e0173f5b93760ae018394dd1 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 14 Nov 2008 12:13:53 +0100 Subject: libdrm-radeon: unreference buffer once cs stream is submited or on cs clean BO are referenced once by reloc to make sure that they not destroyed before we get a chance to flush the cmd stream, so we need to unreference them once in cs submit or cs erase if cs i never submitted so bo can be destructed. --- libdrm/radeon/radeon_cs_gem.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/libdrm/radeon/radeon_cs_gem.c b/libdrm/radeon/radeon_cs_gem.c index f9c9fabb..9488f81c 100644 --- a/libdrm/radeon/radeon_cs_gem.c +++ b/libdrm/radeon/radeon_cs_gem.c @@ -251,7 +251,7 @@ static int cs_gem_emit(struct radeon_cs *cs) { struct cs_gem *csg = (struct cs_gem*)cs; uint64_t chunk_array[2]; - int r; + int r, i; chunk_array[0] = (uint64_t)(intptr_t)&csg->chunks[0]; chunk_array[1] = (uint64_t)(intptr_t)&csg->chunks[1]; @@ -261,10 +261,11 @@ static int cs_gem_emit(struct radeon_cs *cs) r = drmCommandWriteRead(cs->csm->fd, DRM_RADEON_CS2, &csg->cs, sizeof(struct drm_radeon_cs2)); - if (r) { - return r; + for (i = 0; i < csg->base.crelocs; i++) { + radeon_bo_unref(csg->relocs_bo[i]); + csg->relocs_bo[i] = NULL; } - return 0; + return r; } static int cs_gem_destroy(struct radeon_cs *cs) @@ -281,7 +282,16 @@ static int cs_gem_destroy(struct radeon_cs *cs) static int cs_gem_erase(struct radeon_cs *cs) { struct cs_gem *csg = (struct cs_gem*)cs; + int i; + if (csg->relocs_bo) { + for (i = 0; i < csg->base.crelocs; i++) { + if (csg->relocs_bo[i]) { + radeon_bo_unref(csg->relocs_bo[i]); + csg->relocs_bo[i] = NULL; + } + } + } cs->relocs_total_size = 0; cs->cdw = 0; cs->section = 0; -- cgit v1.2.3 From 1f6602185455957bde0fac09dcab5215326d49a0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 15 Nov 2008 12:30:09 +1000 Subject: drm/bo: fix stupid lock imbalance --- linux-core/drm_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 9cf23f21..a1a8098e 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -785,8 +785,8 @@ out: } drm_bo_add_to_lru(bo); BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); -out_unlock: mutex_unlock(&dev->struct_mutex); +out_unlock: return ret; } -- cgit v1.2.3 From 5ae79e7edd819b84d9e447a2ab9b995a862ac3a7 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sat, 15 Nov 2008 10:38:44 +0100 Subject: libdrm-radeon: unref return current BO ptr to reflect BO destruction --- libdrm/radeon/radeon_bo.h | 12 ++++++------ libdrm/radeon/radeon_bo_gem.c | 11 ++++++----- libdrm/radeon/radeon_bo_gem.h | 4 ++-- libdrm/radeon/radeon_cs_gem.c | 9 +++++---- libdrm/radeon/radeon_cs_gem.h | 4 ++-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index ed785034..523cf38e 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -63,7 +63,7 @@ struct radeon_bo_funcs { uint32_t domains, uint32_t flags); void (*bo_ref)(struct radeon_bo *bo); - void (*bo_unref)(struct radeon_bo *bo); + struct radeon_bo *(*bo_unref)(struct radeon_bo *bo); int (*bo_map)(struct radeon_bo *bo, int write); int (*bo_unmap)(struct radeon_bo *bo); }; @@ -118,10 +118,10 @@ static inline void _radeon_bo_ref(struct radeon_bo *bo, bo->bom->funcs->bo_ref(bo); } -static inline void _radeon_bo_unref(struct radeon_bo *bo, - const char *file, - const char *func, - int line) +static inline struct radeon_bo *_radeon_bo_unref(struct radeon_bo *bo, + const char *file, + const char *func, + int line) { bo->cref--; #ifdef RADEON_BO_TRACK @@ -131,7 +131,7 @@ static inline void _radeon_bo_unref(struct radeon_bo *bo, bo->track = NULL; } #endif - bo->bom->funcs->bo_unref(bo); + return bo->bom->funcs->bo_unref(bo); } static inline int _radeon_bo_map(struct radeon_bo *bo, diff --git a/libdrm/radeon/radeon_bo_gem.c b/libdrm/radeon/radeon_bo_gem.c index 8ce82919..b6d5b294 100644 --- a/libdrm/radeon/radeon_bo_gem.c +++ b/libdrm/radeon/radeon_bo_gem.c @@ -115,16 +115,16 @@ static void bo_ref(struct radeon_bo *bo) { } -static void bo_unref(struct radeon_bo *bo) +static struct radeon_bo *bo_unref(struct radeon_bo *bo) { struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; struct drm_gem_close args; if (bo == NULL) { - return; + return NULL; } if (bo->cref) { - return; + return bo; } if (bo_gem->map_count) { munmap(bo->ptr, bo->size); @@ -134,6 +134,7 @@ static void bo_unref(struct radeon_bo *bo) args.handle = bo->handle; ioctl(bo->bom->fd, DRM_IOCTL_GEM_CLOSE, &args); free(bo_gem); + return NULL; } static int bo_map(struct radeon_bo *bo, int write) @@ -182,7 +183,7 @@ static struct radeon_bo_funcs bo_gem_funcs = { bo_unmap }; -struct radeon_bo_manager *radeon_bo_manager_gem(int fd) +struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd) { struct bo_manager_gem *bomg; @@ -195,7 +196,7 @@ struct radeon_bo_manager *radeon_bo_manager_gem(int fd) return (struct radeon_bo_manager*)bomg; } -void radeon_bo_manager_gem_shutdown(struct radeon_bo_manager *bom) +void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom) { struct bo_manager_gem *bomg = (struct bo_manager_gem*)bom; diff --git a/libdrm/radeon/radeon_bo_gem.h b/libdrm/radeon/radeon_bo_gem.h index aaefd8c3..c0f68e6d 100644 --- a/libdrm/radeon/radeon_bo_gem.h +++ b/libdrm/radeon/radeon_bo_gem.h @@ -34,7 +34,7 @@ #include "radeon_bo.h" -struct radeon_bo_manager *radeon_bo_manager_gem(int fd); -void radeon_bo_manager_gem_shutdown(struct radeon_bo_manager *bom); +struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd); +void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom); #endif diff --git a/libdrm/radeon/radeon_cs_gem.c b/libdrm/radeon/radeon_cs_gem.c index 9488f81c..91489dff 100644 --- a/libdrm/radeon/radeon_cs_gem.c +++ b/libdrm/radeon/radeon_cs_gem.c @@ -251,7 +251,8 @@ static int cs_gem_emit(struct radeon_cs *cs) { struct cs_gem *csg = (struct cs_gem*)cs; uint64_t chunk_array[2]; - int r, i; + unsigned i; + int r; chunk_array[0] = (uint64_t)(intptr_t)&csg->chunks[0]; chunk_array[1] = (uint64_t)(intptr_t)&csg->chunks[1]; @@ -282,7 +283,7 @@ static int cs_gem_destroy(struct radeon_cs *cs) static int cs_gem_erase(struct radeon_cs *cs) { struct cs_gem *csg = (struct cs_gem*)cs; - int i; + unsigned i; if (csg->relocs_bo) { for (i = 0; i < csg->base.crelocs; i++) { @@ -318,7 +319,7 @@ static struct radeon_cs_funcs radeon_cs_gem_funcs = { cs_gem_need_flush }; -struct radeon_cs_manager *radeon_cs_manager_gem(int fd) +struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd) { struct radeon_cs_manager *csm; @@ -332,7 +333,7 @@ struct radeon_cs_manager *radeon_cs_manager_gem(int fd) return csm; } -void radeon_cs_manager_gem_shutdown(struct radeon_cs_manager *csm) +void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm) { free(csm); } diff --git a/libdrm/radeon/radeon_cs_gem.h b/libdrm/radeon/radeon_cs_gem.h index f50c5e84..5efd146f 100644 --- a/libdrm/radeon/radeon_cs_gem.h +++ b/libdrm/radeon/radeon_cs_gem.h @@ -35,7 +35,7 @@ #include "radeon_cs.h" -struct radeon_cs_manager *radeon_cs_manager_gem(int fd); -void radeon_cs_manager_gem_shutdown(struct radeon_cs_manager *csm); +struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd); +void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm); #endif -- cgit v1.2.3 From c0ba14fd90e7495d5634c1ce0a9fb5be26230010 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 16 Nov 2008 18:04:43 +0100 Subject: libdrm-radeon: add print callback to cs & small fixes --- libdrm/radeon/radeon_bo.h | 6 +-- libdrm/radeon/radeon_bo_gem.c | 3 +- libdrm/radeon/radeon_cs.h | 6 +++ libdrm/radeon/radeon_cs_gem.c | 103 +++++++++++++++++++++++++++++++++++++++++- libdrm/radeon/radeon_track.c | 1 + 5 files changed, 113 insertions(+), 6 deletions(-) diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index 523cf38e..44dc0901 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -75,13 +75,13 @@ struct radeon_bo_manager { }; static inline void _radeon_bo_debug(struct radeon_bo *bo, - int opcode, + const char *op, const char *file, const char *func, int line) { - fprintf(stderr, "%02d %p 0x%08X 0x%08X 0x%08X [%s %s %d]\n", - opcode, bo, bo->handle, bo->size, bo->cref, file, func, line); + fprintf(stderr, "%s %p 0x%08X 0x%08X 0x%08X [%s %s %d]\n", + op, bo, bo->handle, bo->size, bo->cref, file, func, line); } static inline struct radeon_bo *_radeon_bo_open(struct radeon_bo_manager *bom, diff --git a/libdrm/radeon/radeon_bo_gem.c b/libdrm/radeon/radeon_bo_gem.c index b6d5b294..fdf852a2 100644 --- a/libdrm/radeon/radeon_bo_gem.c +++ b/libdrm/radeon/radeon_bo_gem.c @@ -81,7 +81,6 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, open_arg.name = handle; r = ioctl(bom->fd, DRM_IOCTL_GEM_OPEN, &open_arg); if (r != 0) { - fprintf(stderr, "GEM open failed: %d (%s)\n",r,strerror(r)); free(bo); return NULL; } @@ -95,6 +94,7 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, args.alignment = alignment; args.initial_domain = bo->base.domains; args.no_backing_store = 0; + args.handle = 0; r = drmCommandWriteRead(bom->fd, DRM_RADEON_GEM_CREATE, &args, sizeof(args)); bo->base.handle = args.handle; @@ -133,6 +133,7 @@ static struct radeon_bo *bo_unref(struct radeon_bo *bo) /* close object */ args.handle = bo->handle; ioctl(bo->bom->fd, DRM_IOCTL_GEM_CLOSE, &args); + memset(bo_gem, 0, sizeof(struct radeon_bo_gem)); free(bo_gem); return NULL; } diff --git a/libdrm/radeon/radeon_cs.h b/libdrm/radeon/radeon_cs.h index 63f104b6..e76121ea 100644 --- a/libdrm/radeon/radeon_cs.h +++ b/libdrm/radeon/radeon_cs.h @@ -87,6 +87,7 @@ struct radeon_cs_funcs { int (*cs_destroy)(struct radeon_cs *cs); int (*cs_erase)(struct radeon_cs *cs); int (*cs_need_flush)(struct radeon_cs *cs); + void (*cs_print)(struct radeon_cs *cs, FILE *file); }; struct radeon_cs_manager { @@ -159,4 +160,9 @@ static inline int radeon_cs_need_flush(struct radeon_cs *cs) return cs->csm->funcs->cs_need_flush(cs); } +static inline void radeon_cs_print(struct radeon_cs *cs, FILE *file) +{ + cs->csm->funcs->cs_print(cs, file); +} + #endif diff --git a/libdrm/radeon/radeon_cs_gem.c b/libdrm/radeon/radeon_cs_gem.c index 91489dff..319d1b9e 100644 --- a/libdrm/radeon/radeon_cs_gem.c +++ b/libdrm/radeon/radeon_cs_gem.c @@ -254,6 +254,8 @@ static int cs_gem_emit(struct radeon_cs *cs) unsigned i; int r; + csg->chunks[0].length_dw = cs->cdw; + chunk_array[0] = (uint64_t)(intptr_t)&csg->chunks[0]; chunk_array[1] = (uint64_t)(intptr_t)&csg->chunks[1]; @@ -304,7 +306,103 @@ static int cs_gem_erase(struct radeon_cs *cs) static int cs_gem_need_flush(struct radeon_cs *cs) { - return (cs->relocs_total_size > (16*1024*1024)); + return (cs->relocs_total_size > (32*1024*1024)); +} + +#define PACKET_TYPE0 0 +#define PACKET_TYPE1 1 +#define PACKET_TYPE2 2 +#define PACKET_TYPE3 3 + +#define PACKET3_NOP 0x10 +#define PACKET3_SET_SCISSORS 0x1E +#define PACKET3_3D_DRAW_VBUF 0x28 +#define PACKET3_3D_DRAW_IMMD 0x29 +#define PACKET3_3D_DRAW_INDX 0x2A +#define PACKET3_3D_LOAD_VBPNTR 0x2F +#define PACKET3_INDX_BUFFER 0x33 +#define PACKET3_3D_DRAW_VBUF_2 0x34 +#define PACKET3_3D_DRAW_IMMD_2 0x35 +#define PACKET3_3D_DRAW_INDX_2 0x36 + +#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3) +#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF) +#define CP_PACKET0_GET_REG(h) (((h) & 0x1FFF) << 2) +#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) + +static void cs_gem_print(struct radeon_cs *cs, FILE *file) +{ + unsigned opcode; + unsigned reg; + unsigned cnt; + int i, j; + + for (i = 0; i < cs->cdw;) { + cnt = CP_PACKET_GET_COUNT(cs->packets[i]); + switch (CP_PACKET_GET_TYPE(cs->packets[i])) { + case PACKET_TYPE0: + fprintf(file, "Pkt0 at %d (%d dwords):\n", i, cnt + 1); + reg = CP_PACKET0_GET_REG(cs->packets[i]); + if (CP_PACKET0_GET_ONE_REG_WR(cs->packets[i++])) { + for (j = 0; j <= cnt; j++) { + fprintf(file, " 0x%08X -> 0x%04X\n", + cs->packets[i++], reg); + } + } else { + for (j = 0; j <= cnt; j++) { + fprintf(file, " 0x%08X -> 0x%04X\n", + cs->packets[i++], reg); + reg += 4; + } + } + break; + case PACKET_TYPE3: + fprintf(file, "Pkt3 at %d :\n", i); + opcode = CP_PACKET3_GET_OPCODE(cs->packets[i++]); + switch (opcode) { + case PACKET3_NOP: + fprintf(file, " PACKET3_NOP:\n"); + break; + case PACKET3_3D_DRAW_VBUF: + fprintf(file, " PACKET3_3D_DRAW_VBUF:\n"); + break; + case PACKET3_3D_DRAW_IMMD: + fprintf(file, " PACKET3_3D_DRAW_IMMD:\n"); + break; + case PACKET3_3D_DRAW_INDX: + fprintf(file, " PACKET3_3D_DRAW_INDX:\n"); + break; + case PACKET3_3D_LOAD_VBPNTR: + fprintf(file, " PACKET3_3D_LOAD_VBPNTR:\n"); + break; + case PACKET3_INDX_BUFFER: + fprintf(file, " PACKET3_INDX_BUFFER:\n"); + break; + case PACKET3_3D_DRAW_VBUF_2: + fprintf(file, " PACKET3_3D_DRAW_VBUF_2:\n"); + break; + case PACKET3_3D_DRAW_IMMD_2: + fprintf(file, " PACKET3_3D_DRAW_IMMD_2:\n"); + break; + case PACKET3_3D_DRAW_INDX_2: + fprintf(file, " PACKET3_3D_DRAW_INDX_2:\n"); + break; + default: + fprintf(file, "Unknow opcode 0x%02X at %d\n", opcode, i); + return; + } + for (j = 0; j <= cnt; j++) { + fprintf(file, " 0x%08X\n", cs->packets[i++]); + } + break; + case PACKET_TYPE1: + case PACKET_TYPE2: + default: + fprintf(file, "Unknow packet 0x%08X at %d\n", cs->packets[i], i); + return; + } + } } static struct radeon_cs_funcs radeon_cs_gem_funcs = { @@ -316,7 +414,8 @@ static struct radeon_cs_funcs radeon_cs_gem_funcs = { cs_gem_emit, cs_gem_destroy, cs_gem_erase, - cs_gem_need_flush + cs_gem_need_flush, + cs_gem_print }; struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd) diff --git a/libdrm/radeon/radeon_track.c b/libdrm/radeon/radeon_track.c index c0c6f850..1623906f 100644 --- a/libdrm/radeon/radeon_track.c +++ b/libdrm/radeon/radeon_track.c @@ -94,6 +94,7 @@ void radeon_tracker_remove_track(struct radeon_tracker *tracker, if (track->next) { track->next->prev = track->prev; } + track->next = track->prev = NULL; event = track->events; while (event) { tmp = event; -- cgit v1.2.3 From 7270731a8b7ebe11fe6df4f368c2ed613a530b52 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 16 Nov 2008 18:11:00 +0100 Subject: radeon: protect cs ioctl atomic part with a mutex A small subset of CS need to be atomic (relocation+IB commit to ring) right now, because of the way relocation are handled, we need to protect the whole ioctl. --- shared-core/radeon_cs.c | 6 ++++++ shared-core/radeon_drv.h | 1 + 2 files changed, 7 insertions(+) diff --git a/shared-core/radeon_cs.c b/shared-core/radeon_cs.c index 56f6cbac..9227a011 100644 --- a/shared-core/radeon_cs.c +++ b/shared-core/radeon_cs.c @@ -41,21 +41,25 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) long size; int r, i; + mutex_lock(&dev_priv->cs.cs_mutex); /* set command stream id to 0 which is fake id */ cs_id = 0; cs->cs_id = cs_id; if (dev_priv == NULL) { DRM_ERROR("called with no initialization\n"); + mutex_unlock(&dev_priv->cs.cs_mutex); return -EINVAL; } if (!cs->num_chunks) { + mutex_unlock(&dev_priv->cs.cs_mutex); return 0; } chunk_array = drm_calloc(cs->num_chunks, sizeof(uint64_t), DRM_MEM_DRIVER); if (!chunk_array) { + mutex_unlock(&dev_priv->cs.cs_mutex); return -ENOMEM; } @@ -161,6 +165,7 @@ int radeon_cs2_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) out: dev_priv->cs.ib_free(&parser); + mutex_unlock(&dev_priv->cs.cs_mutex); for (i = 0; i < parser.num_chunks; i++) { if (parser.chunks[i].kdata) @@ -646,6 +651,7 @@ int radeon_cs_init(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; + mutex_init(&dev_priv->cs.cs_mutex); if (dev_priv->chip_family < CHIP_RV280) { dev_priv->cs.id_emit = r100_cs_id_emit; dev_priv->cs.id_last_get = r100_cs_id_last_get; diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index cf3084e1..fdf321d1 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -316,6 +316,7 @@ struct drm_radeon_cs_parser { /* command submission struct */ struct drm_radeon_cs_priv { + struct mutex cs_mutex; uint32_t id_wcnt; uint32_t id_scnt; uint32_t id_last_wcnt; -- cgit v1.2.3 From f46aba43329786c9b2776e82af31d90e1c67eae0 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 16 Nov 2008 18:13:16 +0100 Subject: gem: protect idr_pre with the spinlock There seems to be an issue if we don't protect idr_pre with the spinlock we use for idr operations. --- linux-core/drm_gem.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 607c8b67..0078929a 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -175,12 +175,11 @@ drm_gem_handle_create(struct drm_file *file_priv, * Get the user-visible handle using idr. */ again: + /* do the allocation under our spinlock */ + spin_lock(&file_priv->table_lock); /* ensure there is space available to allocate a handle */ if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) return -ENOMEM; - - /* do the allocation under our spinlock */ - spin_lock(&file_priv->table_lock); ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep); spin_unlock(&file_priv->table_lock); if (ret == -EAGAIN) @@ -258,10 +257,9 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data, return -EINVAL; again: + spin_lock(&dev->object_name_lock); if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) return -ENOMEM; - - spin_lock(&dev->object_name_lock); if (obj->name) { args->name = (uint64_t) obj->name; spin_unlock(&dev->object_name_lock); -- cgit v1.2.3 From e98eda91593b7c0a7494475be8cfd8cb4740f8ec Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 17 Nov 2008 13:35:51 +0100 Subject: Revert "gem: protect idr_pre with the spinlock" This reverts commit f46aba43329786c9b2776e82af31d90e1c67eae0. --- linux-core/drm_gem.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 0078929a..607c8b67 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -175,11 +175,12 @@ drm_gem_handle_create(struct drm_file *file_priv, * Get the user-visible handle using idr. */ again: - /* do the allocation under our spinlock */ - spin_lock(&file_priv->table_lock); /* ensure there is space available to allocate a handle */ if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) return -ENOMEM; + + /* do the allocation under our spinlock */ + spin_lock(&file_priv->table_lock); ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep); spin_unlock(&file_priv->table_lock); if (ret == -EAGAIN) @@ -257,9 +258,10 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data, return -EINVAL; again: - spin_lock(&dev->object_name_lock); if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) return -ENOMEM; + + spin_lock(&dev->object_name_lock); if (obj->name) { args->name = (uint64_t) obj->name; spin_unlock(&dev->object_name_lock); -- cgit v1.2.3 From 8f5d8ba97e82072b2403bff0bf836a09640108a6 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 19 Nov 2008 10:54:11 -0800 Subject: Update modetest --- tests/modetest/Makefile | 14 ++ tests/modetest/modetest.c | 410 ++++++++++++++++++++++++++++++++++++++++++++++ tests/modetest/test | 2 + 3 files changed, 426 insertions(+) create mode 100644 tests/modetest/Makefile create mode 100644 tests/modetest/modetest.c create mode 100755 tests/modetest/test diff --git a/tests/modetest/Makefile b/tests/modetest/Makefile new file mode 100644 index 00000000..8583ae82 --- /dev/null +++ b/tests/modetest/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: modetest.c + gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../libdrm/intel -I../../shared-core -L../../libdrm/.libs -L../../libdrm/intel/.libs -ldrm -ldrm_intel modetest.c + +clean: + @rm -f app + +run: app + sudo ./test diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c new file mode 100644 index 00000000..66c7f9cd --- /dev/null +++ b/tests/modetest/modetest.c @@ -0,0 +1,410 @@ +/* + * DRM based mode setting test program + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + */ +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "intel_bufmgr.h" + +drmModeRes *resources; +int fd, modes; + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct type_name { + int type; + char *name; +}; + +#define type_name_fn(res) \ +char * res##_str(int type) { \ + int i; \ + for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ + if (res##_names[i].type == type) \ + return res##_names[i].name; \ + } \ + return "(invalid)"; \ +} + +struct type_name encoder_type_names[] = { + { DRM_MODE_ENCODER_NONE, "none" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, +}; + +type_name_fn(encoder_type) + +struct type_name connector_status_names[] = { + { DRM_MODE_CONNECTED, "connected" }, + { DRM_MODE_DISCONNECTED, "disconnected" }, + { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, +}; + +type_name_fn(connector_status) + +struct type_name connector_type_names[] = { + { DRM_MODE_CONNECTOR_Unknown, "unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, +}; + +type_name_fn(connector_type) + +void dump_encoders(void) +{ + drmModeEncoder *encoder; + int i; + + printf("Encoders:\n"); + printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); + for (i = 0; i < resources->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + continue; + } + printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", + encoder->encoder_id, + encoder->crtc_id, + encoder_type_str(encoder->encoder_type), + encoder->possible_crtcs, + encoder->possible_clones); + drmModeFreeEncoder(encoder); + } +} + +void dump_connectors(void) +{ + drmModeConnector *connector; + int i, j; + + printf("Connectors:\n"); + printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n"); + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + continue; + } + + printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n", + connector->connector_id, + connector->encoder_id, + connector_status_str(connector->connection), + connector_type_str(connector->connector_type), + connector->mmWidth, connector->mmHeight, + connector->count_modes); + + if (!connector->count_modes) + continue; + + printf(" modes:\n"); + printf(" name refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot)\n"); + for (j = 0; j < connector->count_modes; j++) { + struct drm_mode_modeinfo *mode; + + mode = &connector->modes[j]; + printf(" %s %.02f %d %d %d %d %d %d %d %d\n", + mode->name, + (float)mode->vrefresh / 1000, + mode->hdisplay, + mode->hsync_start, + mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, + mode->vsync_end, + mode->vtotal); + } + drmModeFreeConnector(connector); + } +} + +void dump_crtcs(void) +{ + drmModeCrtc *crtc; + int i; + + for (i = 0; i < resources->count_crtcs; i++) { + crtc = drmModeGetCrtc(fd, resources->crtcs[i]); + + if (!crtc) { + fprintf(stderr, "could not get crtc %i: %s\n", + resources->crtcs[i], strerror(errno)); + continue; + } + drmModeFreeCrtc(crtc); + } +} + +void dump_framebuffers(void) +{ + drmModeFB *fb; + int i; + + for (i = 0; i < resources->count_fbs; i++) { + fb = drmModeGetFB(fd, resources->fbs[i]); + + if (!fb) { + fprintf(stderr, "could not get fb %i: %s\n", + resources->fbs[i], strerror(errno)); + continue; + } + drmModeFreeFB(fb); + } +} + +void set_mode(int connector_id, char *mode_str) +{ + drmModeConnector *connector; + drmModeEncoder *encoder = NULL; + struct drm_mode_modeinfo *mode = NULL; + drm_intel_bufmgr *bufmgr; + drm_intel_bo *bo; + unsigned int fb_id, *fb_ptr; + int i, j, size, ret, width, height; + + /* First, find the connector & mode */ + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + drmModeFreeConnector(connector); + continue; + } + + if (!connector->count_modes) { + drmModeFreeConnector(connector); + continue; + } + + if (connector->connector_id != connector_id) { + drmModeFreeConnector(connector); + continue; + } + + for (j = 0; j < connector->count_modes; j++) { + mode = &connector->modes[j]; + if (!strcmp(mode->name, mode_str)) + break; + } + + /* Found it, break out */ + if (mode) + break; + + drmModeFreeConnector(connector); + } + + if (!mode) { + fprintf(stderr, "failed to find mode \"%s\"\n", mode_str); + return; + } + + width = mode->hdisplay; + height = mode->vdisplay; + + /* Now get the encoder */ + for (i = 0; i < resources->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + drmModeFreeEncoder(encoder); + continue; + } + + if (encoder->encoder_id == connector->encoder_id) + break; + + drmModeFreeEncoder(encoder); + } + + bufmgr = drm_intel_bufmgr_gem_init(fd, 2<<20); + if (!bufmgr) { + fprintf(stderr, "failed to init bufmgr: %s\n", strerror(errno)); + return; + } + + /* Mode size at 32 bpp */ + size = width * height * 4; + + bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096); + if (!bo) { + fprintf(stderr, "failed to alloc buffer: %s\n", + strerror(errno)); + return; + } + + ret = drm_intel_bo_pin(bo, 4096); + if (ret) { + fprintf(stderr, "failed to pin buffer: %s\n", strerror(errno)); + return; + } + + ret = drm_intel_gem_bo_map_gtt(bo); + if (ret) { + fprintf(stderr, "failed to GTT map buffer: %s\n", + strerror(errno)); + return; + } + + fb_ptr = bo->virtual; + + /* paint the buffer blue */ + for (i = 0; i < width * height; i++) + fb_ptr[i] = 0xff; + + ret = drmModeAddFB(fd, width, height, 32, 32, width * 4, bo->handle, + &fb_id); + if (ret) { + fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); + return; + } + + ret = drmModeSetCrtc(fd, encoder->crtc_id, fb_id, 0, 0, + &connector->connector_id, 1, mode); + if (ret) { + fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); + return; + } +} + +extern char *optarg; +extern int optind, opterr, optopt; +static char optstr[] = "ecpmfs:"; + +void usage(char *name) +{ + fprintf(stderr, "usage: %s [-ecpmf]\n", name); + fprintf(stderr, "\t-e\tlist encoders\n"); + fprintf(stderr, "\t-c\tlist connectors\n"); + fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); + fprintf(stderr, "\t-m\tlist modes\n"); + fprintf(stderr, "\t-f\tlist framebuffers\n"); + fprintf(stderr, "\t-s :\tset a mode\n"); + fprintf(stderr, "\n\tDefault is to dump all info.\n"); + exit(0); +} + +#define dump_resource(res) if (res) dump_##res() + +int main(int argc, char **argv) +{ + int c; + int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; + char *modules[] = { "i915", "radeon" }; + char *modeset = NULL, *mode, *connector; + int i, connector_id; + + opterr = 0; + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'e': + encoders = 1; + break; + case 'c': + connectors = 1; + break; + case 'p': + crtcs = 1; + break; + case 'm': + modes = 1; + break; + case 'f': + framebuffers = 1; + break; + case 's': + modeset = strdup(optarg); + break; + default: + usage(argv[0]); + break; + } + } + + if (argc == 1) + encoders = connectors = crtcs = modes = framebuffers = 1; + + for (i = 0; i < ARRAY_SIZE(modules); i++) { + printf("trying to load module %s...", modules[i]); + fd = drmOpen(modules[i], NULL); + if (fd < 0) { + printf("failed.\n"); + } else { + printf("success.\n"); + break; + } + } + + if (i == ARRAY_SIZE(modules)) { + fprintf(stderr, "failed to load any modules, aborting.\n"); + return -1; + } + + resources = drmModeGetResources(fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + drmClose(fd); + return 1; + } + + dump_resource(encoders); + dump_resource(connectors); + dump_resource(crtcs); + dump_resource(framebuffers); + + if (modeset) { + connector = strtok(modeset, ":"); + if (!connector) + usage(argv[0]); + connector_id = atoi(connector); + + mode = strtok(NULL, ":"); + if (!mode) + usage(argv[0]); + printf("setting connector %d to mode %s\n", connector_id, + mode); + set_mode(connector_id, mode); + sleep(3); + } + + sleep(3); + + drmModeFreeResources(resources); + + return 0; +} diff --git a/tests/modetest/test b/tests/modetest/test new file mode 100755 index 00000000..5bb552ef --- /dev/null +++ b/tests/modetest/test @@ -0,0 +1,2 @@ +export LD_LIBRARY_PATH=../../libdrm/.libs:../../libdrm/intel/.libs +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app $@ -- cgit v1.2.3 From 60c1e3a09e33bfaec893c1d4780553b9b344293a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 19 Nov 2008 10:56:48 -0800 Subject: libdrm_intel: fix merge error don't take the lock twice --- libdrm/intel/intel_bufmgr_gem.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 8b8cda62..64d32d38 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -809,8 +809,6 @@ drm_intel_gem_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, pthread_mutex_lock(&bufmgr_gem->lock); - pthread_mutex_lock(&bufmgr_gem->lock); - /* Create a new relocation list if needed */ if (bo_gem->relocs == NULL) drm_intel_setup_reloc_list(bo); -- cgit v1.2.3 From 5923831bafca3cf2358ffc7f8b0079ab4de9da5c Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 20 Nov 2008 10:57:33 -0800 Subject: DRM: make drm_map_type match kernel GEM is upstream, but TTM isn't, so _DRM_GEM needs to be 6, not 7. --- shared-core/drm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index 08882b76..218a469d 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -236,8 +236,8 @@ enum drm_map_type { _DRM_AGP = 3, /**< AGP/GART */ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ - _DRM_TTM = 6, - _DRM_GEM = 7, + _DRM_GEM = 6, + _DRM_TTM = 7, }; /** -- cgit v1.2.3