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 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 linux-core/radeon_buffer.c create mode 100644 linux-core/radeon_fence.c (limited to 'linux-core') 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; +} -- 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 +++------ 2 files changed, 13 insertions(+), 19 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 (limited to 'linux-core') 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 ++++++++++++ 15 files changed, 4801 insertions(+), 2 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 (limited to 'linux-core') 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 + -- 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 --- 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 ++- 5 files changed, 155 insertions(+), 13 deletions(-) (limited to 'linux-core') 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; } -- 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. --- linux-core/drm_crtc.c | 218 +++++++++++++++++++++++++++++++++++++++++--------- linux-core/drm_crtc.h | 12 ++- linux-core/drm_drv.c | 4 +- 3 files changed, 192 insertions(+), 42 deletions(-) (limited to 'linux-core') 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 ) -- 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. --- linux-core/drm_crtc.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 4 +- linux-core/drm_drv.c | 1 + 3 files changed, 127 insertions(+), 6 deletions(-) (limited to 'linux-core') 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 ) -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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. --- linux-core/drm_crtc.c | 95 ++++++++++++++++++++++++++++++++++++++++++++------- linux-core/drm_crtc.h | 27 ++++++++------- linux-core/drm_drv.c | 2 ++ 3 files changed, 99 insertions(+), 25 deletions(-) (limited to 'linux-core') 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 ) -- 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(-) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 14 ++++++++------ linux-core/intel_display.c | 7 ++++++- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 101 ++++++++++++++++++++++++++++++++++--------------- linux-core/drm_crtc.h | 6 +-- linux-core/drm_modes.c | 4 +- 3 files changed, 76 insertions(+), 35 deletions(-) (limited to 'linux-core') 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, -- 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 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core') 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); -- 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 --- linux-core/drm_crtc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 + 1 file changed, 1 insertion(+) create mode 120000 linux-core/i915_init.c (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) (limited to 'linux-core') 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; } + -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 linux-core/drm_fb.c (limited to 'linux-core') 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"); -- 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(+) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +++++++++++++++++---- 5 files changed, 47 insertions(+), 31 deletions(-) (limited to 'linux-core') 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. -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core') 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 = { -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'linux-core') 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); } -- 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 --- linux-core/drm_crtc.c | 30 ++++++++++++++++++++++++++++++ linux-core/drm_crtc.h | 2 ++ linux-core/drm_drv.c | 1 + 3 files changed, 33 insertions(+) (limited to 'linux-core') 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 ) -- 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 --- linux-core/drm_crtc.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'linux-core') 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, -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 - 4 files changed, 16 insertions(+), 19 deletions(-) (limited to 'linux-core') 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, -- 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(-) (limited to 'linux-core') 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 + 1 file changed, 1 insertion(+) (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +++++++------ 8 files changed, 46 insertions(+), 20 deletions(-) (limited to 'linux-core') 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 */ -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 +-- 2 files changed, 53 insertions(+), 23 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'linux-core') 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"); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +++++++------------ 2 files changed, 62 insertions(+), 14 deletions(-) (limited to 'linux-core') 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: -- 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(-) (limited to 'linux-core') 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 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'linux-core') 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) -- 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(-) (limited to 'linux-core') 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 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'linux-core') 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); } -- 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(-) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++++- linux-core/drm_crtc.h | 19 +++- linux-core/drm_drv.c | 4 + 3 files changed, 276 insertions(+), 4 deletions(-) (limited to 'linux-core') 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 ) -- 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(+) (limited to 'linux-core') 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 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 --- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 381 insertions(+), 16 deletions(-) create mode 100644 linux-core/intel_fb.c (limited to 'linux-core') 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"); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'linux-core') 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); -- 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 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) (limited to 'linux-core') 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, -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +- 3 files changed, 65 insertions(+), 9 deletions(-) (limited to 'linux-core') 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) -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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); -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 -------- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'linux-core') 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) -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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. --- linux-core/drm_crtc.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 34 +++++++++ linux-core/drm_drv.c | 1 + 3 files changed, 236 insertions(+), 6 deletions(-) (limited to 'linux-core') 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), -- 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(-) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 270 +++++++++++++++++++++++--------------------------- 1 file changed, 123 insertions(+), 147 deletions(-) (limited to 'linux-core') 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); -- 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 --- linux-core/drm_crtc.c | 202 ++++++++++---------------------------------------- linux-core/drm_crtc.h | 7 +- linux-core/drm_drv.c | 3 +- linux-core/intel_fb.c | 2 - 4 files changed, 41 insertions(+), 173 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 + 24 files changed, 671 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 (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 163 ++++++++++++++++++++++++++++++++++++------------- linux-core/drm_crtc.h | 23 +++++-- linux-core/intel_crt.c | 2 + 3 files changed, 140 insertions(+), 48 deletions(-) (limited to 'linux-core') 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); } -- 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. --- linux-core/drm_crtc.c | 67 ++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'linux-core') 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; -- 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 --- 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 + 5 files changed, 76 insertions(+), 10 deletions(-) (limited to 'linux-core') 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); } -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 10 deletions(-) (limited to 'linux-core') 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; } -- 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(-) (limited to 'linux-core') 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 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 --- linux-core/drm_crtc.c | 59 +++++++++++++++++++++++++++++++++++++++++++++------ linux-core/drm_crtc.h | 5 +++-- 2 files changed, 55 insertions(+), 9 deletions(-) (limited to 'linux-core') 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, -- 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 --- 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 ++++ 6 files changed, 133 insertions(+), 15 deletions(-) (limited to 'linux-core') 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); } -- 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 ++++++++++++++++++++++++++++++++++++++++++++++--- 11 files changed, 208 insertions(+), 14 deletions(-) (limited to 'linux-core') 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) { -- 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 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'linux-core') 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; -- 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 --- 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 +++++++++------------- 7 files changed, 53 insertions(+), 72 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 +++++----- 15 files changed, 116 insertions(+), 111 deletions(-) (limited to 'linux-core') 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; } } -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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 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 ++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 24 deletions(-) (limited to 'linux-core') 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); } -- 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 + 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'linux-core') 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, -- 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(-) (limited to 'linux-core') 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 + 7 files changed, 8 insertions(+), 1 deletion(-) 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 (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 --- 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 ++++++++--- 6 files changed, 208 insertions(+), 7 deletions(-) (limited to 'linux-core') 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; } -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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 +- 3 files changed, 34 insertions(+), 4 deletions(-) (limited to 'linux-core') 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), -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1819 insertions(+), 10 deletions(-) create mode 100644 linux-core/intel_tv.c (limited to 'linux-core') 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; +} -- 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 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core') 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; -- 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 ++++-- 2 files changed, 24 insertions(+), 12 deletions(-) (limited to 'linux-core') 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, -- 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 +-- 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 --- linux-core/drm_bo.c | 37 +++++++++++++++++++++++++++++++++++++ linux-core/drm_drv.c | 2 ++ linux-core/drm_objects.h | 2 ++ 3 files changed, 41 insertions(+) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 --------------------- 6 files changed, 13 insertions(+), 613 deletions(-) delete mode 100644 linux-core/radeon_buffer.c delete mode 100644 linux-core/radeon_fence.c (limited to 'linux-core') 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; -} -- 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 ++++++++-- 6 files changed, 24 insertions(+), 7 deletions(-) (limited to 'linux-core') 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); } -- 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 +++-- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'linux-core') 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, -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'linux-core') 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; } -- 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 +- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'linux-core') 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]; }; -- 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 ---- 7 files changed, 182 insertions(+), 53 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 --- linux-core/drmP.h | 4 ++++ linux-core/drm_drv.c | 3 +++ linux-core/drm_stub.c | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+) (limited to 'linux-core') 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; -- 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 + 1 file changed, 1 insertion(+) create mode 120000 linux-core/amd_legacy_fence.h (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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 + 1 file changed, 1 insertion(+) (limited to 'linux-core') 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); } -- 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 + 1 file changed, 1 insertion(+) create mode 120000 linux-core/amd_cbuffer.h (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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 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 ++++++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 20 deletions(-) create mode 120000 linux-core/amd.h (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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 + 4 files changed, 4 insertions(+), 2 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 (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 2575 insertions(+), 2 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 (limited to 'linux-core') 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); +} -- 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(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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 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 + 1 file changed, 1 insertion(+) (limited to 'linux-core') 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" -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++-- linux-core/drm_crtc.h | 3 ++- linux-core/drm_drv.c | 2 ++ 3 files changed, 57 insertions(+), 3 deletions(-) (limited to 'linux-core') 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, -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +- 6 files changed, 54 insertions(+), 45 deletions(-) (limited to 'linux-core') 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; -- 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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; -- 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 ++++++++++++++++++++++++++++++++++ 3 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 linux-core/intel_bios.c create mode 100644 linux-core/intel_bios.h (limited to 'linux-core') 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_ */ -- 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(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 +++++++++++++++++++++++----------------------- 2 files changed, 24 insertions(+), 24 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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 +- 5 files changed, 5 insertions(+), 7 deletions(-) (limited to 'linux-core') 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; -- 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 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'linux-core') 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) { -- 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 +++++++------- 5 files changed, 62 insertions(+), 81 deletions(-) (limited to 'linux-core') 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; } -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +- 5 files changed, 444 insertions(+), 244 deletions(-) (limited to 'linux-core') 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; /* -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +- 13 files changed, 680 insertions(+), 532 deletions(-) create mode 100644 linux-core/drm_crtc_helper.c create mode 100644 linux-core/drm_crtc_helper.h (limited to 'linux-core') 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; -- 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 +++++++++++----------- 10 files changed, 179 insertions(+), 213 deletions(-) (limited to 'linux-core') 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; -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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 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 ++-- 5 files changed, 38 insertions(+), 15 deletions(-) (limited to 'linux-core') 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) -- 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 --- 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 +++++++------- 24 files changed, 1146 insertions(+), 1127 deletions(-) (limited to 'linux-core') 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); } -- 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 --- 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 +++++++++++++++-- 5 files changed, 42 insertions(+), 16 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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 +++++++++---------- 12 files changed, 272 insertions(+), 249 deletions(-) (limited to 'linux-core') 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; -- 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 --- linux-core/drm_crtc.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 --- 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 +-- 8 files changed, 158 insertions(+), 15 deletions(-) (limited to 'linux-core') 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: -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 --- linux-core/drm_crtc.c | 6 +++++- linux-core/drm_crtc.h | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++++++++++++++++++++------------------- 7 files changed, 328 insertions(+), 243 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'linux-core') 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, -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 +++++++++++++++++++++++++++------------------- 5 files changed, 102 insertions(+), 76 deletions(-) (limited to 'linux-core') 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; -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 ++++++++ 30 files changed, 5038 insertions(+), 14 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 (limited to 'linux-core') 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; +} -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 + 4 files changed, 25 insertions(+), 5 deletions(-) (limited to 'linux-core') 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); -- 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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"); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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. --- linux-core/drm_crtc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'linux-core') 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 ++-- 9 files changed, 28 insertions(+), 28 deletions(-) (limited to 'linux-core') 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) { -- 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 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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 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 +- 5 files changed, 653 insertions(+), 5 deletions(-) create mode 100644 linux-core/nv50_fbcon.c create mode 100644 linux-core/nv50_fbcon.h (limited to 'linux-core') 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; } -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++++-------- 3 files changed, 26 insertions(+), 26 deletions(-) (limited to 'linux-core') 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; -- 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. --- linux-core/drm_crtc.c | 5 ----- linux-core/drm_crtc.h | 3 --- 2 files changed, 8 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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 ++--------------------------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) (limited to 'linux-core') 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, -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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. --- linux-core/drm_crtc.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++-- 14 files changed, 54 insertions(+), 54 deletions(-) (limited to 'linux-core') 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); -- 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 +- 16 files changed, 55 insertions(+), 55 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) (limited to 'linux-core') 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. -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 ++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 205 insertions(+), 9 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++++++++++++++++++++++++++++++++++++ 34 files changed, 17797 insertions(+), 84 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 (limited to 'linux-core') 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)< 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(-) (limited to 'linux-core') 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 + 4 files changed, 194 insertions(+), 24 deletions(-) create mode 120000 linux-core/radeon_cs.c (limited to 'linux-core') 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) -- 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 + 1 file changed, 1 insertion(+) (limited to 'linux-core') 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 -- 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 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'linux-core') 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: -- 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 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'linux-core') 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) { -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +- 15 files changed, 188 insertions(+), 3259 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 (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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 --- linux-core/drm_bo.c | 5 ++--- linux-core/drm_objects.h | 17 ----------------- linux-core/drm_vm.c | 6 ------ 3 files changed, 2 insertions(+), 26 deletions(-) (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +++++++++- 7 files changed, 1376 insertions(+), 127 deletions(-) create mode 100644 linux-core/radeon_legacy_crtc.c create mode 100644 linux-core/radeon_legacy_encoders.c (limited to 'linux-core') 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 -- 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(+) (limited to 'linux-core') 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 ++++++ 1 file changed, 6 insertions(+) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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 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 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 260 insertions(+), 4 deletions(-) (limited to 'linux-core') 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); +} -- 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 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'linux-core') 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; + +} -- 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 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'linux-core') 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, -- 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 - 1 file changed, 1 deletion(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 + 6 files changed, 1378 insertions(+), 522 deletions(-) (limited to 'linux-core') 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) -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++++++++++++++- 2 files changed, 82 insertions(+), 30 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 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 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++ 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'linux-core') 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"); -- 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 ------------------------------------------------- 2 files changed, 92 deletions(-) (limited to 'linux-core') 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 }; /** -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 + 8 files changed, 393 insertions(+), 21 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 37 deletions(-) (limited to 'linux-core') 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 */ -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 287 insertions(+), 38 deletions(-) create mode 100644 linux-core/radeon_pm.c (limited to 'linux-core') 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; +} -- 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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,*/ -- 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(-) (limited to 'linux-core') 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 - 1 file changed, 1 deletion(-) (limited to 'linux-core') 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) -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 2 deletions(-) (limited to 'linux-core') 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) -- 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 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'linux-core') 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); + } } -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 --- 1 file changed, 3 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 ++++--- 6 files changed, 231 insertions(+), 90 deletions(-) (limited to 'linux-core') 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, -- 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 +++++++++++++++ 2 files changed, 78 insertions(+) (limited to 'linux-core') 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 */ -- 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'linux-core') 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); -- 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 + 1 file changed, 1 insertion(+) create mode 120000 linux-core/drm_mode.h (limited to 'linux-core') 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 -- 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(-) (limited to 'linux-core') 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 + 6 files changed, 38 insertions(+), 14 deletions(-) (limited to 'linux-core') 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, -- 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(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 +++++ 1 file changed, 5 insertions(+) (limited to 'linux-core') 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; -- 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 --- linux-core/drm_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core') 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; } -- 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(-) (limited to 'linux-core') 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 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 -- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'linux-core') 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) -- 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(+) (limited to 'linux-core') 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 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'linux-core') 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 -- 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 +++ 2 files changed, 5 insertions(+) (limited to 'linux-core') 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 | -- 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(-) (limited to 'linux-core') 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 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'linux-core') 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; -- 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 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ------------------------------------------------- 1 file changed, 75 deletions(-) (limited to 'linux-core') 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 -- 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 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'linux-core') 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 -- 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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; -- 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 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 linux-core/radeon_gem_proc.c (limited to 'linux-core') 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); +} -- 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(-) (limited to 'linux-core') 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 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'linux-core') 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); } -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 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 ++++++ 1 file changed, 6 insertions(+) (limited to 'linux-core') 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); -- 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(-) (limited to 'linux-core') 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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"); -- 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 --- linux-core/drm_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core') 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 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(+) (limited to 'linux-core') 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 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 (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(+) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'linux-core') 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); -- 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) --- linux-core/radeon_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core') 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 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 --- linux-core/drm_crtc.c | 10 ---------- linux-core/drm_drv.c | 2 -- linux-core/drm_irq.c | 52 --------------------------------------------------- 3 files changed, 64 deletions(-) (limited to 'linux-core') 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) -- 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 --- linux-core/drm_crtc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core') 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; -- 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(-) (limited to 'linux-core') 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 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(-) (limited to 'linux-core') 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(-) (limited to 'linux-core') 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