diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 640339e..fdc60ea 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -30,6 +30,7 @@ #ifdef CONFIG_X86_PAT int __read_mostly pat_enabled = 1; +EXPORT_SYMBOL_GPL(pat_enabled); void __cpuinit pat_disable(char *reason) { diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3a22eb9..a74980b 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -35,6 +35,9 @@ config DRM_R128 config DRM_RADEON tristate "ATI Radeon" + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT depends on DRM && PCI help Choose this option if you have an ATI Radeon graphics card. There @@ -43,6 +46,14 @@ config DRM_RADEON If M is selected, the module will be called radeon. +config DRM_RADEON_KMS + bool "Enable modesetting on radeon by default" + depends on DRM_RADEON + help + Choose this option if you want kernel modesetting enabled by default, + and you have a new enough userspace to support this. Running old + userspaces with this enabled will cause pain. + config DRM_I810 tristate "Intel I810" depends on DRM && AGP && AGP_INTEL diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 4ec5061..d6788df 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -11,7 +11,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \ drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o \ - drm_info.o drm_debugfs.o + drm_info.o drm_debugfs.o \ + drm_fence.o drm_bo.o drm_ttm.o drm_bo_move.o drm_page_alloc.o drm-$(CONFIG_COMPAT) += drm_ioc32.o diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index 628eae3..e7dc671 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -34,9 +34,67 @@ #include "drmP.h" # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ +# define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1)) -static int drm_ati_alloc_pcigart_table(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) +#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, volatile u32 *pci_gart, int gart_idx) +{ + struct drm_local_map *map = &gart_info->mapping; + 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; + } + if ((gart_info->gart_table_location == DRM_ATI_GART_MAIN) || (map->handle == NULL)) + pci_gart[gart_idx] = cpu_to_le32(page_base); + else + DRM_WRITE32(map, gart_idx * sizeof(u32), page_base); +} + +static __inline__ dma_addr_t gart_get_page_from_table(struct drm_ati_pcigart_info *gart_info, volatile u32 *pci_gart, int gart_idx) +{ + struct drm_local_map *map = &gart_info->mapping; + u32 page_base; + dma_addr_t retval; + + if ((gart_info->gart_table_location == DRM_ATI_GART_MAIN) || (map->handle == NULL)) + page_base = le32_to_cpu(pci_gart[gart_idx]); + else + page_base = DRM_READ32(map, gart_idx * sizeof(u32)); + + switch(gart_info->gart_reg_if) { + case DRM_ATI_GART_IGP: + retval = (page_base & ATI_PCIGART_PAGE_MASK); + retval += (((page_base & 0xf0) >> 4) << 16) << 16; + break; + case DRM_ATI_GART_PCIE: + retval = (page_base & ~0xc); + retval <<= 8; + break; + case DRM_ATI_GART_PCI: + retval = page_base; + 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, @@ -44,12 +102,25 @@ static 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((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); 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) { +#ifdef CONFIG_X86 + /* IGPs only exist on x86 in any case */ + if (gart_info->gart_reg_if == DRM_ATI_GART_IGP) + 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; } @@ -63,7 +134,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; } @@ -99,17 +169,13 @@ 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 = NULL, page_base, gart_idx; + u32 *pci_gart = NULL, gart_idx; dma_addr_t bus_address = 0; int i, j, ret = 0; int max_ati_pages, max_real_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); @@ -117,16 +183,20 @@ 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) { pci_gart = gart_info->table_handle->vaddr; 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 %08LX mapped at %08lX\n", - (unsigned long long)bus_address, - (unsigned long)address); + } + + if (!entry) { + DRM_ERROR("no scatter/gather memory!\n"); + goto done; } @@ -153,39 +223,19 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga bus_address = 0; goto done; } - page_base = (u32) entry->busaddr[i]; + entry_addr = entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { - u32 val; - switch(gart_info->gart_reg_if) { - case DRM_ATI_GART_IGP: - val = page_base | 0xc; - break; - case DRM_ATI_GART_PCIE: - val = (page_base >> 8) | 0xc; - break; - default: - case DRM_ATI_GART_PCI: - val = page_base; - break; - } - if (gart_info->gart_table_location == - DRM_ATI_GART_MAIN) - pci_gart[gart_idx] = cpu_to_le32(val); - else - DRM_WRITE32(map, gart_idx * sizeof(u32), val); + gart_insert_page_into_table(gart_info, entry_addr, pci_gart, gart_idx); gart_idx++; - page_base += ATI_PCIGART_PAGE_SIZE; + entry_addr += ATI_PCIGART_PAGE_SIZE; } } + ret = 1; -#if defined(__i386__) || defined(__x86_64__) - wbinvd(); -#else mb(); -#endif done: gart_info->addr = address; @@ -193,3 +243,146 @@ 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; + volatile u32 *pci_gart; + dma_addr_t offset = bo_mem->mm_node->start; + dma_addr_t page_base; + + pci_gart = info->addr; + +#if 0 + j = offset; + while (j < (offset + atipci_be->num_pages)) { + if (gart_get_page_from_table(info, pci_gart, j)) + return -EBUSY; + j++; + } +#endif + 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); + } + + mb(); + 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; + volatile u32 *pci_gart = info->addr; + + if (atipci_be->bound != 1) + return -EINVAL; + + for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) { + if (info->gart_table_location == DRM_ATI_GART_MAIN || info->mapping.handle == NULL) + pci_gart[j] = 0; + else + DRM_WRITE32(&info->mapping, j * sizeof(u32), 0); + } + + mb(); + 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/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index 1479659..851f4c3 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -497,6 +497,177 @@ drm_agp_bind_pages(struct drm_device *dev, } EXPORT_SYMBOL(drm_agp_bind_pages); +/* + * AGP ttm backend interface. + */ + +#ifndef AGP_USER_TYPES +#define AGP_USER_TYPES (1 << 16) +#define AGP_USER_MEMORY (AGP_USER_TYPES) +#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1) +#endif +#define AGP_REQUIRED_MAJOR 0 +#define AGP_REQUIRED_MINOR 102 + +static int drm_agp_needs_unbind_cache_adjust(struct drm_ttm_backend *backend) +{ + return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); +} + + +static int drm_agp_populate(struct drm_ttm_backend *backend, + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page) +{ + struct drm_agp_ttm_backend *agp_be = + container_of(backend, struct drm_agp_ttm_backend, backend); + struct page **cur_page, **last_page = pages + num_pages; + DRM_AGP_MEM *mem; + int dummy_page_count = 0; + + if (drm_alloc_memctl(num_pages * sizeof(void *))) + return -1; + + DRM_DEBUG("drm_agp_populate_ttm\n"); + mem = drm_agp_allocate_memory(agp_be->bridge, num_pages, AGP_USER_MEMORY); + if (!mem) { + drm_free_memctl(num_pages * sizeof(void *)); + return -1; + } + + DRM_DEBUG("Current page count is %ld\n", (long) mem->page_count); + mem->page_count = 0; + for (cur_page = pages; cur_page < last_page; ++cur_page) { + struct page *page = *cur_page; + if (!page) { + page = dummy_read_page; + ++dummy_page_count; + } + mem->memory[mem->page_count++] = phys_to_gart(page_to_phys(page)); + } + if (dummy_page_count) + DRM_DEBUG("Mapped %d dummy pages\n", dummy_page_count); + agp_be->mem = mem; + return 0; +} + +static int drm_agp_bind_ttm(struct drm_ttm_backend *backend, + struct drm_bo_mem_reg *bo_mem) +{ + struct drm_agp_ttm_backend *agp_be = + container_of(backend, struct drm_agp_ttm_backend, backend); + DRM_AGP_MEM *mem = agp_be->mem; + int ret; + 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->type = AGP_USER_MEMORY; + /* CACHED MAPPED implies not snooped memory */ + if (snooped) + mem->type = AGP_USER_CACHED_MEMORY; + + ret = drm_agp_bind_memory(mem, bo_mem->mm_node->start); + if (ret) + DRM_ERROR("AGP Bind memory failed\n"); + + DRM_FLAG_MASKED(backend->flags, (bo_mem->flags & DRM_BO_FLAG_CACHED) ? + DRM_BE_FLAG_BOUND_CACHED : 0, + DRM_BE_FLAG_BOUND_CACHED); + return ret; +} + +static int drm_agp_unbind_ttm(struct drm_ttm_backend *backend) +{ + struct drm_agp_ttm_backend *agp_be = + container_of(backend, struct drm_agp_ttm_backend, backend); + + DRM_DEBUG("drm_agp_unbind_ttm\n"); + if (agp_be->mem->is_bound) + return drm_agp_unbind_memory(agp_be->mem); + else + return 0; +} + +static void drm_agp_clear_ttm(struct drm_ttm_backend *backend) +{ + struct drm_agp_ttm_backend *agp_be = + container_of(backend, struct drm_agp_ttm_backend, backend); + DRM_AGP_MEM *mem = agp_be->mem; + + DRM_DEBUG("drm_agp_clear_ttm\n"); + if (mem) { + unsigned long num_pages = mem->page_count; + backend->func->unbind(backend); + agp_free_memory(mem); + drm_free_memctl(num_pages * sizeof(void *)); + } + agp_be->mem = NULL; +} + +static void drm_agp_destroy_ttm(struct drm_ttm_backend *backend) +{ + struct drm_agp_ttm_backend *agp_be; + + if (backend) { + DRM_DEBUG("drm_agp_destroy_ttm\n"); + agp_be = container_of(backend, struct drm_agp_ttm_backend, backend); + if (agp_be) { + if (agp_be->mem) + backend->func->clear(backend); + drm_ctl_free(agp_be, sizeof(*agp_be), DRM_MEM_TTM); + } + } +} + +static struct drm_ttm_backend_func agp_ttm_backend = { + .needs_ub_cache_adjust = drm_agp_needs_unbind_cache_adjust, + .populate = drm_agp_populate, + .clear = drm_agp_clear_ttm, + .bind = drm_agp_bind_ttm, + .unbind = drm_agp_unbind_ttm, + .destroy = drm_agp_destroy_ttm, +}; + +struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev) +{ + + struct drm_agp_ttm_backend *agp_be; + struct agp_kern_info *info; + + if (!dev->agp) { + DRM_ERROR("AGP is not initialized.\n"); + return NULL; + } + info = &dev->agp->agp_info; + + if (info->version.major != AGP_REQUIRED_MAJOR || + info->version.minor < AGP_REQUIRED_MINOR) { + DRM_ERROR("Wrong agpgart version %d.%d\n" + "\tYou need at least version %d.%d.\n", + info->version.major, + info->version.minor, + AGP_REQUIRED_MAJOR, + AGP_REQUIRED_MINOR); + return NULL; + } + + + agp_be = drm_ctl_calloc(1, sizeof(*agp_be), DRM_MEM_TTM); + if (!agp_be) + return NULL; + + agp_be->mem = NULL; + + agp_be->bridge = dev->agp->bridge; + agp_be->populated = false; + agp_be->backend.func = &agp_ttm_backend; + agp_be->backend.dev = dev; + + return &agp_be->backend; +} +EXPORT_SYMBOL(drm_agp_init_ttm); + void drm_agp_chipset_flush(struct drm_device *dev) { agp_flush_chipset(dev->agp->bridge); diff --git a/drivers/gpu/drm/drm_bo.c b/drivers/gpu/drm/drm_bo.c new file mode 100644 index 0000000..0d59b0a --- /dev/null +++ b/drivers/gpu/drm/drm_bo.c @@ -0,0 +1,2161 @@ +/************************************************************************** + * + * 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" + +/* + * Locking may look a bit complicated but isn't really: + * + * The buffer usage atomic_t needs to be protected by dev->struct_mutex + * when there is a chance that it can be zero before or after the operation. + * + * dev->struct_mutex also protects all lists and list heads, + * Hash tables and hash heads. + * + * bo->mutex protects the buffer object itself excluding the usage field. + * bo->mutex does also protect the buffer list heads, so to manipulate those, + * we need both the bo->mutex and the dev->struct_mutex. + * + * Locking order is bo->mutex, dev->struct_mutex. Therefore list traversal + * is a bit complicated. When dev->struct_mutex is released to grab bo->mutex, + * the list traversal will, in general, need to be restarted. + * + */ + +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_unmap_virtual(struct drm_buffer_object *bo); + +static inline uint64_t drm_bo_type_flags(unsigned type) +{ + return (1ULL << (24 + type)); +} + +/* + * bo locked. dev->struct_mutex locked. + */ + +void drm_bo_add_to_pinned_lru(struct drm_buffer_object *bo) +{ + struct drm_mem_type_manager *man; + + DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); + DRM_ASSERT_LOCKED(&bo->mutex); + + man = &bo->dev->bm.man[bo->pinned_mem_type]; + list_add_tail(&bo->pinned_lru, &man->pinned); +} + +void drm_bo_add_to_lru(struct drm_buffer_object *bo) +{ + struct drm_mem_type_manager *man; + + DRM_ASSERT_LOCKED(&bo->dev->struct_mutex); + + if (!(bo->mem.proposed_flags & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT)) + || bo->mem.mem_type != bo->pinned_mem_type) { + man = &bo->dev->bm.man[bo->mem.mem_type]; + list_add_tail(&bo->lru, &man->lru); + } else { + INIT_LIST_HEAD(&bo->lru); + } +} + +static int drm_bo_vm_pre_move(struct drm_buffer_object *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; + drm_bo_unmap_virtual(bo); + 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; +} + +static void drm_bo_vm_post_move(struct drm_buffer_object *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" + "\tThis might cause a sigbus later.\n"); + } + drm_bo_unlock_kmm(bo); +#endif +} + +/* + * Call bo->mutex locked. + */ + +int drm_bo_add_ttm(struct drm_buffer_object *bo) +{ + struct drm_device *dev = bo->dev; + int ret = 0; + uint32_t page_flags = 0; + + DRM_ASSERT_LOCKED(&bo->mutex); + bo->ttm = NULL; + + if (bo->mem.proposed_flags & DRM_BO_FLAG_WRITE) + page_flags |= DRM_TTM_PAGE_WRITE; + + switch (bo->type) { + case drm_bo_type_device: + case drm_bo_type_kernel: + bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, + page_flags, dev->bm.dummy_read_page); + if (!bo->ttm) + ret = -ENOMEM; + break; + case drm_bo_type_user: + bo->ttm = drm_ttm_create(dev, bo->num_pages << PAGE_SHIFT, + page_flags | DRM_TTM_PAGE_USER, + dev->bm.dummy_read_page); + if (!bo->ttm) + ret = -ENOMEM; + + ret = drm_ttm_set_user(bo->ttm, current, + bo->buffer_start, + bo->num_pages); + if (ret) + return ret; + + break; + default: + DRM_ERROR("Illegal buffer object type\n"); + ret = -EINVAL; + break; + } + + 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, + int evict, int no_wait) +{ + struct drm_device *dev = bo->dev; + struct drm_buffer_manager *bm = &dev->bm; + int old_is_pci = drm_mem_reg_is_pci(dev, &bo->mem); + int new_is_pci = drm_mem_reg_is_pci(dev, mem); + struct drm_mem_type_manager *old_man = &bm->man[bo->mem.mem_type]; + struct drm_mem_type_manager *new_man = &bm->man[mem->mem_type]; + int ret = 0; + + if (old_is_pci || new_is_pci || + ((mem->flags ^ bo->mem.flags) & DRM_BO_FLAG_CACHED)) + ret = drm_bo_vm_pre_move(bo, old_is_pci); + if (ret) + return ret; + + /* + * Create and bind a ttm if required. + */ + + if (!(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (bo->ttm == NULL)) { + ret = drm_bo_add_ttm(bo); + if (ret) + goto out_err; + + if (mem->mem_type != DRM_BO_MEM_LOCAL) { + ret = drm_ttm_bind(bo->ttm, mem); + if (ret) + goto out_err; + } + + if (bo->mem.mem_type == DRM_BO_MEM_LOCAL) { + + 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; + + *old_mem = *mem; + mem->mm_node = NULL; + old_mem->proposed_flags = save_proposed_flags; + DRM_FLAG_MASKED(save_flags, mem->flags, + DRM_BO_MASK_MEMTYPE); + goto moved; + } + + } + + if (!(old_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && + !(new_man->flags & _DRM_FLAG_MEMTYPE_FIXED)) + ret = drm_bo_move_ttm(bo, evict, no_wait, mem); + else if (dev->driver->bo_driver->move) + ret = dev->driver->bo_driver->move(bo, evict, no_wait, mem); + else + ret = drm_bo_move_memcpy(bo, evict, no_wait, mem); + + if (ret) + goto out_err; + +moved: + if (old_is_pci || new_is_pci) + drm_bo_vm_post_move(bo); + + if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { + ret = + dev->driver->bo_driver->invalidate_caches(dev, + bo->mem.flags); + if (ret) + DRM_ERROR("Can not flush read caches\n"); + } + + DRM_FLAG_MASKED(bo->priv_flags, + (evict) ? _DRM_BO_FLAG_EVICTED : 0, + _DRM_BO_FLAG_EVICTED); + + if (bo->mem.mm_node) + bo->offset = (bo->mem.mm_node->start << PAGE_SHIFT) + + bm->man[bo->mem.mem_type].gpu_offset; + + + return 0; + +out_err: + if (old_is_pci || new_is_pci) + drm_bo_vm_post_move(bo); + + new_man = &bm->man[bo->mem.mem_type]; + if ((new_man->flags & _DRM_FLAG_MEMTYPE_FIXED) && bo->ttm) { + drm_ttm_unbind(bo->ttm); + drm_ttm_destroy(bo->ttm); + bo->ttm = NULL; + } + + return ret; +} + +/* + * Call bo->mutex locked. + * Returns -EBUSY if the buffer is currently rendered to or from. 0 otherwise. + */ + +static int drm_bo_busy(struct drm_buffer_object *bo, int check_unfenced) +{ + struct drm_fence_object *fence = bo->fence; + + if (check_unfenced && (bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + return -EBUSY; + + if (fence) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { + drm_fence_usage_deref_unlocked(&bo->fence); + return 0; + } + drm_fence_object_flush(fence, DRM_FENCE_TYPE_EXE); + if (drm_fence_object_signaled(fence, bo->fence_type)) { + drm_fence_usage_deref_unlocked(&bo->fence); + return 0; + } + return -EBUSY; + } + return 0; +} + +static int drm_bo_check_unfenced(struct drm_buffer_object *bo) +{ + int ret; + + mutex_lock(&bo->mutex); + ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + mutex_unlock(&bo->mutex); + return ret; +} + + +/* + * Call bo->mutex locked. + * Wait until the buffer is idle. + */ + +int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int interruptible, + int no_wait, int check_unfenced) +{ + int ret; + + DRM_ASSERT_LOCKED(&bo->mutex); + while(unlikely(drm_bo_busy(bo, check_unfenced))) { + if (no_wait) + return -EBUSY; + + if (check_unfenced && (bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) { + mutex_unlock(&bo->mutex); + wait_event(bo->event_queue, !drm_bo_check_unfenced(bo)); + mutex_lock(&bo->mutex); + bo->priv_flags |= _DRM_BO_FLAG_UNLOCKED; + } + + if (bo->fence) { + struct drm_fence_object *fence; + uint32_t fence_type = bo->fence_type; + + drm_fence_reference_unlocked(&fence, bo->fence); + mutex_unlock(&bo->mutex); + + ret = drm_fence_object_wait(fence, lazy, !interruptible, + fence_type); + + drm_fence_usage_deref_unlocked(&fence); + mutex_lock(&bo->mutex); + bo->priv_flags |= _DRM_BO_FLAG_UNLOCKED; + if (ret) + return ret; + } + + } + return 0; +} +EXPORT_SYMBOL(drm_bo_wait); + +static int drm_bo_expire_fence(struct drm_buffer_object *bo, int allow_errors) +{ + struct drm_device *dev = bo->dev; + struct drm_buffer_manager *bm = &dev->bm; + + if (bo->fence) { + if (bm->nice_mode) { + unsigned long _end = jiffies + 3 * DRM_HZ; + int ret; + do { + ret = drm_bo_wait(bo, 0, 0, 0, 0); + if (ret && allow_errors) + return ret; + + } while (ret && !time_after_eq(jiffies, _end)); + + if (bo->fence) { + bm->nice_mode = 0; + DRM_ERROR("Detected GPU lockup or " + "fence driver was taken down. " + "Evicting buffer.\n"); + } + } + if (bo->fence) + drm_fence_usage_deref_unlocked(&bo->fence); + } + return 0; +} + +/* + * Call dev->struct_mutex locked. + * Attempts to remove all private references to a buffer by expiring its + * fence object and removing from lru lists and memory managers. + */ + +static void drm_bo_cleanup_refs(struct drm_buffer_object *bo, int remove_all) +{ + struct drm_device *dev = bo->dev; + struct drm_buffer_manager *bm = &dev->bm; + + DRM_ASSERT_LOCKED(&dev->struct_mutex); + + atomic_inc(&bo->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&bo->mutex); + + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + + if (bo->fence && drm_fence_object_signaled(bo->fence, + bo->fence_type)) + drm_fence_usage_deref_unlocked(&bo->fence); + + if (bo->fence && remove_all) + (void)drm_bo_expire_fence(bo, 0); + + mutex_lock(&dev->struct_mutex); + + if (!atomic_dec_and_test(&bo->usage)) + goto out; + + if (!bo->fence) { + list_del_init(&bo->lru); + if (bo->mem.mm_node) { + drm_mm_put_block(bo->mem.mm_node); + if (bo->pinned_node == bo->mem.mm_node) + bo->pinned_node = NULL; + bo->mem.mm_node = NULL; + } + list_del_init(&bo->pinned_lru); + if (bo->pinned_node) { + drm_mm_put_block(bo->pinned_node); + bo->pinned_node = NULL; + } + list_del_init(&bo->ddestroy); + mutex_unlock(&bo->mutex); + drm_bo_destroy_locked(bo); + return; + } + + if (list_empty(&bo->ddestroy)) { + drm_fence_object_flush(bo->fence, bo->fence_type); + list_add_tail(&bo->ddestroy, &bm->ddestroy); + schedule_delayed_work(&bm->wq, + ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); + } + +out: + mutex_unlock(&bo->mutex); + return; +} + +/* + * Verify that refcount is 0 and that there are no internal references + * to the buffer object. Then destroy it. + */ + +static void drm_bo_destroy_locked(struct drm_buffer_object *bo) +{ + struct drm_device *dev = bo->dev; + struct drm_buffer_manager *bm = &dev->bm; + + 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) { + if (bo->fence != NULL) { + DRM_ERROR("Fence was non-zero.\n"); + drm_bo_cleanup_refs(bo, 0); + return; + } + +#ifdef DRM_ODD_MM_COMPAT + BUG_ON(!list_empty(&bo->vma_list)); + BUG_ON(!list_empty(&bo->p_mm_list)); +#endif + + if (bo->ttm) { + drm_ttm_unbind(bo->ttm); + drm_ttm_destroy(bo->ttm); + bo->ttm = NULL; + } + + atomic_dec(&bm->count); + + drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + + return; + } + + /* + * Some stuff is still trying to reference the buffer object. + * Get rid of those references. + */ + + drm_bo_cleanup_refs(bo, 0); + + return; +} + +/* + * Call dev->struct_mutex locked. + */ + +static void drm_bo_delayed_delete(struct drm_device *dev, int remove_all) +{ + struct drm_buffer_manager *bm = &dev->bm; + + struct drm_buffer_object *entry, *nentry; + struct list_head *list, *next; + + list_for_each_safe(list, next, &bm->ddestroy) { + 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); + atomic_inc(&nentry->usage); + } + + drm_bo_cleanup_refs(entry, remove_all); + + if (nentry) + atomic_dec(&nentry->usage); + } +} + +static void drm_bo_delayed_workqueue(struct work_struct *work) +{ + struct drm_buffer_manager *bm = + container_of(work, struct drm_buffer_manager, wq.work); + struct drm_device *dev = container_of(bm, struct drm_device, bm); + + DRM_DEBUG("Delayed delete Worker\n"); + + mutex_lock(&dev->struct_mutex); + if (!bm->initialized) { + mutex_unlock(&dev->struct_mutex); + return; + } + drm_bo_delayed_delete(dev, 0); + if (bm->initialized && !list_empty(&bm->ddestroy)) { + schedule_delayed_work(&bm->wq, + ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); + } + mutex_unlock(&dev->struct_mutex); +} + +void drm_bo_usage_deref_locked(struct drm_buffer_object **bo) +{ + struct drm_buffer_object *tmp_bo = *bo; + bo = NULL; + + DRM_ASSERT_LOCKED(&tmp_bo->dev->struct_mutex); + + if (atomic_dec_and_test(&tmp_bo->usage)) + drm_bo_destroy_locked(tmp_bo); +} +EXPORT_SYMBOL(drm_bo_usage_deref_locked); + +void drm_bo_usage_deref_unlocked(struct drm_buffer_object **bo) +{ + struct drm_buffer_object *tmp_bo = *bo; + struct drm_device *dev = tmp_bo->dev; + + *bo = NULL; + if (atomic_dec_and_test(&tmp_bo->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&tmp_bo->usage) == 0) + drm_bo_destroy_locked(tmp_bo); + mutex_unlock(&dev->struct_mutex); + } +} +EXPORT_SYMBOL(drm_bo_usage_deref_unlocked); + +void drm_putback_buffer_objects(struct drm_device *dev) +{ + struct drm_buffer_manager *bm = &dev->bm; + struct list_head *list = &bm->unfenced; + struct drm_buffer_object *entry, *next; + + mutex_lock(&dev->struct_mutex); + list_for_each_entry_safe(entry, next, list, lru) { + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + + mutex_lock(&entry->mutex); + BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); + mutex_lock(&dev->struct_mutex); + + list_del_init(&entry->lru); + DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + wake_up_all(&entry->event_queue); + + /* + * FIXME: Might want to put back on head of list + * instead of tail here. + */ + + drm_bo_add_to_lru(entry); + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_locked(&entry); + } + mutex_unlock(&dev->struct_mutex); +} +EXPORT_SYMBOL(drm_putback_buffer_objects); + +/* + * Note. The caller has to register (if applicable) + * and deregister fence object usage. + */ + +int drm_fence_buffer_objects(struct drm_device *dev, + struct list_head *list, + uint32_t fence_flags, + struct drm_fence_object *fence, + struct drm_fence_object **used_fence) +{ + struct drm_buffer_manager *bm = &dev->bm; + struct drm_buffer_object *entry; + uint32_t fence_type = 0; + uint32_t fence_class = ~0; + int count = 0; + int ret = 0; + struct list_head *l; + + mutex_lock(&dev->struct_mutex); + + if (!list) + list = &bm->unfenced; + + if (fence) + fence_class = fence->fence_class; + + list_for_each_entry(entry, list, lru) { + BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); + fence_type |= entry->new_fence_type; + if (fence_class == ~0) + fence_class = entry->new_fence_class; + else if (entry->new_fence_class != fence_class) { + DRM_ERROR("Unmatching fence classes on unfenced list: " + "%d and %d.\n", + fence_class, + entry->new_fence_class); + ret = -EINVAL; + goto out; + } + count++; + } + + if (!count) { + ret = -EINVAL; + goto out; + } + + if (fence) { + if ((fence_type & fence->type) != fence_type || + (fence->fence_class != fence_class)) { + DRM_ERROR("Given fence doesn't match buffers " + "on unfenced list.\n"); + ret = -EINVAL; + goto out; + } + } else { + mutex_unlock(&dev->struct_mutex); + ret = drm_fence_object_create(dev, fence_class, fence_type, + fence_flags | DRM_FENCE_FLAG_EMIT, + &fence); + mutex_lock(&dev->struct_mutex); + if (ret) + goto out; + } + + count = 0; + l = list->next; + while (l != list) { + prefetch(l->next); + entry = list_entry(l, struct drm_buffer_object, lru); + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + mutex_lock(&dev->struct_mutex); + list_del_init(l); + if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { + count++; + if (entry->fence) + drm_fence_usage_deref_locked(&entry->fence); + entry->fence = drm_fence_reference_locked(fence); + entry->fence_class = entry->new_fence_class; + entry->fence_type = entry->new_fence_type; + DRM_FLAG_MASKED(entry->priv_flags, 0, + _DRM_BO_FLAG_UNFENCED); + wake_up_all(&entry->event_queue); + drm_bo_add_to_lru(entry); + } + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_locked(&entry); + l = list->next; + } + DRM_DEBUG("Fenced %d buffers\n", count); +out: + mutex_unlock(&dev->struct_mutex); + *used_fence = fence; + return ret; +} +EXPORT_SYMBOL(drm_fence_buffer_objects); + +/* if we discard a buffer with no backing store - + * we can just set it back to a clean state + */ +static int drm_bo_reset_local(struct drm_buffer_object *bo) +{ + int ret = 0; + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg *old_mem = &bo->mem; + int old_is_pci = drm_mem_reg_is_pci(dev, &bo->mem); + + ret = drm_bo_vm_pre_move(bo, old_is_pci); + if (ret) + return ret; + + mutex_lock(&dev->struct_mutex); + list_del_init(&bo->lru); + mutex_unlock(&dev->struct_mutex); + + if (old_mem->mm_node) { + mutex_lock(&dev->struct_mutex); + drm_mm_put_block(old_mem->mm_node); + mutex_unlock(&dev->struct_mutex); + } + old_mem->mm_node = NULL; + + bo->mem.mem_type = DRM_BO_MEM_LOCAL; + + bo->mem.flags &= ~DRM_BO_MASK_MEMTYPE; + bo->mem.flags |= (DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_DISCARDABLE | + DRM_BO_FLAG_CLEAN); + + bo->mem.proposed_flags = bo->mem.flags; + return 0; +} +/* + * bo->mutex locked + */ + +static int drm_bo_evict(struct drm_buffer_object *bo, unsigned mem_type, + int no_wait) +{ + int ret = 0; + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg evict_mem; + + /* + * Someone might have modified the buffer before we took the + * buffer mutex. + */ + + do { + bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; + + if (unlikely(bo->mem.flags & + (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT))) + goto out_unlock; + if (unlikely(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + goto out_unlock; + if (unlikely(bo->mem.mem_type != mem_type)) + goto out_unlock; + ret = drm_bo_wait(bo, 0, 1, no_wait, 0); + if (ret) + goto out_unlock; + + } while(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); + + /* if in VRAM and discardable - discard it */ + if (bo->mem.mem_type == DRM_BO_MEM_VRAM && bo->mem.flags & DRM_BO_FLAG_DISCARDABLE) { + drm_bo_reset_local(bo); + goto out_unlock; + } + + evict_mem = bo->mem; + evict_mem.mm_node = NULL; + + evict_mem = bo->mem; + evict_mem.proposed_flags = dev->driver->bo_driver->evict_flags(bo); + + mutex_lock(&dev->struct_mutex); + list_del_init(&bo->lru); + mutex_unlock(&dev->struct_mutex); + + ret = drm_bo_mem_space(bo, &evict_mem, no_wait); + + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed to find memory space for " + "buffer 0x%p eviction.\n", bo); + goto out; + } + + ret = drm_bo_handle_move_mem(bo, &evict_mem, 1, no_wait); + + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Buffer eviction failed\n"); + goto out; + } + + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, + _DRM_BO_FLAG_EVICTED); + +out: + mutex_lock(&dev->struct_mutex); + if (evict_mem.mm_node) { + if (evict_mem.mm_node != bo->pinned_node) + drm_mm_put_block(evict_mem.mm_node); + evict_mem.mm_node = NULL; + } + drm_bo_add_to_lru(bo); + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); + mutex_unlock(&dev->struct_mutex); +out_unlock: + + return ret; +} + +/** + * Repeatedly evict memory from the LRU for @mem_type until we create enough + * space, or we've evicted everything and there isn't enough space. + */ +static int drm_bo_mem_force_space(struct drm_device *dev, + struct drm_bo_mem_reg *mem, + uint32_t mem_type, int no_wait) +{ + struct drm_mm_node *node; + struct drm_buffer_manager *bm = &dev->bm; + struct drm_buffer_object *entry; + struct drm_mem_type_manager *man = &bm->man[mem_type]; + struct list_head *lru; + unsigned long num_pages = mem->num_pages; + int ret; + + mutex_lock(&dev->struct_mutex); + do { + node = drm_mm_search_free(&man->manager, num_pages, + mem->page_alignment, 1); + if (node) + break; + + lru = &man->lru; + if (lru->next == lru) + break; + + entry = list_entry(lru->next, struct drm_buffer_object, lru); + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + ret = drm_bo_evict(entry, mem_type, no_wait); + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_unlocked(&entry); + if (ret) + return ret; + mutex_lock(&dev->struct_mutex); + } while (1); + + if (!node) { + mutex_unlock(&dev->struct_mutex); + return -ENOMEM; + } + + node = drm_mm_get_block(node, num_pages, mem->page_alignment); + if (unlikely(!node)) { + mutex_unlock(&dev->struct_mutex); + return -ENOMEM; + } + + mutex_unlock(&dev->struct_mutex); + mem->mm_node = node; + mem->mem_type = mem_type; + return 0; +} + +static int drm_bo_mt_compatible(struct drm_mem_type_manager *man, + int disallow_fixed, + uint32_t mem_type, + uint64_t mask, uint32_t *res_mask) +{ + uint64_t cur_flags = drm_bo_type_flags(mem_type); + uint64_t flag_diff; + + if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && disallow_fixed) + return 0; + if (man->flags & _DRM_FLAG_MEMTYPE_CACHED) + cur_flags |= DRM_BO_FLAG_CACHED; + if (man->flags & _DRM_FLAG_MEMTYPE_MAPPABLE) + cur_flags |= DRM_BO_FLAG_MAPPABLE; + if (man->flags & _DRM_FLAG_MEMTYPE_CSELECT) + DRM_FLAG_MASKED(cur_flags, mask, DRM_BO_FLAG_CACHED); + + if ((cur_flags & mask & DRM_BO_MASK_MEM) == 0) + return 0; + + if (mem_type == DRM_BO_MEM_LOCAL) { + *res_mask = cur_flags; + return 1; + } + + flag_diff = (mask ^ cur_flags); + if (flag_diff & DRM_BO_FLAG_CACHED_MAPPED) + cur_flags |= DRM_BO_FLAG_CACHED_MAPPED; + + if ((flag_diff & DRM_BO_FLAG_CACHED) && + (!(mask & DRM_BO_FLAG_CACHED) || + (mask & DRM_BO_FLAG_FORCE_CACHING))) + return 0; + + if ((flag_diff & DRM_BO_FLAG_MAPPABLE) && + ((mask & DRM_BO_FLAG_MAPPABLE) || + (mask & DRM_BO_FLAG_FORCE_MAPPABLE))) + return 0; + + *res_mask = cur_flags; + return 1; +} + +/** + * Creates space for memory region @mem according to its type. + * + * This function first searches for free space in compatible memory types in + * the priority order defined by the driver. If free space isn't found, then + * drm_bo_mem_force_space is attempted in priority order to evict and find + * space. + */ +int drm_bo_mem_space(struct drm_buffer_object *bo, + struct drm_bo_mem_reg *mem, int no_wait) +{ + struct drm_device *dev = bo->dev; + struct drm_buffer_manager *bm = &dev->bm; + struct drm_mem_type_manager *man; + + uint32_t num_prios = dev->driver->bo_driver->num_mem_type_prio; + const uint32_t *prios = dev->driver->bo_driver->mem_type_prio; + uint32_t i; + uint32_t mem_type = DRM_BO_MEM_LOCAL; + uint32_t cur_flags; + int type_found = 0; + int type_ok = 0; + int has_eagain = 0; + struct drm_mm_node *node = NULL; + int ret; + + mem->mm_node = NULL; + for (i = 0; i < num_prios; ++i) { + mem_type = prios[i]; + man = &bm->man[mem_type]; + + type_ok = drm_bo_mt_compatible(man, + bo->type == drm_bo_type_user, + mem_type, mem->proposed_flags, + &cur_flags); + + if (!type_ok) + continue; + + if (mem_type == DRM_BO_MEM_LOCAL) + break; + + if ((mem_type == bo->pinned_mem_type) && + (bo->pinned_node != NULL)) { + node = bo->pinned_node; + break; + } + + mutex_lock(&dev->struct_mutex); + if (man->has_type && man->use_type) { + type_found = 1; + node = drm_mm_search_free(&man->manager, mem->num_pages, + mem->page_alignment, 1); + if (node) + node = drm_mm_get_block(node, mem->num_pages, + mem->page_alignment); + } + mutex_unlock(&dev->struct_mutex); + if (node) + break; + } + + if ((type_ok && (mem_type == DRM_BO_MEM_LOCAL)) || node) { + mem->mm_node = node; + mem->mem_type = mem_type; + mem->flags = cur_flags; + return 0; + } + + if (!type_found) + return -EINVAL; + + num_prios = dev->driver->bo_driver->num_mem_busy_prio; + prios = dev->driver->bo_driver->mem_busy_prio; + + for (i = 0; i < num_prios; ++i) { + mem_type = prios[i]; + man = &bm->man[mem_type]; + + if (!man->has_type) + continue; + + if (!drm_bo_mt_compatible(man, + bo->type == drm_bo_type_user, + mem_type, + mem->proposed_flags, + &cur_flags)) + continue; + + ret = drm_bo_mem_force_space(dev, mem, mem_type, no_wait); + + if (ret == 0 && mem->mm_node) { + mem->flags = cur_flags; + return 0; + } + + if (ret == -EAGAIN) + has_eagain = 1; + } + + ret = (has_eagain) ? -EAGAIN : -ENOMEM; + return ret; +} +EXPORT_SYMBOL(drm_bo_mem_space); + +/* + * drm_bo_propose_flags: + * + * @bo: the buffer object getting new flags + * + * @new_flags: the new set of proposed flag bits + * + * @new_mask: the mask of bits changed in new_flags + * + * Modify the proposed_flag bits in @bo + */ +static int drm_bo_modify_proposed_flags (struct drm_buffer_object *bo, + uint64_t new_flags, uint64_t new_mask) +{ + uint32_t new_access; + + /* Copy unchanging bits from existing proposed_flags */ + DRM_FLAG_MASKED(new_flags, bo->mem.proposed_flags, ~new_mask); + + if (bo->type == drm_bo_type_user && + ((new_flags & (DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING)) != + (DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING))) { + DRM_ERROR("User buffers require cache-coherent memory.\n"); + return -EINVAL; + } + + if (bo->type != drm_bo_type_kernel && (new_mask & DRM_BO_FLAG_NO_EVICT) && !DRM_SUSER(DRM_CURPROC)) { + DRM_ERROR("DRM_BO_FLAG_NO_EVICT is only available to priviliged processes.\n"); + return -EPERM; + } + + if (likely(new_mask & DRM_BO_MASK_MEM) && + (bo->mem.flags & DRM_BO_FLAG_NO_EVICT) && + !DRM_SUSER(DRM_CURPROC)) { + if (likely(bo->mem.flags & new_flags & new_mask & + DRM_BO_MASK_MEM)) + new_flags = (new_flags & ~DRM_BO_MASK_MEM) | + (bo->mem.flags & DRM_BO_MASK_MEM); + else { + DRM_ERROR("Incompatible memory type specification " + "for NO_EVICT buffer.\n"); + return -EPERM; + } + } + + if ((new_flags & DRM_BO_FLAG_NO_MOVE)) { + DRM_ERROR("DRM_BO_FLAG_NO_MOVE is not properly implemented yet.\n"); + return -EPERM; + } + + new_access = new_flags & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_READ); + + if (new_access == 0) { + DRM_ERROR("Invalid buffer object rwx properties\n"); + return -EINVAL; + } + + bo->mem.proposed_flags = new_flags; + return 0; +} + +/* + * Call bo->mutex locked. + * Returns -EBUSY if the buffer is currently rendered to or from. 0 otherwise. + * Doesn't do any fence flushing as opposed to the drm_bo_busy function. + */ + +int drm_bo_quick_busy(struct drm_buffer_object *bo, int check_unfenced) +{ + struct drm_fence_object *fence = bo->fence; + + if (check_unfenced && (bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + return -EBUSY; + + if (fence) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { + drm_fence_usage_deref_unlocked(&bo->fence); + return 0; + } + return -EBUSY; + } + return 0; +} + +int drm_bo_evict_cached(struct drm_buffer_object *bo) +{ + int ret = 0; + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + if (bo->mem.mm_node) + ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1); + return ret; +} + +EXPORT_SYMBOL(drm_bo_evict_cached); +/* + * Wait until a buffer is unmapped. + */ + +static int drm_bo_wait_unmapped(struct drm_buffer_object *bo, int no_wait) +{ + int ret = 0; + + if (likely(atomic_read(&bo->mapped)) == 0) + return 0; + + if (unlikely(no_wait)) + return -EBUSY; + + do { + mutex_unlock(&bo->mutex); + ret = wait_event_interruptible(bo->event_queue, + atomic_read(&bo->mapped) == 0); + mutex_lock(&bo->mutex); + bo->priv_flags |= _DRM_BO_FLAG_UNLOCKED; + + if (ret == -ERESTARTSYS) + ret = -EAGAIN; + } while((ret == 0) && atomic_read(&bo->mapped) > 0); + + return ret; +} + +/* + * bo->mutex locked. + * Note that new_mem_flags are NOT transferred to the bo->mem.proposed_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; + struct drm_buffer_manager *bm = &dev->bm; + int ret = 0; + struct drm_bo_mem_reg mem; + + BUG_ON(bo->fence != NULL); + + mem.num_pages = bo->num_pages; + mem.size = mem.num_pages << PAGE_SHIFT; + mem.proposed_flags = new_mem_flags; + mem.page_alignment = bo->mem.page_alignment; + + mutex_lock(&bm->evict_mutex); + mutex_lock(&dev->struct_mutex); + list_del_init(&bo->lru); + mutex_unlock(&dev->struct_mutex); + + /* + * Determine where to move the buffer. + */ + ret = drm_bo_mem_space(bo, &mem, no_wait); + if (ret) + goto out_unlock; + + ret = drm_bo_handle_move_mem(bo, &mem, 0, no_wait); + +out_unlock: + mutex_lock(&dev->struct_mutex); + if (ret || !move_unfenced) { + if (mem.mm_node) { + if (mem.mm_node != bo->pinned_node) + drm_mm_put_block(mem.mm_node); + mem.mm_node = NULL; + } + drm_bo_add_to_lru(bo); + if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) { + wake_up_all(&bo->event_queue); + DRM_FLAG_MASKED(bo->priv_flags, 0, + _DRM_BO_FLAG_UNFENCED); + } + } else { + list_add_tail(&bo->lru, &bm->unfenced); + 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; + bo->mem.proposed_flags &= ~DRM_BO_FLAG_CLEAN; + + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&bm->evict_mutex); + return ret; +} + +static int drm_bo_mem_compat(struct drm_bo_mem_reg *mem) +{ + uint32_t flag_diff = (mem->proposed_flags ^ mem->flags); + + if ((mem->proposed_flags & mem->flags & DRM_BO_MASK_MEM) == 0) + return 0; + if ((flag_diff & DRM_BO_FLAG_CACHED) && + (/* !(mem->proposed_flags & DRM_BO_FLAG_CACHED) ||*/ + (mem->proposed_flags & DRM_BO_FLAG_FORCE_CACHING))) + return 0; + + if ((flag_diff & DRM_BO_FLAG_MAPPABLE) && + ((mem->proposed_flags & DRM_BO_FLAG_MAPPABLE) || + (mem->proposed_flags & DRM_BO_FLAG_FORCE_MAPPABLE))) + return 0; + return 1; +} + +/** + * drm_buffer_object_validate: + * + * @bo: the buffer object to modify + * + * @fence_class: the new fence class covering this buffer + * + * @move_unfenced: a boolean indicating whether switching the + * memory space of this buffer should cause the buffer to + * be placed on the unfenced list. + * + * @no_wait: whether this function should return -EBUSY instead + * of waiting. + * + * Change buffer access parameters. This can involve moving + * the buffer to the correct memory type, pinning the buffer + * or changing the class/type of fence covering this buffer + * + * Must be called with bo locked. + */ + +static int drm_buffer_object_validate(struct drm_buffer_object *bo, + uint32_t fence_class, + int move_unfenced, int no_wait, + int move_buffer) +{ + struct drm_device *dev = bo->dev; + struct drm_buffer_manager *bm = &dev->bm; + int ret; + + if (move_buffer) { + ret = drm_bo_move_buffer(bo, bo->mem.proposed_flags, no_wait, + move_unfenced); + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed moving buffer. %p %d %llx %llx\n", bo, bo->num_pages, bo->mem.proposed_flags, bo->mem.flags ); + if (ret == -ENOMEM) + DRM_ERROR("Out of aperture space or " + "DRM memory quota.\n"); + return ret; + } + } + + /* + * Pinned buffers. + */ + + if (bo->mem.proposed_flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) { + bo->pinned_mem_type = bo->mem.mem_type; + mutex_lock(&dev->struct_mutex); + list_del_init(&bo->pinned_lru); + drm_bo_add_to_pinned_lru(bo); + + if (bo->pinned_node != bo->mem.mm_node) { + if (bo->pinned_node != NULL) + drm_mm_put_block(bo->pinned_node); + bo->pinned_node = bo->mem.mm_node; + } + + mutex_unlock(&dev->struct_mutex); + + } else if (bo->pinned_node != NULL) { + + mutex_lock(&dev->struct_mutex); + + if (bo->pinned_node != bo->mem.mm_node) + drm_mm_put_block(bo->pinned_node); + + list_del_init(&bo->pinned_lru); + bo->pinned_node = NULL; + mutex_unlock(&dev->struct_mutex); + + } + + /* + * We might need to add a TTM. + */ + + if (bo->mem.mem_type == DRM_BO_MEM_LOCAL && bo->ttm == NULL) { + ret = drm_bo_add_ttm(bo); + if (ret) + return ret; + } + /* + * Validation has succeeded, move the access and other + * non-mapping-related flag bits from the proposed flags to + * the active flags + */ + + DRM_FLAG_MASKED(bo->mem.flags, bo->mem.proposed_flags, ~DRM_BO_MASK_MEMTYPE); + + /* + * Finally, adjust lru to be sure. + */ + + mutex_lock(&dev->struct_mutex); + list_del(&bo->lru); + if (move_unfenced) { + list_add_tail(&bo->lru, &bm->unfenced); + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, + _DRM_BO_FLAG_UNFENCED); + } else { + drm_bo_add_to_lru(bo); + if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) { + wake_up_all(&bo->event_queue); + DRM_FLAG_MASKED(bo->priv_flags, 0, + _DRM_BO_FLAG_UNFENCED); + } + } + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +/* + * This function is called with bo->mutex locked, but may release it + * temporarily to wait for events. + */ + +static int drm_bo_prepare_for_validate(struct drm_buffer_object *bo, + uint64_t flags, + uint64_t mask, + uint32_t hint, + uint32_t fence_class, + int no_wait, + int *move_buffer) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_driver *driver = dev->driver->bo_driver; + uint32_t ftype; + + int ret; + + + 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; + + ret = driver->fence_type(bo, &fence_class, &ftype); + + if (ret) { + DRM_ERROR("Driver did not support given buffer permissions.\n"); + return ret; + } + + /* + * We're switching command submission mechanism, + * or cannot simply rely on the hardware serializing for us. + * Insert a driver-dependant barrier or wait for buffer idle. + */ + + if ((fence_class != bo->fence_class) || + ((ftype ^ bo->fence_type) & bo->fence_type)) { + + ret = -EINVAL; + if (driver->command_stream_barrier) { + ret = driver->command_stream_barrier(bo, + fence_class, + ftype, + no_wait); + } + if (ret && ret != -EAGAIN) + ret = drm_bo_wait(bo, 0, 1, no_wait, 1); + + if (ret) + return ret; + } + + bo->new_fence_class = fence_class; + bo->new_fence_type = ftype; + + /* + * Check whether we need to move buffer. + */ + + *move_buffer = 0; + if (!drm_bo_mem_compat(&bo->mem)) { + *move_buffer = 1; + ret = drm_bo_wait(bo, 0, 1, no_wait, 1); + } + + return ret; +} + +/** + * drm_bo_do_validate: + * + * @bo: the buffer object + * + * @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 + * + * 'validate' a buffer object. This changes where the buffer is + * located, along with changing access modes. + */ + +int drm_bo_do_validate(struct drm_buffer_object *bo, + uint64_t flags, uint64_t mask, uint32_t hint, + uint32_t fence_class) +{ + int ret; + int no_wait = (hint & DRM_BO_HINT_DONT_BLOCK) != 0; + int move_buffer; + + mutex_lock(&bo->mutex); + + do { + bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; + + ret = drm_bo_prepare_for_validate(bo, flags, mask, hint, + fence_class, no_wait, + &move_buffer); + if (ret) + goto out; + + } while(unlikely(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED)); + + ret = drm_buffer_object_validate(bo, + fence_class, + !(hint & DRM_BO_HINT_DONT_FENCE), + no_wait, + move_buffer); + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); +out: + mutex_unlock(&bo->mutex); + + return ret; +} +EXPORT_SYMBOL(drm_bo_do_validate); + +int drm_buffer_object_create(struct drm_device *dev, + unsigned long size, + enum drm_bo_type type, + uint64_t flags, + uint32_t hint, + uint32_t page_alignment, + unsigned long buffer_start, + struct drm_buffer_object **buf_obj) +{ + struct drm_buffer_manager *bm = &dev->bm; + struct drm_buffer_object *bo; + int ret = 0; + unsigned long num_pages; + + size += buffer_start & ~PAGE_MASK; + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (num_pages == 0) { + DRM_ERROR("Illegal buffer object size %ld.\n", size); + return -EINVAL; + } + + bo = drm_ctl_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); + + if (!bo) + return -ENOMEM; + + mutex_init(&bo->mutex); + mutex_lock(&bo->mutex); + + atomic_set(&bo->usage, 1); + atomic_set(&bo->mapped, 0); + DRM_INIT_WAITQUEUE(&bo->event_queue); + INIT_LIST_HEAD(&bo->lru); + INIT_LIST_HEAD(&bo->pinned_lru); + INIT_LIST_HEAD(&bo->ddestroy); +#ifdef DRM_ODD_MM_COMPAT + INIT_LIST_HEAD(&bo->p_mm_list); + INIT_LIST_HEAD(&bo->vma_list); +#endif + bo->dev = dev; + bo->type = type; + bo->num_pages = num_pages; + bo->mem.mem_type = DRM_BO_MEM_LOCAL; + bo->mem.num_pages = bo->num_pages; + bo->mem.mm_node = NULL; + bo->mem.page_alignment = page_alignment; + bo->buffer_start = buffer_start & PAGE_MASK; + bo->priv_flags = 0; + bo->mem.flags = (DRM_BO_FLAG_MEM_LOCAL | + DRM_BO_FLAG_MAPPABLE | DRM_BO_FLAG_CLEAN); + bo->mem.proposed_flags = 0; + atomic_inc(&bm->count); + + bo->mem.flags |= DRM_BO_FLAG_CACHED; + /* + * Use drm_bo_modify_proposed_flags to error-check the proposed flags + */ + flags |= DRM_BO_FLAG_CLEAN; + + ret = drm_bo_modify_proposed_flags (bo, flags, flags); + if (ret) + goto out_err; + + /* + * For drm_bo_type_device buffers, allocate + * address space from the device so that applications + * can mmap the buffer from there + */ + if (bo->type == drm_bo_type_device) { + mutex_lock(&dev->struct_mutex); + ret = drm_bo_setup_vm_locked(bo); + mutex_unlock(&dev->struct_mutex); + if (ret) + goto out_err; + } + + mutex_unlock(&bo->mutex); + ret = drm_bo_do_validate(bo, 0, 0, hint | DRM_BO_HINT_DONT_FENCE, + 0); + if (ret) + goto out_err_unlocked; + + *buf_obj = bo; + return 0; + +out_err: + mutex_unlock(&bo->mutex); +out_err_unlocked: + drm_bo_usage_deref_unlocked(&bo); + return ret; +} +EXPORT_SYMBOL(drm_buffer_object_create); + +static int drm_bo_leave_list(struct drm_buffer_object *bo, + uint32_t mem_type, + int free_pinned, + int allow_errors) +{ + struct drm_device *dev = bo->dev; + int ret = 0; + + mutex_lock(&bo->mutex); + + ret = drm_bo_expire_fence(bo, allow_errors); + if (ret) + goto out; + + if (free_pinned) { + DRM_FLAG_MASKED(bo->mem.flags, 0, DRM_BO_FLAG_NO_MOVE); + mutex_lock(&dev->struct_mutex); + list_del_init(&bo->pinned_lru); + if (bo->pinned_node == bo->mem.mm_node) + bo->pinned_node = NULL; + if (bo->pinned_node != NULL) { + drm_mm_put_block(bo->pinned_node); + bo->pinned_node = NULL; + } + mutex_unlock(&dev->struct_mutex); + } + + if (bo->mem.flags & DRM_BO_FLAG_NO_EVICT) { + DRM_ERROR("A DRM_BO_NO_EVICT buffer present at " + "cleanup. Removing flag and evicting.\n"); + bo->mem.flags &= ~DRM_BO_FLAG_NO_EVICT; + bo->mem.proposed_flags &= ~DRM_BO_FLAG_NO_EVICT; + } + + if (bo->mem.mem_type == mem_type) + ret = drm_bo_evict(bo, mem_type, 0); + + if (ret) { + if (allow_errors) { + goto out; + } else { + ret = 0; + DRM_ERROR("Cleanup eviction failed\n"); + } + } + +out: + mutex_unlock(&bo->mutex); + return ret; +} + + +static struct drm_buffer_object *drm_bo_entry(struct list_head *list, + int pinned_list) +{ + if (pinned_list) + return list_entry(list, struct drm_buffer_object, pinned_lru); + else + return list_entry(list, struct drm_buffer_object, lru); +} + +/* + * dev->struct_mutex locked. + */ + +static int drm_bo_force_list_clean(struct drm_device *dev, + struct list_head *head, + unsigned mem_type, + int free_pinned, + int allow_errors, + int pinned_list) +{ + struct list_head *list, *next, *prev; + struct drm_buffer_object *entry, *nentry; + int ret; + int do_restart; + + /* + * The list traversal is a bit odd here, because an item may + * disappear from the list when we release the struct_mutex or + * when we decrease the usage count. Also we're not guaranteed + * to drain pinned lists, so we can't always restart. + */ + +restart: + nentry = NULL; + list_for_each_safe(list, next, head) { + prev = list->prev; + + entry = (nentry != NULL) ? nentry: drm_bo_entry(list, pinned_list); + atomic_inc(&entry->usage); + if (nentry) { + atomic_dec(&nentry->usage); + nentry = NULL; + } + + /* + * Protect the next item from destruction, so we can check + * its list pointers later on. + */ + + if (next != head) { + nentry = drm_bo_entry(next, pinned_list); + atomic_inc(&nentry->usage); + } + mutex_unlock(&dev->struct_mutex); + + ret = drm_bo_leave_list(entry, mem_type, free_pinned, + allow_errors); + mutex_lock(&dev->struct_mutex); + + drm_bo_usage_deref_locked(&entry); + if (ret) + return ret; + + /* + * Has the next item disappeared from the list? + */ + + do_restart = ((next->prev != list) && (next->prev != prev)); + + if (nentry != NULL && do_restart) + drm_bo_usage_deref_locked(&nentry); + + if (do_restart) + goto restart; + } + return 0; +} + +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]; + int ret = -EINVAL; + + if (mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", mem_type); + return ret; + } + + if (!man->has_type) { + DRM_ERROR("Trying to take down uninitialized " + "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; + + ret = 0; + if (mem_type > 0) { + BUG_ON(!list_empty(&bm->unfenced)); + drm_bo_force_list_clean(dev, &man->lru, mem_type, 1, 0, 0); + drm_bo_force_list_clean(dev, &man->pinned, mem_type, 1, 0, 1); + + if (drm_mm_clean(&man->manager)) { + drm_mm_takedown(&man->manager); + } else { + ret = -EBUSY; + } + } + + return ret; +} +EXPORT_SYMBOL(drm_bo_clean_mm); + +/** + *Evict all buffers of a particular mem_type, but leave memory manager + *regions for NO_MOVE buffers intact. New buffers cannot be added at this + *point since we have the hardware lock. + */ + +int drm_bo_lock_mm(struct drm_device *dev, unsigned mem_type) +{ + int ret; + struct drm_buffer_manager *bm = &dev->bm; + struct drm_mem_type_manager *man = &bm->man[mem_type]; + + if (mem_type == 0 || mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory manager memory type %u.\n", mem_type); + return -EINVAL; + } + + if (!man->has_type) { + DRM_ERROR("Memory type %u has not been initialized.\n", + mem_type); + return 0; + } + + ret = drm_bo_force_list_clean(dev, &man->lru, mem_type, 0, 1, 0); + if (ret) + return ret; + ret = drm_bo_force_list_clean(dev, &man->pinned, mem_type, 0, 1, 1); + + return ret; +} + +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; + struct drm_mem_type_manager *man; + + if (type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", type); + return ret; + } + + man = &bm->man[type]; + if (man->has_type) { + DRM_ERROR("Memory manager already initialized for type %d\n", + type); + return ret; + } + + ret = dev->driver->bo_driver->init_mem_type(dev, type, man); + if (ret) + return ret; + + ret = 0; + if (type != DRM_BO_MEM_LOCAL) { + if (!p_size) { + DRM_ERROR("Zero size memory manager type %d\n", type); + return ret; + } + ret = drm_mm_init(&man->manager, p_offset, p_size); + if (ret) + return ret; + } + 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); + + return 0; +} +EXPORT_SYMBOL(drm_bo_init_mm); + +/* + * This function is intended to be called on drm driver unload. + * If you decide to call it from lastclose, you must protect the call + * from a potentially racing drm_bo_driver_init in firstopen. + * (This may happen on X server restart). + */ + +int drm_bo_driver_finish(struct drm_device *dev) +{ + struct drm_buffer_manager *bm = &dev->bm; + int ret = 0; + unsigned i = DRM_BO_MEM_TYPES; + struct drm_mem_type_manager *man; + + mutex_lock(&dev->struct_mutex); + + if (!bm->initialized) + goto out; + bm->initialized = 0; + + while (i--) { + man = &bm->man[i]; + if (man->has_type) { + man->use_type = 0; + 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); + } + man->has_type = 0; + } + } + mutex_unlock(&dev->struct_mutex); + + if (!cancel_delayed_work(&bm->wq)) + flush_scheduled_work(); + + mutex_lock(&dev->struct_mutex); + drm_bo_delayed_delete(dev, 1); + if (list_empty(&bm->ddestroy)) + DRM_DEBUG("Delayed destroy list was clean\n"); + + if (list_empty(&bm->man[0].lru)) + DRM_DEBUG("Swap list was clean\n"); + + if (list_empty(&bm->man[0].pinned)) + DRM_DEBUG("NO_MOVE list was clean\n"); + + if (list_empty(&bm->unfenced)) + DRM_DEBUG("Unfenced list was clean\n"); + + if (bm->dummy_read_page) + __free_page(bm->dummy_read_page); + + drm_page_alloc_fini(); +out: + mutex_unlock(&dev->struct_mutex); + return ret; +} +EXPORT_SYMBOL(drm_bo_driver_finish); + +/* + * This function is intended to be called on drm driver load. + * If you decide to call it from firstopen, you must protect the call + * from a potentially racing drm_bo_driver_finish in lastclose. + * (This may happen on X server restart). + */ + +int drm_bo_driver_init(struct drm_device *dev) +{ + struct drm_bo_driver *driver = dev->driver->bo_driver; + struct drm_buffer_manager *bm = &dev->bm; + int ret = -EINVAL; + + drm_page_alloc_init(); + + bm->dummy_read_page = NULL; + mutex_lock(&dev->struct_mutex); + if (!driver) + goto out_unlock; + + bm->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32); + if (!bm->dummy_read_page) { + ret = -ENOMEM; + goto out_unlock; + } + + /* + * 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, 1); + if (ret) { + __free_page(bm->dummy_read_page); + bm->dummy_read_page = NULL; + goto out_unlock; + } + + INIT_DELAYED_WORK(&bm->wq, drm_bo_delayed_workqueue); + bm->initialized = 1; + bm->nice_mode = 1; + atomic_set(&bm->count, 0); + bm->cur_pages = 0; + INIT_LIST_HEAD(&bm->unfenced); + INIT_LIST_HEAD(&bm->ddestroy); +out_unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} +EXPORT_SYMBOL(drm_bo_driver_init); + +/* + * buffer object vm functions. + */ + +int drm_mem_reg_is_pci(struct drm_device *dev, struct drm_bo_mem_reg *mem) +{ + struct drm_buffer_manager *bm = &dev->bm; + struct drm_mem_type_manager *man = &bm->man[mem->mem_type]; + + if (!(man->flags & _DRM_FLAG_MEMTYPE_FIXED)) { + if (mem->mem_type == DRM_BO_MEM_LOCAL) + return 0; + + if (man->flags & _DRM_FLAG_MEMTYPE_CMA) + return 0; + + if (mem->flags & DRM_BO_FLAG_CACHED) + return 0; + } + return 1; +} +EXPORT_SYMBOL(drm_mem_reg_is_pci); + +/** + * \c Get the PCI offset for the buffer object memory. + * + * \param bo The buffer object. + * \param bus_base On return the base of the PCI region + * \param bus_offset On return the byte offset into the PCI region + * \param bus_size On return the byte size of the buffer object or zero if + * the buffer object memory is not accessible through a PCI region. + * \return Failure indication. + * + * Returns -EINVAL if the buffer object is currently not mappable. + * Otherwise returns zero. + */ + +int drm_bo_pci_offset(struct drm_device *dev, + struct drm_bo_mem_reg *mem, + unsigned long *bus_base, + unsigned long *bus_offset, unsigned long *bus_size) +{ + struct drm_buffer_manager *bm = &dev->bm; + struct drm_mem_type_manager *man = &bm->man[mem->mem_type]; + + *bus_size = 0; + if (!(man->flags & _DRM_FLAG_MEMTYPE_MAPPABLE)) + return -EINVAL; + + if (drm_mem_reg_is_pci(dev, mem)) { + *bus_offset = mem->mm_node->start << PAGE_SHIFT; + *bus_size = mem->num_pages << PAGE_SHIFT; + *bus_base = man->io_offset; + } + + return 0; +} + +/** + * \c Kill all user-space virtual mappings of this buffer object. + * + * \param bo The buffer object. + * + * Call bo->mutex locked. + */ + +void drm_bo_unmap_virtual(struct drm_buffer_object *bo) +{ + struct drm_device *dev = bo->dev; + 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); +} + +/** + * drm_bo_takedown_vm_locked: + * + * @bo: the buffer object to remove any drm device mapping + * + * Remove any associated vm mapping on the drm device node that + * would have been created for a drm_bo_type_device buffer + */ +void drm_bo_takedown_vm_locked(struct drm_buffer_object *bo) +{ + struct drm_map_list *list; + drm_local_map_t *map; + struct drm_device *dev = bo->dev; + + DRM_ASSERT_LOCKED(&dev->struct_mutex); + if (bo->type != drm_bo_type_device) + return; + + list = &bo->map_list; + if (list->user_token) { + drm_ht_remove_item(&dev->map_hash, &list->hash); + list->user_token = 0; + } + if (list->file_offset_node) { + drm_mm_put_block(list->file_offset_node); + list->file_offset_node = NULL; + } + + map = list->map; + if (!map) + return; + + drm_ctl_free(map, sizeof(*map), DRM_MEM_BUFOBJ); + list->map = NULL; + list->user_token = 0ULL; + drm_bo_usage_deref_locked(&bo); +} +EXPORT_SYMBOL(drm_bo_takedown_vm_locked); + +/** + * drm_bo_setup_vm_locked: + * + * @bo: the buffer to allocate address space for + * + * Allocate address space in the drm device so that applications + * can mmap the buffer and access the contents. This only + * applies to drm_bo_type_device objects as others are not + * placed in the drm device address space. + */ +static int drm_bo_setup_vm_locked(struct drm_buffer_object *bo) +{ + struct drm_map_list *list = &bo->map_list; + drm_local_map_t *map; + struct drm_device *dev = bo->dev; + + DRM_ASSERT_LOCKED(&dev->struct_mutex); + list->map = drm_ctl_calloc(1, sizeof(*map), DRM_MEM_BUFOBJ); + if (!list->map) + return -ENOMEM; + + map = list->map; + map->offset = 0; + map->type = _DRM_TTM; + map->flags = _DRM_REMOVABLE; + map->size = bo->mem.num_pages * PAGE_SIZE; + atomic_inc(&bo->usage); + map->handle = (void *)bo; + + list->file_offset_node = drm_mm_search_free(&dev->offset_manager, + bo->mem.num_pages, 0, 0); + + if (unlikely(!list->file_offset_node)) { + drm_bo_takedown_vm_locked(bo); + return -ENOMEM; + } + + list->file_offset_node = drm_mm_get_block(list->file_offset_node, + bo->mem.num_pages, 0); + + if (unlikely(!list->file_offset_node)) { + drm_bo_takedown_vm_locked(bo); + return -ENOMEM; + } + + list->hash.key = list->file_offset_node->start; + if (drm_ht_insert_item(&dev->map_hash, &list->hash)) { + drm_bo_takedown_vm_locked(bo); + return -ENOMEM; + } + + list->user_token = ((uint64_t) list->hash.key) << PAGE_SHIFT; + + 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; + +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); + + 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(1); + + mutex_unlock(&dev->struct_mutex); + +} +EXPORT_SYMBOL(drm_bo_evict_mm); diff --git a/drivers/gpu/drm/drm_bo_move.c b/drivers/gpu/drm/drm_bo_move.c new file mode 100644 index 0000000..abeab6a --- /dev/null +++ b/drivers/gpu/drm/drm_bo_move.c @@ -0,0 +1,709 @@ +/************************************************************************** + * + * 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 + */ + +#include "drmP.h" + +#if defined(CONFIG_X86) +#include +#endif + +/** + * Free the old memory node unless it's a pinned region and we + * have not been requested to free also pinned regions. + */ + +static void drm_bo_free_old_node(struct drm_buffer_object *bo) +{ + struct drm_bo_mem_reg *old_mem = &bo->mem; + + if (old_mem->mm_node && (old_mem->mm_node != bo->pinned_node)) { + mutex_lock(&bo->dev->struct_mutex); + drm_mm_put_block(old_mem->mm_node); + mutex_unlock(&bo->dev->struct_mutex); + } + old_mem->mm_node = NULL; +} + +int drm_bo_move_ttm(struct drm_buffer_object *bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem) +{ + struct drm_ttm *ttm = bo->ttm; + 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; + int ret; + + if (old_mem->mem_type != DRM_BO_MEM_LOCAL) { + if (evict) + drm_ttm_evict(ttm); + else + drm_ttm_unbind(ttm); + + drm_bo_free_old_node(bo); + DRM_FLAG_MASKED(old_mem->flags, + DRM_BO_FLAG_CACHED | DRM_BO_FLAG_MAPPABLE | + DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEMTYPE); + old_mem->mem_type = DRM_BO_MEM_LOCAL; + save_flags = old_mem->flags; + } + if (new_mem->mem_type != DRM_BO_MEM_LOCAL) { + ret = drm_ttm_bind(ttm, new_mem); + if (ret) + return ret; + } + + *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); + return 0; +} +EXPORT_SYMBOL(drm_bo_move_ttm); + +/** + * \c Return a kernel virtual address to the buffer object PCI memory. + * + * \param bo The buffer object. + * \return Failure indication. + * + * Returns -EINVAL if the buffer object is currently not mappable. + * Returns -ENOMEM if the ioremap operation failed. + * Otherwise returns zero. + * + * After a successfull call, bo->iomap contains the virtual address, or NULL + * if the buffer object content is not accessible through PCI space. + * Call bo->mutex locked. + */ + +int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg *mem, + void **virtual) +{ + struct drm_buffer_manager *bm = &dev->bm; + struct drm_mem_type_manager *man = &bm->man[mem->mem_type]; + unsigned long bus_offset; + unsigned long bus_size; + unsigned long bus_base; + int ret; + void *addr; + + *virtual = NULL; + ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset, &bus_size); + if (ret || bus_size == 0) + return ret; + + if (!(man->flags & _DRM_FLAG_NEEDS_IOREMAP)) + addr = (void *)(((u8 *) man->io_addr) + bus_offset); + else { + addr = ioremap_nocache(bus_base + bus_offset, bus_size); + if (!addr) + return -ENOMEM; + } + *virtual = addr; + return 0; +} +EXPORT_SYMBOL(drm_mem_reg_ioremap); + +/** + * \c Unmap mapping obtained using drm_bo_ioremap + * + * \param bo The buffer object. + * + * Call bo->mutex locked. + */ + +void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg *mem, + void *virtual) +{ + struct drm_buffer_manager *bm; + struct drm_mem_type_manager *man; + + bm = &dev->bm; + man = &bm->man[mem->mem_type]; + + if (virtual && (man->flags & _DRM_FLAG_NEEDS_IOREMAP)) + iounmap(virtual); +} +EXPORT_SYMBOL(drm_mem_reg_iounmap); + +static int drm_copy_io_page(void *dst, void *src, unsigned long page) +{ + uint32_t *dstP = + (uint32_t *) ((unsigned long)dst + (page << PAGE_SHIFT)); + uint32_t *srcP = + (uint32_t *) ((unsigned long)src + (page << PAGE_SHIFT)); + + int i; + for (i = 0; i < PAGE_SIZE / sizeof(uint32_t); ++i) + iowrite32(ioread32(srcP++), dstP++); + return 0; +} + +static int drm_copy_io_ttm_page(struct drm_ttm *ttm, void *src, + unsigned long page) +{ + struct page *d = drm_ttm_get_page(ttm, page); + void *dst; + + if (!d) + return -ENOMEM; + + src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); + dst = kmap(d); + if (!dst) + return -ENOMEM; + + memcpy_fromio(dst, src, PAGE_SIZE); + kunmap(d); + return 0; +} + +static int drm_copy_ttm_io_page(struct drm_ttm *ttm, void *dst, unsigned long page) +{ + struct page *s = drm_ttm_get_page(ttm, page); + void *src; + + if (!s) + return -ENOMEM; + + dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); + src = kmap(s); + if (!src) + return -ENOMEM; + + memcpy_toio(dst, src, PAGE_SIZE); + kunmap(s); + return 0; +} + +int drm_bo_move_memcpy(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; + struct drm_bo_mem_reg *old_mem = &bo->mem; + struct drm_bo_mem_reg old_copy = *old_mem; + void *old_iomap; + void *new_iomap; + int ret; + uint64_t save_flags = old_mem->flags; + uint64_t save_proposed_flags = old_mem->proposed_flags; + unsigned long i; + unsigned long page; + unsigned long add = 0; + int dir; + + ret = drm_mem_reg_ioremap(dev, old_mem, &old_iomap); + if (ret) + return ret; + ret = drm_mem_reg_ioremap(dev, new_mem, &new_iomap); + if (ret) + goto out; + + if (old_iomap == NULL && new_iomap == NULL) + goto out2; + if (old_iomap == NULL && ttm == NULL) + goto out2; + + add = 0; + dir = 1; + + 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; + add = new_mem->num_pages - 1; + } + + for (i = 0; i < new_mem->num_pages; ++i) { + page = i * dir + add; + if (old_iomap == NULL) + ret = drm_copy_ttm_io_page(ttm, new_iomap, page); + else if (new_iomap == NULL) + ret = drm_copy_io_ttm_page(ttm, old_iomap, page); + else + ret = drm_copy_io_page(new_iomap, old_iomap, page); + 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: + drm_mem_reg_iounmap(dev, &old_copy, old_iomap); + return ret; +} +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 + * object. Call bo->mutex locked. + */ + +int drm_buffer_object_transfer(struct drm_buffer_object *bo, + struct drm_buffer_object **new_obj) +{ + struct drm_buffer_object *fbo; + struct drm_device *dev = bo->dev; + struct drm_buffer_manager *bm = &dev->bm; + + fbo = drm_ctl_calloc(1, sizeof(*fbo), DRM_MEM_BUFOBJ); + if (!fbo) + return -ENOMEM; + + *fbo = *bo; + mutex_init(&fbo->mutex); + mutex_lock(&fbo->mutex); + mutex_lock(&dev->struct_mutex); + + DRM_INIT_WAITQUEUE(&bo->event_queue); + INIT_LIST_HEAD(&fbo->ddestroy); + INIT_LIST_HEAD(&fbo->lru); + INIT_LIST_HEAD(&fbo->pinned_lru); +#ifdef DRM_ODD_MM_COMPAT + INIT_LIST_HEAD(&fbo->vma_list); + INIT_LIST_HEAD(&fbo->p_mm_list); +#endif + + fbo->fence = drm_fence_reference_locked(bo->fence); + fbo->pinned_node = NULL; + fbo->mem.mm_node->private = (void *)fbo; + atomic_set(&fbo->usage, 1); + atomic_inc(&bm->count); + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&fbo->mutex); + + *new_obj = fbo; + return 0; +} + +/* + * Since move is underway, we need to block signals in this function. + * We cannot restart until it has finished. + */ + +int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo, + int evict, int no_wait, uint32_t fence_class, + uint32_t fence_type, uint32_t fence_flags, + 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_bo_mem_reg *old_mem = &bo->mem; + int ret; + uint64_t save_flags = old_mem->flags; + uint64_t save_proposed_flags = old_mem->proposed_flags; + struct drm_buffer_object *old_obj; + + if (bo->fence) + drm_fence_usage_deref_unlocked(&bo->fence); + ret = drm_fence_object_create(dev, fence_class, fence_type, + fence_flags | DRM_FENCE_FLAG_EMIT, + &bo->fence); + bo->fence_type = fence_type; + if (ret) + return ret; + +#ifdef DRM_ODD_MM_COMPAT + /* + * In this mode, we don't allow pipelining a copy blit, + * since the buffer will be accessible from user space + * the moment we return and rebuild the page tables. + * + * With normal vm operation, page tables are rebuilt + * on demand using fault(), which waits for buffer idle. + */ + if (1) +#else + if (evict || ((bo->mem.mm_node == bo->pinned_node) && + bo->mem.mm_node != NULL)) +#endif + { + if (bo->fence) { + (void) drm_fence_object_wait(bo->fence, 0, 1, + bo->fence_type); + drm_fence_usage_deref_unlocked(&bo->fence); + } + drm_bo_free_old_node(bo); + + if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (bo->ttm != NULL)) { + drm_ttm_unbind(bo->ttm); + drm_ttm_destroy(bo->ttm); + bo->ttm = NULL; + } + } else { + + /* This should help pipeline ordinary buffer moves. + * + * Hang old buffer memory on a new buffer object, + * and leave it to be released when the GPU + * operation has completed. + */ + + ret = drm_buffer_object_transfer(bo, &old_obj); + + if (ret) + return ret; + + if (!(man->flags & _DRM_FLAG_MEMTYPE_FIXED)) + old_obj->ttm = NULL; + else + bo->ttm = NULL; + + mutex_lock(&dev->struct_mutex); + list_del_init(&old_obj->lru); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + drm_bo_add_to_lru(old_obj); + + drm_bo_usage_deref_locked(&old_obj); + mutex_unlock(&dev->struct_mutex); + + } + + *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); + return 0; +} +EXPORT_SYMBOL(drm_bo_move_accel_cleanup); + +int drm_bo_same_page(unsigned long offset, + unsigned long offset2) +{ + return (offset & PAGE_MASK) == (offset2 & PAGE_MASK); +} +EXPORT_SYMBOL(drm_bo_same_page); + +unsigned long drm_bo_offset_end(unsigned long offset, + unsigned long end) +{ + offset = (offset + PAGE_SIZE) & PAGE_MASK; + return (end < offset) ? end : offset; +} +EXPORT_SYMBOL(drm_bo_offset_end); + +static pgprot_t drm_kernel_io_prot(uint32_t map_type) +{ + pgprot_t tmp = PAGE_KERNEL; + +#if defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { + pgprot_val(tmp) |= _PAGE_PCD; + pgprot_val(tmp) &= ~_PAGE_PWT; +#if defined(CONFIG_X86_PAT) + /* for a scatter gather backed map, use + WC page bits */ + if (((map_type == _DRM_FRAME_BUFFER) || (map_type == _DRM_SCATTER_GATHER)) && pat_enabled) + tmp = PAGE_KERNEL_WC; +#endif + } +#elif defined(__powerpc__) + pgprot_val(tmp) |= _PAGE_NO_CACHE; + if (map_type == _DRM_REGISTERS) + pgprot_val(tmp) |= _PAGE_GUARDED; +#endif +#if defined(__ia64__) + if (map_type == _DRM_TTM) + tmp = pgprot_writecombine(tmp); + else + tmp = pgprot_noncached(tmp); +#endif + return tmp; +} + +static int drm_bo_ioremap(struct drm_buffer_object *bo, unsigned long bus_base, + unsigned long bus_offset, unsigned long bus_size, + struct drm_bo_kmap_obj *map) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg *mem = &bo->mem; + struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type]; + + if (!(man->flags & _DRM_FLAG_NEEDS_IOREMAP)) { + map->bo_kmap_type = bo_map_premapped; + map->virtual = (void *)(((u8 *) man->io_addr) + bus_offset); + } else { + map->bo_kmap_type = bo_map_iomap; + map->virtual = ioremap_nocache(bus_base + bus_offset, bus_size); + } + return (!map->virtual) ? -ENOMEM : 0; +} + +static int drm_bo_kmap_ttm(struct drm_buffer_object *bo, + unsigned long start_page, unsigned long num_pages, + struct drm_bo_kmap_obj *map) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg *mem = &bo->mem; + struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type]; + pgprot_t prot; + struct drm_ttm *ttm = bo->ttm; + struct page *d; + int i; + + BUG_ON(!ttm); + + if (num_pages == 1 && (mem->flags & DRM_BO_FLAG_CACHED)) { + + /* + * We're mapping a single page, and the desired + * page protection is consistent with the bo. + */ + + map->bo_kmap_type = bo_map_kmap; + map->page = drm_ttm_get_page(ttm, start_page); + map->virtual = kmap(map->page); + } else { + /* + * Populate the part we're mapping; + */ + + for (i = start_page; i < start_page + num_pages; ++i) { + d = drm_ttm_get_page(ttm, i); + if (!d) + return -ENOMEM; + } + + /* + * We need to use vmap to get the desired page protection + * or to make the buffer object look contigous. + */ + + prot = (mem->flags & DRM_BO_FLAG_CACHED) ? + PAGE_KERNEL : + drm_kernel_io_prot(man->drm_bus_maptype); + map->bo_kmap_type = bo_map_vmap; + map->virtual = vmap(ttm->pages + start_page, + num_pages, 0, prot); + } + return (!map->virtual) ? -ENOMEM : 0; +} + +/* + * This function is to be used for kernel mapping of buffer objects. + * It chooses the appropriate mapping method depending on the memory type + * and caching policy the buffer currently has. + * Mapping multiple pages or buffers that live in io memory is a bit slow and + * consumes vmalloc space. Be restrictive with such mappings. + * Mapping single pages usually returns the logical kernel address, + * (which is fast) + * BUG may use slower temporary mappings for high memory pages or + * uncached / write-combined pages. + * + * The function fills in a drm_bo_kmap_obj which can be used to return the + * kernel virtual address of the buffer. + * + * Code servicing a non-priviliged user request is only allowed to map one + * page at a time. We might need to implement a better scheme to stop such + * processes from consuming all vmalloc space. + */ + +int drm_bo_kmap(struct drm_buffer_object *bo, unsigned long start_page, + unsigned long num_pages, struct drm_bo_kmap_obj *map) +{ + int ret; + unsigned long bus_base; + unsigned long bus_offset; + unsigned long bus_size; + + map->virtual = NULL; + + if (num_pages > bo->num_pages) + return -EINVAL; + if (start_page > bo->num_pages) + return -EINVAL; +#if 0 + if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC)) + return -EPERM; +#endif + ret = drm_bo_pci_offset(bo->dev, &bo->mem, &bus_base, + &bus_offset, &bus_size); + + if (ret) + return ret; + + /* 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); + } else { + bus_offset += start_page << PAGE_SHIFT; + bus_size = num_pages << PAGE_SHIFT; + return drm_bo_ioremap(bo, bus_base, bus_offset, bus_size, map); + } +} +EXPORT_SYMBOL(drm_bo_kmap); + +void drm_bo_kunmap(struct drm_bo_kmap_obj *map) +{ + if (!map->virtual) + return; + + switch (map->bo_kmap_type) { + case bo_map_iomap: + iounmap(map->virtual); + break; + case bo_map_vmap: + vunmap(map->virtual); + break; + case bo_map_kmap: + kunmap(map->page); + break; + case bo_map_premapped: + break; + default: + BUG(); + } + map->virtual = NULL; + map->page = NULL; +} +EXPORT_SYMBOL(drm_bo_kunmap); + +int drm_bo_pfn_prot(struct drm_buffer_object *bo, + unsigned long dst_offset, + unsigned long *pfn, + pgprot_t *prot) +{ + struct drm_bo_mem_reg *mem = &bo->mem; + struct drm_device *dev = bo->dev; + unsigned long bus_offset; + unsigned long bus_size; + unsigned long bus_base; + struct drm_mem_type_manager *man = &dev->bm.man[mem->mem_type]; + int ret; + + ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset, + &bus_size); + if (ret) + return -EINVAL; + + if (bus_size != 0) + *pfn = (bus_base + bus_offset + dst_offset) >> PAGE_SHIFT; + else if (!bo->ttm) + return -EINVAL; + else + *pfn = page_to_pfn(drm_ttm_get_page(bo->ttm, dst_offset >> PAGE_SHIFT)); + + *prot = (mem->flags & DRM_BO_FLAG_CACHED) ? + PAGE_KERNEL : drm_kernel_io_prot(man->drm_bus_maptype); + + return 0; +} +EXPORT_SYMBOL(drm_bo_pfn_prot); + diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 6d80d17..4d2161f 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -249,7 +249,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t 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->primary->master->lock.hw_lock != NULL) { + if (dev->primary->master->lock.hw_lock != &dev->default_lock) { vfree(map->handle); drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EBUSY; @@ -463,8 +463,8 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) vfree(map->handle); if (master) { if (dev->sigdata.lock == master->lock.hw_lock) - dev->sigdata.lock = NULL; - master->lock.hw_lock = NULL; /* SHM removed */ + dev->sigdata.lock = &dev->default_lock; + master->lock.hw_lock = &dev->default_lock; master->lock.file_priv = NULL; wake_up_interruptible_all(&master->lock.lock_queue); } @@ -481,6 +481,9 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) case _DRM_GEM: DRM_ERROR("tried to rmmap GEM object\n"); break; + case _DRM_TTM: + BUG_ON(1); + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); @@ -1580,6 +1583,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) @@ -1590,6 +1594,7 @@ 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; } @@ -1607,6 +1612,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/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 94a7688..c580c55 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1511,7 +1511,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, 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/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 4589044..f6182a5 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -849,6 +849,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) set->x, set->y, old_fb); if (ret != 0) goto fail_set_mode; + set->crtc->x = set->x; + set->crtc->y = set->y; } kfree(save_encoders); @@ -988,3 +990,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/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index c77c6c6..2cba5f5 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -48,6 +48,7 @@ static struct drm_info_list drm_debugfs_list[] = { {"bufs", drm_bufs_info, 0}, {"gem_names", drm_gem_name_info, DRIVER_GEM}, {"gem_objects", drm_gem_object_info, DRIVER_GEM}, + {"page_alloc", drm_page_alloc_info, 0}, #if DRM_DEBUG_CODE {"vma", drm_vma_info, 0}, #endif diff --git a/drivers/gpu/drm/drm_dma.c b/drivers/gpu/drm/drm_dma.c index 7a8e2fb..0b2df71 100644 --- a/drivers/gpu/drm/drm_dma.c +++ b/drivers/gpu/drm/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/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index f01def1..11eedcb 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -167,8 +167,12 @@ int drm_lastclose(struct drm_device * dev) if (dev->driver->lastclose) 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_core_check_feature(dev, DRIVER_MODESET)) drm_irq_uninstall(dev); @@ -317,9 +321,34 @@ static const struct file_operations drm_stub_fops = { static int __init drm_core_init(void) { int ret = -ENOMEM; + struct sysinfo si; + unsigned long avail_memctl_mem; + unsigned long max_memctl_mem; idr_init(&drm_minors_idr); + si_meminfo(&si); + + /* + * AGP only allows low / DMA32 memory ATM. + */ + + avail_memctl_mem = si.totalram - si.totalhigh; + + /* + * Avoid overflows + */ + + max_memctl_mem = 1UL << (32 - PAGE_SHIFT); + max_memctl_mem = (max_memctl_mem / si.mem_unit) * PAGE_SIZE; + + if (avail_memctl_mem >= max_memctl_mem) + avail_memctl_mem = max_memctl_mem; + + drm_init_memctl(avail_memctl_mem/2, avail_memctl_mem*3/4, si.mem_unit); + + ret = -ENOMEM; + if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) goto err_p1; diff --git a/drivers/gpu/drm/drm_fence.c b/drivers/gpu/drm/drm_fence.c new file mode 100644 index 0000000..f1c386c --- /dev/null +++ b/drivers/gpu/drm/drm_fence.c @@ -0,0 +1,540 @@ +/************************************************************************** + * + * 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" + + +/* + * Convenience function to be called by fence::wait methods that + * need polling. + */ + +int drm_fence_wait_polling(struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask, + unsigned long end_jiffies) +{ + struct drm_device *dev = fence->dev; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; + uint32_t count = 0; + int ret; + + DECLARE_WAITQUEUE(entry, current); + add_wait_queue(&fc->fence_queue, &entry); + + ret = 0; + + for (;;) { + __set_current_state((interruptible) ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); + if (drm_fence_object_signaled(fence, mask)) + break; + if (time_after_eq(jiffies, end_jiffies)) { + ret = -EBUSY; + break; + } + if (lazy) + schedule_timeout(1); + else if ((++count & 0x0F) == 0){ + __set_current_state(TASK_RUNNING); + schedule(); + __set_current_state((interruptible) ? + TASK_INTERRUPTIBLE : + TASK_UNINTERRUPTIBLE); + } + if (interruptible && signal_pending(current)) { + ret = -EAGAIN; + break; + } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&fc->fence_queue, &entry); + return ret; +} +EXPORT_SYMBOL(drm_fence_wait_polling); + +/* + * Typically called by the IRQ handler. + */ + +void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, + uint32_t sequence, uint32_t type, uint32_t error) +{ + int wake = 0; + uint32_t diff; + uint32_t relevant_type; + uint32_t new_type; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; + struct drm_fence_driver *driver = dev->driver->fence_driver; + struct list_head *head; + struct drm_fence_object *fence, *next; + int found = 0; + + if (list_empty(&fc->ring)) + return; + + list_for_each_entry(fence, &fc->ring, ring) { + diff = (sequence - fence->sequence) & driver->sequence_mask; + if (diff > driver->wrap_diff) { + found = 1; + break; + } + } + + fc->waiting_types &= ~type; + head = (found) ? &fence->ring : &fc->ring; + + list_for_each_entry_safe_reverse(fence, next, head, ring) { + if (&fence->ring == &fc->ring) + break; + + if (error) { + fence->error = error; + fence->signaled_types = fence->type; + list_del_init(&fence->ring); + wake = 1; + break; + } + + if (type & DRM_FENCE_TYPE_EXE) + type |= fence->native_types; + + relevant_type = type & fence->type; + new_type = (fence->signaled_types | relevant_type) ^ + fence->signaled_types; + + if (new_type) { + fence->signaled_types |= new_type; + DRM_DEBUG("Fence %p signaled 0x%08x\n", + fence, fence->signaled_types); + + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); + + if (new_type & fence->waiting_types) + wake = 1; + } + + fc->waiting_types |= fence->waiting_types & ~fence->signaled_types; + + if (!(fence->type & ~fence->signaled_types)) { + DRM_DEBUG("Fence completely signaled %p\n", + fence); + list_del_init(&fence->ring); + } + } + + /* + * Reinstate lost waiting types. + */ + + if ((fc->waiting_types & type) != type) { + head = head->prev; + list_for_each_entry(fence, head, ring) { + if (&fence->ring == &fc->ring) + break; + diff = (fc->highest_waiting_sequence - fence->sequence) & + driver->sequence_mask; + if (diff > driver->wrap_diff) + break; + + fc->waiting_types |= fence->waiting_types & ~fence->signaled_types; + } + } + + if (wake) + wake_up_all(&fc->fence_queue); +} +EXPORT_SYMBOL(drm_fence_handler); + +static void drm_fence_unring(struct drm_device *dev, struct list_head *ring) +{ + struct drm_fence_manager *fm = &dev->fm; + unsigned long flags; + + write_lock_irqsave(&fm->lock, flags); + list_del_init(ring); + write_unlock_irqrestore(&fm->lock, flags); +} + +void drm_fence_usage_deref_locked(struct drm_fence_object **fence) +{ + struct drm_fence_object *tmp_fence = *fence; + struct drm_device *dev = tmp_fence->dev; + struct drm_fence_manager *fm = &dev->fm; + + DRM_ASSERT_LOCKED(&dev->struct_mutex); + *fence = NULL; + if (atomic_dec_and_test(&tmp_fence->usage)) { + drm_fence_unring(dev, &tmp_fence->ring); + DRM_DEBUG("Destroyed a fence object %p\n", + tmp_fence); + atomic_dec(&fm->count); + drm_ctl_free(tmp_fence, sizeof(*tmp_fence), DRM_MEM_FENCE); + } +} +EXPORT_SYMBOL(drm_fence_usage_deref_locked); + +void drm_fence_usage_deref_unlocked(struct drm_fence_object **fence) +{ + struct drm_fence_object *tmp_fence = *fence; + struct drm_device *dev = tmp_fence->dev; + struct drm_fence_manager *fm = &dev->fm; + + *fence = NULL; + if (atomic_dec_and_test(&tmp_fence->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&tmp_fence->usage) == 0) { + drm_fence_unring(dev, &tmp_fence->ring); + atomic_dec(&fm->count); + drm_ctl_free(tmp_fence, sizeof(*tmp_fence), DRM_MEM_FENCE); + } + mutex_unlock(&dev->struct_mutex); + } +} +EXPORT_SYMBOL(drm_fence_usage_deref_unlocked); + +struct drm_fence_object +*drm_fence_reference_locked(struct drm_fence_object *src) +{ + DRM_ASSERT_LOCKED(&src->dev->struct_mutex); + + atomic_inc(&src->usage); + return src; +} + +void drm_fence_reference_unlocked(struct drm_fence_object **dst, + struct drm_fence_object *src) +{ + mutex_lock(&src->dev->struct_mutex); + *dst = src; + atomic_inc(&src->usage); + mutex_unlock(&src->dev->struct_mutex); +} +EXPORT_SYMBOL(drm_fence_reference_unlocked); + +int drm_fence_object_signaled(struct drm_fence_object *fence, uint32_t mask) +{ + unsigned long flags; + int signaled; + struct drm_device *dev = fence->dev; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_driver *driver = dev->driver->fence_driver; + + mask &= fence->type; + read_lock_irqsave(&fm->lock, flags); + signaled = (mask & fence->signaled_types) == mask; + read_unlock_irqrestore(&fm->lock, flags); + if (!signaled && driver->poll) { + write_lock_irqsave(&fm->lock, flags); + driver->poll(dev, fence->fence_class, mask); + signaled = (mask & fence->signaled_types) == mask; + write_unlock_irqrestore(&fm->lock, flags); + } + return signaled; +} +EXPORT_SYMBOL(drm_fence_object_signaled); + + +int drm_fence_object_flush(struct drm_fence_object *fence, + uint32_t type) +{ + struct drm_device *dev = fence->dev; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; + struct drm_fence_driver *driver = dev->driver->fence_driver; + unsigned long irq_flags; + uint32_t saved_pending_flush; + uint32_t diff; + int call_flush; + + if (type & ~fence->type) { + DRM_ERROR("Flush trying to extend fence type, " + "0x%x, 0x%x\n", type, fence->type); + return -EINVAL; + } + + write_lock_irqsave(&fm->lock, irq_flags); + fence->waiting_types |= type; + fc->waiting_types |= fence->waiting_types; + diff = (fence->sequence - fc->highest_waiting_sequence) & + driver->sequence_mask; + + if (diff < driver->wrap_diff) + fc->highest_waiting_sequence = fence->sequence; + + /* + * fence->waiting_types has changed. Determine whether + * we need to initiate some kind of flush as a result of this. + */ + + saved_pending_flush = fc->pending_flush; + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); + + if (driver->poll) + driver->poll(dev, fence->fence_class, fence->waiting_types); + + call_flush = fc->pending_flush; + write_unlock_irqrestore(&fm->lock, irq_flags); + + if (call_flush && driver->flush) + driver->flush(dev, fence->fence_class); + + return 0; +} +EXPORT_SYMBOL(drm_fence_object_flush); + +/* + * Make sure old fence objects are signaled before their fence sequences are + * wrapped around and reused. + */ + +void drm_fence_flush_old(struct drm_device *dev, uint32_t fence_class, + uint32_t sequence) +{ + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence_class]; + struct drm_fence_object *fence; + unsigned long irq_flags; + struct drm_fence_driver *driver = dev->driver->fence_driver; + int call_flush; + + uint32_t diff; + + write_lock_irqsave(&fm->lock, irq_flags); + + list_for_each_entry_reverse(fence, &fc->ring, ring) { + diff = (sequence - fence->sequence) & driver->sequence_mask; + if (diff <= driver->flush_diff) + break; + + fence->waiting_types = fence->type; + fc->waiting_types |= fence->type; + + if (driver->needed_flush) + fc->pending_flush |= driver->needed_flush(fence); + } + + if (driver->poll) + driver->poll(dev, fence_class, fc->waiting_types); + + call_flush = fc->pending_flush; + write_unlock_irqrestore(&fm->lock, irq_flags); + + if (call_flush && driver->flush) + driver->flush(dev, fence->fence_class); + + /* + * FIXME: Shold we implement a wait here for really old fences? + */ + +} +EXPORT_SYMBOL(drm_fence_flush_old); + +int drm_fence_object_wait(struct drm_fence_object *fence, + int lazy, int ignore_signals, uint32_t mask) +{ + struct drm_device *dev = fence->dev; + struct drm_fence_driver *driver = dev->driver->fence_driver; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; + int ret = 0; + unsigned long _end = 3 * DRM_HZ; + + if (mask & ~fence->type) { + DRM_ERROR("Wait trying to extend fence type" + " 0x%08x 0x%08x\n", mask, fence->type); + BUG(); + return -EINVAL; + } + + 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) + ret = wait_event_interruptible_timeout + (fc->fence_queue, + drm_fence_object_signaled(fence, mask), + 3 * DRM_HZ); + else + ret = wait_event_timeout + (fc->fence_queue, + drm_fence_object_signaled(fence, mask), + 3 * DRM_HZ); + + if (unlikely(ret == -ERESTARTSYS)) + return -EAGAIN; + + if (unlikely(ret == 0)) + return -EBUSY; + + return 0; + } + + return drm_fence_wait_polling(fence, lazy, !ignore_signals, mask, + _end); +} +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) +{ + struct drm_device *dev = fence->dev; + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_driver *driver = dev->driver->fence_driver; + struct drm_fence_class_manager *fc = &fm->fence_class[fence->fence_class]; + unsigned long flags; + uint32_t sequence; + uint32_t native_types; + int ret; + + drm_fence_unring(dev, &fence->ring); + ret = driver->emit(dev, fence_class, fence_flags, &sequence, + &native_types); + if (ret) + return ret; + + write_lock_irqsave(&fm->lock, flags); + fence->fence_class = fence_class; + fence->type = type; + fence->waiting_types = 0; + fence->signaled_types = 0; + fence->error = 0; + fence->sequence = sequence; + fence->native_types = native_types; + if (list_empty(&fc->ring)) + fc->highest_waiting_sequence = sequence - 1; + list_add_tail(&fence->ring, &fc->ring); + fc->latest_queued_sequence = sequence; + write_unlock_irqrestore(&fm->lock, flags); + return 0; +} +EXPORT_SYMBOL(drm_fence_object_emit); + +static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class, + uint32_t type, + uint32_t fence_flags, + struct drm_fence_object *fence) +{ + int ret = 0; + unsigned long flags; + struct drm_fence_manager *fm = &dev->fm; + + mutex_lock(&dev->struct_mutex); + atomic_set(&fence->usage, 1); + mutex_unlock(&dev->struct_mutex); + + write_lock_irqsave(&fm->lock, flags); + INIT_LIST_HEAD(&fence->ring); + + /* + * Avoid hitting BUG() for kernel-only fence objects. + */ + + fence->fence_class = fence_class; + fence->type = type; + fence->signaled_types = 0; + fence->waiting_types = 0; + fence->sequence = 0; + fence->error = 0; + fence->dev = dev; + write_unlock_irqrestore(&fm->lock, flags); + if (fence_flags & DRM_FENCE_FLAG_EMIT) { + ret = drm_fence_object_emit(fence, fence_flags, + fence->fence_class, type); + } + return ret; +} + +int drm_fence_object_create(struct drm_device *dev, uint32_t fence_class, + uint32_t type, unsigned flags, + struct drm_fence_object **c_fence) +{ + struct drm_fence_object *fence; + int ret; + struct drm_fence_manager *fm = &dev->fm; + + fence = drm_ctl_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + if (!fence) { + DRM_ERROR("Out of memory creating fence object\n"); + return -ENOMEM; + } + ret = drm_fence_object_init(dev, fence_class, type, flags, fence); + if (ret) { + drm_fence_usage_deref_unlocked(&fence); + return ret; + } + *c_fence = fence; + atomic_inc(&fm->count); + + return 0; +} +EXPORT_SYMBOL(drm_fence_object_create); + +void drm_fence_manager_init(struct drm_device *dev) +{ + struct drm_fence_manager *fm = &dev->fm; + struct drm_fence_class_manager *fence_class; + struct drm_fence_driver *fed = dev->driver->fence_driver; + int i; + unsigned long flags; + + rwlock_init(&fm->lock); + write_lock_irqsave(&fm->lock, flags); + fm->initialized = 0; + if (!fed) + goto out_unlock; + + fm->initialized = 1; + fm->num_classes = fed->num_classes; + BUG_ON(fm->num_classes > _DRM_FENCE_CLASSES); + + for (i = 0; i < fm->num_classes; ++i) { + fence_class = &fm->fence_class[i]; + + memset(fence_class, 0, sizeof(*fence_class)); + INIT_LIST_HEAD(&fence_class->ring); + DRM_INIT_WAITQUEUE(&fence_class->fence_queue); + } + + atomic_set(&fm->count, 0); + out_unlock: + write_unlock_irqrestore(&fm->lock, flags); +} + +void drm_fence_manager_takedown(struct drm_device *dev) +{ +} + diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 09a3571..71da516 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -478,6 +478,10 @@ int drm_release(struct inode *inode, struct file *filp) } mutex_unlock(&dev->ctxlist_mutex); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_fb_release(file_priv); + mutex_lock(&dev->struct_mutex); if (file_priv->is_master) { @@ -511,6 +515,7 @@ int drm_release(struct inode *inode, struct file *filp) /* drop the reference held my the file priv */ drm_master_put(&file_priv->master); file_priv->is_master = 0; + list_del(&file_priv->lhead); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index f0f6c6b..dfe452e 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -35,6 +35,7 @@ #include #include "drmP.h" +#include "drm_page_alloc.h" /** * Called when "/proc/dri/.../name" is read. @@ -273,6 +274,13 @@ int drm_gem_object_info(struct seq_file *m, void* data) return 0; } +int drm_page_alloc_info(struct seq_file *m, void *data) +{ + seq_printf(m, "Cached: %d/%d\n", drm_page_alloc_data.cached_pages_in_list, drm_page_alloc_data.total_cached_pages); + seq_printf(m, "Uncached: %d/%d\n", drm_page_alloc_data.uncached_pages_in_list, drm_page_alloc_data.total_uncached_pages); + return 0; +} + #if DRM_DEBUG_CODE int drm_vma_info(struct seq_file *m, void *data) diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index 0c707f5..4942f9d 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -36,6 +36,112 @@ #include #include "drmP.h" + +static struct { + spinlock_t lock; + uint64_t cur_used; + uint64_t emer_used; + uint64_t low_threshold; + uint64_t high_threshold; + uint64_t emer_threshold; +} drm_memctl = { + .lock = SPIN_LOCK_UNLOCKED +}; + +static inline size_t drm_size_align(size_t size) +{ + size_t tmpSize = 4; + if (size > PAGE_SIZE) + return PAGE_ALIGN(size); + + while (tmpSize < size) + tmpSize <<= 1; + + return (size_t) tmpSize; +} + +int drm_alloc_memctl(size_t size) +{ + int ret = 0; + unsigned long a_size = drm_size_align(size); + unsigned long new_used; + + spin_lock(&drm_memctl.lock); + new_used = drm_memctl.cur_used + a_size; + if (likely(new_used < drm_memctl.high_threshold)) { + drm_memctl.cur_used = new_used; + goto out; + } + + /* + * Allow small allocations from root-only processes to + * succeed until the emergency threshold is reached. + */ + + new_used += drm_memctl.emer_used; + if (unlikely(!DRM_SUSER(DRM_CURPROC) || + (a_size > 16*PAGE_SIZE) || + (new_used > drm_memctl.emer_threshold))) { + ret = -ENOMEM; + goto out; + } + + drm_memctl.cur_used = drm_memctl.high_threshold; + drm_memctl.emer_used = new_used - drm_memctl.high_threshold; +out: + spin_unlock(&drm_memctl.lock); + return ret; +} +EXPORT_SYMBOL(drm_alloc_memctl); + + +void drm_free_memctl(size_t size) +{ + unsigned long a_size = drm_size_align(size); + + spin_lock(&drm_memctl.lock); + if (likely(a_size >= drm_memctl.emer_used)) { + a_size -= drm_memctl.emer_used; + drm_memctl.emer_used = 0; + } else { + drm_memctl.emer_used -= a_size; + a_size = 0; + } + drm_memctl.cur_used -= a_size; + spin_unlock(&drm_memctl.lock); +} +EXPORT_SYMBOL(drm_free_memctl); + +void drm_query_memctl(uint64_t *cur_used, + uint64_t *emer_used, + uint64_t *low_threshold, + uint64_t *high_threshold, + uint64_t *emer_threshold) +{ + spin_lock(&drm_memctl.lock); + *cur_used = drm_memctl.cur_used; + *emer_used = drm_memctl.emer_used; + *low_threshold = drm_memctl.low_threshold; + *high_threshold = drm_memctl.high_threshold; + *emer_threshold = drm_memctl.emer_threshold; + spin_unlock(&drm_memctl.lock); +} +EXPORT_SYMBOL(drm_query_memctl); + +void drm_init_memctl(size_t p_low_threshold, + size_t p_high_threshold, + size_t unit_size) +{ + spin_lock(&drm_memctl.lock); + drm_memctl.emer_used = 0; + drm_memctl.cur_used = 0; + drm_memctl.low_threshold = p_low_threshold * unit_size; + drm_memctl.high_threshold = p_high_threshold * unit_size; + drm_memctl.emer_threshold = (drm_memctl.high_threshold >> 4) + + drm_memctl.high_threshold; + spin_unlock(&drm_memctl.lock); +} + #ifdef DEBUG_MEMORY #include "drm_memory_debug.h" #else @@ -77,6 +183,7 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) } return pt; } +EXPORT_SYMBOL(drm_realloc); #if __OS_HAS_AGP static void *agp_remap(unsigned long offset, unsigned long size, diff --git a/drivers/gpu/drm/drm_page_alloc.c b/drivers/gpu/drm/drm_page_alloc.c new file mode 100644 index 0000000..fad6ae3 --- /dev/null +++ b/drivers/gpu/drm/drm_page_alloc.c @@ -0,0 +1,171 @@ +/* + * 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 + +#include "drm_page_alloc.h" + +static struct list_head uncached_free_list; +static struct list_head cached_free_list; + +static struct mutex page_alloc_mutex; +static int page_alloc_inited; + +struct drm_page_alloc_usage drm_page_alloc_data; + +/* add 1MB at a time */ +#define NUM_PAGES_TO_ADD 256 + +static inline void drm_page_put(struct page *page, int cached) +{ + if (!cached) + unmap_page_from_agp(page); + put_page(page); + __free_page(page); +} + +int drm_add_pages_locked(int num_pages, int cached) +{ + struct page *page; + int i; + + DRM_DEBUG("adding %scached memory %ld\n", cached ? "" : "un", + 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); + if (!cached) { +#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); + drm_page_alloc_data.total_uncached_pages++; + drm_page_alloc_data.uncached_pages_in_list++; + } else { + list_add(&page->lru, &cached_free_list); + drm_page_alloc_data.total_cached_pages++; + drm_page_alloc_data.cached_pages_in_list++; + } + } + return i; +} + +struct page *drm_get_page(int cached) +{ + struct page *page = NULL; + int ret; + struct list_head *free_list; + + free_list = cached ? &cached_free_list : &uncached_free_list; + + mutex_lock(&page_alloc_mutex); + if (list_empty(free_list)) { + ret = drm_add_pages_locked(NUM_PAGES_TO_ADD, cached); + if (ret == 0) + return NULL; + } + + page = list_first_entry(free_list, struct page, lru); + list_del(&page->lru); + if (cached) + drm_page_alloc_data.cached_pages_in_list--; + else + drm_page_alloc_data.uncached_pages_in_list--; + + mutex_unlock(&page_alloc_mutex); + return page; +} + +void drm_put_page(struct page *page, int cached) +{ + mutex_lock(&page_alloc_mutex); + if (cached) { + drm_page_alloc_data.cached_pages_in_list++; + list_add(&page->lru, &cached_free_list); + } else { + drm_page_alloc_data.uncached_pages_in_list++; + list_add(&page->lru, &uncached_free_list); + } + mutex_unlock(&page_alloc_mutex); +} + +void drm_release_all_pages(int cached) +{ + struct page *page, *tmp; + struct list_head *free_list; + + free_list = cached ? &cached_free_list : &uncached_free_list; + + list_for_each_entry_safe(page, tmp, free_list, lru) { + list_del(&page->lru); + drm_page_put(page, cached); + } + drm_page_alloc_data.total_cached_pages = 0; + drm_page_alloc_data.total_uncached_pages = 0; +} + +int drm_page_alloc_init(void) +{ + + if (page_alloc_inited) + return 0; + + INIT_LIST_HEAD(&uncached_free_list); + INIT_LIST_HEAD(&cached_free_list); + + mutex_init(&page_alloc_mutex); + page_alloc_inited = 1; + return 0; + +} + +void drm_page_alloc_fini(void) +{ + if (!page_alloc_inited) + return; + + page_alloc_inited = 0; + drm_release_all_pages(0); + drm_release_all_pages(1); +} + diff --git a/drivers/gpu/drm/drm_page_alloc.h b/drivers/gpu/drm/drm_page_alloc.h new file mode 100644 index 0000000..9cf1138 --- /dev/null +++ b/drivers/gpu/drm/drm_page_alloc.h @@ -0,0 +1,33 @@ +/* + * 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 + */ + +struct drm_page_alloc_usage { + int total_uncached_pages; + int total_cached_pages; + int cached_pages_in_list; + int uncached_pages_in_list; +}; + +extern struct drm_page_alloc_usage drm_page_alloc_data; diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index b9631e3..8f0d4de 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -102,6 +102,7 @@ struct drm_master *drm_master_create(struct drm_minor *minor) drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); INIT_LIST_HEAD(&master->magicfree); master->minor = minor; + master->lock.hw_lock = &minor->dev->default_lock; list_add_tail(&master->head, &minor->master_list); @@ -211,6 +212,7 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); + mutex_init(&dev->bm.evict_mutex); idr_init(&dev->drw_idr); @@ -222,7 +224,12 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, dev->hose = pdev->sysdata; #endif - if (drm_ht_create(&dev->map_hash, 12)) { + 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_ht_remove(&dev->map_hash); return -ENOMEM; } @@ -255,7 +262,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, } } - retcode = drm_ctxbitmap_init(dev); if (retcode) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); @@ -271,6 +277,13 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, } } + /* + * Set up default lock for DRI2, which doesn't need a lock. + * User space will override this in the legacy DRI case. + */ + dev->sigdata.lock = &dev->default_lock; + + drm_fence_manager_init(dev); return 0; error_out_unreg: @@ -463,6 +476,7 @@ int drm_put_minor(struct drm_minor **minor_p) *minor_p = NULL; return 0; } +EXPORT_SYMBOL(drm_put_minor); /** * Called via drm_exit() at module unload time or when pci device is diff --git a/drivers/gpu/drm/drm_ttm.c b/drivers/gpu/drm/drm_ttm.c new file mode 100644 index 0000000..ae64a83 --- /dev/null +++ b/drivers/gpu/drm/drm_ttm.c @@ -0,0 +1,476 @@ +/************************************************************************** + * + * 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" +#include + +/** + * Allocates storage for pointers to the pages that back the ttm. + * + * Uses kmalloc if possible. Otherwise falls back to vmalloc. + */ +static void drm_ttm_alloc_page_directory(struct drm_ttm *ttm) +{ + unsigned long size = ttm->num_pages * sizeof(*ttm->pages); + ttm->pages = NULL; + + if (drm_alloc_memctl(size)) + return; + + if (size <= PAGE_SIZE) + ttm->pages = drm_calloc(1, size, DRM_MEM_TTM); + + if (!ttm->pages) { + ttm->pages = vmalloc_user(size); + if (ttm->pages) + ttm->page_flags |= DRM_TTM_PAGEDIR_VMALLOC; + } + if (!ttm->pages) + drm_free_memctl(size); +} + +static void drm_ttm_free_page_directory(struct drm_ttm *ttm) +{ + unsigned long size = ttm->num_pages * sizeof(*ttm->pages); + + if (ttm->page_flags & DRM_TTM_PAGEDIR_VMALLOC) { + vfree(ttm->pages); + ttm->page_flags &= ~DRM_TTM_PAGEDIR_VMALLOC; + } else { + drm_free(ttm->pages, size, DRM_MEM_TTM); + } + drm_free_memctl(size); + ttm->pages = NULL; +} + +static struct page *drm_ttm_alloc_page(struct drm_ttm *ttm, int cached) +{ + struct page *page; + + if (drm_alloc_memctl(PAGE_SIZE)) + return NULL; + + page = drm_get_page(cached); + if (!page) { + drm_free_memctl(PAGE_SIZE); + return NULL; + } + return page; +} + +/* + * Change caching policy for the linear kernel map + * for range of pages in a ttm. + */ +static int drm_ttm_set_caching(struct drm_ttm *ttm, int noncached, int alloc_cached) +{ + int i; + struct page **cur_page; + int ret; + + if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached) + return 0; + + { + ret = drm_ttm_populate(ttm, alloc_cached); + if (ret != 0) + return ret; + } + + if (noncached) + drm_clflush_pages(ttm->pages, ttm->num_pages); + + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages + i; + if (*cur_page) { + if (!PageHighMem(*cur_page)) { + if (noncached) { +#ifdef CONFIG_X86 + set_memory_wc((unsigned long)page_address(*cur_page), 1); +#else + map_page_into_agp(*cur_page); +#endif + } else { + unmap_page_from_agp(*cur_page); + } + } + } + } + + DRM_FLAG_MASKED(ttm->page_flags, noncached, DRM_TTM_PAGE_UNCACHED); + + return 0; +} + + +static void drm_ttm_free_user_pages(struct drm_ttm *ttm) +{ + int write; + int dirty; + struct page *page; + int i; + + BUG_ON(!(ttm->page_flags & DRM_TTM_PAGE_USER)); + write = ((ttm->page_flags & DRM_TTM_PAGE_WRITE) != 0); + dirty = ((ttm->page_flags & DRM_TTM_PAGE_USER_DIRTY) != 0); + + for (i = 0; i < ttm->num_pages; ++i) { + page = ttm->pages[i]; + if (page == NULL) + continue; + + if (page == ttm->dummy_read_page) { + BUG_ON(write); + continue; + } + + if (write && dirty && !PageReserved(page)) + set_page_dirty_lock(page); + + ttm->pages[i] = NULL; + put_page(page); + } +} + +static void drm_ttm_free_alloced_pages(struct drm_ttm *ttm) +{ + int i; + struct drm_buffer_manager *bm = &ttm->dev->bm; + struct page **cur_page; + int cached = !(ttm->page_flags & DRM_TTM_PAGE_UNCACHED); + + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages + i; + if (*cur_page) { + drm_put_page(*cur_page, cached); + drm_free_memctl(PAGE_SIZE); + --bm->cur_pages; + } + } +} + +/* + * Free all resources associated with a ttm. + */ + +int drm_ttm_destroy(struct drm_ttm *ttm) +{ + struct drm_ttm_backend *be; + + if (!ttm) + return 0; + + be = ttm->be; + if (be) { + be->func->destroy(be); + ttm->be = NULL; + } + + if (ttm->pages) { + if (ttm->page_flags & DRM_TTM_PAGE_USER) { + if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) + drm_ttm_set_caching(ttm, 0, 0); + + drm_ttm_free_user_pages(ttm); + } else + drm_ttm_free_alloced_pages(ttm); + + drm_ttm_free_page_directory(ttm); + } + + drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM); + return 0; +} + +struct page *drm_ttm_get_page(struct drm_ttm *ttm, int index) +{ + struct page *p; + struct drm_buffer_manager *bm = &ttm->dev->bm; + int cached = !(ttm->page_flags & DRM_TTM_PAGE_UNCACHED); + + while(NULL == (p = ttm->pages[index])) { + if (cached) + ttm->page_flags |= DRM_TTM_PAGE_ALLOC_CACHED; + + p = drm_ttm_alloc_page(ttm, cached); + if (!p) + return NULL; + + if (PageHighMem(p)) + ttm->pages[--ttm->first_himem_page] = p; + else + ttm->pages[++ttm->last_lomem_page] = p; + + ++bm->cur_pages; + } + return p; +} +EXPORT_SYMBOL(drm_ttm_get_page); + +/** + * drm_ttm_set_user: + * + * @ttm: the ttm to map pages to. This must always be + * a freshly created ttm. + * + * @tsk: a pointer to the address space from which to map + * pages. + * + * @write: a boolean indicating that write access is desired + * + * start: the starting address + * + * Map a range of user addresses to a new ttm object. This + * provides access to user memory from the graphics device. + */ +int drm_ttm_set_user(struct drm_ttm *ttm, + struct task_struct *tsk, + unsigned long start, + unsigned long num_pages) +{ + struct mm_struct *mm = tsk->mm; + int ret; + int write = (ttm->page_flags & DRM_TTM_PAGE_WRITE) != 0; + + BUG_ON(num_pages != ttm->num_pages); + BUG_ON((ttm->page_flags & DRM_TTM_PAGE_USER) == 0); + + down_read(&mm->mmap_sem); + ret = get_user_pages(tsk, mm, start, num_pages, + write, 0, ttm->pages, NULL); + up_read(&mm->mmap_sem); + + if (ret != num_pages && write) { + drm_ttm_free_user_pages(ttm); + return -ENOMEM; + } + + return 0; +} + +/** + * drm_ttm_populate: + * + * @ttm: the object to allocate pages for + * + * Allocate pages for all unset page entries, then + * call the backend to create the hardware mappings + */ +int drm_ttm_populate(struct drm_ttm *ttm, int cached) +{ + struct page *page; + unsigned long i; + struct drm_ttm_backend *be; + + if (ttm->state != ttm_unpopulated) + return 0; + + be = ttm->be; + + /* set page flags */ + if (cached) + ttm->page_flags &= ~DRM_TTM_PAGE_UNCACHED; + else + ttm->page_flags |= DRM_TTM_PAGE_UNCACHED; + + for (i = 0; i < ttm->num_pages; ++i) { + page = drm_ttm_get_page(ttm, i); + if (!page) + return -ENOMEM; + } + + be->func->populate(be, ttm->num_pages, ttm->pages, ttm->dummy_read_page); + ttm->state = ttm_unbound; + return 0; +} + +/** + * drm_ttm_create: + * + * @dev: the drm_device + * + * @size: The size (in bytes) of the desired object + * + * @page_flags: various DRM_TTM_PAGE_* flags. See drm_object.h. + * + * Allocate and initialize a ttm, leaving it unpopulated at this time + */ + +struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, + uint32_t page_flags, struct page *dummy_read_page) +{ + struct drm_bo_driver *bo_driver = dev->driver->bo_driver; + struct drm_ttm *ttm; + + if (!bo_driver) + return NULL; + + ttm = drm_ctl_calloc(1, sizeof(*ttm), DRM_MEM_TTM); + if (!ttm) + return NULL; + + ttm->dev = dev; + atomic_set(&ttm->vma_count, 0); + + ttm->destroy = 0; + ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + ttm->first_himem_page = ttm->num_pages; + ttm->last_lomem_page = -1; + + ttm->page_flags = page_flags; + + ttm->dummy_read_page = dummy_read_page; + + /* + * Account also for AGP module memory usage. + */ + + drm_ttm_alloc_page_directory(ttm); + if (!ttm->pages) { + drm_ttm_destroy(ttm); + DRM_ERROR("Failed allocating page table\n"); + return NULL; + } + ttm->be = bo_driver->create_ttm_backend_entry(dev); + if (!ttm->be) { + drm_ttm_destroy(ttm); + DRM_ERROR("Failed creating ttm backend entry\n"); + return NULL; + } + ttm->state = ttm_unpopulated; + return ttm; +} + +/** + * drm_ttm_evict: + * + * @ttm: the object to be unbound from the aperture. + * + * Transition a ttm from bound to evicted, where it + * isn't present in the aperture, but various caches may + * not be consistent. + */ +void drm_ttm_evict(struct drm_ttm *ttm) +{ + struct drm_ttm_backend *be = ttm->be; + int ret; + + if (ttm->state == ttm_bound) { + ret = be->func->unbind(be); + BUG_ON(ret); + } + + ttm->state = ttm_evicted; +} + +/** + * drm_ttm_fixup_caching: + * + * @ttm: the object to set unbound + * + * XXX this function is misnamed. Transition a ttm from evicted to + * unbound, flushing caches as appropriate. + */ +void drm_ttm_fixup_caching(struct drm_ttm *ttm) +{ + if (ttm->state == ttm_evicted) { + struct drm_ttm_backend *be = ttm->be; + if (be->func->needs_ub_cache_adjust(be)) + if (ttm->page_flags & DRM_TTM_PAGE_ALLOC_CACHED) + drm_ttm_set_caching(ttm, 0, 1); + ttm->state = ttm_unbound; + } +} + +/** + * drm_ttm_unbind: + * + * @ttm: the object to unbind from the graphics device + * + * Unbind an object from the aperture. This removes the mappings + * from the graphics device and flushes caches if necessary. + */ +void drm_ttm_unbind(struct drm_ttm *ttm) +{ + if (ttm->state == ttm_bound) + drm_ttm_evict(ttm); + + drm_ttm_fixup_caching(ttm); +} + +/** + * drm_ttm_bind: + * + * @ttm: the ttm object to bind to the graphics device + * + * @bo_mem: the aperture memory region which will hold the object + * + * Bind a ttm object to the aperture. This ensures that the necessary + * pages are allocated, flushes CPU caches as needed and marks the + * ttm as DRM_TTM_PAGE_USER_DIRTY to indicate that it may have been + * modified by the GPU + */ +int drm_ttm_bind(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem) +{ + struct drm_bo_driver *bo_driver = ttm->dev->driver->bo_driver; + int ret = 0; + struct drm_ttm_backend *be; + int cached = (bo_mem->flags & DRM_BO_FLAG_CACHED); + + if (!ttm) + return -EINVAL; + if (ttm->state == ttm_bound) + return 0; + + be = ttm->be; + + if ((ttm->state == ttm_unbound || ttm->state == ttm_unpopulated) && !cached) + drm_ttm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED, cached); + else if ((bo_mem->flags & DRM_BO_FLAG_CACHED_MAPPED) && + bo_driver->ttm_cache_flush) + bo_driver->ttm_cache_flush(ttm); + + ret = drm_ttm_populate(ttm, cached); + if (ret) + return ret; + + ret = be->func->bind(be, bo_mem); + if (ret) { + ttm->state = ttm_evicted; + DRM_ERROR("Couldn't bind backend.\n"); + return ret; + } + + ttm->state = ttm_bound; + if (ttm->page_flags & DRM_TTM_PAGE_USER) + ttm->page_flags |= DRM_TTM_PAGE_USER_DIRTY; + return 0; +} +EXPORT_SYMBOL(drm_ttm_bind); diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 22f7656..e6bbf0e 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -37,9 +37,15 @@ #if defined(__ia64__) #include #endif +#if defined(CONFIG_X86) +#include +#endif static void drm_vm_open(struct vm_area_struct *vma); static void drm_vm_close(struct vm_area_struct *vma); +static int drm_bo_mmap_locked(struct vm_area_struct *vma, + struct file *filp, + drm_local_map_t *map); static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) { @@ -49,6 +55,14 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { pgprot_val(tmp) |= _PAGE_PCD; pgprot_val(tmp) &= ~_PAGE_PWT; +#if defined(CONFIG_X86_PAT) + /* if PAT is enabled and we are mapping a + TTM mapping */ + if (map_type == _DRM_TTM && pat_enabled) { + pgprot_val(tmp) &= ~_PAGE_PCD; + pgprot_val(tmp) |= _PAGE_PWT; + } +#endif } #elif defined(__powerpc__) pgprot_val(tmp) |= _PAGE_NO_CACHE; @@ -272,6 +286,9 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) case _DRM_GEM: DRM_ERROR("tried to rmmap GEM object\n"); break; + case _DRM_TTM: + BUG_ON(1); + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); } @@ -396,6 +413,8 @@ static struct vm_operations_struct drm_vm_sg_ops = { .close = drm_vm_close, }; + + /** * \c open method for shared virtual memory. * @@ -422,6 +441,7 @@ 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; @@ -572,7 +592,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) return drm_mmap_dma(filp, vma); if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) { - DRM_ERROR("Could not find map\n"); + DRM_ERROR("Could not find map %08x\n", vma->vm_pgoff); return -EINVAL; } @@ -652,6 +672,8 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; vma->vm_page_prot = drm_dma_prot(map->type, vma); break; + case _DRM_TTM: + return drm_bo_mmap_locked(vma, filp, map); default: return -EINVAL; /* This should never happen. */ } @@ -676,3 +698,187 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) return ret; } EXPORT_SYMBOL(drm_mmap); + +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; + 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 = VM_FAULT_NOPAGE; + unsigned long address = (unsigned long)vmf->virtual_address; + unsigned long page_last; + bool is_iomem; + int i; + + dev = bo->dev; + err = mutex_lock_interruptible(&bo->mutex); + if (err) { + return VM_FAULT_NOPAGE; + } + + err = drm_bo_wait(bo, 0, 1, 0, 1); + if (err) { + ret = (err != -EAGAIN) ? VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; + 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) ? VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; + goto out_unlock; + } + } + + err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset, + &bus_size); + + if (err) { + ret = VM_FAULT_SIGBUS; + goto out_unlock; + } + + is_iomem = (bus_size != 0); + page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + page_last = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + + if (is_iomem) { + struct drm_mem_type_manager *man = &dev->bm.man[bo->mem.mem_type]; + vma->vm_page_prot = drm_io_prot(man->drm_bus_maptype, vma); + } else { + ttm = bo->ttm; + drm_ttm_fixup_caching(ttm); + vma->vm_page_prot = (bo->mem.flags & DRM_BO_FLAG_CACHED) ? + vm_get_page_prot(vma->vm_flags) : + drm_io_prot(_DRM_TTM, vma); + } +#define TTM_BO_VM_NUM_PREFAULT 16 + for (i = 0; i < TTM_BO_VM_NUM_PREFAULT; i++) { + if (is_iomem) + pfn = ((bus_base + bus_offset) >> PAGE_SHIFT) + page_offset; + else { + ttm = bo->ttm; + page = drm_ttm_get_page(ttm, page_offset); + if (!page && i == 0) { + ret = VM_FAULT_OOM; + goto out_unlock; + } else if (!page) { + break; + } + pfn = page_to_pfn(page); + } + + err = vm_insert_mixed(vma, address, pfn); + if ((err == -EBUSY) || (err != 0 && i > 0)) + break; + else if (err != 0) { + ret = (err != -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; + goto out_unlock; + } + address += PAGE_SIZE; + if (++page_offset >= page_last) + break; + } +out_unlock: + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); + mutex_unlock(&bo->mutex); + return ret; +} + +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; + bo->mem.proposed_flags &= ~DRM_BO_FLAG_CLEAN; + + drm_vm_open_locked(vma); + atomic_inc(&bo->usage); +} + +/** + * \c vma open method for buffer objects. + * + * \param vma virtual memory area. + */ + +static void drm_bo_vm_open(struct vm_area_struct *vma) +{ + struct drm_buffer_object *bo = (struct drm_buffer_object *) vma->vm_private_data; + struct drm_device *dev = bo->dev; + + mutex_lock(&dev->struct_mutex); + drm_bo_vm_open_locked(vma); + mutex_unlock(&dev->struct_mutex); +} + +/** + * \c vma close method for buffer objects. + * + * \param vma virtual memory area. + */ + +static void drm_bo_vm_close(struct vm_area_struct *vma) +{ + struct drm_buffer_object *bo = (struct drm_buffer_object *) vma->vm_private_data; + struct drm_device *dev = bo->dev; + + drm_vm_close(vma); + if (bo) { + mutex_lock(&dev->struct_mutex); + drm_bo_usage_deref_locked((struct drm_buffer_object **) + &vma->vm_private_data); + mutex_unlock(&dev->struct_mutex); + } + return; +} + + +static struct vm_operations_struct drm_bo_vm_ops = { + .fault = drm_bo_vm_fault, + .open = drm_bo_vm_open, + .close = drm_bo_vm_close, +}; + + +/** + * mmap buffer object memory. + * + * \param vma virtual memory area. + * \param file_priv DRM file private. + * \param map The buffer object drm map. + * \return zero on success or a negative number on failure. + */ + +int drm_bo_mmap_locked(struct vm_area_struct *vma, + struct file *filp, + drm_local_map_t *map) +{ + vma->vm_ops = &drm_bo_vm_ops; + vma->vm_private_data = map->handle; + vma->vm_file = filp; + vma->vm_flags |= VM_RESERVED | VM_IO; + vma->vm_flags |= VM_MIXEDMAP; + drm_bo_vm_open_locked(vma); + return 0; +} diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ee7ce7b..95422bb 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -397,7 +397,8 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) return ret; } -/* Needs the lock as it touches the ring. +/* Needs the lock as it touches the ring, though if user space haven't + * set up a lock, we expect it to not touch the ring. */ int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 64773ce..178386d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -763,12 +763,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (!master_priv->sarea_priv) return 0; - if (pipe) { - master_priv->sarea_priv->pipeB_x = x; - master_priv->sarea_priv->pipeB_y = y; - } else { + switch (pipe) { + case 0: master_priv->sarea_priv->pipeA_x = x; master_priv->sarea_priv->pipeA_y = y; + break; + case 1: + master_priv->sarea_priv->pipeB_x = x; + master_priv->sarea_priv->pipeB_y = y; + break; + default: + DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); + break; } return 0; @@ -891,12 +897,12 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) switch (pipe) { case 0: - master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0; - master_priv->sarea_priv->pipeA_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: - master_priv->sarea_priv->pipeB_w = enabled ? crtc->mode.hdisplay : 0; - master_priv->sarea_priv->pipeB_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/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 52ce439..0eea827 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -3,7 +3,11 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. ccflags-y := -Iinclude/drm -radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o r600_cp.o +radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o r600_cp.o \ + radeon_gem.o radeon_buffer.o radeon_fence.o radeon_cs.o \ + radeon_i2c.o radeon_fb.o radeon_encoders.o radeon_connectors.o radeon_display.o \ + atombios_crtc.o atom.o radeon_atombios.o radeon_combios.o radeon_legacy_crtc.o \ + radeon_legacy_encoders.o radeon_cursor.o radeon_pm.o radeon_gem_debugfs.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h new file mode 100644 index 0000000..f1f18a4 --- /dev/null +++ b/drivers/gpu/drm/radeon/ObjectID.h @@ -0,0 +1,518 @@ +/* +* 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 +#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 */ +/****************************************************/ +#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 +#define GRAPH_OBJECT_ENUM_ID5 0x05 +#define GRAPH_OBJECT_ENUM_ID6 0x06 + +/****************************************************/ +/* 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) + +#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 */ +/****************************************************/ +/* +#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) + +#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 */ +/****************************************************/ +#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/drivers/gpu/drm/radeon/atom-bits.h b/drivers/gpu/drm/radeon/atom-bits.h new file mode 100644 index 0000000..f94d2e2 --- /dev/null +++ b/drivers/gpu/drm/radeon/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/drivers/gpu/drm/radeon/atom-names.h b/drivers/gpu/drm/radeon/atom-names.h new file mode 100644 index 0000000..2cdc170 --- /dev/null +++ b/drivers/gpu/drm/radeon/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/drivers/gpu/drm/radeon/atom-types.h b/drivers/gpu/drm/radeon/atom-types.h new file mode 100644 index 0000000..1125b86 --- /dev/null +++ b/drivers/gpu/drm/radeon/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/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c new file mode 100644 index 0000000..1154791 --- /dev/null +++ b/drivers/gpu/drm/radeon/atom.c @@ -0,0 +1,1141 @@ +/* + * 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 = le32_to_cpu(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); + val = gctx->card->pll_read(gctx->card, idx); + break; + case ATOM_ARG_MC: + idx = U8(*ptr); + (*ptr)++; + if(print) + DEBUG("MC[0x%02X]", idx); + val = gctx->card->mc_read(gctx->card, idx); + break; + } + 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] = cpu_to_le32(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->pll_write(gctx->card, idx, val); + break; + case ATOM_ARG_MC: + idx = U8(*ptr); + (*ptr)++; + DEBUG("MC[0x%02X]", idx); + gctx->card->mc_write(gctx->card, idx, val); + 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] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR)); + ps[1] = cpu_to_le32(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/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h new file mode 100644 index 0000000..289de33 --- /dev/null +++ b/drivers/gpu/drm/radeon/atom.h @@ -0,0 +1,150 @@ +/* + * 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_FB 3 +#define ATOM_ARG_ID 4 +#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 + void (* pll_write)(struct card_info *, uint32_t, uint32_t); // filled by driver + uint32_t (* pll_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/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h new file mode 100644 index 0000000..9932b09 --- /dev/null +++ b/drivers/gpu/drm/radeon/atombios.h @@ -0,0 +1,5025 @@ +/* + * 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; //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 + 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; //Atomic Table, used only by Bios + USHORT DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + 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 + 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; + +// For backward compatible +#define ReadEDIDFromHWAssistedI2C ProcessI2cChannelTransaction +#define UNIPHYTransmitterControl DIG1TransmitterControl +#define LVTMATransmitterControl DIG2TransmitterControl +#define SetCRTC_DPM_State GetConditionalGoldenSetting +#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange + +typedef struct _ATOM_MASTER_COMMAND_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + 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 + 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; + +/****************************************************************************/ +// Structures used by ComputeMemoryEnginePLLTable +/****************************************************************************/ +#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 _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 +}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; + +/****************************************************************************/ +// Structures used by SetMemoryClockTable +/****************************************************************************/ +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; + +/****************************************************************************/ +// 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 + UCHAR ucPadding[3]; +}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 + UCHAR ucPadding[3]; +}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} + 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; + +/****************************************************************************/ +// Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structures used by DIG1EncoderControlTable +// DIG2EncoderControlTable +// ExternalEncoderControlTable +/****************************************************************************/ +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 + +//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_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; + 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 + + +// 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 + // 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 + +/****************************************************************************/ +// Structures used by BlankCRTCTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structures used by EnableCRTCTable +// EnableCRTCMemReqTable +// UpdateCRTC_DoubleBufferRegistersTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structures used by SetCRTC_OverScanTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structures used by SetCRTC_ReplicationTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structures used by SelectCRTC_SourceTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structures used by SetPixelClockTable +// GetPixelClockTable +/****************************************************************************/ +//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 + +/****************************************************************************/ +// Structures used by AdjustDisplayPllTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structures used by EnableYUVTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// 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 +{ + 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 + +/****************************************************************************/ +// Structures used by PowerConnectorDetectionTable +/****************************************************************************/ +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**********************/ + +/****************************************************************************/ +// Structures used by EnableSpreadSpectrumOnPPLLTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structures used by ### +/****************************************************************************/ +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 **********************/ + + +/****************************************************************************/ +// 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 + 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 + + +//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 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 +{ + 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; + +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: +#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 + +//========================================================================================== +//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 + +/****************************************************************************/ +// 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 + +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; + +/****************************************************************************/ +// 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; + 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 + +/****************************************************************************/ +// 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! + 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; + +/****************************************************************************/ +// Structure used in MultimediaCapabilityInfoTable +/****************************************************************************/ +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; + +/****************************************************************************/ +// Structure used in MultimediaConfigInfoTable +/****************************************************************************/ +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; + +/****************************************************************************/ +// Structures used in FirmwareInfoTable +/****************************************************************************/ + +// 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 + +/****************************************************************************/ +// 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 +#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 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; + +/* +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 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. + +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: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. + +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) + +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 + +#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_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_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 ) +#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_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 | 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 + +#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; + + +/****************************************************************************/ +// Structure used in GPIO_I2C_InfoTable +/****************************************************************************/ +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; + +/****************************************************************************/ +// Common Structure used in other structures +/****************************************************************************/ + +#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 + +/****************************************************************************/ +// Structure used in SetCRTC_UsingDTDTimingTable +/****************************************************************************/ +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; + +/****************************************************************************/ +// Structure used in SetCRTC_TimingTable +/****************************************************************************/ +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 + +/****************************************************************************/ +// Structure used in StandardVESA_TimingTable +// AnalogTV_InfoTable +// ComponentVideoInfoTable +/****************************************************************************/ +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; + +/****************************************************************************/ +// 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 + +//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 +{ + 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; + +/****************************************************************************/ +// Structure used in AnalogTV_InfoTable (Top level) +/****************************************************************************/ +//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_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 + +//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 + +/***********************************************************************************/ +// 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 +{ + 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; + +/****************************************************************************/ +// Structure used in GPIO_Pin_LUTTable +/****************************************************************************/ +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; + +/****************************************************************************/ +// Structure used in ComponentVideoInfoTable +/****************************************************************************/ +#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 + +/****************************************************************************/ +// Structure used in object_InfoTable +/****************************************************************************/ +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 +/****************************************************************************/ +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_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 + +#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_DFP4_DPMS_STATE 0x04000000L +#define ATOM_S2_DFP5_DPMS_STATE 0x08000000L + +#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 +#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_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 +#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_DFP4_ACTIVE 0x00000400L +#define ATOM_S3_DFP5_ACTIVE 0x00000800L + +#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_DFP4_CRTC_ACTIVE 0x04000000L +#define ATOM_S3_DFP5_CRTC_ACTIVE 0x08000000L + +#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 + +//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_DFP4_ACTIVEb1 0x04 +#define ATOM_S3_DFP5_ACTIVEb1 0x08 + +#define ATOM_S3_ACTIVE_CRTC1w0 0xFFF + +#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_DFP4_CRTC_ACTIVEb3 0x04 +#define ATOM_S3_DFP5_CRTC_ACTIVEb3 0x08 + +#define ATOM_S3_ACTIVE_CRTC2w1 0xFFF + +#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_DFP4b1 0x04 +#define ATOM_S5_DOS_REQ_DFP5b1 0x08 + +#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_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 +#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_DFP4 0x04000000L +#define ATOM_S6_ACC_REQ_DFP5 0x08000000L + +#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 +#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_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 +#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_DTD_FORMAT 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 + +#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; + 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 + +/////////////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 +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 + 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 + 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 +////////////////////////////////////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; + + +typedef struct _ATOM_MEMORY_FORMAT +{ + ULONG ulDllDisClock; // memory DLL will be disable when target memory clock is below this clock + 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; + 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_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; + 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_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; + 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 +#define ATOM_DP_ACTION_BLANKING 0x07 + +// 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 + +/*********************************************************************************/ + +#pragma pack() // BIOS data must use byte aligment + +#endif /* _ATOMBIOS_H */ diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c new file mode 100644 index 0000000..ac268dd --- /dev/null +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -0,0 +1,629 @@ +/* + * 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" + +#include "radeon_fixed.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); + 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 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; + } +} + +static void +atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, SET_CRTC_USING_DTD_TIMING_PARAMETERS *crtc_param) +{ + 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) +{ + 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) +{ + 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 = NULL; + struct radeon_encoder *radeon_encoder = NULL; + uint8_t frev, crev; + int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); + SET_PIXEL_CLOCK_PS_ALLOCATION args; + PIXEL_CLOCK_PARAMETERS *spc1_ptr; + 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; + struct radeon_pll *pll; + int pll_flags = 0; + + memset(&args, 0, sizeof(args)); + + if (radeon_is_avivo(dev_priv)) { + uint32_t ss_cntl; + + if (radeon_is_dce32(dev_priv) && mode->clock > 200000) /* range limits??? */ + pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; + else + pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + + /* disable spread spectrum clocking for now -- thanks Hedy Lamarr */ + if (radeon_crtc->crtc_id == 0) { + ss_cntl = RADEON_READ(AVIVO_P1PLL_INT_SS_CNTL); + RADEON_WRITE(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1); + } else { + ss_cntl = RADEON_READ(AVIVO_P2PLL_INT_SS_CNTL); + RADEON_WRITE(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1); + } + } else { + pll_flags |= RADEON_PLL_LEGACY; + + 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 (!radeon_is_avivo(dev_priv)) { + if (encoder->encoder_type != DRM_MODE_ENCODER_DAC) + pll_flags |= RADEON_PLL_NO_ODD_POST_DIV; + if (!radeon_is_avivo(dev_priv) && (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)) + pll_flags |= RADEON_PLL_USE_REF_DIV; + } + radeon_encoder = to_radeon_encoder(encoder); + } + } + + 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); + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + switch(frev) { + case 1: + switch(crev) { + case 1: + spc1_ptr = (PIXEL_CLOCK_PARAMETERS *)&args.sPCLKInput; + spc1_ptr->usPixelClock = cpu_to_le16(sclock); + spc1_ptr->usRefDiv = cpu_to_le16(ref_div); + spc1_ptr->usFbDiv = cpu_to_le16(fb_div); + spc1_ptr->ucPostDiv = post_div; + spc1_ptr->ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; + spc1_ptr->ucCRTC = radeon_crtc->crtc_id; + spc1_ptr->ucRefDivSrc = 1; + break; + case 2: + spc2_ptr = (PIXEL_CLOCK_PARAMETERS_V2 *)&args.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: + if (!encoder) + return; + spc3_ptr = (PIXEL_CLOCK_PARAMETERS_V3 *)&args.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); + spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id; + spc3_ptr->ucEncoderMode = atombios_get_encoder_mode(encoder); + 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 *)&args); +} + +int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct 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; + + if (!crtc->fb) + return -EINVAL; + + radeon_fb = to_radeon_framebuffer(crtc->fb); + + obj = radeon_fb->obj; + obj_priv = obj->driver_private; + + if (radeon_gem_object_pin(obj, 0, RADEON_GEM_DOMAIN_VRAM)) + return -EINVAL; + + 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 -EINVAL; + } + + /* 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_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, 0); + RADEON_WRITE(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0); + RADEON_WRITE(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width); + RADEON_WRITE(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height); + + 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); + + RADEON_WRITE(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, + crtc->mode.vdisplay); + x &= ~3; + y &= ~1; + 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); + + 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); + + if (old_fb) { + radeon_fb = to_radeon_framebuffer(old_fb); + radeon_gem_object_unpin(radeon_fb->obj); + } + return 0; +} + +int atombios_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder; + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; + + /* TODO color tiling */ + memset(&crtc_timing, 0, sizeof(crtc_timing)); + + //todo tv + 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; + + 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, old_fb); + 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, old_fb); + radeon_legacy_atom_set_surface(crtc); + } + radeon_init_disp_bandwidth(dev); + return 0; +} + +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); + 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 = { + .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); +} + +void radeon_init_disp_bw_avivo(struct drm_device *dev, + struct drm_display_mode *mode1, + uint32_t pixel_bytes1, + struct drm_display_mode *mode2, + uint32_t pixel_bytes2) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + fixed20_12 min_mem_eff; + fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff; + fixed20_12 sclk_ff, mclk_ff; + uint32_t dc_lb_memory_split, temp; + + min_mem_eff.full = rfixed_const_8(0); + if (dev_priv->disp_priority == 2) { + uint32_t mc_init_misc_lat_timer = 0; + if (dev_priv->chip_family == CHIP_RV515) + mc_init_misc_lat_timer = RADEON_READ_MCIND(dev_priv, RV515_MC_INIT_MISC_LAT_TIMER); + else if (dev_priv->chip_family == CHIP_RS690) + mc_init_misc_lat_timer = RADEON_READ_MCIND(dev_priv, RS690_MC_INIT_MISC_LAT_TIMER); + + mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT); + mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT); + + if (mode2) + mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); + if (mode1) + mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); + + if (dev_priv->chip_family == CHIP_RV515) + RADEON_WRITE_MCIND(RV515_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); + else if (dev_priv->chip_family == CHIP_RS690) + RADEON_WRITE_MCIND(RS690_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); + } + + /* + * determine is there is enough bw for current mode + */ + temp_ff.full = rfixed_const(100); + mclk_ff.full = rfixed_const(dev_priv->mode_info.mclk); + mclk_ff.full = rfixed_div(mclk_ff, temp_ff); + sclk_ff.full = rfixed_const(dev_priv->mode_info.sclk); + sclk_ff.full = rfixed_div(sclk_ff, temp_ff); + + temp = (dev_priv->ram_width / 8) * (dev_priv->is_ddr ? 2 : 1); + temp_ff.full = rfixed_const(temp); + mem_bw.full = rfixed_mul(mclk_ff, temp_ff); + mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); + + pix_clk.full = 0; + pix_clk2.full = 0; + peak_disp_bw.full = 0; + if (mode1) { + temp_ff.full = rfixed_const(1000); + pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ + pix_clk.full = rfixed_div(pix_clk, temp_ff); + temp_ff.full = rfixed_const(pixel_bytes1); + peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); + } + if (mode2) { + temp_ff.full = rfixed_const(1000); + pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ + pix_clk2.full = rfixed_div(pix_clk2, temp_ff); + temp_ff.full = rfixed_const(pixel_bytes2); + peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); + } + + if (peak_disp_bw.full >= mem_bw.full) { + DRM_ERROR("You may not have enough display bandwidth for current mode\n" + "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); + printk("peak disp bw %d, mem_bw %d\n", rfixed_trunc(peak_disp_bw), + rfixed_trunc(mem_bw)); + } + + /* + * Line Buffer Setup + * There is a single line buffer shared by both display controllers. + * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between the display + * controllers. The paritioning can either be done manually or via one of four + * preset allocations specified in bits 1:0: + * 0 - line buffer is divided in half and shared between each display controller + * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4 + * 2 - D1 gets the whole buffer + * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4 + * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual allocation mode. + * In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits + * 14:4; D2 allocation follows D1. + */ + + /* is auto or manual better ? */ + dc_lb_memory_split = RADEON_READ(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK; + dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; +#if 1 + /* auto */ + if (mode1 && mode2) { + if (mode1->hdisplay > mode2->hdisplay) { + if (mode1->hdisplay > 2560) + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q; + else + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; + } else if (mode2->hdisplay > mode1->hdisplay) { + if (mode2->hdisplay > 2560) + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; + else + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; + } else + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF; + } else if (mode1) { + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY; + } else if (mode2) { + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q; + } +#else + /* manual */ + dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE; + dc_lb_memory_split &= ~(AVIVO_DC_LB_DISP1_END_ADR_MASK << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); + if (mode1) { + dc_lb_memory_split |= ((((mode1->hdisplay / 2) + 64 /*???*/) & AVIVO_DC_LB_DISP1_END_ADR_MASK) + << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); + } else if (mode2) { + dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT); + } + +#endif + RADEON_WRITE(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split); +} diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c index cb2e470..284be37 100644 --- a/drivers/gpu/drm/radeon/r300_cmdbuf.c +++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c @@ -35,6 +35,7 @@ #include "drm.h" #include "radeon_drm.h" #include "radeon_drv.h" +#include "radeon_reg.h" #include "r300_reg.h" #include @@ -160,16 +161,15 @@ static u8 r300_reg_flags[0x10000 >> 2]; void r300_init_reg_flags(struct drm_device *dev) { - int i; + int i, j; drm_radeon_private_t *dev_priv = dev->dev_private; memset(r300_reg_flags, 0, 0x10000 >> 2); -#define ADD_RANGE_MARK(reg, count,mark) \ - for(i=((reg)>>2);i<((reg)>>2)+(count);i++)\ - r300_reg_flags[i]|=(mark); +#define ADD_RANGE_MARK(reg, count,mark) do { \ + for(i = ((reg) >> 2); i < ((reg) >> 2) + (count); i++) \ + r300_reg_flags[i] = (mark); \ + } while(0) -#define MARK_SAFE 1 -#define MARK_CHECK_OFFSET 2 #define ADD_RANGE(reg, count) ADD_RANGE_MARK(reg, count, MARK_SAFE) @@ -249,11 +249,21 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R300_TX_BORDER_COLOR_0, 16); /* Sporadic registers used as primitives are emitted */ - ADD_RANGE(R300_ZB_ZCACHE_CTLSTAT, 1); + ADD_RANGE(R300_RB3D_ZCACHE_CTLSTAT, 1); ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1); ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8); ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8); + ADD_RANGE(R500_SU_REG_DEST, 1); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R420) { + ADD_RANGE(R300_DST_PIPE_CONFIG, 1); + } + + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) + ADD_RANGE_MARK(AVIVO_D1MODE_VLINE_START_END, 1, MARK_CHECK_WAIT_VLINE); + else + ADD_RANGE_MARK(RADEON_CRTC_GUI_TRIG_VLINE, 1, MARK_CHECK_WAIT_VLINE); + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) { ADD_RANGE(R500_VAP_INDEX_OFFSET, 1); ADD_RANGE(R500_US_CONFIG, 2); @@ -263,7 +273,9 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R500_RS_INST_0, 16); ADD_RANGE(R500_RB3D_COLOR_CLEAR_VALUE_AR, 2); ADD_RANGE(R500_RB3D_CONSTANT_COLOR_AR, 2); - ADD_RANGE(R500_ZB_FIFO_SIZE, 2); +// ADD_RANGE(R500_ZB_FIFO_SIZE 2); + ADD_RANGE(R500_GA_US_VECTOR_INDEX, 2); + } else { ADD_RANGE(R300_PFS_CNTL_0, 3); ADD_RANGE(R300_PFS_NODE_0, 4); @@ -274,11 +286,127 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R300_PFS_INSTR3_0, 64); ADD_RANGE(R300_RS_INTERP_0, 8); ADD_RANGE(R300_RS_ROUTE_0, 8); + } + + /* add 2d blit engine registers for DDX */ + ADD_RANGE(RADEON_SRC_Y_X, 3); /* 1434, 1438, 143c, + SRC_Y_X, DST_Y_X, DST_HEIGHT_WIDTH + */ + ADD_RANGE(RADEON_DP_GUI_MASTER_CNTL, 1); /* 146c */ + ADD_RANGE(RADEON_DP_BRUSH_BKGD_CLR, 2); /* 1478, 147c */ + ADD_RANGE(RADEON_DP_SRC_FRGD_CLR, 2); /* 15d8, 15dc */ + ADD_RANGE(RADEON_DP_CNTL, 1); /* 16c0 */ + ADD_RANGE(RADEON_DP_WRITE_MASK, 1); /* 16cc */ + ADD_RANGE(RADEON_DEFAULT_SC_BOTTOM_RIGHT, 1); /* 16e8 */ + + ADD_RANGE(RADEON_DSTCACHE_CTLSTAT, 1); + ADD_RANGE(RADEON_WAIT_UNTIL, 1); + + ADD_RANGE_MARK(RADEON_DST_OFFSET, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_SRC_OFFSET, 1, MARK_CHECK_OFFSET); + + ADD_RANGE_MARK(RADEON_DST_PITCH_OFFSET, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_SRC_PITCH_OFFSET, 1, MARK_CHECK_OFFSET); + + /* TODO SCISSOR */ + ADD_RANGE_MARK(R300_SC_SCISSOR0, 2, MARK_CHECK_SCISSOR); + ADD_RANGE(R300_SC_CLIP_0_A, 2); + ADD_RANGE(R300_SC_CLIP_1_A, 2); + ADD_RANGE(R300_SC_CLIP_2_A, 2); + ADD_RANGE(R300_SC_CLIP_3_A, 2); + ADD_RANGE(R300_SC_CLIP_RULE, 1); + ADD_RANGE(R300_SC_SCREENDOOR, 1); + + ADD_RANGE(R300_VAP_PVS_CODE_CNTL_0, 4); + ADD_RANGE(R300_VAP_PVS_VECTOR_INDX_REG, 2); + ADD_RANGE(R300_VAP_PVS_UPLOAD_DATA, 1); + + if (dev_priv->chip_family <= CHIP_RV280) { + + for (j = 0; j < RADEON_MAX_STATE_PACKETS; j++) { + ADD_RANGE(radeon_packet[j].start, radeon_packet[j].len); + } + + ADD_RANGE(RADEON_SE_TCL_VECTOR_INDX_REG, 2); + ADD_RANGE(RADEON_SE_TCL_SCALAR_INDX_REG, 2); + + ADD_RANGE(RADEON_RE_TOP_LEFT, 1); + ADD_RANGE(RADEON_RE_WIDTH_HEIGHT, 1); + ADD_RANGE(RADEON_AUX_SC_CNTL, 1); + ADD_RANGE(RADEON_RB3D_DSTCACHE_CTLSTAT, 1); + ADD_RANGE(RADEON_RB3D_PLANEMASK, 1); + ADD_RANGE(RADEON_SE_CNTL, 1); + ADD_RANGE(RADEON_PP_CNTL, 1); + ADD_RANGE(RADEON_PP_MISC, 7); + ADD_RANGE(RADEON_RB3D_CNTL, 1); + ADD_RANGE_MARK(RADEON_RB3D_COLOROFFSET, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); + ADD_RANGE(RADEON_RB3D_COLORPITCH, 1); + ADD_RANGE(RADEON_RB3D_BLENDCNTL, 1); + + if (dev_priv->chip_family >= CHIP_R200) { + ADD_RANGE(R200_PP_CNTL_X, 1); + ADD_RANGE(R200_PP_TXMULTI_CTL_0, 1); + ADD_RANGE(R200_SE_VTX_STATE_CNTL, 1); + ADD_RANGE(R200_RE_CNTL, 1); + ADD_RANGE(R200_SE_VTE_CNTL, 1); + ADD_RANGE(R200_SE_VAP_CNTL, 1); + + ADD_RANGE(R200_PP_TXFILTER_0, 1); + ADD_RANGE(R200_PP_TXFORMAT_0, 1); + ADD_RANGE(R200_PP_TXFORMAT_X_0, 1); + ADD_RANGE(R200_PP_TXSIZE_0, 1); + ADD_RANGE(R200_PP_TXPITCH_0, 1); + ADD_RANGE(R200_PP_TFACTOR_0, 1); + + ADD_RANGE(R200_PP_TXFILTER_1, 1); + ADD_RANGE(R200_PP_TXFORMAT_1, 1); + ADD_RANGE(R200_PP_TXFORMAT_X_1, 1); + ADD_RANGE(R200_PP_TXSIZE_1, 1); + ADD_RANGE(R200_PP_TXPITCH_1, 1); + ADD_RANGE(R200_PP_TFACTOR_1, 1); + + ADD_RANGE_MARK(R200_PP_TXOFFSET_0, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_1, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_2, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_3, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_4, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(R200_PP_TXOFFSET_5, 1, MARK_CHECK_OFFSET); + + ADD_RANGE(R200_SE_VTX_FMT_0, 1); + ADD_RANGE(R200_SE_VTX_FMT_1, 1); + ADD_RANGE(R200_PP_TXCBLEND_0, 1); + ADD_RANGE(R200_PP_TXCBLEND2_0, 1); + ADD_RANGE(R200_PP_TXABLEND_0, 1); + ADD_RANGE(R200_PP_TXABLEND2_0, 1); + + } else { + + ADD_RANGE(RADEON_SE_COORD_FMT, 1); + ADD_RANGE(RADEON_SE_CNTL_STATUS, 1); + + ADD_RANGE(RADEON_PP_TXFILTER_0, 1); + ADD_RANGE(RADEON_PP_TXFORMAT_0, 1); + ADD_RANGE(RADEON_PP_TEX_SIZE_0, 1); + ADD_RANGE(RADEON_PP_TEX_PITCH_0, 1); + + ADD_RANGE(RADEON_PP_TXFILTER_1, 1); + ADD_RANGE(RADEON_PP_TXFORMAT_1, 1); + ADD_RANGE(RADEON_PP_TEX_SIZE_1, 1); + ADD_RANGE(RADEON_PP_TEX_PITCH_1, 1); + + ADD_RANGE(RADEON_PP_TXCBLEND_0, 1); + ADD_RANGE(RADEON_PP_TXABLEND_0, 1); + ADD_RANGE(RADEON_SE_VTX_FMT, 1); + ADD_RANGE_MARK(RADEON_PP_TXOFFSET_0, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_PP_TXOFFSET_1, 1, MARK_CHECK_OFFSET); + ADD_RANGE_MARK(RADEON_PP_TXOFFSET_2, 1, MARK_CHECK_OFFSET); + } } } -static __inline__ int r300_check_range(unsigned reg, int count) +int r300_check_range(unsigned reg, int count) { int i; if (reg & ~0xffff) @@ -289,6 +417,13 @@ static __inline__ int r300_check_range(unsigned reg, int count) return 0; } +int r300_get_reg_flags(unsigned reg) +{ + if (reg & ~0xffff) + return -1; + return r300_reg_flags[(reg >> 2)]; +} + static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t * dev_priv, drm_radeon_kcmd_buffer_t diff --git a/drivers/gpu/drm/radeon/r300_reg.h b/drivers/gpu/drm/radeon/r300_reg.h index bdbc95f..f595982 100644 --- a/drivers/gpu/drm/radeon/r300_reg.h +++ b/drivers/gpu/drm/radeon/r300_reg.h @@ -126,15 +126,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* END: Wild guesses */ #define R300_SE_VTE_CNTL 0x20b0 -# define R300_VPORT_X_SCALE_ENA 0x00000001 -# define R300_VPORT_X_OFFSET_ENA 0x00000002 -# define R300_VPORT_Y_SCALE_ENA 0x00000004 -# define R300_VPORT_Y_OFFSET_ENA 0x00000008 -# define R300_VPORT_Z_SCALE_ENA 0x00000010 -# define R300_VPORT_Z_OFFSET_ENA 0x00000020 -# define R300_VTX_XY_FMT 0x00000100 -# define R300_VTX_Z_FMT 0x00000200 -# define R300_VTX_W0_FMT 0x00000400 # define R300_VTX_W0_NORMALIZE 0x00000800 # define R300_VTX_ST_DENORMALIZED 0x00001000 @@ -490,7 +481,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. # define R300_OFIFO_HIGHWATER_SHIFT 22 /* two bits only */ # define R300_CUBE_FIFO_HIGHWATER_COL_SHIFT 24 -#define R300_GB_SELECT 0x401C + # define R300_GB_FOG_SELECT_C0A 0 # define R300_GB_FOG_SELECT_C1A 1 # define R300_GB_FOG_SELECT_C2A 2 @@ -952,7 +943,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* 32 bit chroma key */ #define R300_TX_CHROMA_KEY_0 0x4580 /* ff00ff00 == { 0, 1.0, 0, 1.0 } */ -#define R300_TX_BORDER_COLOR_0 0x45C0 /* END: Texture specification */ @@ -1337,7 +1327,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* gap */ -#define R300_RB3D_COLOROFFSET0 0x4E28 # define R300_COLOROFFSET_MASK 0xFFFFFFF0 /* GUESS */ #define R300_RB3D_COLOROFFSET1 0x4E2C /* GUESS */ #define R300_RB3D_COLOROFFSET2 0x4E30 /* GUESS */ @@ -1349,7 +1338,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. * Bit 17: 4x2 tiles * Bit 18: Extremely weird tile like, but some pixels duplicated? */ -#define R300_RB3D_COLORPITCH0 0x4E38 # define R300_COLORPITCH_MASK 0x00001FF8 /* GUESS */ # define R300_COLOR_TILE_ENABLE (1 << 16) /* GUESS */ # define R300_COLOR_MICROTILE_ENABLE (1 << 17) /* GUESS */ @@ -1362,7 +1350,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #define R300_RB3D_COLORPITCH2 0x4E40 /* GUESS */ #define R300_RB3D_COLORPITCH3 0x4E44 /* GUESS */ -#define R300_RB3D_AARESOLVE_CTL 0x4E88 +//#define R300_RB3D_AARESOLVE_CTL 0x4E88 /* gap */ /* Guess by Vladimir. diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index bc9d09d..c3f12e6 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -1720,7 +1720,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev, radeon_write_agp_location(dev_priv, (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & 0xffff0000) | - (dev_priv->gart_vm_start >> 16))); + (dev_priv->gart_vm_start >> 16)), 0); ring_start = (dev_priv->cp_ring->offset - dev->agp->base diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c new file mode 100644 index 0000000..4ac4c40 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -0,0 +1,1050 @@ +/* + * 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" + +/* from radeon_encoder.c */ +extern uint32_t +radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac); +extern void +radeon_link_encoder_connector(struct drm_device *dev); +extern void +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device); + +extern int radeon_ddc_dump(struct drm_connector *connector); + +/* from radeon_connector.c */ +extern void +radeon_add_atom_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus, + bool linkb, + uint32_t igp_lane_info); + +/* from radeon_legacy_encoder.c */ +extern void +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device); + +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(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.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; +} + +static bool radeon_atom_apply_quirks(struct drm_device *dev, + uint32_t supported_device, + int *connector_type, + struct radeon_i2c_bus_rec *i2c_bus) +{ + + /* Asus M2A-VM HDMI board lists the DVI port as HDMI */ + if ((dev->pdev->device == 0x791e) && + (dev->pdev->subsystem_vendor == 0x1043) && + (dev->pdev->subsystem_device == 0x826d)) { + if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) && + (supported_device == ATOM_DEVICE_DFP3_SUPPORT)) + *connector_type = DRM_MODE_CONNECTOR_DVID; + } + + /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */ + if ((dev->pdev->device == 0x7941) && + (dev->pdev->subsystem_vendor == 0x147b) && + (dev->pdev->subsystem_device == 0x2412)) { + if (*connector_type == DRM_MODE_CONNECTOR_DVII) + return false; + } + + /* Falcon NW laptop lists vga ddc line for LVDS */ + if ((dev->pdev->device == 0x5653) && + (dev->pdev->subsystem_vendor == 0x1462) && + (dev->pdev->subsystem_device == 0x0291)) { + if (*connector_type == DRM_MODE_CONNECTOR_LVDS) + i2c_bus->valid = false; + } + + /* Funky macbooks */ + if ((dev->pdev->device == 0x71C5) && + (dev->pdev->subsystem_vendor == 0x106b) && + (dev->pdev->subsystem_device == 0x0080)) { + if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) || + (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) + return false; + } + + /* some BIOSes seem to report DAC on HDMI - they hurt me with their lies */ + if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) || + (*connector_type == DRM_MODE_CONNECTOR_HDMIB)) { + if (supported_device & (ATOM_DEVICE_CRT_SUPPORT)) + return false; + } + + /* ASUS HD 3600 XT board lists the DVI port as HDMI */ + if ((dev->pdev->device == 0x9598) && + (dev->pdev->subsystem_vendor == 0x1043) && + (dev->pdev->subsystem_device == 0x01da)) { + if (*connector_type == DRM_MODE_CONNECTOR_HDMIB) + *connector_type = DRM_MODE_CONNECTOR_DVID; + } + + return true; +} + +const int supported_devices_connector_convert[] = +{ + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_VGA, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_DVIA, + DRM_MODE_CONNECTOR_SVIDEO, + DRM_MODE_CONNECTOR_Composite, + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_HDMIA, + DRM_MODE_CONNECTOR_HDMIB, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_9PinDIN, + DRM_MODE_CONNECTOR_DisplayPort +}; + +const int object_connector_convert[] = +{ + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_VGA, + DRM_MODE_CONNECTOR_Composite, + DRM_MODE_CONNECTOR_SVIDEO, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_9PinDIN, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_HDMIA, + DRM_MODE_CONNECTOR_HDMIB, + DRM_MODE_CONNECTOR_HDMIB, + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_9PinDIN, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_DisplayPort +}; + +bool radeon_get_atom_connector_info_from_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, line_mux = 0; + ATOM_CONNECTOR_OBJECT_TABLE *con_obj; + ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; + ATOM_OBJECT_HEADER *obj_header; + int i, j, path_size, device_support; + int connector_type; + uint16_t igp_lane_info; + bool linkb; + struct drm_connector *connector; + struct radeon_i2c_bus_rec ddc_bus; + + atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); + + if (data_offset == 0) + return false; + + if (crev < 2) + return false; + + obj_header = (ATOM_OBJECT_HEADER *)(ctx->bios + data_offset); + path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) + (ctx->bios + data_offset + le16_to_cpu(obj_header->usDisplayPathTableOffset)); + con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *) + (ctx->bios + data_offset + le16_to_cpu(obj_header->usConnectorObjectTableOffset)); + device_support = le16_to_cpu(obj_header->usDeviceSupport); + + path_size = 0; + for (i = 0; i < path_obj->ucNumOfDispPath; i++) { + uint8_t *addr = (uint8_t *)path_obj->asDispPath; + ATOM_DISPLAY_OBJECT_PATH *path; + addr += path_size; + path = (ATOM_DISPLAY_OBJECT_PATH *)addr; + path_size += path->usSize; + linkb = false; + + if (device_support & path->usDeviceTag) { + uint8_t con_obj_id, con_obj_num, con_obj_type; + + con_obj_id = (path->usConnObjectId & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + con_obj_num = (path->usConnObjectId & ENUM_ID_MASK) >> ENUM_ID_SHIFT; + con_obj_type = (path->usConnObjectId & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; + + if ((path->usDeviceTag == ATOM_DEVICE_TV1_SUPPORT) || + (path->usDeviceTag == ATOM_DEVICE_TV2_SUPPORT) || + (path->usDeviceTag == ATOM_DEVICE_CV_SUPPORT)) + continue; + + if ((dev_priv->chip_family == CHIP_RS780) && + (con_obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) { + uint16_t igp_offset = 0; + ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj; + + index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); + + atom_parse_data_header(ctx, index, &size, &frev, &crev, &igp_offset); + + if (crev >= 2) { + igp_obj = (ATOM_INTEGRATED_SYSTEM_INFO_V2 *)(ctx->bios + igp_offset); + + if (igp_obj) { + uint32_t slot_config, ct; + + if (con_obj_num == 1) + slot_config = igp_obj->ulDDISlot1Config; + else + slot_config = igp_obj->ulDDISlot2Config; + + ct = (slot_config >> 16) & 0xff; + connector_type = object_connector_convert[ct]; + igp_lane_info = slot_config & 0xffff; + } else + continue; + } else + continue; + } else { + igp_lane_info = 0; + connector_type = object_connector_convert[con_obj_id]; + } + + if (connector_type == DRM_MODE_CONNECTOR_Unknown) + continue; + + for (j = 0; j < ((path->usSize - 8) / 2); j++) { + uint8_t enc_obj_id, enc_obj_num, enc_obj_type; + + enc_obj_id = (path->usGraphicObjIds[j] & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + enc_obj_num = (path->usGraphicObjIds[j] & ENUM_ID_MASK) >> ENUM_ID_SHIFT; + enc_obj_type = (path->usGraphicObjIds[j] & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; + + /* FIXME: add support for router objects */ + if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) { + if (enc_obj_num == 2) + linkb = true; + else + linkb = false; + + radeon_add_atom_encoder(dev, + enc_obj_id, + path->usDeviceTag); + + } + } + + /* look up gpio for ddc */ + if ((path->usDeviceTag & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) { + for (j = 0; j < con_obj->ucNumberOfObjects; j++) { + if (path->usConnObjectId == le16_to_cpu(con_obj->asObjects[j].usObjectID)) { + ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *) + (ctx->bios + data_offset + le16_to_cpu(con_obj->asObjects[j].usRecordOffset)); + ATOM_I2C_RECORD *i2c_record; + + 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: + i2c_record = (ATOM_I2C_RECORD *)record; + line_mux = i2c_record->sucI2cId.bfI2C_LineMux; + break; + } + record = (ATOM_COMMON_RECORD_HEADER *)((char *)record + record->ucRecordSize); + } + break; + } + } + } else + line_mux = 0; + + if ((path->usDeviceTag == ATOM_DEVICE_TV1_SUPPORT) || + (path->usDeviceTag == ATOM_DEVICE_TV2_SUPPORT) || + (path->usDeviceTag == ATOM_DEVICE_CV_SUPPORT)) + ddc_bus.valid = false; + else + ddc_bus = radeon_lookup_gpio(dev, line_mux); + + radeon_add_atom_connector(dev, + path->usConnObjectId, + path->usDeviceTag, + connector_type, + &ddc_bus, + linkb, + igp_lane_info); + + + } + } + + radeon_link_encoder_connector(dev); + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + radeon_ddc_dump(connector); + + return true; +} + +bool radeon_get_atom_connector_info_from_supported_devices_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; + uint8_t line_mux, dac; + int connector_type; + struct drm_connector *connector; + union atom_supported_devices *supported_devices; + struct radeon_i2c_bus_rec ddc_bus; + int i; + + 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))) { + continue; + } + + if (i == ATOM_DEVICE_CV_INDEX) { + DRM_DEBUG("Skipping Component Video\n"); + continue; + } + + if (i == ATOM_DEVICE_TV1_INDEX) { + DRM_DEBUG("Skipping TV Out\n"); + continue; + } + + connector_type = supported_devices_connector_convert[ci.sucConnectorInfo.sbfAccess.bfConnectorType]; + + if (connector_type == DRM_MODE_CONNECTOR_Unknown) + continue; + + dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC; + + if ((dev_priv->chip_family == CHIP_RS690) || + (dev_priv->chip_family == CHIP_RS740)) { + if ((i == ATOM_DEVICE_DFP2_INDEX) || (i == ATOM_DEVICE_DFP3_INDEX)) + line_mux = ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1; + else + line_mux = ci.sucI2cId.sbfAccess.bfI2C_LineMux; + } else + line_mux = ci.sucI2cId.sbfAccess.bfI2C_LineMux; + + /* give tv unique connector ids */ + if (i == ATOM_DEVICE_TV1_INDEX) { + ddc_bus.valid = false; + line_mux = 50; + } else if (i == ATOM_DEVICE_TV2_INDEX) { + ddc_bus.valid = false; + line_mux = 51; + } else if (i == ATOM_DEVICE_CV_INDEX) { + ddc_bus.valid = false; + line_mux = 52; + } else + ddc_bus = radeon_lookup_gpio(dev, line_mux); + + if (!radeon_atom_apply_quirks(dev, (1 << i), &connector_type, &ddc_bus)) + continue; + + radeon_add_atom_connector(dev, + line_mux, + (1 << i), + connector_type, + &ddc_bus, + false, + 0); + + if (radeon_is_avivo(dev_priv) || radeon_r4xx_atom) + radeon_add_atom_encoder(dev, + radeon_get_encoder_id(dev, (1 << i), dac), + (1 << i)); + else + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, (1 << i), dac), + (1 << i)); + } + + radeon_link_encoder_connector(dev); + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + radeon_ddc_dump(connector); + + 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 *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); + + if (firmware_info) { + /* pixel clocks */ + p1pll->reference_freq = le16_to_cpu(firmware_info->info.usReferenceClock); + p1pll->reference_div = 0; + + 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 (p1pll->pll_out_min == 0) { + if (radeon_is_avivo(dev_priv)) + p1pll->pll_out_min = 64800; + else + p1pll->pll_out_min = 20000; + } + + p1pll->pll_in_min = le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input); + p1pll->pll_in_max = le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input); + + *p2pll = *p1pll; + + /* 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; +} + +struct radeon_encoder_int_tmds * +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; + struct radeon_encoder_int_tmds *tmds = NULL; + + 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); + + if (tmds_info) { + tmds = kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); + + if (!tmds) + return NULL; + + maxfreq = le16_to_cpu(tmds_info->usMaxFrequency); + for (i = 0; i < 4; i++) { + tmds->tmds_pll[i].freq = le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency); + tmds->tmds_pll[i].value = tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f; + tmds->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VCO_Gain & 0x3f) << 6; + tmds->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_DutyCycle & 0xf) << 12; + tmds->tmds_pll[i].value |= (tmds_info->asMiscInfo[i].ucPLL_VoltageSwing & 0xf) << 16; + + DRM_DEBUG("TMDS PLL From ATOMBIOS %u %x\n", + tmds->tmds_pll[i].freq, + tmds->tmds_pll[i].value); + + if (maxfreq == tmds->tmds_pll[i].freq) { + tmds->tmds_pll[i].freq = 0xffffffff; + break; + } + } + } + return tmds; +} + +union lvds_info { + struct _ATOM_LVDS_INFO info; + struct _ATOM_LVDS_INFO_V12 info_12; +}; + +struct radeon_encoder_atom_dig * +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; + 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; + struct radeon_encoder_atom_dig *lvds = NULL; + + 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); + + if (lvds_info) { + lvds = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); + + if (!lvds) + return NULL; + + lvds->native_mode.dotclock = le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10; + lvds->native_mode.panel_xres = le16_to_cpu(lvds_info->info.sLCDTiming.usHActive); + lvds->native_mode.panel_yres = le16_to_cpu(lvds_info->info.sLCDTiming.usVActive); + lvds->native_mode.hblank = le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time); + lvds->native_mode.hoverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset); + lvds->native_mode.hsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth); + lvds->native_mode.vblank = le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time); + lvds->native_mode.voverplus = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset); + lvds->native_mode.vsync_width = le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth); + lvds->panel_pwr_delay = le16_to_cpu(lvds_info->info.usOffDelayInMs); + lvds->lvds_misc = lvds_info->info.ucLVDS_Misc; + + encoder->native_mode = lvds->native_mode; + } + return lvds; +} + +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); +} + +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; + 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); +} + +/* at some point we may want to break this out into individual functions */ +void +radeon_atombios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected) +{ + struct drm_device *dev = connector->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch; + + if (dev_priv->chip_family >= CHIP_R600) { + bios_0_scratch = RADEON_READ(R600_BIOS_0_SCRATCH); + bios_3_scratch = RADEON_READ(R600_BIOS_3_SCRATCH); + bios_6_scratch = RADEON_READ(R600_BIOS_6_SCRATCH); + } else { + bios_0_scratch = RADEON_READ(RADEON_BIOS_0_SCRATCH); + bios_3_scratch = RADEON_READ(RADEON_BIOS_3_SCRATCH); + bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + } + + if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) { + if (connected) { + DRM_DEBUG("TV1 connected\n"); + bios_3_scratch |= ATOM_S3_TV1_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_TV1; + } else { + DRM_DEBUG("TV1 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_TV1_MASK; + bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) { + if (connected) { + DRM_DEBUG("CV connected\n"); + bios_3_scratch |= ATOM_S3_CV_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_CV; + } else { + DRM_DEBUG("CV disconnected\n"); + bios_0_scratch &= ~ATOM_S0_CV_MASK; + bios_3_scratch &= ~ATOM_S3_CV_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) { + if (connected) { + DRM_DEBUG("LCD1 connected\n"); + bios_0_scratch |= ATOM_S0_LCD1; + bios_3_scratch |= ATOM_S3_LCD1_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1; + } else { + DRM_DEBUG("LCD1 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_LCD1; + bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) { + if (connected) { + DRM_DEBUG("CRT1 connected\n"); + bios_0_scratch |= ATOM_S0_CRT1_COLOR; + bios_3_scratch |= ATOM_S3_CRT1_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1; + } else { + DRM_DEBUG("CRT1 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_CRT1_MASK; + bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) { + if (connected) { + DRM_DEBUG("CRT2 connected\n"); + bios_0_scratch |= ATOM_S0_CRT2_COLOR; + bios_3_scratch |= ATOM_S3_CRT2_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2; + } else { + DRM_DEBUG("CRT2 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_CRT2_MASK; + bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP1 connected\n"); + bios_0_scratch |= ATOM_S0_DFP1; + bios_3_scratch |= ATOM_S3_DFP1_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1; + } else { + DRM_DEBUG("DFP1 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP1; + bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP2 connected\n"); + bios_0_scratch |= ATOM_S0_DFP2; + bios_3_scratch |= ATOM_S3_DFP2_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2; + } else { + DRM_DEBUG("DFP2 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP2; + bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP3 connected\n"); + bios_0_scratch |= ATOM_S0_DFP3; + bios_3_scratch |= ATOM_S3_DFP3_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3; + } else { + DRM_DEBUG("DFP3 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP3; + bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP4 connected\n"); + bios_0_scratch |= ATOM_S0_DFP4; + bios_3_scratch |= ATOM_S3_DFP4_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4; + } else { + DRM_DEBUG("DFP4 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP4; + bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP5 connected\n"); + bios_0_scratch |= ATOM_S0_DFP5; + bios_3_scratch |= ATOM_S3_DFP5_ACTIVE; + bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5; + } else { + DRM_DEBUG("DFP5 disconnected\n"); + bios_0_scratch &= ~ATOM_S0_DFP5; + bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE; + bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5; + } + } + + if (dev_priv->chip_family >= CHIP_R600) { + RADEON_WRITE(R600_BIOS_0_SCRATCH, bios_0_scratch); + RADEON_WRITE(R600_BIOS_3_SCRATCH, bios_3_scratch); + RADEON_WRITE(R600_BIOS_6_SCRATCH, bios_6_scratch); + } else { + RADEON_WRITE(RADEON_BIOS_0_SCRATCH, bios_0_scratch); + RADEON_WRITE(RADEON_BIOS_3_SCRATCH, bios_3_scratch); + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); + } +} + +void +radeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc) +{ + 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 bios_3_scratch; + + if (dev_priv->chip_family >= CHIP_R600) + bios_3_scratch = RADEON_READ(R600_BIOS_3_SCRATCH); + else + bios_3_scratch = RADEON_READ(RADEON_BIOS_3_SCRATCH); + + if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 18); + } + if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 24); + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 16); + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 20); + } + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 17); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 19); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 23); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) { + bios_3_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE; + bios_3_scratch |= (crtc << 25); + } + + if (dev_priv->chip_family >= CHIP_R600) + RADEON_WRITE(R600_BIOS_3_SCRATCH, bios_3_scratch); + else + RADEON_WRITE(RADEON_BIOS_3_SCRATCH, bios_3_scratch); +} + +void +radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on) +{ + 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 bios_2_scratch; + + if (dev_priv->chip_family >= CHIP_R600) + bios_2_scratch = RADEON_READ(R600_BIOS_2_SCRATCH); + else + bios_2_scratch = RADEON_READ(RADEON_BIOS_2_SCRATCH); + + if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_CV_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP4_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP4_DPMS_STATE; + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) { + if (on) + bios_2_scratch &= ~ATOM_S2_DFP5_DPMS_STATE; + else + bios_2_scratch |= ATOM_S2_DFP5_DPMS_STATE; + } + + if (dev_priv->chip_family >= CHIP_R600) + RADEON_WRITE(R600_BIOS_2_SCRATCH, bios_2_scratch); + else + RADEON_WRITE(RADEON_BIOS_2_SCRATCH, bios_2_scratch); +} diff --git a/drivers/gpu/drm/radeon/radeon_buffer.c b/drivers/gpu/drm/radeon/radeon_buffer.c new file mode 100644 index 0000000..3bc3d79 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_buffer.c @@ -0,0 +1,473 @@ +/************************************************************************** + * + * 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" + +extern int radeon_no_gart_wb; + +struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device * dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; +#if __OS_HAS_AGP + if (dev_priv->flags & RADEON_IS_AGP) + return drm_agp_init_ttm(dev); + else +#endif + 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; + + if (!dev_priv->cp_running) + return 0; + + BEGIN_RING(6); + RADEON_PURGE_CACHE(); + RADEON_PURGE_ZCACHE(); + RADEON_WAIT_UNTIL_3D_IDLE(); + ADVANCE_RING(); + COMMIT_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; + if (radeon_no_gart_wb == 2) + man->flags |= _DRM_FLAG_MEMTYPE_CMA; + else + man->flags |= _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; +} + +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_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; + int num_loops; + 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; + + num_loops = DIV_ROUND_UP(pages, 8191); + + BEGIN_RING(4 + (10 * num_loops)); + + 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 */ + 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); + 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(cur_pages | (stride_pixels << 16)); + } + + OUT_RING(CP_PACKET0(RADEON_DSTCACHE_CTLSTAT, 0)); + OUT_RING(RADEON_RB2D_DC_FLUSH_ALL); + RADEON_WAIT_UNTIL_2D_IDLE(); + ADVANCE_RING(); + + COMMIT_RING(); + return; +} + +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_device *dev = bo->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t old_start, new_start; + + 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_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; + int num_loops; + RING_LOCALS; + + if (!dev_priv) + return; + + if (!radeon_vram_zero) + 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; + + num_loops = DIV_ROUND_UP(pages, 8191); + + BEGIN_RING(4 + (8*num_loops)); + + 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 */ + 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_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 + OUT_RING(clip); // SC_BOT_RITE + + OUT_RING(0); // COLOR + + OUT_RING(pages); /* x - y */ + OUT_RING(cur_pages | (stride_pixels << 16)); + } + + OUT_RING(CP_PACKET0(RADEON_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; + + if (new_mem->mem_type != DRM_BO_MEM_VRAM) + return -1; + + + new_start = new_mem->mm_node->start << PAGE_SHIFT; + 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) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_mem_reg tmp_mem; + int ret; + + tmp_mem = *new_mem; + + /* 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_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; + + 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); + 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; +} + +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; + + /* 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) +{ + struct drm_device *dev = bo->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (!dev_priv->cp_running) + goto fallback; + + if (bo->mem.mem_type == DRM_BO_MEM_VRAM && radeon_no_gart_wb) + 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 (radeon_move_flip(bo, evict, no_wait, new_mem)) + goto fallback; + } + return 0; +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); +} + + +/* + * 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) +{ + struct drm_device *dev = bo->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + int cached = 0; + + if (!(dev_priv->flags & RADEON_IS_AGP)) + cached = DRM_BO_FLAG_CACHED; + + switch (bo->mem.mem_type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return DRM_BO_FLAG_MEM_LOCAL | cached; + default: + return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_LOCAL | cached; + } +} diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c new file mode 100644 index 0000000..5f5a4cb --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -0,0 +1,1768 @@ +/* + * 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" + +/* from radeon_encoder.c */ +extern uint32_t +radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac); +extern void +radeon_link_encoder_connector(struct drm_device *dev); + +extern int radeon_ddc_dump(struct drm_connector *connector); + +/* from radeon_connector.c */ +extern void +radeon_add_legacy_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus); + +/* from radeon_legacy_encoder.c */ +extern void +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device); + +/* 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_TMDS_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_DETECTED_MEM_TABLE, /* offset from misc info */ + COMBIOS_ASIC_INIT_5_TABLE, /* offset from misc info */ + COMBIOS_RAM_RESET_TABLE, /* offset from mem config */ + 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 */ + 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, + 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 +}; + +const int legacy_connector_convert[] = +{ + DRM_MODE_CONNECTOR_Unknown, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_VGA, + DRM_MODE_CONNECTOR_DVII, + DRM_MODE_CONNECTOR_DVID, + DRM_MODE_CONNECTOR_Composite, + DRM_MODE_CONNECTOR_SVIDEO, + DRM_MODE_CONNECTOR_Unknown, +}; + +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_TMDS_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_DETECTED_MEM_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 + 0x7); + 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_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); + 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; + + 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; + 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.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; + i2c.get_data_reg = ddc_line + 4; + } 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; +} + +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 *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); + + /* 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) { + p1pll->pll_in_min = radeon_bios32(dev_priv, pll_info + 0x36); + p1pll->pll_in_max = radeon_bios32(dev_priv, pll_info + 0x3a); + } else { + p1pll->pll_in_min = 40; + p1pll->pll_in_max = 500; + } + *p2pll = *p1pll; + + /* 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); + + 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 + 0xa); + mclk = radeon_bios16(dev_priv, pll_info + 0x8); + if (sclk == 0) + sclk = 200 * 100; + if (mclk == 0) + mclk = 200 * 100; + + mode_info->sclk = sclk; + mode_info->mclk = mclk; + + return true; + } + return false; +} + +struct radeon_encoder_primary_dac * +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; + struct radeon_encoder_primary_dac *p_dac = NULL; + + /* check CRT table */ + dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); + if (dac_info) { + p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL); + + if (!p_dac) + return NULL; + + 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; + p_dac->ps2_pdac_adj = (bg << 8) | (dac); + } else { + bg = radeon_bios8(dev_priv, dac_info + 0x2) & 0xf; + dac = radeon_bios8(dev_priv, dac_info + 0x3) & 0xf; + p_dac->ps2_pdac_adj = (bg << 8) | (dac); + } + + } + + return p_dac; +} + +static enum radeon_tv_std +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; + enum radeon_tv_std tv_std = TV_STD_NTSC; + + 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: + tv_std = TV_STD_NTSC; + DRM_INFO("Default TV standard: NTSC\n"); + break; + case 2: + tv_std = TV_STD_PAL; + DRM_INFO("Default TV standard: PAL\n"); + break; + case 3: + tv_std = TV_STD_PAL_M; + DRM_INFO("Default TV standard: PAL-M\n"); + break; + case 4: + tv_std = TV_STD_PAL_60; + DRM_INFO("Default TV standard: PAL-60\n"); + break; + case 5: + tv_std = TV_STD_NTSC_J; + DRM_INFO("Default TV standard: NTSC-J\n"); + break; + case 6: + tv_std = TV_STD_SCART_PAL; + DRM_INFO("Default TV standard: SCART-PAL\n"); + break; + default: + 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 tv_std; +} + +struct radeon_encoder_tv_dac * +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; + struct radeon_encoder_tv_dac *tv_dac = NULL; + + /* first check TV table */ + dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE); + if (dac_info) { + tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); + + if (!tv_dac) + return NULL; + + 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; + tv_dac->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; + tv_dac->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; + tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); + } else if (rev > 1) { + bg = radeon_bios8(dev_priv, dac_info + 0xc) & 0xf; + dac = (radeon_bios8(dev_priv, dac_info + 0xc) >> 4) & 0xf; + tv_dac->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; + tv_dac->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; + tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20); + } + + tv_dac->tv_std = radeon_combios_get_tv_info(encoder); + + } else { + /* then check CRT table */ + dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); + if (dac_info) { + tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL); + + if (!tv_dac) + return NULL; + + 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; + tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); + tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj; + tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; + } else { + bg = radeon_bios8(dev_priv, dac_info + 0x4) & 0xf; + dac = radeon_bios8(dev_priv, dac_info + 0x5) & 0xf; + tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20); + tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj; + tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj; + } + } + } + + return tv_dac; +} + +struct radeon_encoder_lvds * +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; + struct radeon_encoder_lvds *lvds = NULL; + + lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); + + if (lcd_info) { + lvds = kzalloc(sizeof(struct radeon_encoder_lvds), GFP_KERNEL); + + if (!lvds) + return NULL; + + 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); + + lvds->native_mode.panel_xres = radeon_bios16(dev_priv, lcd_info + 25); + lvds->native_mode.panel_yres = radeon_bios16(dev_priv, lcd_info + 27); + + DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres, lvds->native_mode.panel_yres); + + lvds->panel_vcc_delay = radeon_bios16(dev_priv, lcd_info + 44); + if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0) + lvds->panel_vcc_delay = 2000; + + lvds->panel_pwr_delay = radeon_bios16(dev_priv, lcd_info + 0x24); + lvds->panel_digon_delay = radeon_bios16(dev_priv, lcd_info + 0x38) & 0xf; + lvds->panel_blon_delay = (radeon_bios16(dev_priv, lcd_info + 0x38) >> 4) & 0xf; + + lvds->panel_ref_divider = radeon_bios16(dev_priv, lcd_info + 46); + lvds->panel_post_divider = radeon_bios8(dev_priv, lcd_info + 48); + lvds->panel_fb_divider = radeon_bios16(dev_priv, lcd_info + 49); + if ((lvds->panel_ref_divider != 0) && + (lvds->panel_fb_divider > 3)) + lvds->use_bios_dividers = true; + + panel_setup = radeon_bios32(dev_priv, lcd_info + 0x39); + lvds->lvds_gen_cntl = 0xff00; + if (panel_setup & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_PANEL_FORMAT; + + if ((panel_setup >> 4) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_PANEL_TYPE; + + switch ((panel_setup >> 8) & 0x7) { + case 0: + lvds->lvds_gen_cntl |= RADEON_LVDS_NO_FM; + break; + case 1: + lvds->lvds_gen_cntl |= RADEON_LVDS_2_GREY; + break; + case 2: + lvds->lvds_gen_cntl |= RADEON_LVDS_4_GREY; + break; + default: + break; + } + + if ((panel_setup >> 16) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_FP_POL_LOW; + + if ((panel_setup >> 17) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_LP_POL_LOW; + + if ((panel_setup >> 18) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_DTM_POL_LOW; + + if ((panel_setup >> 23) & 0x1) + lvds->lvds_gen_cntl |= RADEON_LVDS_BL_CLK_SEL; + + lvds->lvds_gen_cntl |= (panel_setup & 0xf0000000); + + + 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, tmp) == lvds->native_mode.panel_xres) && + (radeon_bios16(dev_priv, tmp + 2) == lvds->native_mode.panel_yres)) { + lvds->native_mode.hblank = (radeon_bios16(dev_priv, tmp + 17) - + radeon_bios16(dev_priv, tmp + 19)) * 8; + lvds->native_mode.hoverplus = (radeon_bios16(dev_priv, tmp + 21) - + radeon_bios16(dev_priv, tmp + 19) - 1) * 8; + lvds->native_mode.hsync_width = radeon_bios8(dev_priv, tmp + 23) * 8; + + lvds->native_mode.vblank = (radeon_bios16(dev_priv, tmp + 24) - + radeon_bios16(dev_priv, tmp + 26)); + lvds->native_mode.voverplus = ((radeon_bios16(dev_priv, tmp + 28) & 0x7ff) - + radeon_bios16(dev_priv, tmp + 26)); + lvds->native_mode.vsync_width = ((radeon_bios16(dev_priv, tmp + 28) & 0xf800) >> 11); + lvds->native_mode.dotclock = radeon_bios16(dev_priv, tmp + 9) * 10; + lvds->native_mode.flags = 0; + } + } + encoder->native_mode = lvds->native_mode; + } else + DRM_INFO("No panel info found in BIOS\n"); + return lvds; +} + +struct radeon_encoder_int_tmds * +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 tmds_info; + int i, n; + uint8_t ver; + struct radeon_encoder_int_tmds *tmds = NULL; + + tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); + + if (tmds_info) { + tmds = kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL); + + if (!tmds) + return NULL; + + 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++) { + tmds->tmds_pll[i].value = radeon_bios32(dev_priv, tmds_info + i * 10 + 0x08); + tmds->tmds_pll[i].freq = radeon_bios16(dev_priv, tmds_info + i * 10 + 0x10); + DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n", + tmds->tmds_pll[i].freq, + tmds->tmds_pll[i].value); + } + } 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++) { + tmds->tmds_pll[i].value = radeon_bios32(dev_priv, tmds_info + stride + 0x08); + tmds->tmds_pll[i].freq = radeon_bios16(dev_priv, tmds_info + stride + 0x10); + if (i == 0) + stride += 10; + else + stride += 6; + DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n", + tmds->tmds_pll[i].freq, + tmds->tmds_pll[i].value); + } + } + } else + DRM_INFO("No TMDS info found in BIOS\n"); + return tmds; +} + +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; + 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 bool radeon_apply_legacy_quirks(struct drm_device *dev, + int bios_index, + enum radeon_combios_connector *legacy_connector, + struct radeon_i2c_bus_rec *ddc_i2c) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + + /* XPRESS DDC quirks */ + if ((dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) && + ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC) + *ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); + else if ((dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) && + ddc_i2c->mask_clk_reg == RADEON_GPIO_MONID) { + ddc_i2c->valid = true; + ddc_i2c->mask_clk_mask = (0x20 << 8); + ddc_i2c->mask_data_mask = 0x80; + ddc_i2c->a_clk_mask = (0x20 << 8); + ddc_i2c->a_data_mask = 0x80; + ddc_i2c->put_clk_mask = (0x20 << 8); + ddc_i2c->put_data_mask = 0x80; + ddc_i2c->get_clk_mask = (0x20 << 8); + ddc_i2c->get_data_mask = 0x80; + ddc_i2c->mask_clk_reg = RADEON_GPIOPAD_MASK; + ddc_i2c->mask_data_reg = RADEON_GPIOPAD_MASK; + ddc_i2c->a_clk_reg = RADEON_GPIOPAD_A; + ddc_i2c->a_data_reg = RADEON_GPIOPAD_A; + ddc_i2c->put_clk_reg = RADEON_GPIOPAD_EN; + ddc_i2c->put_data_reg = RADEON_GPIOPAD_EN; + ddc_i2c->get_clk_reg = RADEON_LCD_GPIO_Y_REG; + ddc_i2c->get_data_reg = RADEON_LCD_GPIO_Y_REG; + } + + /* 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 (*legacy_connector == CONNECTOR_CRT_LEGACY && + ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC) + return 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 (*legacy_connector == CONNECTOR_DVI_I_LEGACY) + *legacy_connector = CONNECTOR_CRT_LEGACY; + + } + + /* 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 (*legacy_connector == CONNECTOR_DVI_I_LEGACY) + return false; + } + + return true; +} + +bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t conn_info, entry, devices; + uint16_t tmp; + enum radeon_combios_ddc ddc_type; + enum radeon_combios_connector connector; + int i = 0; + struct radeon_i2c_bus_rec ddc_i2c; + struct drm_connector *drm_connector; + + DRM_DEBUG("\n"); + conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE); + if (conn_info) { + for (i = 0; i < 4; i++) { + entry = conn_info + 2 + i * 2; + + if (!radeon_bios16(dev_priv, entry)) + break; + + tmp = radeon_bios16(dev_priv, entry); + + connector = (tmp >> 12) & 0xf; + + ddc_type = (tmp >> 8) & 0xf; + switch (ddc_type) { + case DDC_MONID: + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); + break; + case DDC_DVI: + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + break; + case DDC_VGA: + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + break; + case DDC_CRT2: + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + break; + default: + break; + } + + radeon_apply_legacy_quirks(dev, i, &connector, &ddc_i2c); + + switch (connector) { + case CONNECTOR_PROPRIETARY_LEGACY: + if ((tmp >> 4) & 0x1) + devices = ATOM_DEVICE_DFP2_SUPPORT; + else + devices= ATOM_DEVICE_DFP1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, devices, 0), + devices); + radeon_add_legacy_connector(dev, + i, + devices, + legacy_connector_convert[connector], + &ddc_i2c); + break; + case CONNECTOR_CRT_LEGACY: + if (tmp & 0x1) { + devices = ATOM_DEVICE_CRT2_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), + ATOM_DEVICE_CRT2_SUPPORT); + } else { + devices = ATOM_DEVICE_CRT1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), + ATOM_DEVICE_CRT1_SUPPORT); + } + radeon_add_legacy_connector(dev, + i, + devices, + legacy_connector_convert[connector], + &ddc_i2c); + break; + case CONNECTOR_DVI_I_LEGACY: + devices = 0; + if (tmp & 0x1) { + devices |= ATOM_DEVICE_CRT2_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_CRT2_SUPPORT, 2), + ATOM_DEVICE_CRT2_SUPPORT); + } else { + devices |= ATOM_DEVICE_CRT1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), + ATOM_DEVICE_CRT1_SUPPORT); + } + if ((tmp >> 4) & 0x1) { + devices |= ATOM_DEVICE_DFP2_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_DFP2_SUPPORT, 0), + ATOM_DEVICE_DFP2_SUPPORT); + } else { + devices |= ATOM_DEVICE_DFP1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), + ATOM_DEVICE_DFP1_SUPPORT); + } + radeon_add_legacy_connector(dev, + i, + devices, + legacy_connector_convert[connector], + &ddc_i2c); + break; + case CONNECTOR_DVI_D_LEGACY: + if ((tmp >> 4) & 0x1) + devices = ATOM_DEVICE_DFP2_SUPPORT; + else + devices= ATOM_DEVICE_DFP1_SUPPORT; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, devices, 0), + devices); + radeon_add_legacy_connector(dev, + i, + devices, + legacy_connector_convert[connector], + &ddc_i2c); + break; + case CONNECTOR_CTV_LEGACY: + case CONNECTOR_STV_LEGACY: + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_TV1_SUPPORT, 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, + i, + ATOM_DEVICE_TV1_SUPPORT, + legacy_connector_convert[connector], + &ddc_i2c); + break; + default: + DRM_ERROR("Unknown connector type: %d\n", connector); + continue; + } + + } + } else { + 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"); + + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_CRT1_SUPPORT, 1), + ATOM_DEVICE_CRT1_SUPPORT); + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_DFP1_SUPPORT, 0), + ATOM_DEVICE_DFP1_SUPPORT); + + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + radeon_add_legacy_connector(dev, + 0, + ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_DFP1_SUPPORT, + DRM_MODE_CONNECTOR_DVII, + &ddc_i2c); + } else { + DRM_DEBUG("No connector info found\n"); + return false; + } + } + + if (dev_priv->flags & RADEON_IS_MOBILITY || + dev_priv->flags & RADEON_IS_IGP) { + uint16_t lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE); + if (lcd_info) { + uint16_t lcd_ddc_info = combios_get_table_offset(dev, COMBIOS_LCD_DDC_INFO_TABLE); + + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_LCD1_SUPPORT, 0), + ATOM_DEVICE_LCD1_SUPPORT); + + if (lcd_ddc_info) { + ddc_type = radeon_bios8(dev_priv, lcd_ddc_info + 2); + switch(ddc_type) { + case DDC_MONID: + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID); + break; + case DDC_DVI: + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC); + break; + case DDC_VGA: + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC); + break; + case DDC_CRT2: + ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC); + break; + case DDC_LCD: + ddc_i2c = combios_setup_i2c_bus(RADEON_LCD_GPIO_MASK); + ddc_i2c.mask_clk_mask = radeon_bios32(dev_priv, lcd_ddc_info + 3); + ddc_i2c.mask_data_mask = radeon_bios32(dev_priv, lcd_ddc_info + 7); + ddc_i2c.a_clk_mask = radeon_bios32(dev_priv, lcd_ddc_info + 3); + ddc_i2c.a_data_mask = radeon_bios32(dev_priv, lcd_ddc_info + 7); + ddc_i2c.put_clk_mask = radeon_bios32(dev_priv, lcd_ddc_info + 3); + ddc_i2c.put_data_mask = radeon_bios32(dev_priv, lcd_ddc_info + 7); + ddc_i2c.get_clk_mask = radeon_bios32(dev_priv, lcd_ddc_info + 3); + ddc_i2c.get_data_mask = radeon_bios32(dev_priv, lcd_ddc_info + 7); + break; + case DDC_GPIO: + ddc_i2c = combios_setup_i2c_bus(RADEON_MDGPIO_EN_REG); + ddc_i2c.mask_clk_mask = radeon_bios32(dev_priv, lcd_ddc_info + 3); + ddc_i2c.mask_data_mask = radeon_bios32(dev_priv, lcd_ddc_info + 7); + ddc_i2c.a_clk_mask = radeon_bios32(dev_priv, lcd_ddc_info + 3); + ddc_i2c.a_data_mask = radeon_bios32(dev_priv, lcd_ddc_info + 7); + ddc_i2c.put_clk_mask = radeon_bios32(dev_priv, lcd_ddc_info + 3); + ddc_i2c.put_data_mask = radeon_bios32(dev_priv, lcd_ddc_info + 7); + ddc_i2c.get_clk_mask = radeon_bios32(dev_priv, lcd_ddc_info + 3); + ddc_i2c.get_data_mask = radeon_bios32(dev_priv, lcd_ddc_info + 7); + break; + default: + ddc_i2c.valid = false; + break; + } + DRM_DEBUG("LCD DDC Info Table found!\n"); + } else + ddc_i2c.valid = false; + + radeon_add_legacy_connector(dev, + 5, + ATOM_DEVICE_LCD1_SUPPORT, + DRM_MODE_CONNECTOR_LVDS, + &ddc_i2c); + } + } + + /* 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') { + radeon_add_legacy_encoder(dev, + radeon_get_encoder_id(dev, ATOM_DEVICE_TV1_SUPPORT, 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, + 6, + ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c); + } + } + } + + radeon_link_encoder_connector(dev); + + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) + radeon_ddc_dump(drm_connector); + + 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); + } + } +} + +static uint32_t combios_detect_ram(struct drm_device *dev, int ram, int mem_addr_mapping) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t mem_cntl; + uint32_t mem_size; + uint32_t addr = 0; + + mem_cntl = RADEON_READ(RADEON_MEM_CNTL); + if (mem_cntl & RV100_HALF_MODE) + ram /= 2; + mem_size = ram; + mem_cntl &= ~(0xff << 8); + mem_cntl |= (mem_addr_mapping & 0xff) << 8; + RADEON_WRITE(RADEON_MEM_CNTL, mem_cntl); + RADEON_READ(RADEON_MEM_CNTL); + + /* sdram reset ? */ + + /* something like this???? */ + while (ram--) { + addr = ram * 1024 * 1024; + /* write to each page */ + RADEON_WRITE(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); + RADEON_WRITE(RADEON_MM_DATA, 0xdeadbeef); + /* read back and verify */ + RADEON_WRITE(RADEON_MM_INDEX, (addr) | RADEON_MM_APER); + if (RADEON_READ(RADEON_MM_DATA) != 0xdeadbeef) + return 0; + } + + return mem_size; +} + +static void combios_write_ram_size(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint8_t rev; + uint16_t offset; + uint32_t mem_size = 0; + uint32_t mem_cntl = 0; + + /* should do something smarter here I guess... */ + if (dev_priv->flags & RADEON_IS_IGP) + return; + + /* first check detected mem table */ + offset = combios_get_table_offset(dev, COMBIOS_DETECTED_MEM_TABLE); + if (offset) { + rev = radeon_bios8(dev_priv, offset); + if (rev < 3) { + mem_cntl = radeon_bios32(dev_priv, offset + 1); + mem_size = radeon_bios16(dev_priv, offset + 5); + if (((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R200) && + ((dev->pdev->device != 0x515e) && (dev->pdev->device != 0x5969))) + RADEON_WRITE(RADEON_MEM_CNTL, mem_cntl); + } + } + + if (!mem_size) { + offset = combios_get_table_offset(dev, COMBIOS_MEM_CONFIG_TABLE); + if (offset) { + rev = radeon_bios8(dev_priv, offset - 1); + if (rev < 1) { + if (((dev_priv->flags & RADEON_FAMILY_MASK) < CHIP_R200) && + ((dev->pdev->device != 0x515e) && (dev->pdev->device != 0x5969))) { + int ram = 0; + int mem_addr_mapping = 0; + + while (radeon_bios8(dev_priv, offset)) { + ram = radeon_bios8(dev_priv, offset); + mem_addr_mapping = radeon_bios8(dev_priv, offset + 1); + if (mem_addr_mapping != 0x25) + ram *= 2; + mem_size = combios_detect_ram(dev, ram, mem_addr_mapping); + if (mem_size) + break; + offset += 2; + } + } else + mem_size = radeon_bios8(dev_priv, offset); + } else { + mem_size = radeon_bios8(dev_priv, offset); + mem_size *= 2; /* convert to MB */ + } + } + } + + mem_size *= (1024 * 1024); /* convert to bytes */ + RADEON_WRITE(RADEON_CONFIG_MEMSIZE, mem_size); +} + +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) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + 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); + + if (!(dev_priv->flags & RADEON_IS_IGP)) { + /* 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); + + /* write CONFIG_MEMSIZE */ + combios_write_ram_size(dev); + } + + /* DYN CLK 1 */ + table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); + if (table) + combios_parse_pll_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); +} + +void +radeon_combios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected) +{ + struct drm_device *dev = connector->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + uint32_t bios_4_scratch = RADEON_READ(RADEON_BIOS_4_SCRATCH); + uint32_t bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); + + if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) { + if (connected) { + DRM_DEBUG("TV1 connected\n"); + /* fix me */ + bios_4_scratch |= RADEON_TV1_ATTACHED_SVIDEO; + /*save->bios_4_scratch |= RADEON_TV1_ATTACHED_COMP;*/ + bios_5_scratch |= RADEON_TV1_ON; + bios_5_scratch |= RADEON_ACC_REQ_TV1; + } else { + DRM_DEBUG("TV1 disconnected\n"); + bios_4_scratch &= ~RADEON_TV1_ATTACHED_MASK; + bios_5_scratch &= ~RADEON_TV1_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_TV1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) { + if (connected) { + DRM_DEBUG("LCD1 connected\n"); + bios_4_scratch |= RADEON_LCD1_ATTACHED; + bios_5_scratch |= RADEON_LCD1_ON; + bios_5_scratch |= RADEON_ACC_REQ_LCD1; + } else { + DRM_DEBUG("LCD1 disconnected\n"); + bios_4_scratch &= ~RADEON_LCD1_ATTACHED; + bios_5_scratch &= ~RADEON_LCD1_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_LCD1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) { + if (connected) { + DRM_DEBUG("CRT1 connected\n"); + bios_4_scratch |= RADEON_CRT1_ATTACHED_COLOR; + bios_5_scratch |= RADEON_CRT1_ON; + bios_5_scratch |= RADEON_ACC_REQ_CRT1; + } else { + DRM_DEBUG("CRT1 disconnected\n"); + bios_4_scratch &= ~RADEON_CRT1_ATTACHED_MASK; + bios_5_scratch &= ~RADEON_CRT1_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_CRT1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) { + if (connected) { + DRM_DEBUG("CRT2 connected\n"); + bios_4_scratch |= RADEON_CRT2_ATTACHED_COLOR; + bios_5_scratch |= RADEON_CRT2_ON; + bios_5_scratch |= RADEON_ACC_REQ_CRT2; + } else { + DRM_DEBUG("CRT2 disconnected\n"); + bios_4_scratch &= ~RADEON_CRT2_ATTACHED_MASK; + bios_5_scratch &= ~RADEON_CRT2_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_CRT2; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP1 connected\n"); + bios_4_scratch |= RADEON_DFP1_ATTACHED; + bios_5_scratch |= RADEON_DFP1_ON; + bios_5_scratch |= RADEON_ACC_REQ_DFP1; + } else { + DRM_DEBUG("DFP1 disconnected\n"); + bios_4_scratch &= ~RADEON_DFP1_ATTACHED; + bios_5_scratch &= ~RADEON_DFP1_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_DFP1; + } + } + if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) && + (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) { + if (connected) { + DRM_DEBUG("DFP2 connected\n"); + bios_4_scratch |= RADEON_DFP2_ATTACHED; + bios_5_scratch |= RADEON_DFP2_ON; + bios_5_scratch |= RADEON_ACC_REQ_DFP2; + } else { + DRM_DEBUG("DFP2 disconnected\n"); + bios_4_scratch &= ~RADEON_DFP2_ATTACHED; + bios_5_scratch &= ~RADEON_DFP2_ON; + bios_5_scratch &= ~RADEON_ACC_REQ_DFP2; + } + } + RADEON_WRITE(RADEON_BIOS_4_SCRATCH, bios_4_scratch); + RADEON_WRITE(RADEON_BIOS_5_SCRATCH, bios_5_scratch); +} + +void +radeon_combios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc) +{ + 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 bios_5_scratch = RADEON_READ(RADEON_BIOS_5_SCRATCH); + + if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + bios_5_scratch &= ~RADEON_TV1_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_TV1_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) { + bios_5_scratch &= ~RADEON_CRT1_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_CRT1_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + bios_5_scratch &= ~RADEON_CRT2_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_CRT2_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + bios_5_scratch &= ~RADEON_LCD1_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_LCD1_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) { + bios_5_scratch &= ~RADEON_DFP1_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_DFP1_CRTC_SHIFT); + } + if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) { + bios_5_scratch &= ~RADEON_DFP2_CRTC_MASK; + bios_5_scratch |= (crtc << RADEON_DFP2_CRTC_SHIFT); + } + RADEON_WRITE(RADEON_BIOS_5_SCRATCH, bios_5_scratch); +} + +void +radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on) +{ + 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 bios_6_scratch = RADEON_READ(RADEON_BIOS_6_SCRATCH); + + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { + if (on) + bios_6_scratch |= RADEON_TV_DPMS_ON; + else + bios_6_scratch &= ~RADEON_TV_DPMS_ON; + } + if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { + if (on) + bios_6_scratch |= RADEON_CRT_DPMS_ON; + else + bios_6_scratch &= ~RADEON_CRT_DPMS_ON; + } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (on) + bios_6_scratch |= RADEON_LCD_DPMS_ON; + else + bios_6_scratch &= ~RADEON_LCD_DPMS_ON; + } + if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (on) + bios_6_scratch |= RADEON_DFP_DPMS_ON; + else + bios_6_scratch &= ~RADEON_DFP_DPMS_ON; + } + RADEON_WRITE(RADEON_BIOS_6_SCRATCH, bios_6_scratch); +} diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c new file mode 100644 index 0000000..0fb98cb --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -0,0 +1,610 @@ +/* + * 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" + +extern void +radeon_combios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected); +extern void +radeon_atombios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected); + +static void +radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status) +{ + struct drm_device *dev = connector->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_encoder *best_encoder = NULL; + struct drm_encoder *encoder = NULL; + struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + struct drm_mode_object *obj; + bool connected; + int i; + + best_encoder = connector_funcs->best_encoder(connector); + + 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 ((encoder == best_encoder) && (status == connector_status_connected)) + connected = true; + else + connected = false; + + if (dev_priv->is_atom_bios) + radeon_atombios_connected_scratch_regs(connector, encoder, connected); + else + radeon_combios_connected_scratch_regs(connector, encoder, 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 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; + struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + + if (native_mode->panel_xres != 0 && + native_mode->panel_yres != 0 && + native_mode->dotclock != 0) { + mode = drm_mode_create(dev); + + mode->hdisplay = native_mode->panel_xres; + mode->vdisplay = native_mode->panel_yres; + + mode->htotal = mode->hdisplay + native_mode->hblank; + mode->hsync_start = mode->hdisplay + native_mode->hoverplus; + mode->hsync_end = mode->hsync_start + native_mode->hsync_width; + mode->vtotal = mode->vdisplay + native_mode->vblank; + mode->vsync_start = mode->vdisplay + native_mode->voverplus; + mode->vsync_end = mode->vsync_start + native_mode->vsync_width; + mode->clock = native_mode->dotclock; + mode->flags = 0; + + mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; + drm_mode_set_name(mode); + + DRM_DEBUG("Adding native panel mode %s\n", mode->name); + } + 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); + struct drm_encoder *encoder; + int ret = 0; + struct edid *edid; + struct drm_display_mode *mode; + + if (radeon_connector->ddc_bus) { + ret = radeon_ddc_get_modes(radeon_connector); + if (ret > 0) + return ret; + } + +native: + encoder = radeon_best_single_encoder(connector); + if (!encoder) + return 0; + + /* 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; +} + +static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector) +{ + enum drm_connector_status ret = connector_status_connected; + // check acpi lid status ??? + radeon_connector_update_scratch_regs(connector, ret); + return ret; +} + +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); + kfree(radeon_connector->con_priv); + 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, + .set_property = radeon_connector_set_property, +}; + +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_vga_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + + return MODE_OK; +} + +static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + bool dret; + enum drm_connector_status ret = connector_status_disconnected; + + radeon_i2c_do_lock(radeon_connector, 1); + dret = radeon_ddc_probe(radeon_connector); + radeon_i2c_do_lock(radeon_connector, 0); + if (dret) + ret = connector_status_connected; + else { + /* if EDID fails to a load detect */ + encoder = radeon_best_single_encoder(connector); + if (!encoder) + ret = connector_status_disconnected; + else { + encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); + } + } + + radeon_connector_update_scratch_regs(connector, ret); + return ret; +} + +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_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, +}; + +static int radeon_dvi_get_modes(struct drm_connector *connector) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + int ret; + + ret = radeon_ddc_get_modes(radeon_connector); + /* reset scratch regs here since radeon_dvi_detect doesn't check digital bit */ + radeon_connector_update_scratch_regs(connector, connector_status_connected); + return ret; +} + +static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) +{ + 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 = connector_status_disconnected; + bool dret; + + radeon_i2c_do_lock(radeon_connector, 1); + dret = radeon_ddc_probe(radeon_connector); + radeon_i2c_do_lock(radeon_connector, 0); + if (dret) + ret = connector_status_connected; + else { + 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; + break; + } + } + } + } + + /* updated in get modes as well since we need to know if it's analog or digital */ + radeon_connector_update_scratch_regs(connector, ret); + return ret; +} + +/* okay need to be smart in here about which encoder to pick */ +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); + 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_dvi_connector_helper_funcs = { + .get_modes = radeon_dvi_get_modes, + .mode_valid = radeon_vga_mode_valid, + .best_encoder = radeon_dvi_encoder, +}; + +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, +}; + +void +radeon_add_atom_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus, + bool linkb, + uint32_t igp_lane_info) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *radeon_dig_connector; + uint32_t subpixel_order = SubPixelNone; + + /* fixme - tv/cv/din */ + if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || + (connector_type == DRM_MODE_CONNECTOR_SVIDEO) || + (connector_type == DRM_MODE_CONNECTOR_Composite) || + (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) + return; + + /* see if we already added it */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + if (radeon_connector->connector_id == connector_id) { + radeon_connector->devices |= supported_device; + return; + } + } + + radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); + if (!radeon_connector) + return; + + connector = &radeon_connector->base; + + radeon_connector->connector_id = connector_id; + radeon_connector->devices = supported_device; + switch (connector_type) { + case DRM_MODE_CONNECTOR_VGA: + drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); + if (!radeon_connector->ddc_bus) + goto failed; + } + break; + case DRM_MODE_CONNECTOR_DVIA: + drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + break; + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); + if (!radeon_dig_connector) + goto failed; + radeon_dig_connector->linkb = linkb; + radeon_dig_connector->igp_lane_info = igp_lane_info; + radeon_connector->con_priv = radeon_dig_connector; + drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); + if (!radeon_dig_connector) + goto failed; + radeon_dig_connector->linkb = linkb; + radeon_dig_connector->igp_lane_info = igp_lane_info; + radeon_connector->con_priv = radeon_dig_connector; + drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); + if (!radeon_dig_connector) + goto failed; + radeon_dig_connector->linkb = linkb; + radeon_dig_connector->igp_lane_info = igp_lane_info; + radeon_connector->con_priv = radeon_dig_connector; + drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_9PinDIN: + break; + case DRM_MODE_CONNECTOR_LVDS: + radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); + if (!radeon_dig_connector) + goto failed; + radeon_dig_connector->linkb = linkb; + radeon_dig_connector->igp_lane_info = igp_lane_info; + radeon_connector->con_priv = radeon_dig_connector; + drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + } + + connector->display_info.subpixel_order = subpixel_order; + drm_sysfs_connector_add(connector); + return; + +failed: + if (radeon_connector->ddc_bus) + radeon_i2c_destroy(radeon_connector->ddc_bus); + drm_connector_cleanup(connector); + kfree(connector); +} + +void +radeon_add_legacy_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + uint32_t subpixel_order = SubPixelNone; + + /* fixme - tv/cv/din */ + if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || + (connector_type == DRM_MODE_CONNECTOR_SVIDEO) || + (connector_type == DRM_MODE_CONNECTOR_Composite) || + (connector_type == DRM_MODE_CONNECTOR_9PinDIN)) + return; + + /* see if we already added it */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + if (radeon_connector->connector_id == connector_id) { + radeon_connector->devices |= supported_device; + return; + } + } + + radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); + if (!radeon_connector) + return; + + connector = &radeon_connector->base; + + radeon_connector->connector_id = connector_id; + radeon_connector->devices = supported_device; + switch (connector_type) { + case DRM_MODE_CONNECTOR_VGA: + drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); + if (!radeon_connector->ddc_bus) + goto failed; + } + break; + case DRM_MODE_CONNECTOR_DVIA: + drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + break; + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_9PinDIN: + break; + case DRM_MODE_CONNECTOR_LVDS: + drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); + drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); + if (i2c_bus->valid) { + radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); + if (!radeon_connector->ddc_bus) + goto failed; + } + subpixel_order = SubPixelHorizontalRGB; + break; + } + + connector->display_info.subpixel_order = subpixel_order; + drm_sysfs_connector_add(connector); + return; + +failed: + if (radeon_connector->ddc_bus) + radeon_i2c_destroy(radeon_connector->ddc_bus); + drm_connector_cleanup(connector); + kfree(connector); +} diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 77a7a4d..abad524 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -46,8 +46,12 @@ static void radeon_do_cp_start(drm_radeon_private_t * dev_priv); u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off) { u32 val; - - if (dev_priv->flags & RADEON_IS_AGP) { + if (dev_priv->mm.ring_read.bo) { + val = *(((volatile u32 *) + dev_priv->mm.ring_read.kmap.virtual) + + (off / sizeof(u32))); + val = le32_to_cpu(val); + } else if (dev_priv->flags & RADEON_IS_AGP) { val = DRM_READ32(dev_priv->ring_rptr, off); } else { val = *(((volatile u32 *) @@ -60,9 +64,11 @@ u32 radeon_read_ring_rptr(drm_radeon_private_t *dev_priv, u32 off) u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv) { - if (dev_priv->writeback_works) + if (dev_priv->writeback_works) { + if (dev_priv->mm.ring_read.bo) + return readl(dev_priv->mm.ring_read.kmap.virtual); return radeon_read_ring_rptr(dev_priv, 0); - else { + } else { if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return RADEON_READ(R600_CP_RB_RPTR); else @@ -72,7 +78,10 @@ u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv) void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val) { - if (dev_priv->flags & RADEON_IS_AGP) + if (dev_priv->mm.ring_read.bo) + *(((volatile u32 *) dev_priv->mm.ring_read.kmap.virtual) + + (off / sizeof(u32))) = cpu_to_le32(val); + else if (dev_priv->flags & RADEON_IS_AGP) DRM_WRITE32(dev_priv->ring_rptr, off, val); else *(((volatile u32 *) dev_priv->ring_rptr->handle) + @@ -81,12 +90,19 @@ void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 val) void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val) { + if (dev_priv->mm.ring_read.bo) { + writel(val, dev_priv->mm.ring_read.kmap.virtual); + return; + } radeon_write_ring_rptr(dev_priv, 0, val); } u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index) { if (dev_priv->writeback_works) { + if (dev_priv->mm.ring_read.bo) { + return readl(dev_priv->mm.ring_read.kmap.virtual + RADEON_SCRATCHOFF(index)); + } if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return radeon_read_ring_rptr(dev_priv, R600_SCRATCHOFF(index)); @@ -151,15 +167,18 @@ static u32 RS600_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) return ret; } -static u32 IGP_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) +u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) { if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) return RS690_READ_MCIND(dev_priv, addr); else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) return RS600_READ_MCIND(dev_priv, addr); - else + else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) return RS480_READ_MCIND(dev_priv, addr); + else + return R500_READ_MCIND(dev_priv, addr); } u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) @@ -169,39 +188,66 @@ u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv) return RADEON_READ(R700_MC_VM_FB_LOCATION); else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return RADEON_READ(R600_MC_VM_FB_LOCATION); - else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) - return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION); else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) return RS690_READ_MCIND(dev_priv, RS690_MC_FB_LOCATION); else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) return RS600_READ_MCIND(dev_priv, RS600_MC_FB_LOCATION); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) + return R500_READ_MCIND(dev_priv, RV515_MC_FB_LOCATION); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) return R500_READ_MCIND(dev_priv, R520_MC_FB_LOCATION); else return RADEON_READ(RADEON_MC_FB_LOCATION); } -static void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) +void radeon_read_agp_location(drm_radeon_private_t *dev_priv, u32 *agp_lo, u32 *agp_hi) +{ + if (dev_priv->chip_family == CHIP_RV770) { + *agp_lo = RADEON_READ(R600_MC_VM_AGP_BOT); + *agp_hi = RADEON_READ(R600_MC_VM_AGP_TOP); + } else if (dev_priv->chip_family == CHIP_R600) { + *agp_lo = RADEON_READ(R600_MC_VM_AGP_BOT); + *agp_hi = RADEON_READ(R600_MC_VM_AGP_TOP); + } else if (dev_priv->chip_family == CHIP_RV515) { + *agp_lo = RADEON_READ_MCIND(dev_priv, RV515_MC_AGP_LOCATION); + *agp_hi = 0; + } else if (dev_priv->chip_family == CHIP_RS600) { + *agp_lo = RADEON_READ_MCIND(dev_priv, RS600_MC_AGP_LOCATION); + *agp_hi = 0; + } else if (dev_priv->chip_family == CHIP_RS690 || + dev_priv->chip_family == CHIP_RS740) { + *agp_lo = RADEON_READ_MCIND(dev_priv, RS690_MC_AGP_LOCATION); + *agp_hi = 0; + } else if (dev_priv->chip_family >= CHIP_R520) { + *agp_lo = RADEON_READ_MCIND(dev_priv, R520_MC_AGP_LOCATION); + *agp_hi = 0; + } else { + *agp_lo = RADEON_READ(RADEON_MC_AGP_LOCATION); + *agp_hi = 0; + } +} + +void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc) { if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) RADEON_WRITE(R700_MC_VM_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) RADEON_WRITE(R600_MC_VM_FB_LOCATION, fb_loc); - else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) - R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc); else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) RS690_WRITE_MCIND(RS690_MC_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) RS600_WRITE_MCIND(RS600_MC_FB_LOCATION, fb_loc); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) + R500_WRITE_MCIND(RV515_MC_FB_LOCATION, fb_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) R500_WRITE_MCIND(R520_MC_FB_LOCATION, fb_loc); else RADEON_WRITE(RADEON_MC_FB_LOCATION, fb_loc); } -void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc) +void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc, u32 agp_loc_hi) { /*R6xx/R7xx: AGP_TOP and BOT are actually 18 bits each */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) { @@ -210,13 +256,13 @@ void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc) } else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) { RADEON_WRITE(R600_MC_VM_AGP_BOT, agp_loc & 0xffff); /* FIX ME */ RADEON_WRITE(R600_MC_VM_AGP_TOP, (agp_loc >> 16) & 0xffff); - } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) - R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc); - else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || - ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) + } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) RS690_WRITE_MCIND(RS690_MC_AGP_LOCATION, agp_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) RS600_WRITE_MCIND(RS600_MC_AGP_LOCATION, agp_loc); + else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) + R500_WRITE_MCIND(RV515_MC_AGP_LOCATION, agp_loc); else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) R500_WRITE_MCIND(R520_MC_AGP_LOCATION, agp_loc); else @@ -234,16 +280,16 @@ void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) RADEON_WRITE(R700_MC_VM_AGP_BASE, r6xx_agp_base); else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) RADEON_WRITE(R600_MC_VM_AGP_BASE, r6xx_agp_base); - else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) { - R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo); - R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi); - } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || + else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) { RS690_WRITE_MCIND(RS690_MC_AGP_BASE, agp_base_lo); RS690_WRITE_MCIND(RS690_MC_AGP_BASE_2, agp_base_hi); } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) { RS600_WRITE_MCIND(RS600_AGP_BASE, agp_base_lo); RS600_WRITE_MCIND(RS600_AGP_BASE_2, agp_base_hi); + } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV515) { + R500_WRITE_MCIND(RV515_MC_AGP_BASE, agp_base_lo); + R500_WRITE_MCIND(RV515_MC_AGP_BASE_2, agp_base_hi); } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) { R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo); R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi); @@ -277,20 +323,111 @@ void radeon_enable_bm(struct drm_radeon_private *dev_priv) } /* PCIE cards appears to not need this */ } -static int RADEON_READ_PLL(struct drm_device * dev, int addr) +void radeon_pll_errata_after_index(struct drm_radeon_private *dev_priv) { - drm_radeon_private_t *dev_priv = dev->dev_private; + if (!(dev_priv->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS)) + return; + + (void)RADEON_READ(RADEON_CLOCK_CNTL_DATA); + (void)RADEON_READ(RADEON_CRTC_GEN_CNTL); +} + +void radeon_pll_errata_after_data(struct drm_radeon_private *dev_priv) +{ + /* This workarounds is necessary on RV100, RS100 and RS200 chips + * or the chip could hang on a subsequent access + */ + if (dev_priv->pll_errata & CHIP_ERRATA_PLL_DELAY) + udelay(5000); - RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x1f); - return RADEON_READ(RADEON_CLOCK_CNTL_DATA); + /* This function is required to workaround a hardware bug in some (all?) + * revisions of the R300. This workaround should be called after every + * CLOCK_CNTL_INDEX register access. If not, register reads afterward + * may not be correct. + */ + if (dev_priv->pll_errata & CHIP_ERRATA_R300_CG) { + uint32_t save, tmp; + + save = RADEON_READ(RADEON_CLOCK_CNTL_INDEX); + tmp = save & ~(0x3f | RADEON_PLL_WR_EN); + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, tmp); + tmp = RADEON_READ(RADEON_CLOCK_CNTL_DATA); + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, save); + } +} + +u32 RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr) +{ + uint32_t data; + + RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, addr & 0x3f); + radeon_pll_errata_after_index(dev_priv); + data = RADEON_READ(RADEON_CLOCK_CNTL_DATA); + radeon_pll_errata_after_data(dev_priv); + return data; +} + +void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data) +{ + RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, ((addr & 0x3f) | RADEON_PLL_WR_EN)); + radeon_pll_errata_after_index(dev_priv); + RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, data); + radeon_pll_errata_after_data(dev_priv); } -static u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) +u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr) { RADEON_WRITE8(RADEON_PCIE_INDEX, addr & 0xff); return RADEON_READ(RADEON_PCIE_DATA); } +/* ATOM accessor methods */ +static uint32_t cail_pll_read(struct card_info *info, uint32_t reg) +{ + uint32_t ret = RADEON_READ_PLL(info->dev->dev_private, reg); + DRM_DEBUG("(%x) = %x\n", reg, ret); + return ret; +} + +static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + DRM_DEBUG("(%x, %x)\n", reg, val); + RADEON_WRITE_PLL(info->dev->dev_private, reg, val); +} + +static uint32_t cail_mc_read(struct card_info *info, uint32_t reg) +{ + uint32_t ret = RADEON_READ_MCIND(info->dev->dev_private, reg); + + /* DRM_DEBUG("(%x) = %x\n", reg, ret); */ + return ret; +} + +static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + drm_radeon_private_t *dev_priv = info->dev->dev_private; + /* DRM_DEBUG("(%x, %x)\n", reg, val);*/ + RADEON_WRITE_MCIND(reg, val); +} + +static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + drm_radeon_private_t *dev_priv = info->dev->dev_private; + + // DRM_DEBUG("(%x, %x)\n", reg*4, val); + RADEON_WRITE(reg*4, val); +} + +static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) +{ + uint32_t ret; + drm_radeon_private_t *dev_priv = info->dev->dev_private; + + ret = RADEON_READ(reg*4); + // DRM_DEBUG("(%x) = %x\n", reg*4, ret); + return ret; +} + #if RADEON_FIFO_DEBUG static void radeon_status(drm_radeon_private_t * dev_priv) { @@ -373,7 +510,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries) return -EBUSY; } -static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) +int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) { int i, ret; @@ -433,7 +570,7 @@ static void radeon_init_pipes(drm_radeon_private_t *dev_priv) } if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV515) { - RADEON_WRITE_PLL(R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4)); + RADEON_WRITE_PLL(dev_priv, R500_DYN_SCLK_PWMEM_PIPE, (1 | ((gb_pipe_sel >> 8) & 0xf) << 4)); RADEON_WRITE(R300_SU_REG_DEST, ((1 << dev_priv->num_gb_pipes) - 1)); } RADEON_WRITE(R300_GB_TILE_CONFIG, gb_tile_config); @@ -547,7 +684,6 @@ static void radeon_do_cp_flush(drm_radeon_private_t * dev_priv) DRM_DEBUG("\n"); #if 0 u32 tmp; - tmp = RADEON_READ(RADEON_CP_RB_WPTR) | (1 << 31); RADEON_WRITE(RADEON_CP_RB_WPTR, tmp); #endif @@ -588,10 +724,15 @@ static void radeon_do_cp_start(drm_radeon_private_t * dev_priv) BEGIN_RING(8); /* isync can only be written through cp on r5xx write it here */ OUT_RING(CP_PACKET0(RADEON_ISYNC_CNTL, 0)); + if (dev_priv->chip_family > CHIP_RV280) + OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI | + dev_priv->mm_enabled ? 0 : RADEON_ISYNC_CPSCRATCH_IDLEGUI); + else OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D | RADEON_ISYNC_ANY3D_IDLE2D | - RADEON_ISYNC_WAIT_IDLEGUI | - RADEON_ISYNC_CPSCRATCH_IDLEGUI); + RADEON_ISYNC_WAIT_IDLEGUI); RADEON_PURGE_CACHE(); RADEON_PURGE_ZCACHE(); RADEON_WAIT_UNTIL_IDLE(); @@ -642,15 +783,15 @@ static int radeon_do_engine_reset(struct drm_device * dev) if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) { /* may need something similar for newer chips */ clock_cntl_index = RADEON_READ(RADEON_CLOCK_CNTL_INDEX); - mclk_cntl = RADEON_READ_PLL(dev, RADEON_MCLK_CNTL); + mclk_cntl = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); - RADEON_WRITE_PLL(RADEON_MCLK_CNTL, (mclk_cntl | - RADEON_FORCEON_MCLKA | - RADEON_FORCEON_MCLKB | - RADEON_FORCEON_YCLKA | - RADEON_FORCEON_YCLKB | - RADEON_FORCEON_MC | - RADEON_FORCEON_AIC)); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, (mclk_cntl | + RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB | + RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | + RADEON_FORCEON_MC | + RADEON_FORCEON_AIC)); } rbbm_soft_reset = RADEON_READ(RADEON_RBBM_SOFT_RESET); @@ -675,7 +816,7 @@ static int radeon_do_engine_reset(struct drm_device * dev) RADEON_READ(RADEON_RBBM_SOFT_RESET); if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV410) { - RADEON_WRITE_PLL(RADEON_MCLK_CNTL, mclk_cntl); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, mclk_cntl); RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, clock_cntl_index); RADEON_WRITE(RADEON_RBBM_SOFT_RESET, rbbm_soft_reset); } @@ -691,7 +832,8 @@ static int radeon_do_engine_reset(struct drm_device * dev) dev_priv->cp_running = 0; /* Reset any pending vertex, indirect buffers */ - radeon_freelist_reset(dev); + if (dev->dma) + radeon_freelist_reset(dev); return 0; } @@ -710,9 +852,13 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, */ if (!dev_priv->new_memmap) radeon_write_fb_location(dev_priv, - ((dev_priv->gart_vm_start - 1) & 0xffff0000) - | (dev_priv->fb_location >> 16)); - + ((dev_priv->gart_vm_start - 1) & 0xffff0000) + | (dev_priv->fb_location >> 16)); + + if (dev_priv->mm.ring.bo) { + ring_start = dev_priv->mm.ring.bo->offset + + dev_priv->gart_vm_start; + } else #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { radeon_write_agp_base(dev_priv, dev->agp->base); @@ -720,7 +866,7 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, radeon_write_agp_location(dev_priv, (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & 0xffff0000) | - (dev_priv->gart_vm_start >> 16))); + (dev_priv->gart_vm_start >> 16)), 0); ring_start = (dev_priv->cp_ring->offset - dev->agp->base @@ -742,6 +888,12 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, SET_RING_HEAD(dev_priv, cur_read_ptr); dev_priv->ring.tail = cur_read_ptr; + + if (dev_priv->mm.ring_read.bo) { + RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, + dev_priv->mm.ring_read.bo->offset + + dev_priv->gart_vm_start); + } else #if __OS_HAS_AGP if (dev_priv->flags & RADEON_IS_AGP) { RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, @@ -781,7 +933,10 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, RADEON_WRITE(RADEON_SCRATCH_ADDR, RADEON_READ(RADEON_CP_RB_RPTR_ADDR) + RADEON_SCRATCH_REG_OFFSET); - RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); + if (dev_priv->chip_family > CHIP_R300) + RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7f); + else + RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x1f); radeon_enable_bm(dev_priv); @@ -794,32 +949,53 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, radeon_write_ring_rptr(dev_priv, RADEON_SCRATCHOFF(2), 0); RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0); + RADEON_WRITE(RADEON_LAST_SWI_REG, 0); + + RADEON_WRITE(RADEON_SCRATCH_REG4, 0); + + RADEON_WRITE(RADEON_SCRATCH_REG6, 0); + /* reset sarea copies of these */ - master_priv = file_priv->master->driver_priv; - if (master_priv->sarea_priv) { - master_priv->sarea_priv->last_frame = 0; - master_priv->sarea_priv->last_dispatch = 0; - master_priv->sarea_priv->last_clear = 0; + if (file_priv) { + master_priv = file_priv->master->driver_priv; + if (master_priv->sarea_priv) { + master_priv->sarea_priv->last_frame = 0; + master_priv->sarea_priv->last_dispatch = 0; + master_priv->sarea_priv->last_clear = 0; + } } radeon_do_wait_for_idle(dev_priv); /* Sync everything up */ + if (dev_priv->chip_family > CHIP_RV280) { RADEON_WRITE(RADEON_ISYNC_CNTL, (RADEON_ISYNC_ANY2D_IDLE3D | RADEON_ISYNC_ANY3D_IDLE2D | RADEON_ISYNC_WAIT_IDLEGUI | RADEON_ISYNC_CPSCRATCH_IDLEGUI)); - + } else { + RADEON_WRITE(RADEON_ISYNC_CNTL, + (RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI)); + } } static void radeon_test_writeback(drm_radeon_private_t * dev_priv) { - u32 tmp; + u32 tmp, scratch1_store; + void *ring_read_ptr; + + if (dev_priv->mm.ring_read.bo) + ring_read_ptr = dev_priv->mm.ring_read.kmap.virtual; + else + ring_read_ptr = dev_priv->ring_rptr->handle; /* Start with assuming that writeback doesn't work */ dev_priv->writeback_works = 0; + scratch1_store = RADEON_READ(RADEON_SCRATCH_REG1); /* Writeback doesn't seem to work everywhere, test it here and possibly * enable it if it appears to work */ @@ -848,10 +1024,12 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv) DRM_INFO("writeback forced off\n"); } + /* write back previous value */ + RADEON_WRITE(RADEON_SCRATCH_REG1, scratch1_store); + if (!dev_priv->writeback_works) { - /* Disable writeback to avoid unnecessary bus master transfer */ - RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) | - RADEON_RB_NO_UPDATE); + /* Disable writeback to avoid unnecessary bus master transfers */ + RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) | RADEON_RB_NO_UPDATE); RADEON_WRITE(RADEON_SCRATCH_UMSK, 0); } } @@ -862,68 +1040,90 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on) u32 temp; if (on) { + u32 size_reg; DRM_DEBUG("programming igp gart %08X %08lX %08X\n", - dev_priv->gart_vm_start, - (long)dev_priv->gart_info.bus_addr, - dev_priv->gart_size); + dev_priv->gart_vm_start, + (long)dev_priv->gart_info.bus_addr, + dev_priv->gart_size); + + switch(dev_priv->gart_size/(1024*1024)) { + case 32: size_reg = RS480_VA_SIZE_32MB; break; + case 64: size_reg = RS480_VA_SIZE_64MB; break; + case 128: size_reg = RS480_VA_SIZE_128MB; break; + case 256: size_reg = RS480_VA_SIZE_256MB; break; + case 512: size_reg = RS480_VA_SIZE_512MB; break; + case 1024: size_reg = RS480_VA_SIZE_1GB; break; + case 2048: size_reg = RS480_VA_SIZE_2GB; break; + default: + DRM_ERROR("Unable to use IGP GART table size %d\n", dev_priv->gart_info.table_size); + size_reg = RS480_VA_SIZE_32MB; + break; + } - temp = IGP_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL); + temp = RADEON_READ_MCIND(dev_priv, RS480_MC_MISC_CNTL); if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) - IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN | - RS690_BLOCK_GFX_D3_EN)); + RADEON_WRITE_MCIND(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN | + RS690_BLOCK_GFX_D3_EN)); else - IGP_WRITE_MCIND(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN); + RADEON_WRITE_MCIND(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN); - IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | - RS480_VA_SIZE_32MB)); + RADEON_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | size_reg)); - temp = IGP_READ_MCIND(dev_priv, RS480_GART_FEATURE_ID); - IGP_WRITE_MCIND(RS480_GART_FEATURE_ID, (RS480_HANG_EN | - RS480_TLB_ENABLE | - RS480_GTW_LAC_EN | - RS480_1LEVEL_GART)); + temp = RADEON_READ_MCIND(dev_priv, RS480_GART_FEATURE_ID); + RADEON_WRITE_MCIND(RS480_GART_FEATURE_ID, (RS480_HANG_EN | + RS480_TLB_ENABLE | + RS480_GTW_LAC_EN | + RS480_1LEVEL_GART)); temp = dev_priv->gart_info.bus_addr & 0xfffff000; temp |= (upper_32_bits(dev_priv->gart_info.bus_addr) & 0xff) << 4; - IGP_WRITE_MCIND(RS480_GART_BASE, temp); - - temp = IGP_READ_MCIND(dev_priv, RS480_AGP_MODE_CNTL); - IGP_WRITE_MCIND(RS480_AGP_MODE_CNTL, ((1 << RS480_REQ_TYPE_SNOOP_SHIFT) | - RS480_REQ_TYPE_SNOOP_DIS)); - - radeon_write_agp_base(dev_priv, dev_priv->gart_vm_start); + RADEON_WRITE_MCIND(RS480_GART_BASE, temp); + + /* enable snooping on gart mapped address */ + temp = RADEON_READ_MCIND(dev_priv, RS480_AGP_MODE_CNTL); + temp &= (RS480_REQ_TYPE_SNOOP_DIS); + temp |= (1 << RS480_REQ_TYPE_SNOOP_SHIFT); + RADEON_WRITE_MCIND(RS480_AGP_MODE_CNTL, temp); + + if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) { + RADEON_WRITE_MCIND(RS690_MC_AGP_BASE, + (unsigned int)dev_priv->gart_vm_start); + RADEON_WRITE_MCIND(RS690_MC_AGP_BASE_2, 0); + } else { + RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start); + RADEON_WRITE(RS480_AGP_BASE_2, 0); + } - dev_priv->gart_size = 32*1024*1024; - temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & - 0xffff0000) | (dev_priv->gart_vm_start >> 16)); + temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & + 0xffff0000) | (dev_priv->gart_vm_start >> 16)); - radeon_write_agp_location(dev_priv, temp); + radeon_write_agp_location(dev_priv, temp, 0); - temp = IGP_READ_MCIND(dev_priv, RS480_AGP_ADDRESS_SPACE_SIZE); - IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | - RS480_VA_SIZE_32MB)); + temp = RADEON_READ_MCIND(dev_priv, RS480_AGP_ADDRESS_SPACE_SIZE); + RADEON_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | + size_reg)); do { - temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + temp = RADEON_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); if ((temp & RS480_GART_CACHE_INVALIDATE) == 0) break; DRM_UDELAY(1); - } while (1); + } while(1); - IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, - RS480_GART_CACHE_INVALIDATE); + RADEON_WRITE_MCIND(RS480_GART_CACHE_CNTRL, + RS480_GART_CACHE_INVALIDATE); do { - temp = IGP_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + temp = RADEON_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); if ((temp & RS480_GART_CACHE_INVALIDATE) == 0) break; DRM_UDELAY(1); - } while (1); + } while(1); - IGP_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0); + RADEON_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0); } else { - IGP_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, 0); + RADEON_WRITE_MCIND(RS480_AGP_ADDRESS_SPACE_SIZE, 0); } } @@ -939,11 +1139,11 @@ static void rs600_set_igpgart(drm_radeon_private_t *dev_priv, int on) (long)dev_priv->gart_info.bus_addr, dev_priv->gart_size); - IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (RS600_EFFECTIVE_L2_CACHE_SIZE(6) | - RS600_EFFECTIVE_L2_QUEUE_SIZE(6))); + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, (RS600_EFFECTIVE_L2_CACHE_SIZE(6) | + RS600_EFFECTIVE_L2_QUEUE_SIZE(6))); for (i = 0; i < 19; i++) - IGP_WRITE_MCIND(RS600_MC_PT0_CLIENT0_CNTL + i, + RADEON_WRITE_MCIND(RS600_MC_PT0_CLIENT0_CNTL + i, (RS600_ENABLE_TRANSLATION_MODE_OVERRIDE | RS600_SYSTEM_ACCESS_MODE_IN_SYS | RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH | @@ -951,55 +1151,55 @@ static void rs600_set_igpgart(drm_radeon_private_t *dev_priv, int on) RS600_ENABLE_FRAGMENT_PROCESSING | RS600_EFFECTIVE_L1_QUEUE_SIZE(3))); - IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL, (RS600_ENABLE_PAGE_TABLE | - RS600_PAGE_TABLE_TYPE_FLAT)); + RADEON_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL, (RS600_ENABLE_PAGE_TABLE | + RS600_PAGE_TABLE_TYPE_FLAT)); /* disable all other contexts */ for (i = 1; i < 8; i++) - IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL + i, 0); + RADEON_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_CNTL + i, 0); /* setup the page table aperture */ - IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR, - dev_priv->gart_info.bus_addr); - IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR, - dev_priv->gart_vm_start); - IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR, - (dev_priv->gart_vm_start + dev_priv->gart_size - 1)); - IGP_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0); + RADEON_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR, + dev_priv->gart_info.bus_addr); + RADEON_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR, + dev_priv->gart_vm_start); + RADEON_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR, + (dev_priv->gart_vm_start + dev_priv->gart_size - 1)); + RADEON_WRITE_MCIND(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0); /* setup the system aperture */ - IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR, - dev_priv->gart_vm_start); - IGP_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR, - (dev_priv->gart_vm_start + dev_priv->gart_size - 1)); + RADEON_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR, + dev_priv->gart_vm_start); + RADEON_WRITE_MCIND(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR, + (dev_priv->gart_vm_start + dev_priv->gart_size - 1)); /* enable page tables */ - temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); - IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, (temp | RS600_ENABLE_PT)); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, (temp | RS600_ENABLE_PT)); - temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1); - IGP_WRITE_MCIND(RS600_MC_CNTL1, (temp | RS600_ENABLE_PAGE_TABLES)); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_CNTL1); + RADEON_WRITE_MCIND(RS600_MC_CNTL1, (temp | RS600_ENABLE_PAGE_TABLES)); /* invalidate the cache */ - temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE); - IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); - temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); temp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE; - IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); - temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE); - IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); - temp = IGP_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); } else { - IGP_WRITE_MCIND(RS600_MC_PT0_CNTL, 0); - temp = IGP_READ_MCIND(dev_priv, RS600_MC_CNTL1); + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, 0); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_CNTL1); temp &= ~RS600_ENABLE_PAGE_TABLES; - IGP_WRITE_MCIND(RS600_MC_CNTL1, temp); + RADEON_WRITE_MCIND(RS600_MC_CNTL1, temp); } } @@ -1022,7 +1222,7 @@ static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) dev_priv->gart_vm_start + dev_priv->gart_size - 1); - radeon_write_agp_location(dev_priv, 0xffffffc0); /* ?? */ + radeon_write_agp_location(dev_priv, 0xffffffc0, 0); /* ?? */ RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, RADEON_PCIE_TX_GART_EN); @@ -1033,7 +1233,7 @@ static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on) } /* Enable or disable PCI GART on the chip */ -static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) +void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; @@ -1072,7 +1272,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) /* Turn off AGP aperture -- is this required for PCI GART? */ - radeon_write_agp_location(dev_priv, 0xffffffc0); + radeon_write_agp_location(dev_priv, 0xffffffc0, 0); RADEON_WRITE(RADEON_AGP_COMMAND, 0); /* clear AGP_COMMAND */ } else { RADEON_WRITE(RADEON_AIC_CNTL, @@ -1162,17 +1362,6 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, */ dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1; - switch(init->func) { - case RADEON_INIT_R200_CP: - dev_priv->microcode_version = UCODE_R200; - break; - case RADEON_INIT_R300_CP: - dev_priv->microcode_version = UCODE_R300; - break; - default: - dev_priv->microcode_version = UCODE_R100; - } - dev_priv->do_boxes = 0; dev_priv->cp_mode = init->cp_mode; @@ -1220,9 +1409,8 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, */ dev_priv->depth_clear.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE | (dev_priv->color_fmt << 10) | - (dev_priv->microcode_version == - UCODE_R100 ? RADEON_ZBLOCK16 : 0)); - + (dev_priv->chip_family < CHIP_R200 ? RADEON_ZBLOCK16 : 0)); + dev_priv->depth_clear.rb3d_zstencilcntl = (dev_priv->depth_fmt | RADEON_Z_TEST_ALWAYS | @@ -1419,28 +1607,41 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, dev_priv->gart_info.table_mask = DMA_BIT_MASK(32); /* if we have an offset set from userspace */ if (dev_priv->pcigart_offset_set) { - dev_priv->gart_info.bus_addr = - (resource_size_t)dev_priv->pcigart_offset + dev_priv->fb_location; - dev_priv->gart_info.mapping.offset = - dev_priv->pcigart_offset + dev_priv->fb_aper_offset; - dev_priv->gart_info.mapping.size = - dev_priv->gart_info.table_size; - - drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = - dev_priv->gart_info.mapping.handle; - - if (dev_priv->flags & RADEON_IS_PCIE) - dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; - else - dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; - dev_priv->gart_info.gart_table_location = - DRM_ATI_GART_FB; - DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n", - dev_priv->gart_info.addr, - dev_priv->pcigart_offset); + /* if it came from userspace - remap it */ + if (dev_priv->pcigart_offset_set == 1) { + dev_priv->gart_info.bus_addr = + (resource_size_t)dev_priv->pcigart_offset + dev_priv->fb_location; + dev_priv->gart_info.mapping.offset = + dev_priv->pcigart_offset + dev_priv->fb_aper_offset; + dev_priv->gart_info.mapping.size = + dev_priv->gart_info.table_size; + + /* this is done by the mm now */ + drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev); + dev_priv->gart_info.addr = + dev_priv->gart_info.mapping.handle; + + memset(dev_priv->gart_info.addr, 0, dev_priv->gart_info.table_size); + if (dev_priv->flags & RADEON_IS_PCIE) + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE; + else + dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI; + dev_priv->gart_info.gart_table_location = + DRM_ATI_GART_FB; + + DRM_DEBUG("Setting phys_pci_gart to %p %08lX\n", + dev_priv->gart_info.addr, + dev_priv->pcigart_offset); + } } else { + + if (dev_priv->flags & RADEON_IS_PCIE) { + DRM_ERROR + ("Cannot use PCI Express without GART in FB memory\n"); + radeon_do_cleanup_cp(dev); + return -EINVAL; + } if (dev_priv->flags & RADEON_IS_IGPGART) dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP; else @@ -1449,12 +1650,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, DRM_ATI_GART_MAIN; dev_priv->gart_info.addr = NULL; dev_priv->gart_info.bus_addr = 0; - if (dev_priv->flags & RADEON_IS_PCIE) { - DRM_ERROR - ("Cannot use PCI Express without GART in FB memory\n"); - radeon_do_cleanup_cp(dev); - return -EINVAL; - } + } sctrl = RADEON_READ(RADEON_SURFACE_CNTL); @@ -1486,6 +1682,9 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, radeon_set_pcigart(dev_priv, 1); } + /* Start with assuming that writeback doesn't work */ + dev_priv->writeback_works = 0; + radeon_cp_load_microcode(dev_priv); radeon_cp_init_ring_buffer(dev, dev_priv, file_priv); @@ -1540,8 +1739,11 @@ static int radeon_do_cleanup_cp(struct drm_device * dev) if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB) { - drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); - dev_priv->gart_info.addr = NULL; + if (dev_priv->pcigart_offset_set == 1) { + drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev); + dev_priv->gart_info.addr = NULL; + dev_priv->pcigart_offset_set = 0; + } } } /* only clear to the start of flags */ @@ -1594,6 +1796,10 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri { drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_init_t *init = data; + + /* on a modesetting driver ignore this stuff */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -1622,6 +1828,9 @@ int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_pr drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (dev_priv->cp_running) { @@ -1652,6 +1861,9 @@ int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_pri int ret; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv->cp_running) @@ -1699,6 +1911,9 @@ void radeon_do_release(struct drm_device * dev) drm_radeon_private_t *dev_priv = dev->dev_private; int i, ret; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + if (dev_priv) { if (dev_priv->cp_running) { /* Stop the cp */ @@ -1750,6 +1965,9 @@ void radeon_do_release(struct drm_device * dev) radeon_mem_takedown(&(dev_priv->gart_heap)); radeon_mem_takedown(&(dev_priv->fb_heap)); + if (dev_priv->user_mm_enable) + radeon_gem_mm_fini(dev); + /* deallocate kernel resources */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) r600_do_cleanup_cp(dev); @@ -1765,6 +1983,9 @@ int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_pr drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { @@ -1788,7 +2009,9 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); - LOCK_TEST_WITH_RETURN(dev, file_priv); + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + LOCK_TEST_WITH_RETURN(dev, file_priv); if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return r600_do_cp_idle(dev_priv); @@ -1803,6 +2026,9 @@ int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_p drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return r600_do_resume_cp(dev, file_priv); else @@ -1814,6 +2040,9 @@ int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *fil drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + LOCK_TEST_WITH_RETURN(dev, file_priv); if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) @@ -2040,6 +2269,824 @@ int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_ return ret; } +static void radeon_get_vram_type(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + if (dev_priv->flags & RADEON_IS_IGP || (dev_priv->chip_family >= CHIP_R300)) + dev_priv->is_ddr = true; + else if (RADEON_READ(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR) + dev_priv->is_ddr = true; + else + dev_priv->is_ddr = false; + + if ((dev_priv->chip_family >= CHIP_R600) && + (dev_priv->chip_family <= CHIP_RV635)) { + int chansize; + + tmp = RADEON_READ(R600_RAMCFG); + if (tmp & R600_CHANSIZE_OVERRIDE) + chansize = 16; + else if (tmp & R600_CHANSIZE) + chansize = 64; + else + chansize = 32; + + if (dev_priv->chip_family == CHIP_R600) + dev_priv->ram_width = 8 * chansize; + else if (dev_priv->chip_family == CHIP_RV670) + dev_priv->ram_width = 4 * chansize; + else if ((dev_priv->chip_family == CHIP_RV610) || + (dev_priv->chip_family == CHIP_RV620)) + dev_priv->ram_width = chansize; + else if ((dev_priv->chip_family == CHIP_RV630) || + (dev_priv->chip_family == CHIP_RV635)) + dev_priv->ram_width = 2 * chansize; + } else if (dev_priv->chip_family == CHIP_RV515) { + tmp = RADEON_READ_MCIND(dev_priv, RV515_MC_CNTL); + tmp &= RV515_MEM_NUM_CHANNELS_MASK; + switch (tmp) { + case 0: dev_priv->ram_width = 64; break; + case 1: dev_priv->ram_width = 128; break; + default: dev_priv->ram_width = 128; break; + } + } else if ((dev_priv->chip_family >= CHIP_R520) && + (dev_priv->chip_family <= CHIP_RV570)) { + tmp = RADEON_READ_MCIND(dev_priv, R520_MC_CNTL0); + switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) { + case 0: dev_priv->ram_width = 32; break; + case 1: dev_priv->ram_width = 64; break; + case 2: dev_priv->ram_width = 128; break; + case 3: dev_priv->ram_width = 256; break; + default: dev_priv->ram_width = 128; break; + } + } else if ((dev_priv->chip_family == CHIP_RV100) || + (dev_priv->chip_family == CHIP_RS100) || + (dev_priv->chip_family == CHIP_RS200)) { + tmp = RADEON_READ(RADEON_MEM_CNTL); + if (tmp & RV100_HALF_MODE) + dev_priv->ram_width = 32; + else + dev_priv->ram_width = 64; + + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + dev_priv->ram_width /= 4; + dev_priv->is_ddr = true; + } + } else if (dev_priv->chip_family <= CHIP_RV280) { + tmp = RADEON_READ(RADEON_MEM_CNTL); + if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) + dev_priv->ram_width = 128; + else + dev_priv->ram_width = 64; + } else { + /* newer IGPs */ + dev_priv->ram_width = 128; + } + DRM_DEBUG("RAM width %d bits %cDR\n", dev_priv->ram_width, dev_priv->is_ddr ? 'D' : 'S'); +} + +static void radeon_force_some_clocks(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); +} + +static void radeon_set_dynamic_clock(struct drm_device *dev, int mode) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t tmp; + + switch(mode) { + case 0: + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_E2 | RADEON_SCLK_FORCE_SE | + RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_VIP | + RADEON_SCLK_FORCE_RE | RADEON_SCLK_FORCE_PB | + RADEON_SCLK_FORCE_TAM | RADEON_SCLK_FORCE_TDM | + RADEON_SCLK_FORCE_RB); + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + } else if (dev_priv->chip_family == CHIP_RV350) { + /* for RV350/M10, no delays are required. */ + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp |= (R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | + R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | + R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | + R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); + tmp |= RADEON_DYN_STOP_LAT_MASK; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_E2); + tmp |= RADEON_SCLK_FORCE_SE; + + if ( dev_priv->flags & RADEON_SINGLE_CRTC ) { + tmp |= ( RADEON_SCLK_FORCE_RB | + RADEON_SCLK_FORCE_TDM | + RADEON_SCLK_FORCE_TAM | + RADEON_SCLK_FORCE_PB | + RADEON_SCLK_FORCE_RE | + RADEON_SCLK_FORCE_VIP | + RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_HDP ); + } else if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350)) { + tmp |= ( RADEON_SCLK_FORCE_HDP | + RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_DISP2 | + RADEON_SCLK_FORCE_TOP | + RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP); + } + + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + udelay(16000); + + if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350)) { + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp |= ( R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + udelay(16000); + } + + if (dev_priv->flags & RADEON_IS_IGP) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + tmp &= ~(RADEON_FORCEON_MCLKA | + RADEON_FORCEON_YCLKA); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, tmp); + udelay(16000); + } + + if ((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250) || + (dev_priv->chip_family == CHIP_RV280)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp |= RADEON_SCLK_MORE_FORCEON; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + udelay(16000); + } + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + udelay(16000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + } + DRM_DEBUG("Dynamic Clock Scaling Disabled\n"); + break; + case 1: + if (dev_priv->flags & RADEON_SINGLE_CRTC) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + if ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) > + RADEON_CFG_ATI_REV_A13) { + tmp &= ~(RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_RB); + } + tmp &= ~(RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_SE | + RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_RE | + RADEON_SCLK_FORCE_PB | RADEON_SCLK_FORCE_TAM | + RADEON_SCLK_FORCE_TDM); + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + } else if ((dev_priv->chip_family == CHIP_R300) || + (dev_priv->chip_family == CHIP_R350) || + (dev_priv->chip_family == CHIP_RV350)) { + if (dev_priv->chip_family == CHIP_RV350) { + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp &= ~(R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + tmp |= (R300_SCLK_TCL_MAX_DYN_STOP_LAT | + R300_SCLK_GA_MAX_DYN_STOP_LAT | + R300_SCLK_CBA_MAX_DYN_STOP_LAT); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP | + RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 | + RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 | + R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT | + RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR | + R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX | + R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK | + R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0); + tmp |= RADEON_DYN_STOP_LAT_MASK; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb | + R300_DVOCLK_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + R300_PIXCLK_DVO_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb | + R300_PIXCLK_TRANS_ALWAYS_ONb | + R300_PIXCLK_TVO_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb | + R300_P2G2CLK_ALWAYS_ONb); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_MISC); + tmp |= (RADEON_MC_MCLK_DYN_ENABLE | + RADEON_IO_MCLK_DYN_ENABLE); + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_MISC, tmp); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + tmp |= (RADEON_FORCEON_MCLKA | + RADEON_FORCEON_MCLKB); + + tmp &= ~(RADEON_FORCEON_YCLKA | + RADEON_FORCEON_YCLKB | + RADEON_FORCEON_MC); + + /* Some releases of vbios have set DISABLE_MC_MCLKA + and DISABLE_MC_MCLKB bits in the vbios table. Setting these + bits will cause H/W hang when reading video memory with dynamic clocking + enabled. */ + if ((tmp & R300_DISABLE_MC_MCLKA) && + (tmp & R300_DISABLE_MC_MCLKB)) { + /* If both bits are set, then check the active channels */ + tmp = RADEON_READ_PLL(dev_priv, RADEON_MCLK_CNTL); + if (dev_priv->ram_width == 64) { + if (RADEON_READ(RADEON_MEM_CNTL) & R300_MEM_USE_CD_CH_ONLY) + tmp &= ~R300_DISABLE_MC_MCLKB; + else + tmp &= ~R300_DISABLE_MC_MCLKA; + } else { + tmp &= ~(R300_DISABLE_MC_MCLKA | + R300_DISABLE_MC_MCLKB); + } + } + + RADEON_WRITE_PLL(dev_priv, RADEON_MCLK_CNTL, tmp); + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + tmp &= ~(R300_SCLK_FORCE_VAP); + tmp |= RADEON_SCLK_FORCE_CP; + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, R300_SCLK_CNTL2); + tmp &= ~(R300_SCLK_FORCE_TCL | + R300_SCLK_FORCE_GA | + R300_SCLK_FORCE_CBA); + RADEON_WRITE_PLL(dev_priv, R300_SCLK_CNTL2, tmp); + } + } else { + tmp = RADEON_READ_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL); + tmp &= ~(RADEON_ACTIVE_HILO_LAT_MASK | + RADEON_DISP_DYN_STOP_LAT_MASK | + RADEON_DYN_STOP_MODE_MASK); + + tmp |= (RADEON_ENGIN_DYNCLK_MODE | + (0x01 << RADEON_ACTIVE_HILO_LAT_SHIFT)); + RADEON_WRITE_PLL(dev_priv, RADEON_CLK_PWRMGT_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_CLK_PIN_CNTL); + tmp |= RADEON_SCLK_DYN_START_CNTL; + RADEON_WRITE_PLL(dev_priv, RADEON_CLK_PIN_CNTL, tmp); + udelay(15000); + + /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200 + to lockup randomly, leave them as set by BIOS. + */ + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_CNTL); + /*tmp &= RADEON_SCLK_SRC_SEL_MASK;*/ + tmp &= ~RADEON_SCLK_FORCEON_MASK; + + /*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300*/ + if (((dev_priv->chip_family == CHIP_RV250) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) || + ((dev_priv->chip_family == CHIP_RV100) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) <= + RADEON_CFG_ATI_REV_A13))){ + tmp |= RADEON_SCLK_FORCE_CP; + tmp |= RADEON_SCLK_FORCE_VIP; + } + + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_CNTL, tmp); + + if ((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250) || + (dev_priv->chip_family == CHIP_RV280)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_SCLK_MORE_CNTL); + tmp &= ~RADEON_SCLK_MORE_FORCEON; + + /* RV200::A11 A12 RV250::A11 A12 */ + if (((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250)) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) { + tmp |= RADEON_SCLK_MORE_FORCEON; + } + RADEON_WRITE_PLL(dev_priv, RADEON_SCLK_MORE_CNTL, tmp); + udelay(15000); + } + + /* RV200::A11 A12, RV250::A11 A12 */ + if (((dev_priv->chip_family == CHIP_RV200) || + (dev_priv->chip_family == CHIP_RV250)) && + ((RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) < + RADEON_CFG_ATI_REV_A13)) { + tmp = RADEON_READ_PLL(dev_priv, RADEON_PLL_PWRMGT_CNTL); + tmp |= RADEON_TCL_BYPASS_DISABLE; + RADEON_WRITE_PLL(dev_priv, RADEON_PLL_PWRMGT_CNTL, tmp); + } + udelay(15000); + + /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK)*/ + tmp = RADEON_READ_PLL(dev_priv, RADEON_PIXCLKS_CNTL); + tmp |= (RADEON_PIX2CLK_ALWAYS_ONb | + RADEON_PIX2CLK_DAC_ALWAYS_ONb | + RADEON_PIXCLK_BLEND_ALWAYS_ONb | + RADEON_PIXCLK_GV_ALWAYS_ONb | + RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb | + RADEON_PIXCLK_LVDS_ALWAYS_ONb | + RADEON_PIXCLK_TMDS_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, tmp); + udelay(15000); + + tmp = RADEON_READ_PLL(dev_priv, RADEON_VCLK_ECP_CNTL); + tmp |= (RADEON_PIXCLK_ALWAYS_ONb | + RADEON_PIXCLK_DAC_ALWAYS_ONb); + + RADEON_WRITE_PLL(dev_priv, RADEON_VCLK_ECP_CNTL, tmp); + udelay(15000); + } + DRM_DEBUG("Dynamic Clock Scaling Enabled\n"); + break; + default: + break; + } + +} + +int radeon_modeset_cp_suspend(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; + + ret = radeon_do_cp_idle(dev_priv); + if (ret) + DRM_ERROR("failed to idle CP on suspend\n"); + + radeon_do_cp_stop(dev_priv); + radeon_do_engine_reset(dev); + if (dev_priv->flags & RADEON_IS_AGP) { + } else { + radeon_set_pcigart(dev_priv, 0); + } + + return 0; +} + +int radeon_modeset_cp_resume(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + radeon_do_wait_for_idle(dev_priv); +#if __OS_HAS_AGP + if (dev_priv->flags & RADEON_IS_AGP) { + /* Turn off PCI GART */ + radeon_set_pcigart(dev_priv, 0); + } else +#endif + { + /* Turn on PCI GART */ + radeon_set_pcigart(dev_priv, 1); + } + radeon_gart_flush(dev); + + radeon_cp_load_microcode(dev_priv); + radeon_cp_init_ring_buffer(dev, dev_priv, NULL); + + radeon_do_engine_reset(dev); + + radeon_test_writeback(dev_priv); + + radeon_do_cp_start(dev_priv); + return 0; +} + +int radeon_modeset_cp_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + /* allocate a ring and ring rptr bits from GART space */ + /* these are allocated in GEM files */ + + /* Start with assuming that writeback doesn't work */ + dev_priv->writeback_works = 0; + + if (dev_priv->chip_family > CHIP_R600) + return 0; + + dev_priv->ring.size = RADEON_DEFAULT_RING_SIZE; + dev_priv->cp_mode = RADEON_CSQ_PRIBM_INDBM; + + dev_priv->ring.start = (u32 *)(void *)(unsigned long)dev_priv->mm.ring.kmap.virtual; + dev_priv->ring.end = (u32 *)(void *)(unsigned long)dev_priv->mm.ring.kmap.virtual + + dev_priv->ring.size / sizeof(u32); + dev_priv->ring.size_l2qw = drm_order(dev_priv->ring.size / 8); + dev_priv->ring.rptr_update = 4096; + dev_priv->ring.rptr_update_l2qw = drm_order(4096 / 8); + dev_priv->ring.fetch_size = 32; + dev_priv->ring.fetch_size_l2ow = drm_order(32 / 16); + dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; + dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; + + dev_priv->new_memmap = true; + + r300_init_reg_flags(dev); + + /* turn off HDP read cache for now */ + RADEON_WRITE(RADEON_HOST_PATH_CNTL, RADEON_READ(RADEON_HOST_PATH_CNTL) | RADEON_HP_LIN_RD_CACHE_DIS); + + return radeon_modeset_cp_resume(dev); +} + +static bool radeon_read_bios(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + u8 __iomem *bios; + size_t size; + + bios = pci_map_rom(dev->pdev, &size); + if (!bios) { + return false; + } + + if (size == 0) + goto fail; + + if (bios[0] != 0x55 || bios[1] != 0xaa) + goto fail; + + dev_priv->bios = kmalloc(size, GFP_KERNEL); + if (!dev_priv->bios) { + pci_unmap_rom(dev->pdev, bios); + return -1; + } + + memcpy(dev_priv->bios, bios, size); + + pci_unmap_rom(dev->pdev, bios); + + return true; +fail: + pci_unmap_rom(dev->pdev, bios); + kfree(dev_priv->bios); + dev_priv->bios = NULL; + return false; +} + +static bool radeon_read_disabled_bios(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + bool ret; + + if (dev_priv->chip_family >= CHIP_R600) { + uint32_t viph_control = RADEON_READ(RADEON_VIPH_CONTROL); + uint32_t bus_cntl = RADEON_READ(RADEON_BUS_CNTL); + uint32_t d1vga_control = RADEON_READ(AVIVO_D1VGA_CONTROL); + uint32_t d2vga_control = RADEON_READ(AVIVO_D2VGA_CONTROL); + uint32_t vga_render_control = RADEON_READ(AVIVO_VGA_RENDER_CONTROL); + uint32_t rom_cntl = RADEON_READ(R600_ROM_CNTL); + uint32_t general_pwrmgt = RADEON_READ(R600_GENERAL_PWRMGT); + uint32_t low_vid_lower_gpio_cntl = RADEON_READ(R600_LOW_VID_LOWER_GPIO_CNTL); + uint32_t medium_vid_lower_gpio_cntl = RADEON_READ(R600_MEDIUM_VID_LOWER_GPIO_CNTL); + uint32_t high_vid_lower_gpio_cntl = RADEON_READ(R600_HIGH_VID_LOWER_GPIO_CNTL); + uint32_t ctxsw_vid_lower_gpio_cntl = RADEON_READ(R600_CTXSW_VID_LOWER_GPIO_CNTL); + uint32_t lower_gpio_enable = RADEON_READ(R600_LOWER_GPIO_ENABLE); + + /* disable VIP */ + RADEON_WRITE(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); + + /* enable the rom */ + RADEON_WRITE(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + + /* Disable VGA mode */ + RADEON_WRITE(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + RADEON_WRITE(AVIVO_D2VGA_CONTROL, (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + RADEON_WRITE(AVIVO_VGA_RENDER_CONTROL, (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); + + RADEON_WRITE(R600_ROM_CNTL, ((rom_cntl & ~R600_SCK_PRESCALE_CRYSTAL_CLK_MASK) | + (1 << R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT) | + R600_SCK_OVERWRITE)); + + RADEON_WRITE(R600_GENERAL_PWRMGT, (general_pwrmgt & ~R600_OPEN_DRAIN_PADS)); + RADEON_WRITE(R600_LOW_VID_LOWER_GPIO_CNTL, (low_vid_lower_gpio_cntl & ~0x400)); + RADEON_WRITE(R600_MEDIUM_VID_LOWER_GPIO_CNTL, (medium_vid_lower_gpio_cntl & ~0x400)); + RADEON_WRITE(R600_HIGH_VID_LOWER_GPIO_CNTL, (high_vid_lower_gpio_cntl & ~0x400)); + RADEON_WRITE(R600_CTXSW_VID_LOWER_GPIO_CNTL, (ctxsw_vid_lower_gpio_cntl & ~0x400)); + RADEON_WRITE(R600_LOWER_GPIO_ENABLE, (lower_gpio_enable | 0x400)); + + ret = radeon_read_bios(dev); + + /* restore regs */ + RADEON_WRITE(RADEON_VIPH_CONTROL, viph_control); + RADEON_WRITE(RADEON_BUS_CNTL, bus_cntl); + RADEON_WRITE(AVIVO_D1VGA_CONTROL, d1vga_control); + RADEON_WRITE(AVIVO_D2VGA_CONTROL, d2vga_control); + RADEON_WRITE(AVIVO_VGA_RENDER_CONTROL, vga_render_control); + RADEON_WRITE(R600_ROM_CNTL, rom_cntl); + RADEON_WRITE(R600_GENERAL_PWRMGT, general_pwrmgt); + RADEON_WRITE(R600_LOW_VID_LOWER_GPIO_CNTL, low_vid_lower_gpio_cntl); + RADEON_WRITE(R600_MEDIUM_VID_LOWER_GPIO_CNTL, medium_vid_lower_gpio_cntl); + RADEON_WRITE(R600_HIGH_VID_LOWER_GPIO_CNTL, high_vid_lower_gpio_cntl); + RADEON_WRITE(R600_CTXSW_VID_LOWER_GPIO_CNTL, ctxsw_vid_lower_gpio_cntl); + RADEON_WRITE(R600_LOWER_GPIO_ENABLE, lower_gpio_enable); + } else if (dev_priv->chip_family >= CHIP_RS600) { + uint32_t seprom_cntl1 = RADEON_READ(RADEON_SEPROM_CNTL1); + uint32_t viph_control = RADEON_READ(RADEON_VIPH_CONTROL); + uint32_t bus_cntl = RADEON_READ(RADEON_BUS_CNTL); + uint32_t d1vga_control = RADEON_READ(AVIVO_D1VGA_CONTROL); + uint32_t d2vga_control = RADEON_READ(AVIVO_D2VGA_CONTROL); + uint32_t vga_render_control = RADEON_READ(AVIVO_VGA_RENDER_CONTROL); + uint32_t gpiopad_a = RADEON_READ(RADEON_GPIOPAD_A); + uint32_t gpiopad_en = RADEON_READ(RADEON_GPIOPAD_EN); + uint32_t gpiopad_mask = RADEON_READ(RADEON_GPIOPAD_MASK); + + RADEON_WRITE(RADEON_SEPROM_CNTL1, ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) | + (0xc << RADEON_SCK_PRESCALE_SHIFT))); + + RADEON_WRITE(RADEON_GPIOPAD_A, 0); + RADEON_WRITE(RADEON_GPIOPAD_EN, 0); + RADEON_WRITE(RADEON_GPIOPAD_MASK, 0); + + /* disable VIP */ + RADEON_WRITE(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); + + /* enable the rom */ + RADEON_WRITE(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + + /* Disable VGA mode */ + RADEON_WRITE(AVIVO_D1VGA_CONTROL, (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + RADEON_WRITE(AVIVO_D2VGA_CONTROL, (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE | + AVIVO_DVGA_CONTROL_TIMING_SELECT))); + RADEON_WRITE(AVIVO_VGA_RENDER_CONTROL, (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK)); + + ret = radeon_read_bios(dev); + + /* restore regs */ + RADEON_WRITE(RADEON_SEPROM_CNTL1, seprom_cntl1); + RADEON_WRITE(RADEON_VIPH_CONTROL, viph_control); + RADEON_WRITE(RADEON_BUS_CNTL, bus_cntl); + RADEON_WRITE(AVIVO_D1VGA_CONTROL, d1vga_control); + RADEON_WRITE(AVIVO_D2VGA_CONTROL, d2vga_control); + RADEON_WRITE(AVIVO_VGA_RENDER_CONTROL, vga_render_control); + RADEON_WRITE(RADEON_GPIOPAD_A, gpiopad_a); + RADEON_WRITE(RADEON_GPIOPAD_EN, gpiopad_en); + RADEON_WRITE(RADEON_GPIOPAD_MASK, gpiopad_mask); + + } else { + uint32_t seprom_cntl1 = RADEON_READ(RADEON_SEPROM_CNTL1); + uint32_t viph_control = RADEON_READ(RADEON_VIPH_CONTROL); + uint32_t bus_cntl = RADEON_READ(RADEON_BUS_CNTL); + uint32_t crtc_gen_cntl = RADEON_READ(RADEON_CRTC_GEN_CNTL); + uint32_t crtc2_gen_cntl = 0; + uint32_t crtc_ext_cntl = RADEON_READ(RADEON_CRTC_EXT_CNTL); + uint32_t fp2_gen_cntl = 0; + + if (dev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) + fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + + if (!(dev_priv->flags & RADEON_SINGLE_CRTC)) + crtc2_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL); + + RADEON_WRITE(RADEON_SEPROM_CNTL1, ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) | + (0xc << RADEON_SCK_PRESCALE_SHIFT))); + + /* disable VIP */ + RADEON_WRITE(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN)); + + /* enable the rom */ + RADEON_WRITE(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM)); + + /* Turn off mem requests and CRTC for both controllers */ + RADEON_WRITE(RADEON_CRTC_GEN_CNTL, ((crtc_gen_cntl & ~RADEON_CRTC_EN) | + (RADEON_CRTC_DISP_REQ_EN_B | + RADEON_CRTC_EXT_DISP_EN))); + if (!(dev_priv->flags & RADEON_SINGLE_CRTC)) + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, ((crtc2_gen_cntl & ~RADEON_CRTC2_EN) | + RADEON_CRTC2_DISP_REQ_EN_B)); + + /* Turn off CRTC */ + RADEON_WRITE(RADEON_CRTC_EXT_CNTL, ((crtc_ext_cntl & ~RADEON_CRTC_CRT_ON) | + (RADEON_CRTC_SYNC_TRISTAT | + RADEON_CRTC_DISPLAY_DIS))); + + if (dev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) + RADEON_WRITE(RADEON_FP2_GEN_CNTL, (fp2_gen_cntl & ~RADEON_FP2_ON)); + + ret = radeon_read_bios(dev); + + /* restore regs */ + RADEON_WRITE(RADEON_SEPROM_CNTL1, seprom_cntl1); + RADEON_WRITE(RADEON_VIPH_CONTROL, viph_control); + RADEON_WRITE(RADEON_BUS_CNTL, bus_cntl); + RADEON_WRITE(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl); + if (!(dev_priv->flags & RADEON_SINGLE_CRTC)) + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + RADEON_WRITE(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + if (dev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) + RADEON_WRITE(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + } + return ret; +} + + +static bool radeon_get_bios(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret = 0; + uint16_t tmp; + + ret = radeon_read_bios(dev); + if (ret == false) + ret = radeon_read_disabled_bios(dev); + + if (ret == false || !dev_priv->bios) { + DRM_ERROR("Unable to locate a BIOS ROM\n"); + return false; + } + + if (dev_priv->bios[0] != 0x55 || dev_priv->bios[1] != 0xaa) + goto free_bios; + + dev_priv->bios_header_start = radeon_bios16(dev_priv, 0x48); + + if (!dev_priv->bios_header_start) + goto free_bios; + + tmp = dev_priv->bios_header_start + 4; + if (!memcmp(dev_priv->bios + tmp, "ATOM", 4) || + !memcmp(dev_priv->bios + tmp, "MOTA", 4)) + dev_priv->is_atom_bios = true; + else + dev_priv->is_atom_bios = false; + + DRM_DEBUG("%sBIOS detected\n", dev_priv->is_atom_bios ? "ATOM" : "COM"); + return true; +free_bios: + kfree(dev_priv->bios); + dev_priv->bios = NULL; + return false; +} + +int radeon_modeset_preinit(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + static struct card_info card; + int ret; + + card.dev = dev; + card.reg_read = cail_reg_read; + card.reg_write = cail_reg_write; + card.mc_read = cail_mc_read; + card.mc_write = cail_mc_write; + card.pll_read = cail_pll_read; + card.pll_write = cail_pll_write; + + ret = radeon_get_bios(dev); + if (!ret) + return -1; + + if (dev_priv->is_atom_bios) { + dev_priv->mode_info.atom_context = atom_parse(&card, dev_priv->bios); + radeon_atom_initialize_bios_scratch_regs(dev); + } else + radeon_combios_initialize_bios_scratch_regs(dev); + + radeon_get_clock_info(dev); + + /* configure initial usec timeout here */ + dev_priv->usec_timeout = RADEON_DEFAULT_CP_TIMEOUT; + + return 0; +} + +int radeon_static_clocks_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if (radeon_dynclks != -1) { + + if (dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) + radeon_dynclks = 0; + + if ((dev_priv->flags & RADEON_IS_MOBILITY) && !radeon_is_avivo(dev_priv)) { + radeon_set_dynamic_clock(dev, radeon_dynclks); + } else if (radeon_is_avivo(dev_priv)) { + if (radeon_dynclks) { + radeon_atom_static_pwrmgt_setup(dev, 1); + radeon_atom_dyn_clk_setup(dev, 1); + } + } + } + if (radeon_is_r300(dev_priv) || radeon_is_rv100(dev_priv)) + radeon_force_some_clocks(dev); + return 0; +} + +static bool radeon_card_posted(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t reg; + + if (radeon_is_avivo(dev_priv)) { + reg = RADEON_READ(AVIVO_D1CRTC_CONTROL) | RADEON_READ(AVIVO_D2CRTC_CONTROL); + if (reg & AVIVO_CRTC_EN) + return true; + } else { + reg = RADEON_READ(RADEON_CRTC_GEN_CNTL) | RADEON_READ(RADEON_CRTC2_GEN_CNTL); + if (reg & RADEON_CRTC_EN) + return true; + } + return false; + +} int radeon_driver_load(struct drm_device *dev, unsigned long flags) { drm_radeon_private_t *dev_priv; @@ -2053,6 +3100,8 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)dev_priv; dev_priv->flags = flags; + dev_priv->chip_family = flags & RADEON_FAMILY_MASK; + switch (flags & RADEON_FAMILY_MASK) { case CHIP_R100: case CHIP_RV200: @@ -2073,6 +3122,21 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) break; } + /* don't enable kms by default on r600 yet */ + if (radeon_modeset == -1) { + if ((dev_priv->chip_family >= CHIP_R600)) { + dev->driver->driver_features &= ~DRIVER_MODESET; + drm_put_minor(&dev->control); + radeon_modeset = 0; + } else + radeon_modeset = 1; + } + + /* rs480s have a gart size issue */ + if ((radeon_gart_size == 512) && + ((dev_priv->chip_family == CHIP_RS400 || dev_priv->chip_family == CHIP_RS480))) + radeon_gart_size = 32; + if (drm_device_is_agp(dev)) dev_priv->flags |= RADEON_IS_AGP; else if (drm_device_is_pcie(dev)) @@ -2080,9 +3144,34 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) else dev_priv->flags |= RADEON_IS_PCI; + DRM_DEBUG("%s card detected\n", + ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + if (dev_priv->flags & RADEON_IS_AGP) { + /* disable AGP for any chips after RV280 if not specified */ + if ((dev_priv->chip_family > CHIP_RV280) && (radeon_agpmode == 0)) + radeon_agpmode = -1; + + if (radeon_agpmode == -1) { + dev_priv->flags &= ~RADEON_IS_AGP; + if (dev_priv->chip_family >= CHIP_RV515 || + dev_priv->chip_family == CHIP_RV380 || + dev_priv->chip_family == CHIP_RV410 || + dev_priv->chip_family == CHIP_R423) { + DRM_INFO("Forcing AGP to PCIE mode\n"); + dev_priv->flags |= RADEON_IS_PCIE; + } else { + DRM_INFO("Forcing AGP to PCI mode\n"); + dev_priv->flags |= RADEON_IS_PCI; + } + } + } + } + ret = drm_addmap(dev, drm_get_resource_start(dev, 2), drm_get_resource_len(dev, 2), _DRM_REGISTERS, - _DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio); + _DRM_DRIVER | _DRM_READ_ONLY, &dev_priv->mmio); if (ret != 0) return ret; @@ -2092,8 +3181,63 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) return ret; } - DRM_DEBUG("%s card detected\n", - ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + radeon_modeset_preinit(dev); + + radeon_get_vram_type(dev); + + dev_priv->pll_errata = 0; + + if (dev_priv->chip_family == CHIP_R300 && + (RADEON_READ(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) == RADEON_CFG_ATI_REV_A11) + dev_priv->pll_errata |= CHIP_ERRATA_R300_CG; + + if (dev_priv->chip_family == CHIP_RV200 || + dev_priv->chip_family == CHIP_RS200) + dev_priv->pll_errata |= CHIP_ERRATA_PLL_DUMMYREADS; + + + if (dev_priv->chip_family == CHIP_RV100 || + dev_priv->chip_family == CHIP_RS100 || + dev_priv->chip_family == CHIP_RS200) + dev_priv->pll_errata |= CHIP_ERRATA_PLL_DELAY; + + /* check if cards are posted or not */ + if (!radeon_card_posted(dev) && dev_priv->bios) { + DRM_INFO("GPU not posted. posting now...\n"); + 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); + } + } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + radeon_static_clocks_init(dev); + + /* init memory manager - start with all of VRAM and a 32MB GART aperture for now */ + dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + + ret = radeon_gem_mm_init(dev); + if (ret) + goto modeset_fail; + + radeon_modeset_init(dev); + + radeon_modeset_cp_init(dev); + dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); + + drm_irq_install(dev); + } + + + return ret; +modeset_fail: + dev->driver->driver_features &= ~DRIVER_MODESET; + drm_put_minor(&dev->control); return ret; } @@ -2147,18 +3291,12 @@ void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) */ int radeon_driver_firstopen(struct drm_device *dev) { - int ret; - drm_local_map_t *map; drm_radeon_private_t *dev_priv = dev->dev_private; - dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; - dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); - ret = drm_addmap(dev, dev_priv->fb_aper_offset, - drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER, - _DRM_WRITE_COMBINING, &map); - if (ret != 0) - return ret; + dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; return 0; } @@ -2167,6 +3305,14 @@ int radeon_driver_unload(struct drm_device *dev) { drm_radeon_private_t *dev_priv = dev->dev_private; + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + drm_irq_uninstall(dev); + radeon_modeset_cleanup(dev); + radeon_gem_mm_fini(dev); + } + + drm_rmmap(dev, dev_priv->mmio); + DRM_DEBUG("\n"); drm_rmmap(dev, dev_priv->mmio); @@ -2214,3 +3360,41 @@ void radeon_commit_ring(drm_radeon_private_t *dev_priv) RADEON_READ(RADEON_CP_RB_RPTR); } } + +void radeon_gart_flush(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t loop = 0, val; + if (dev_priv->flags & RADEON_IS_IGPGART) { + RADEON_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + RADEON_WRITE_MCIND(RS480_GART_CACHE_CNTRL, RS480_GART_CACHE_INVALIDATE); + val = RADEON_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + while ((val & RS480_GART_CACHE_INVALIDATE) && loop++ < 100000) { + val = RADEON_READ_MCIND(dev_priv, RS480_GART_CACHE_CNTRL); + } + if (loop == 100000) + DRM_ERROR("Failed to invalidate IGP GART TLB\n"); + RADEON_WRITE_MCIND(RS480_GART_CACHE_CNTRL, 0); + } else if (dev_priv->flags & RADEON_IS_PCIE) { + u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); + tmp |= RADEON_PCIE_TX_GART_INVALIDATE_TLB; + RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL); + tmp &= ~RADEON_PCIE_TX_GART_INVALIDATE_TLB; + RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp); + } else if (dev_priv->chip_family == CHIP_RS600) { + u32 temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + + temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE); + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + + temp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE; + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + + temp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE); + RADEON_WRITE_MCIND(RS600_MC_PT0_CNTL, temp); + temp = RADEON_READ_MCIND(dev_priv, RS600_MC_PT0_CNTL); + } +} diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c new file mode 100644 index 0000000..1152552 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -0,0 +1,684 @@ +/* + * Copyright 2008 Jerome Glisse. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Jerome Glisse + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" +#include "r300_reg.h" + +int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv) +{ + struct drm_radeon_cs_parser parser; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_radeon_cs *cs = data; + uint32_t cs_id; + struct drm_radeon_cs_chunk __user **chunk_ptr = NULL; + uint64_t *chunk_array; + uint64_t *chunk_array_ptr; + long size; + int r, i; + + mutex_lock(&dev_priv->cs.cs_mutex); + /* set command stream id to 0 which is fake id */ + cs_id = 0; + cs->cs_id = cs_id; + + if (dev_priv == NULL) { + DRM_ERROR("called with no initialization\n"); + mutex_unlock(&dev_priv->cs.cs_mutex); + return -EINVAL; + } + if (!cs->num_chunks) { + mutex_unlock(&dev_priv->cs.cs_mutex); + return 0; + } + + + chunk_array = drm_calloc(cs->num_chunks, sizeof(uint64_t), DRM_MEM_DRIVER); + if (!chunk_array) { + mutex_unlock(&dev_priv->cs.cs_mutex); + return -ENOMEM; + } + + chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks); + + if (DRM_COPY_FROM_USER(chunk_array, chunk_array_ptr, sizeof(uint64_t)*cs->num_chunks)) { + r = -EFAULT; + goto out; + } + + parser.dev = dev; + parser.file_priv = fpriv; + parser.reloc_index = -1; + parser.ib_index = -1; + parser.num_chunks = cs->num_chunks; + /* copy out the chunk headers */ + parser.chunks = drm_calloc(parser.num_chunks, sizeof(struct drm_radeon_kernel_chunk), DRM_MEM_DRIVER); + if (!parser.chunks) { + r = -ENOMEM; + goto out; + } + + for (i = 0; i < parser.num_chunks; i++) { + struct drm_radeon_cs_chunk user_chunk; + + chunk_ptr = (void __user *)(unsigned long)chunk_array[i]; + + if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr, sizeof(struct drm_radeon_cs_chunk))){ + r = -EFAULT; + goto out; + } + parser.chunks[i].chunk_id = user_chunk.chunk_id; + + if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) + parser.reloc_index = i; + + if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_IB) + parser.ib_index = i; + + parser.chunks[i].length_dw = user_chunk.length_dw; + parser.chunks[i].chunk_data = (uint32_t *)(unsigned long)user_chunk.chunk_data; + + parser.chunks[i].kdata = NULL; + size = parser.chunks[i].length_dw * sizeof(uint32_t); + + switch(parser.chunks[i].chunk_id) { + case RADEON_CHUNK_ID_IB: + if (size == 0) { + r = -EINVAL; + goto out; + } + case RADEON_CHUNK_ID_RELOCS: + if (size) { + parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER); + if (!parser.chunks[i].kdata) { + r = -ENOMEM; + goto out; + } + + if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) { + r = -EFAULT; + goto out; + } + } else + parser.chunks[i].kdata = NULL; + break; + default: + break; + } + DRM_DEBUG("chunk %d %d %d %p\n", i, parser.chunks[i].chunk_id, parser.chunks[i].length_dw, + parser.chunks[i].chunk_data); + } + + + if (parser.chunks[parser.ib_index].length_dw > (16 * 1024)) { + DRM_ERROR("cs->dwords too big: %d\n", parser.chunks[parser.ib_index].length_dw); + r = -EINVAL; + goto out; + } + + /* get ib */ + r = dev_priv->cs.ib_get(&parser); + if (r) { + DRM_ERROR("ib_get failed\n"); + goto out; + } + + + r = radeon_gem_prelocate(&parser); + if (r) { + goto out; + } + + /* now parse command stream */ + r = dev_priv->cs.parse(&parser); + if (r) { + goto out; + } + + /* emit cs id sequence */ + dev_priv->cs.id_emit(&parser, &cs_id); + + cs->cs_id = cs_id; + cs->gart_limit = dev_priv->mm.gart_useable; + cs->vram_limit = dev_priv->mm.vram_visible; + +out: + dev_priv->cs.ib_free(&parser, r); + mutex_unlock(&dev_priv->cs.cs_mutex); + + for (i = 0; i < parser.num_chunks; i++) { + if (parser.chunks[i].kdata) + drm_free(parser.chunks[i].kdata, parser.chunks[i].length_dw * sizeof(uint32_t), DRM_MEM_DRIVER); + } + + drm_free(parser.chunks, sizeof(struct drm_radeon_kernel_chunk)*parser.num_chunks, DRM_MEM_DRIVER); + drm_free(chunk_array, sizeof(uint64_t)*parser.num_chunks, DRM_MEM_DRIVER); + + return r; +} + +/* for non-mm */ +static int radeon_nomm_relocate(struct drm_radeon_cs_parser *parser, uint32_t *reloc, uint32_t *offset) +{ + *offset = reloc[1]; + return 0; +} + +/* special case CRTC relocation for vline waits + * userspace doesn't know which CRTC it controls so we have a special sequence + * packet0 VLINE_START_END, value + * packet0 WAIT_UNTIL, crtc line | crtc_num + * packet0 NOP, crtc_id + * we relocate the vline register and the wait until crtc_num bit + */ +static int radeon_cs_relocate_crtc(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) +{ + struct drm_device *dev = parser->dev; + struct drm_mode_object *obj; + struct drm_crtc *crtc; + struct radeon_crtc *radeon_crtc; + uint32_t hdr, reg, val, packet3_hdr; + int ret = 0; + int crtc_id; + struct drm_radeon_kernel_chunk *ib_chunk; + + ib_chunk = &parser->chunks[parser->ib_index]; + + hdr = ib_chunk->kdata[offset_dw]; + reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + val = ib_chunk->kdata[offset_dw + 1]; + packet3_hdr = ib_chunk->kdata[offset_dw + 4]; + + mutex_lock(&dev->mode_config.mutex); + obj = drm_mode_object_find(parser->dev, ib_chunk->kdata[offset_dw + 5], DRM_MODE_OBJECT_CRTC); + if (!obj) { + ret = -EINVAL; + goto out; + } + crtc = obj_to_crtc(obj); + radeon_crtc = to_radeon_crtc(crtc); + + crtc_id = radeon_crtc->crtc_id; + + /* + * need to edit both packets + */ + /* vline start end - for crtc0 no work to do */ + if (crtc_id == 1) { + switch (reg) { + case AVIVO_D1MODE_VLINE_START_END: + hdr &= R300_CP_PACKET0_REG_MASK; + hdr |= AVIVO_D2MODE_VLINE_START_END >> 2; + break; + case RADEON_CRTC_GUI_TRIG_VLINE: + hdr &= R300_CP_PACKET0_REG_MASK; + hdr |= RADEON_CRTC2_GUI_TRIG_VLINE >> 2; + break; + default: + DRM_ERROR("unknown CRTC relocation\n"); + ret = -EINVAL; + goto out; + } + /* relocate the WAIT_UNTIL */ + ib_chunk->kdata[offset_dw] = hdr; + ib_chunk->kdata[offset_dw + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1; + } +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +#define RELOC_SIZE 2 +#define RELOC_SIZE_NEW 0 +#define RADEON_2D_OFFSET_MASK 0x3fffff + +static __inline__ int radeon_cs_relocate_packet0(struct drm_radeon_cs_parser *parser, uint32_t offset_dw) +{ + struct drm_device *dev = parser->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t hdr, reg, val, packet3_hdr; + uint32_t tmp, offset; + struct drm_radeon_kernel_chunk *ib_chunk; + int ret; + + ib_chunk = &parser->chunks[parser->ib_index]; +// if (parser->reloc_index == -1) +// is_old = 1; + + hdr = ib_chunk->kdata[offset_dw]; + reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + val = ib_chunk->kdata[offset_dw + 1]; + packet3_hdr = ib_chunk->kdata[offset_dw + 2]; + + /* this is too strict we may want to expand the length in the future and have + old kernels ignore it. */ + if (parser->reloc_index == -1) { + if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) { + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16), reg); + return -EINVAL; + } + } else { + if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16))) { + DRM_ERROR("Packet 3 was %x should have been %x: reg is %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE_NEW << 16), reg); + return -EINVAL; + + } + } + + switch(reg) { + case RADEON_DST_PITCH_OFFSET: + case RADEON_SRC_PITCH_OFFSET: + /* pass in the start of the reloc */ + ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + 2, &offset); + if (ret) + return ret; + tmp = (val & RADEON_2D_OFFSET_MASK) << 10; + val &= ~RADEON_2D_OFFSET_MASK; + offset += tmp; + offset >>= 10; + val |= offset; + break; + case RADEON_RB3D_DEPTHOFFSET: + case RADEON_RB3D_COLOROFFSET: + case R300_RB3D_COLOROFFSET0: + case R300_ZB_DEPTHOFFSET: + case R200_PP_TXOFFSET_0: + case R200_PP_TXOFFSET_1: + case R200_PP_TXOFFSET_2: + case R200_PP_TXOFFSET_3: + case R200_PP_TXOFFSET_4: + case R200_PP_TXOFFSET_5: + case RADEON_PP_TXOFFSET_0: + case RADEON_PP_TXOFFSET_1: + case RADEON_PP_TXOFFSET_2: + case R300_TX_OFFSET_0: + case R300_TX_OFFSET_0+4: + case R300_TX_OFFSET_0+8: + case R300_TX_OFFSET_0+12: + case R300_TX_OFFSET_0+16: + case R300_TX_OFFSET_0+20: + case R300_TX_OFFSET_0+24: + case R300_TX_OFFSET_0+28: + case R300_TX_OFFSET_0+32: + case R300_TX_OFFSET_0+36: + case R300_TX_OFFSET_0+40: + case R300_TX_OFFSET_0+44: + case R300_TX_OFFSET_0+48: + case R300_TX_OFFSET_0+52: + case R300_TX_OFFSET_0+56: + case R300_TX_OFFSET_0+60: + ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + 2, &offset); + if (ret) + return ret; + + offset &= 0xffffffe0; + val += offset; + break; + default: + break; + } + + ib_chunk->kdata[offset_dw + 1] = val; + return 0; +} + +static int radeon_cs_relocate_packet3(struct drm_radeon_cs_parser *parser, + uint32_t offset_dw) +{ + drm_radeon_private_t *dev_priv = parser->dev->dev_private; + uint32_t hdr, num_dw, reg, i; + uint32_t offset, val, tmp, nptr, cptr; + uint32_t *reloc; + int ret; + struct drm_radeon_kernel_chunk *ib_chunk; + + ib_chunk = &parser->chunks[parser->ib_index]; +// if (parser->reloc_index == -1) +// is_old = 1; + + hdr = ib_chunk->kdata[offset_dw]; + num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16; + reg = hdr & 0xff00; + + switch(reg) { + case RADEON_CNTL_HOSTDATA_BLT: + { + val = ib_chunk->kdata[offset_dw + 2]; + ret = dev_priv->cs.relocate(parser, ib_chunk->kdata + offset_dw + num_dw + 2, &offset); + if (ret) + return ret; + + tmp = (val & RADEON_2D_OFFSET_MASK) << 10; + val &= ~RADEON_2D_OFFSET_MASK; + offset += tmp; + offset >>= 10; + val |= offset; + + ib_chunk->kdata[offset_dw + 2] = val; + } + case RADEON_3D_LOAD_VBPNTR: + nptr = ib_chunk->kdata[offset_dw + 1]; + cptr = offset_dw + 3; + for (i = 0; i < (nptr & ~1); i+= 2) { + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + reloc += ((i + 0) * 2); + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[cptr] += offset; + cptr += 1; + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + reloc += ((i + 1) * 2); + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[cptr] += offset; + cptr += 2; + } + if (nptr & 1) { + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + reloc += ((nptr - 1) * 2); + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[cptr] += offset; + } + break; + case RADEON_CP_INDX_BUFFER: + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[offset_dw + 2] += offset; + break; + case RADEON_3D_RNDR_GEN_INDX_PRIM: + reloc = ib_chunk->kdata + offset_dw + num_dw + 2; + ret = dev_priv->cs.relocate(parser, reloc, &offset); + if (ret) { + return ret; + } + ib_chunk->kdata[offset_dw + 1] += offset; + break; + default: + DRM_ERROR("reg is %x, not RADEON_CNTL_HOSTDATA_BLT\n", reg); + return -EINVAL; + } + return 0; +} + +int radeon_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p) +{ + uint32_t hdr, num_dw, reg; + int count_dw = 1; + int ret; + bool one_reg; + uint32_t offset_dw = *offset_dw_p; + int incr = 2; + + hdr = parser->chunks[parser->ib_index].kdata[offset_dw]; + num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; + reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2; + one_reg = !!(hdr & RADEON_ONE_REG_WR); + + while (count_dw < num_dw) { + /* need to have something like the r300 validation here - + list of allowed registers */ + int flags; + + ret = r300_check_range(reg, 1); + switch(ret) { + case -1: + DRM_ERROR("Illegal register %x\n", reg); + break; + case 0: + break; + case 1: + flags = r300_get_reg_flags(reg); + if (flags == MARK_CHECK_OFFSET) { + if (num_dw > 2) { + DRM_ERROR("Cannot relocate inside type stream of reg0 packets\n"); + return -EINVAL; + } + + ret = radeon_cs_relocate_packet0(parser, offset_dw); + if (ret) { + DRM_ERROR("failed to relocate packet\n"); + return ret; + } + DRM_DEBUG("need to relocate %x %d\n", reg, flags); + /* okay it should be followed by a NOP */ + } else if (flags == MARK_CHECK_SCISSOR) { + DRM_DEBUG("need to validate scissor %x %d\n", reg, flags); + } else if (flags == MARK_CHECK_WAIT_VLINE) { + ret = radeon_cs_relocate_crtc(parser, offset_dw); + if (ret) { + DRM_ERROR("failed to relocate packet\n"); + return ret; + } + incr = 4; + } else { + DRM_ERROR("illegal register %x %d %d\n", reg, flags, offset_dw); + return -EINVAL; + } + break; + } + if (one_reg) + break; + + count_dw++; + reg += 4; + } + *offset_dw_p += incr; + return 0; +} + +int radeon_cs_parse(struct drm_radeon_cs_parser *parser) +{ + volatile int rb; + struct drm_radeon_kernel_chunk *ib_chunk; + /* scan the packet for various things */ + int count_dw = 0, size_dw; + int ret = 0; + + ib_chunk = &parser->chunks[parser->ib_index]; + size_dw = ib_chunk->length_dw; + + while (count_dw < size_dw && ret == 0) { + int hdr = ib_chunk->kdata[count_dw]; + int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16; + int reg; + + switch (hdr & RADEON_CP_PACKET_MASK) { + case RADEON_CP_PACKET0: + ret = radeon_cs_packet0(parser, &count_dw); + break; + case RADEON_CP_PACKET1: + case RADEON_CP_PACKET2: + reg = hdr & RADEON_CP_PACKET0_REG_MASK; + DRM_DEBUG("Packet 1/2: %d %x\n", num_dw, reg); + num_dw += 1; + break; + + case RADEON_CP_PACKET3: + reg = hdr & 0xff00; + num_dw += 2; + switch(reg) { + case RADEON_CNTL_HOSTDATA_BLT: + case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */ + case RADEON_CP_INDX_BUFFER: + case RADEON_3D_RNDR_GEN_INDX_PRIM: + radeon_cs_relocate_packet3(parser, count_dw); + break; + + case RADEON_CNTL_BITBLT_MULTI: + DRM_ERROR("need relocate packet 3 for %x\n", reg); + break; + + case RADEON_3D_DRAW_IMMD: /* triggers drawing using in-packet vertex data */ + case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ + case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ + case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ + case RADEON_3D_DRAW_VBUF: /* triggers drawing of vertex buffers setup elsewhere */ + case RADEON_3D_DRAW_INDX: /* triggers drawing using indices to vertex buffer */ + case RADEON_WAIT_FOR_IDLE: + case RADEON_CP_NOP: + break; + default: + DRM_ERROR("unknown packet 3 %x\n", reg); + ret = -EINVAL; + } + break; + } + + count_dw += num_dw; + } + + if (ret) + return ret; + + + /* copy the packet into the IB */ + memcpy(parser->ib, ib_chunk->kdata, ib_chunk->length_dw * sizeof(uint32_t)); + + /* read back last byte to flush WC buffers */ + rb = readl((parser->ib + (ib_chunk->length_dw-1) * sizeof(uint32_t))); + + return 0; +} + +uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon) +{ + /* FIXME: protect with a spinlock */ + /* FIXME: check if wrap affect last reported wrap & sequence */ + radeon->cs.id_scnt = (radeon->cs.id_scnt + 1) & 0x00FFFFFF; + if (!radeon->cs.id_scnt) { + /* increment wrap counter */ + radeon->cs.id_wcnt += 0x01000000; + /* valid sequence counter start at 1 */ + radeon->cs.id_scnt = 1; + } + return (radeon->cs.id_scnt | radeon->cs.id_wcnt); +} + +void r100_cs_id_emit(struct drm_radeon_cs_parser *parser, uint32_t *id) +{ + drm_radeon_private_t *dev_priv = parser->dev->dev_private; + RING_LOCALS; + + dev_priv->irq_emitted = radeon_update_breadcrumb(parser->dev); + /* ISYNC_CNTL should have CPSCRACTH bit set */ + *id = radeon_cs_id_get(dev_priv); + /* emit id in SCRATCH4 (not used yet in old drm) */ + BEGIN_RING(10); + OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); + OUT_RING(parser->card_offset); + OUT_RING(parser->chunks[parser->ib_index].length_dw); + OUT_RING(CP_PACKET2()); + OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG4, 0)); + OUT_RING(*id); + OUT_RING_REG(RADEON_LAST_SWI_REG, dev_priv->irq_emitted); + OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); + ADVANCE_RING(); + COMMIT_RING(); + +} + +void r300_cs_id_emit(struct drm_radeon_cs_parser *parser, uint32_t *id) +{ + drm_radeon_private_t *dev_priv = parser->dev->dev_private; + RING_LOCALS; + + dev_priv->irq_emitted = radeon_update_breadcrumb(parser->dev); + + /* ISYNC_CNTL should not have CPSCRACTH bit set */ + *id = radeon_cs_id_get(dev_priv); + + /* emit id in SCRATCH6 */ + BEGIN_RING(18); + OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1)); + OUT_RING(parser->card_offset); + OUT_RING(parser->chunks[parser->ib_index].length_dw); + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(0); + + OUT_RING_REG(R300_RB3D_DSTCACHE_CTLSTAT, R300_RB3D_DC_FLUSH); + OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 1)); + OUT_RING(6); + OUT_RING(*id); + OUT_RING_REG(R300_RB3D_DSTCACHE_CTLSTAT, R300_RB3D_DC_FINISH|R300_RB3D_DC_FLUSH); + /* emit inline breadcrumb for TTM fencing */ +#if 1 + RADEON_WAIT_UNTIL_3D_IDLE(); + OUT_RING_REG(RADEON_LAST_SWI_REG, dev_priv->irq_emitted); +#else + OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 1)); + OUT_RING(3); /* breadcrumb register */ + OUT_RING(dev_priv->irq_emitted); + OUT_RING(CP_PACKET2()); +#endif + OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); + ADVANCE_RING(); + COMMIT_RING(); + +} + +uint32_t r100_cs_id_last_get(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + return GET_SCRATCH(dev_priv, 4); +} + +uint32_t r300_cs_id_last_get(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + return GET_SCRATCH(dev_priv, 6); +} + +int radeon_cs_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + mutex_init(&dev_priv->cs.cs_mutex); + if (dev_priv->chip_family < CHIP_RV280) { + dev_priv->cs.id_emit = r100_cs_id_emit; + dev_priv->cs.id_last_get = r100_cs_id_last_get; + } else if (dev_priv->chip_family < CHIP_R600) { + dev_priv->cs.id_emit = r300_cs_id_emit; + dev_priv->cs.id_last_get = r300_cs_id_last_get; + } + + dev_priv->cs.parse = radeon_cs_parse; + /* ib get depends on memory manager or not so memory manager */ + dev_priv->cs.relocate = radeon_nomm_relocate; + return 0; +} diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c new file mode 100644 index 0000000..7ddc8fd --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -0,0 +1,264 @@ +/* + * 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; + int ret; + + if (!handle) { + /* turn off cursor */ + radeon_hide_cursor(crtc); + obj = NULL; + goto unpin; + } + + if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) { + DRM_ERROR("bad cursor width or height %d x %d\n", width, height); + return -EINVAL; + } + + 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; + } + + ret = radeon_gem_object_pin(obj, 0, RADEON_GEM_DOMAIN_VRAM); + if (ret) + goto fail; + + 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); + +unpin: + if (radeon_crtc->cursor_bo) { + radeon_gem_object_unpin(radeon_crtc->cursor_bo); + mutex_lock(&crtc->dev->struct_mutex); + drm_gem_object_unreference(radeon_crtc->cursor_bo); + mutex_unlock(&crtc->dev->struct_mutex); + } + + radeon_crtc->cursor_bo = obj; + return 0; +fail: + 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 = -y + 1; + if (xorigin >= CURSOR_WIDTH) + xorigin = CURSOR_WIDTH - 1; + if (yorigin >= CURSOR_HEIGHT) + yorigin = CURSOR_HEIGHT - 1; + + 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)); + 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/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c new file mode 100644 index 0000000..bb047ec --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -0,0 +1,670 @@ +/* + * 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" +#include "drm_edid.h" + +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; + + 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); + + RADEON_WRITE8(AVIVO_DC_LUT_RW_INDEX, 0); + for (i = 0; i < 256; i++) { + RADEON_WRITE(AVIVO_DC_LUT_30_COLOR, + (radeon_crtc->lut_r[i] << 20) | + (radeon_crtc->lut_g[i] << 10) | + (radeon_crtc->lut_b[i] << 0)); + } + + RADEON_WRITE(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); +} + +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; + int i; + uint32_t dac2_cntl; + + dac2_cntl = RADEON_READ(RADEON_DAC_CNTL2); + if (radeon_crtc->crtc_id == 0) + dac2_cntl &= (uint32_t)~RADEON_DAC2_PALETTE_ACC_CTL; + else + dac2_cntl |= RADEON_DAC2_PALETTE_ACC_CTL; + RADEON_WRITE(RADEON_DAC_CNTL2, dac2_cntl); + + RADEON_WRITE8(RADEON_PALETTE_INDEX, 0); + for (i = 0; i < 256; i++) { + RADEON_WRITE(RADEON_PALETTE_30_DATA, + (radeon_crtc->lut_r[i] << 20) | + (radeon_crtc->lut_g[i] << 10) | + (radeon_crtc->lut_b[i] << 0)); + } +} + +void radeon_crtc_load_lut(struct drm_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 */ +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 >> 6; + radeon_crtc->lut_g[regno] = green >> 6; + radeon_crtc->lut_b[regno] = blue >> 6; +} + +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, j; + + if (size != 256) + return; + + if (!crtc->fb) + return; + + /* copy in the colors from userspace */ + for (i = 0; i < 256; i++) { + radeon_crtc->lut_r[i] = red[i] >> 6; + radeon_crtc->lut_g[i] = green[i] >> 6; + radeon_crtc->lut_b[i] = blue[i] >> 6; + } + + radeon_crtc_load_lut(crtc); +} + +static void radeon_crtc_destroy(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (radeon_crtc->mode_set.mode) + drm_mode_destroy(crtc->dev, radeon_crtc->mode_set.mode); + drm_crtc_cleanup(crtc); + kfree(radeon_crtc); +} + +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 << 2; + radeon_crtc->lut_g[i] = i << 2; + radeon_crtc->lut_b[i] = i << 2; + } + + 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); +} + +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; + /* do all the mac and stuff */ + + if (dev_priv->is_atom_bios) { + if (dev_priv->chip_family >= CHIP_R600) + return radeon_get_atom_connector_info_from_object_table(dev); + else + return radeon_get_atom_connector_info_from_supported_devices_table(dev); + } else + return radeon_get_legacy_connector_info_from_bios(dev); +} + +int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) +{ + struct edid *edid; + int ret = 0; + + if (!radeon_connector->ddc_bus) + return -1; + 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) { + /* 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); + return ret; + } + drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); + 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; + 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); + } + 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 %lu %lu\n", freq, pll->min_ref_div, pll->max_ref_div); + 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) || + (post_div == 13) || + (post_div == 14) || + (post_div == 15)) + 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)) || + ((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; + 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 *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) + ret = radeon_atom_get_clock_info(dev); + else + ret = radeon_combios_get_clock_info(dev); + + if (ret) { + 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)) { + p1pll->min_post_div = 2; + p1pll->max_post_div = 0x7f; + p2pll->min_post_div = 2; + p2pll->max_post_div = 0x7f; + } else { + p1pll->min_post_div = 1; + p1pll->max_post_div = 16; + p2pll->min_post_div = 1; + p2pll->max_post_div = 12; + } + + 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; + +} + +/* 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); + struct drm_device *dev = fb->dev; + + if (fb->fbdev) + radeonfb_remove(dev, fb); + + 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); +} + +static int radeon_user_framebuffer_create_handle(struct drm_framebuffer *fb, + struct drm_file *file_priv, + unsigned int *handle) +{ + struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); + + return drm_gem_handle_create(file_priv, radeon_fb->obj, 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_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object *obj) +{ + 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); + + radeon_fb->obj = obj; + + 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; + struct drm_gem_object *obj; + + obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); + + return radeon_framebuffer_create(dev, mode_cmd, obj); +} + +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); + + 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); +} + +void radeon_init_disp_bandwidth(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_display_mode *modes[2]; + int pixel_bytes[2]; + struct drm_crtc *crtc; + + pixel_bytes[0] = pixel_bytes[1] = 0; + modes[0] = modes[1] = NULL; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (crtc->enabled && crtc->fb) { + modes[radeon_crtc->crtc_id] = &crtc->mode; + pixel_bytes[radeon_crtc->crtc_id] = crtc->fb->bits_per_pixel / 8; + } + } + + if (radeon_is_avivo(dev_priv)) { + radeon_init_disp_bw_avivo(dev, + modes[0], + pixel_bytes[0], + modes[1], + pixel_bytes[1]); + } else { + radeon_init_disp_bw_legacy(dev, + modes[0], + pixel_bytes[0], + modes[1], + pixel_bytes[1]); + } +} diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 13a60f4..298ae3d 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -35,48 +35,105 @@ #include "radeon_drv.h" #include "drm_pciids.h" +#include int radeon_no_wb; +int radeon_dynclks = -1; +int radeon_r4xx_atom = 0; +int radeon_agpmode = 0; +int radeon_vram_zero = 0; +int radeon_gart_size = 512; /* default gart size */ +int radeon_vram_limit = -1; +int radeon_no_gart_wb = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); -static int radeon_suspend(struct drm_device *dev, pm_message_t state) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; +int radeon_modeset = -1; +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); + +MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); +module_param_named(agpmode, radeon_agpmode, int, 0444); + +MODULE_PARM_DESC(vramzero, "Zero VRAM for new objects"); +module_param_named(vramzero, radeon_vram_zero, int, 0600); + +MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32,64, etc)\n"); +module_param_named(gartsize, radeon_gart_size, int, 0600); + +MODULE_PARM_DESC(vramlimit, "Restrict VRAM vfor testing"); +module_param_named(vramlimit, radeon_vram_limit, int, 0600); + +MODULE_PARM_DESC(no_gart_wb, "avoid using GART for moves from VRAM to GTT"); +module_param_named(no_gart_wb, radeon_no_gart_wb, int, 0600); + +static struct drm_driver driver; - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) - return 0; +static struct pci_device_id pciidlist[] = { + radeon_PCI_IDS +}; + +#if defined(CONFIG_DRM_RADEON_KMS) +MODULE_DEVICE_TABLE(pci, pciidlist); +#endif - /* Disable *all* interrupts */ - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) - RADEON_WRITE(R500_DxMODE_INT_MASK, 0); - RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); - return 0; +static int __devinit +radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + return drm_get_dev(pdev, ent, &driver); } -static int radeon_resume(struct drm_device *dev) +static void +radeon_pci_remove(struct pci_dev *pdev) { - drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_device *dev = pci_get_drvdata(pdev); - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) - return 0; + drm_put_dev(dev); +} - /* Restore interrupt registers */ - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) - RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); - RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); - return 0; +static int +radeon_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + return radeon_suspend(dev, state); } -static struct pci_device_id pciidlist[] = { - radeon_PCI_IDS +static int +radeon_pci_resume(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + return radeon_resume(dev); +} + + +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 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, @@ -92,6 +149,10 @@ static struct drm_driver driver = { .disable_vblank = radeon_disable_vblank, .master_create = radeon_master_create, .master_destroy = radeon_master_destroy, +#if defined(CONFIG_DEBUG_FS) + .debugfs_init = radeon_gem_debugfs_init, + .debugfs_cleanup = radeon_gem_debugfs_cleanup, +#endif .irq_preinstall = radeon_driver_irq_preinstall, .irq_postinstall = radeon_driver_irq_postinstall, .irq_uninstall = radeon_driver_irq_uninstall, @@ -100,7 +161,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, @@ -117,8 +182,15 @@ static struct drm_driver driver = { .pci_driver = { .name = DRIVER_NAME, .id_table = pciidlist, + .probe = radeon_pci_probe, + .remove = radeon_pci_remove, + .suspend = radeon_pci_suspend, + .resume = radeon_pci_resume, }, + .fence_driver = &radeon_fence_driver, + .bo_driver = &radeon_bo_driver, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, @@ -130,6 +202,29 @@ static struct drm_driver driver = { static int __init radeon_init(void) { driver.num_ioctls = radeon_max_ioctl; + + /* if enabled by default */ +#if defined(CONFIG_DRM_RADEON_KMS) && defined(CONFIG_X86) + driver.driver_features |= DRIVER_MODESET; + if (radeon_modeset == 0) + driver.driver_features &= ~DRIVER_MODESET; +#else + if (radeon_modeset == -1) + radeon_modeset = 0; +#endif + + if (radeon_modeset == 1) + driver.driver_features |= DRIVER_MODESET; + + /* if the vga console setting is enabled still + * let modprobe override it */ +#ifdef CONFIG_VGA_CONSOLE + if (vgacon_text_force() && radeon_modeset == -1) { + driver.driver_features &= ~DRIVER_MODESET; + radeon_modeset = 0; + } +#endif + return drm_init(&driver); } diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 8071d96..fb1e40a 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -34,6 +34,8 @@ /* General customization: */ +#include "atom.h" + #define DRIVER_AUTHOR "Gareth Hughes, Keith Whitwell, others." #define DRIVER_NAME "radeon" @@ -149,12 +151,6 @@ enum radeon_family { CHIP_LAST, }; -enum radeon_cp_microcode_version { - UCODE_R100, - UCODE_R200, - UCODE_R300, -}; - /* * Chip flags */ @@ -172,6 +168,34 @@ enum radeon_chip_flags { RADEON_IS_IGPGART = 0x01000000UL, }; +/* + * Errata workarounds + */ +enum radeon_pll_errata { + CHIP_ERRATA_R300_CG = 0x00000001, + CHIP_ERRATA_PLL_DUMMYREADS = 0x00000002, + CHIP_ERRATA_PLL_DELAY = 0x00000004 +}; + +enum radeon_ext_tmds_chip { + RADEON_DVOCHIP_NONE, + RADEON_SIL_164, + RADEON_SIL_1178 +}; + +#if defined(__powerpc__) +enum radeon_mac_model { + RADEON_MAC_NONE, + RADEON_MAC_IBOOK, + RADEON_MAC_POWERBOOK_EXTERNAL, + RADEON_MAC_POWERBOOK_INTERNAL, + RADEON_MAC_POWERBOOK_VGA, + RADEON_MAC_MINI_EXTERNAL, + RADEON_MAC_MINI_INTERNAL, + RADEON_MAC_IMAC_G5_ISIGHT +}; +#endif + typedef struct drm_radeon_freelist { unsigned int age; struct drm_buf *buf; @@ -235,18 +259,90 @@ struct radeon_virt_surface { #define RADEON_FLUSH_EMITED (1 << 0) #define RADEON_PURGE_EMITED (1 << 1) +struct radeon_mm_obj { + struct drm_buffer_object *bo; + struct drm_bo_kmap_obj kmap; +}; + +struct radeon_mm_info { + uint64_t vram_offset; // Offset into GPU space + uint64_t vram_size; + uint64_t vram_visible; + + uint64_t gart_start; + uint64_t gart_size; + + uint64_t gart_useable; + + void *pcie_table_backup; + + struct radeon_mm_obj pcie_table; + struct radeon_mm_obj ring; + struct radeon_mm_obj ring_read; + + struct radeon_mm_obj dma_bufs; + struct drm_map fake_agp_map; +}; + +#include "radeon_mode.h" + struct drm_radeon_master_private { drm_local_map_t *sarea; drm_radeon_sarea_t *sarea_priv; }; +struct drm_radeon_kernel_chunk { + uint32_t chunk_id; + uint32_t length_dw; + uint32_t __user *chunk_data; + uint32_t *kdata; +}; + +struct drm_radeon_cs_parser { + struct drm_device *dev; + struct drm_file *file_priv; + uint32_t num_chunks; + struct drm_radeon_kernel_chunk *chunks; + int ib_index; + int reloc_index; + uint32_t card_offset; + void *ib; +}; + +/* command submission struct */ +struct drm_radeon_cs_priv { + struct mutex cs_mutex; + uint32_t id_wcnt; + uint32_t id_scnt; + uint32_t id_last_wcnt; + uint32_t id_last_scnt; + + int (*parse)(struct drm_radeon_cs_parser *parser); + void (*id_emit)(struct drm_radeon_cs_parser *parser, uint32_t *id); + uint32_t (*id_last_get)(struct drm_device *dev); + /* this ib handling callback are for hidding memory manager drm + * from memory manager less drm, free have to emit ib discard + * sequence into the ring */ + int (*ib_get)(struct drm_radeon_cs_parser *parser); + uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib); + void (*ib_free)(struct drm_radeon_cs_parser *parser, int error); + /* do a relocation either MM or non-MM */ + int (*relocate)(struct drm_radeon_cs_parser *parser, + uint32_t *reloc, uint32_t *offset); +}; + + + +struct radeon_pm_regs { + uint32_t crtc_ext_cntl; + uint32_t bios_scratch[8]; +}; + typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; - u32 fb_location; - u32 fb_size; - int new_memmap; - + bool new_memmap; + bool user_mm_enable; /* userspace enabled the memory manager */ int gart_size; u32 gart_vm_start; unsigned long gart_buffers_offset; @@ -261,8 +357,6 @@ typedef struct drm_radeon_private { int usec_timeout; - int microcode_version; - struct { u32 boxes; int freelist_timeouts; @@ -298,7 +392,6 @@ typedef struct drm_radeon_private { unsigned long buffers_offset; unsigned long gart_textures_offset; - drm_local_map_t *sarea; drm_local_map_t *cp_ring; drm_local_map_t *ring_rptr; drm_local_map_t *gart_textures; @@ -307,8 +400,8 @@ typedef struct drm_radeon_private { struct mem_block *fb_heap; /* SW interrupt */ + int counter; wait_queue_head_t swi_queue; - atomic_t swi_emitted; int vblank_crtc; uint32_t irq_enable_reg; uint32_t r500_disp_irq_reg; @@ -316,9 +409,6 @@ typedef struct drm_radeon_private { struct radeon_surface surfaces[RADEON_MAX_SURFACES]; struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES]; - unsigned long pcigart_offset; - unsigned int pcigart_offset_set; - struct drm_ati_pcigart_info gart_info; u32 scratch_ages[5]; @@ -328,6 +418,9 @@ typedef struct drm_radeon_private { int num_gb_pipes; int track_flush; + + bool mm_enabled; + struct radeon_mm_info mm; drm_local_map_t *mmio; /* r6xx/r7xx pipe/shader config */ @@ -349,6 +442,40 @@ typedef struct drm_radeon_private { int r700_sc_hiz_tile_fifo_size; int r700_sc_earlyz_tile_fifo_fize; + uint32_t chip_family; + + unsigned long pcigart_offset; + unsigned int pcigart_offset_set; + struct drm_ati_pcigart_info gart_info; + + struct radeon_mode_info mode_info; + + uint8_t *bios; /* copy of the BIOS image */ + bool is_atom_bios; + uint16_t bios_header_start; + u32 fb_location; + u32 fb_size; + bool is_ddr; + u32 ram_width; + + uint32_t mc_fb_location; + uint32_t mc_agp_loc_lo; + uint32_t mc_agp_loc_hi; + + enum radeon_pll_errata pll_errata; + + struct radeon_mm_obj **ib_objs; + /* ib bitmap */ + uint64_t ib_alloc_bitmap; // TO DO replace with a real bitmap + struct drm_radeon_cs_priv cs; + + struct radeon_pm_regs pmregs; + int irq_emitted; + atomic_t irq_received; + + uint32_t aper_size; + int vram_mtrr; + int disp_priority; } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { @@ -363,8 +490,15 @@ typedef struct drm_radeon_kcmd_buffer { } drm_radeon_kcmd_buffer_t; extern int radeon_no_wb; +extern int radeon_dynclks; +extern int radeon_r4xx_atom; extern struct drm_ioctl_desc radeon_ioctls[]; extern int radeon_max_ioctl; +extern int radeon_agpmode; +extern int radeon_modeset; +extern int radeon_vram_zero; +extern int radeon_gart_size; +extern int radeon_vram_limit; extern u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv); extern void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val); @@ -398,7 +532,7 @@ extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_fi extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv); -extern void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc); +extern void radeon_write_agp_location(drm_radeon_private_t *dev_priv, u32 agp_loc, u32 agp_loc_hi); extern void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base); extern u32 RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr); @@ -407,12 +541,9 @@ extern struct drm_buf *radeon_freelist_get(struct drm_device * dev); extern int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n); +extern int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv); extern int radeon_do_cp_idle(drm_radeon_private_t * dev_priv); -extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags); -extern int radeon_presetup(struct drm_device *dev); -extern int radeon_driver_postcleanup(struct drm_device *dev); - extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -428,6 +559,7 @@ extern void radeon_write_ring_rptr(drm_radeon_private_t *dev_priv, u32 off, u32 extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state); extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int); extern void radeon_do_release(struct drm_device * dev); extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc); @@ -444,13 +576,13 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value); extern int radeon_driver_load(struct drm_device *dev, unsigned long flags); extern int radeon_driver_unload(struct drm_device *dev); extern int radeon_driver_firstopen(struct drm_device *dev); -extern void radeon_driver_preclose(struct drm_device *dev, +extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv); -extern void radeon_driver_postclose(struct drm_device *dev, +extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file *file_priv); extern void radeon_driver_lastclose(struct drm_device * dev); -extern int radeon_driver_open(struct drm_device *dev, - struct drm_file *file_priv); +extern int radeon_driver_open(struct drm_device * dev, + struct drm_file * file_priv); extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); @@ -479,6 +611,12 @@ extern int r600_cp_dispatch_indirect(struct drm_device *dev, extern int r600_page_table_init(struct drm_device *dev); extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); +extern int radeon_modeset_cp_suspend(struct drm_device *dev); +extern int radeon_modeset_cp_resume(struct drm_device *dev); +/* radeon_pm.c */ +int radeon_suspend(struct drm_device *dev, pm_message_t state); +int radeon_resume(struct drm_device *dev); + /* Flags for stats.boxes */ #define RADEON_BOX_DMA_IDLE 0x1 @@ -487,12 +625,17 @@ extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pciga #define RADEON_BOX_WAIT_IDLE 0x8 #define RADEON_BOX_TEXTURE_LOAD 0x10 +#define R600_CONFIG_MEMSIZE 0x5428 +#define R600_CONFIG_APER_SIZE 0x5430 /* Register definitions, register access macros and drmAddMap constants * for Radeon kernel driver. */ #define RADEON_MM_INDEX 0x0000 +# define RADEON_MM_APER (1 << 31) #define RADEON_MM_DATA 0x0004 +#include "radeon_reg.h" + #define RADEON_AGP_COMMAND 0x0f60 #define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config */ # define RADEON_AGP_ENABLE (1<<8) @@ -668,16 +811,6 @@ extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pciga #define R520_MC_IND_WR_EN (1 << 24) #define R520_MC_IND_DATA 0x74 -#define RV515_MC_FB_LOCATION 0x01 -#define RV515_MC_AGP_LOCATION 0x02 -#define RV515_MC_AGP_BASE 0x03 -#define RV515_MC_AGP_BASE_2 0x04 - -#define R520_MC_FB_LOCATION 0x04 -#define R520_MC_AGP_LOCATION 0x05 -#define R520_MC_AGP_BASE 0x06 -#define R520_MC_AGP_BASE_2 0x07 - #define RADEON_MPP_TB_CONFIG 0x01c0 #define RADEON_MEM_CNTL 0x0140 #define RADEON_MEM_SDRAM_MODE_REG 0x0158 @@ -741,6 +874,7 @@ extern void r600_page_table_cleanup(struct drm_device *dev, struct drm_ati_pciga #define RADEON_SCRATCH_REG3 0x15ec #define RADEON_SCRATCH_REG4 0x15f0 #define RADEON_SCRATCH_REG5 0x15f4 +#define RADEON_SCRATCH_REG6 0x15f8 #define RADEON_SCRATCH_UMSK 0x0770 #define RADEON_SCRATCH_ADDR 0x0774 @@ -763,6 +897,12 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); #define R600_SCRATCHOFF(x) (R600_SCRATCH_REG_OFFSET + 4*(x)) +#define RADEON_CRTC_CRNT_FRAME 0x0214 +#define RADEON_CRTC2_CRNT_FRAME 0x0314 + +#define RADEON_CRTC_STATUS 0x005c +#define RADEON_CRTC2_STATUS 0x03fc + #define RADEON_GEN_INT_CNTL 0x0040 # define RADEON_CRTC_VBLANK_MASK (1 << 0) # define RADEON_CRTC2_VBLANK_MASK (1 << 9) @@ -780,10 +920,13 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); # define RADEON_SW_INT_FIRE (1 << 26) # define R500_DISPLAY_INT_STATUS (1 << 0) -#define RADEON_HOST_PATH_CNTL 0x0130 -# define RADEON_HDP_SOFT_RESET (1 << 26) -# define RADEON_HDP_WC_TIMEOUT_MASK (7 << 28) -# define RADEON_HDP_WC_TIMEOUT_28BCLK (7 << 28) +#define RADEON_HOST_PATH_CNTL 0x0130 +# define RADEON_HDP_APER_CNTL (1 << 23) +# define RADEON_HP_LIN_RD_CACHE_DIS (1 << 24) +# define RADEON_HDP_SOFT_RESET (1 << 26) +# define RADEON_HDP_READ_BUFFER_INVALIDATED (1 << 27) + +#define RADEON_NB_TOM 0x15c #define RADEON_ISYNC_CNTL 0x1724 # define RADEON_ISYNC_ANY2D_IDLE3D (1 << 0) @@ -822,12 +965,17 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); #define RADEON_PP_TXFILTER_1 0x1c6c #define RADEON_PP_TXFILTER_2 0x1c84 -#define R300_RB2D_DSTCACHE_CTLSTAT 0x342c /* use R300_DSTCACHE_CTLSTAT */ -#define R300_DSTCACHE_CTLSTAT 0x1714 -# define R300_RB2D_DC_FLUSH (3 << 0) -# define R300_RB2D_DC_FREE (3 << 2) -# define R300_RB2D_DC_FLUSH_ALL 0xf -# define R300_RB2D_DC_BUSY (1 << 31) +#define R300_RB2D_DSTCACHE_CTLSTAT 0x342c /* use R300_DSTCACHE_CTLSTAT */ +#define R300_DSTCACHE_CTLSTAT 0x1714 +# define R300_RB2D_DC_FLUSH (3 << 0) +# define R300_RB2D_DC_FREE (3 << 2) +//# define R300_RB2D_DC_FLUSH_ALL 0xf +# define R300_RB2D_DC_BUSY (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_RB3D_CNTL 0x1c3c # define RADEON_ALPHA_BLEND_ENABLE (1 << 0) # define RADEON_PLANE_MASK_ENABLE (1 << 1) @@ -854,11 +1002,6 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); # define R300_ZC_FLUSH (1 << 0) # define R300_ZC_FREE (1 << 1) # define R300_ZC_BUSY (1 << 31) -#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c -# define RADEON_RB3D_DC_FLUSH (3 << 0) -# define RADEON_RB3D_DC_FREE (3 << 2) -# define RADEON_RB3D_DC_FLUSH_ALL 0xf -# define RADEON_RB3D_DC_BUSY (1 << 31) #define R300_RB3D_DSTCACHE_CTLSTAT 0x4e4c # define R300_RB3D_DC_FLUSH (2 << 0) # define R300_RB3D_DC_FREE (2 << 2) @@ -866,15 +1009,15 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); #define RADEON_RB3D_ZSTENCILCNTL 0x1c2c # define RADEON_Z_TEST_MASK (7 << 4) # define RADEON_Z_TEST_ALWAYS (7 << 4) -# define RADEON_Z_HIERARCHY_ENABLE (1 << 8) +# define RADEON_Z_HIERARCHY_ENABLE (1 << 8) # define RADEON_STENCIL_TEST_ALWAYS (7 << 12) # define RADEON_STENCIL_S_FAIL_REPLACE (2 << 16) # define RADEON_STENCIL_ZPASS_REPLACE (2 << 20) # define RADEON_STENCIL_ZFAIL_REPLACE (2 << 24) -# define RADEON_Z_COMPRESSION_ENABLE (1 << 28) -# define RADEON_FORCE_Z_DIRTY (1 << 29) +# define RADEON_Z_COMPRESSION_ENABLE (1 << 28) +# define RADEON_FORCE_Z_DIRTY (1 << 29) # define RADEON_Z_WRITE_ENABLE (1 << 30) -# define RADEON_Z_DECOMPRESSION_ENABLE (1 << 31) +# define RADEON_Z_DECOMPRESSION_ENABLE (1 << 31) #define RADEON_RBBM_SOFT_RESET 0x00f0 # define RADEON_SOFT_RESET_CP (1 << 0) # define RADEON_SOFT_RESET_HI (1 << 1) @@ -1052,6 +1195,7 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); # define RADEON_PRE_WRITE_LIMIT_SHIFT 23 #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) @@ -1062,6 +1206,8 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); # define RADEON_CSQ_PRIBM_INDBM (4 << 28) # define RADEON_CSQ_PRIPIO_INDPIO (15 << 28) +#define RADEON_CP_CSQ_STAT 0x07f8 + #define RADEON_AIC_CNTL 0x01d0 # define RADEON_PCIGART_TRANSLATE_EN (1 << 0) # define RS400_MSI_REARM (1 << 3) @@ -1144,27 +1290,6 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); #define RADEON_NUM_VERTICES_SHIFT 16 #define RADEON_COLOR_FORMAT_CI8 2 -#define RADEON_COLOR_FORMAT_ARGB1555 3 -#define RADEON_COLOR_FORMAT_RGB565 4 -#define RADEON_COLOR_FORMAT_ARGB8888 6 -#define RADEON_COLOR_FORMAT_RGB332 7 -#define RADEON_COLOR_FORMAT_RGB8 9 -#define RADEON_COLOR_FORMAT_ARGB4444 15 - -#define RADEON_TXFORMAT_I8 0 -#define RADEON_TXFORMAT_AI88 1 -#define RADEON_TXFORMAT_RGB332 2 -#define RADEON_TXFORMAT_ARGB1555 3 -#define RADEON_TXFORMAT_RGB565 4 -#define RADEON_TXFORMAT_ARGB4444 5 -#define RADEON_TXFORMAT_ARGB8888 6 -#define RADEON_TXFORMAT_RGBA8888 7 -#define RADEON_TXFORMAT_Y8 8 -#define RADEON_TXFORMAT_VYUY422 10 -#define RADEON_TXFORMAT_YVYU422 11 -#define RADEON_TXFORMAT_DXT1 12 -#define RADEON_TXFORMAT_DXT23 14 -#define RADEON_TXFORMAT_DXT45 15 #define R200_PP_TXCBLEND_0 0x2f00 #define R200_PP_TXCBLEND_1 0x2f10 @@ -1275,16 +1400,44 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); #define R200_SE_TCL_POINT_SPRITE_CNTL 0x22c4 -#define R200_PP_TRI_PERF 0x2cf8 +#define R200_PP_TRI_PERF 0x2cf8 #define R200_PP_AFS_0 0x2f80 -#define R200_PP_AFS_1 0x2f00 /* same as txcblend_0 */ +#define R200_PP_AFS_1 0x2f00 /* same as txcblend_0 */ #define R200_VAP_PVS_CNTL_1 0x22D0 #define RADEON_CRTC_CRNT_FRAME 0x0214 #define RADEON_CRTC2_CRNT_FRAME 0x0314 +/* MPEG settings from VHA code */ +#define RADEON_VHA_SETTO16_1 0x2694 +#define RADEON_VHA_SETTO16_2 0x2680 +#define RADEON_VHA_SETTO0_1 0x1840 +#define RADEON_VHA_FB_OFFSET 0x19e4 +#define RADEON_VHA_SETTO1AND70S 0x19d8 +#define RADEON_VHA_DST_PITCH 0x1408 + +// set as reference header +#define RADEON_VHA_BACKFRAME0_OFF_Y 0x1840 +#define RADEON_VHA_BACKFRAME1_OFF_PITCH_Y 0x1844 +#define RADEON_VHA_BACKFRAME0_OFF_U 0x1848 +#define RADEON_VHA_BACKFRAME1_OFF_PITCH_U 0x184c +#define RADOEN_VHA_BACKFRAME0_OFF_V 0x1850 +#define RADEON_VHA_BACKFRAME1_OFF_PITCH_V 0x1854 +#define RADEON_VHA_FORWFRAME0_OFF_Y 0x1858 +#define RADEON_VHA_FORWFRAME1_OFF_PITCH_Y 0x185c +#define RADEON_VHA_FORWFRAME0_OFF_U 0x1860 +#define RADEON_VHA_FORWFRAME1_OFF_PITCH_U 0x1864 +#define RADEON_VHA_FORWFRAME0_OFF_V 0x1868 +#define RADEON_VHA_FORWFRAME0_OFF_PITCH_V 0x1880 +#define RADEON_VHA_BACKFRAME0_OFF_Y_2 0x1884 +#define RADEON_VHA_BACKFRAME1_OFF_PITCH_Y_2 0x1888 +#define RADEON_VHA_BACKFRAME0_OFF_U_2 0x188c +#define RADEON_VHA_BACKFRAME1_OFF_PITCH_U_2 0x1890 +#define RADEON_VHA_BACKFRAME0_OFF_V_2 0x1894 +#define RADEON_VHA_BACKFRAME1_OFF_PITCH_V_2 0x1898 + #define R500_D1CRTC_STATUS 0x609c #define R500_D2CRTC_STATUS 0x689c #define R500_CRTC_V_BLANK (1<<0) @@ -1746,6 +1899,8 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index); #define RADEON_RING_HIGH_MARK 128 #define RADEON_PCIGART_TABLE_SIZE (32*1024) +#define RADEON_DEFAULT_RING_SIZE (1024*1024) +#define RADEON_DEFAULT_CP_TIMEOUT 100000 /* usecs */ #define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) #define RADEON_WRITE(reg, val) \ @@ -1760,11 +1915,24 @@ do { \ #define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) #define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) -#define RADEON_WRITE_PLL(addr, val) \ -do { \ - RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, \ - ((addr) & 0x1f) | RADEON_PLL_WR_EN ); \ - RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, (val)); \ +extern u32 RADEON_READ_PLL(struct drm_radeon_private *dev_priv, int addr); +extern void RADEON_WRITE_PLL(struct drm_radeon_private *dev_priv, int addr, uint32_t data); +extern u32 RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr); + +#define RADEON_WRITE_P(reg, val, mask) \ +do { \ + uint32_t tmp = RADEON_READ(reg); \ + tmp &= (mask); \ + tmp |= ((val) & ~(mask)); \ + RADEON_WRITE(reg, tmp); \ +} while(0) + +#define RADEON_WRITE_PLL_P(dev_priv, addr, val, mask) \ +do { \ + uint32_t tmp_ = RADEON_READ_PLL(dev_priv, addr); \ + tmp_ &= (mask); \ + tmp_ |= ((val) & ~(mask)); \ + RADEON_WRITE_PLL(dev_priv, addr, tmp_); \ } while (0) #define RADEON_WRITE_PCIE(addr, val) \ @@ -1802,15 +1970,18 @@ do { \ RADEON_WRITE(RS600_MC_DATA, val); \ } while (0) -#define IGP_WRITE_MCIND(addr, val) \ +#define RADEON_WRITE_MCIND(addr, val) \ do { \ if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) || \ - ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) \ + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS740)) \ RS690_WRITE_MCIND(addr, val); \ else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS600) \ RS600_WRITE_MCIND(addr, val); \ - else \ + else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) || \ + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) \ RS480_WRITE_MCIND(addr, val); \ + else \ + R500_WRITE_MCIND(addr, val); \ } while (0) #define CP_PACKET0( reg, n ) \ @@ -1831,7 +2002,7 @@ do { \ #define RADEON_WAIT_UNTIL_2D_IDLE() do { \ OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ OUT_RING( (RADEON_WAIT_2D_IDLECLEAN | \ - RADEON_WAIT_HOST_IDLECLEAN) ); \ + RADEON_WAIT_HOST_IDLECLEAN | RADEON_WAIT_DMA_GUI_IDLE) ); \ } while (0) #define RADEON_WAIT_UNTIL_3D_IDLE() do { \ @@ -2036,4 +2207,159 @@ extern void radeon_commit_ring(drm_radeon_private_t *dev_priv); write &= mask; \ } while (0) +/* radeon GEM->TTM munger */ +struct drm_radeon_gem_object { + /* wrap a TTM bo */ + struct drm_buffer_object *bo; + struct drm_fence_object *fence; + struct drm_gem_object *obj; + int pin_count; +}; + +#define RADEON_IB_MEMORY (1*1024*1024) +#define RADEON_IB_SIZE (65536) +#define RADEON_NUM_IB (RADEON_IB_MEMORY / RADEON_IB_SIZE) + +extern int radeon_gem_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int radeon_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +extern void radeon_fence_handler(struct drm_device *dev); +extern int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class, + uint32_t flags, uint32_t *sequence, + uint32_t *native_type); +extern void radeon_poke_flush(struct drm_device *dev, uint32_t class); +extern int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags); + +/* radeon_buffer.c */ +extern struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device *dev); +extern int radeon_fence_types(struct drm_buffer_object *bo, uint32_t *class, uint32_t *type); +extern int radeon_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags); +extern int radeon_init_mem_type(struct drm_device * dev, uint32_t type, + struct drm_mem_type_manager * man); +extern int radeon_move(struct drm_buffer_object * bo, + int evict, int no_wait, struct drm_bo_mem_reg * new_mem); + +extern void radeon_gart_flush(struct drm_device *dev); +extern uint64_t radeon_evict_flags(struct drm_buffer_object *bo); + +#define BREADCRUMB_BITS 31 +#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) + +/* Breadcrumb - swi irq */ +#define READ_BREADCRUMB(dev_priv) GET_SCRATCH(dev_priv, 3) + +static inline int radeon_update_breadcrumb(struct drm_device *dev) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv; + + ++dev_priv->counter; + if (dev_priv->counter > BREADCRUMB_MASK) + dev_priv->counter = 1; + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + } + return dev_priv->counter; +} + +#define radeon_is_avivo(dev_priv) ((dev_priv->chip_family >= CHIP_RS600)) + +#define radeon_is_dce3(dev_priv) ((dev_priv->chip_family >= CHIP_RV620)) + +#define radeon_is_dce32(dev_priv) ((dev_priv->chip_family >= CHIP_RV730)) + +#define radeon_is_rv100(dev_priv) ((dev_priv->chip_family == CHIP_RV100) || \ + (dev_priv->chip_family == CHIP_RV200) || \ + (dev_priv->chip_family == CHIP_RS100) || \ + (dev_priv->chip_family == CHIP_RS200) || \ + (dev_priv->chip_family == CHIP_RV250) || \ + (dev_priv->chip_family == CHIP_RV280) || \ + (dev_priv->chip_family == CHIP_RS300)) + +#define radeon_is_r300(dev_priv) ((dev_priv->chip_family == CHIP_R300) || \ + (dev_priv->chip_family == CHIP_RV350) || \ + (dev_priv->chip_family == CHIP_R350) || \ + (dev_priv->chip_family == CHIP_RV380) || \ + (dev_priv->chip_family == CHIP_R420) || \ + (dev_priv->chip_family == CHIP_R423) || \ + (dev_priv->chip_family == CHIP_RV410) || \ + (dev_priv->chip_family == CHIP_RS400) || \ + (dev_priv->chip_family == CHIP_RS480)) + +#define radeon_bios8(dev_priv, v) (dev_priv->bios[v]) +#define radeon_bios16(dev_priv, v) (dev_priv->bios[v] | (dev_priv->bios[(v) + 1] << 8)) +#define radeon_bios32(dev_priv, v) ((dev_priv->bios[v]) | \ + (dev_priv->bios[(v) + 1] << 8) | \ + (dev_priv->bios[(v) + 2] << 16) | \ + (dev_priv->bios[(v) + 3] << 24)) + +extern void radeon_pll_errata_after_index(struct drm_radeon_private *dev_priv); +extern int radeon_emit_irq(struct drm_device * dev); + +extern void radeon_gem_free_object(struct drm_gem_object *obj); +extern int radeon_gem_init_object(struct drm_gem_object *obj); +extern int radeon_gem_mm_init(struct drm_device *dev); +extern void radeon_gem_mm_fini(struct drm_device *dev); +extern int radeon_gem_pin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_object_pin(struct drm_gem_object *obj, + uint32_t alignment, uint32_t pin_domain); +int radeon_gem_object_unpin(struct drm_gem_object *obj); +int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int radeon_gem_wait_rendering(struct drm_device *dev, void *data, + struct drm_file *file_priv); +struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, + int initial_domain, bool discardable); +int radeon_modeset_init(struct drm_device *dev); +void radeon_modeset_cleanup(struct drm_device *dev); +extern u32 RADEON_READ_MCIND(drm_radeon_private_t *dev_priv, int addr); +void radeon_read_agp_location(drm_radeon_private_t *dev_priv, u32 *agp_lo, u32 *agp_hi); +void radeon_write_fb_location(drm_radeon_private_t *dev_priv, u32 fb_loc); +extern void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on); +#define RADEONFB_CONN_LIMIT 4 + +extern int radeon_master_create(struct drm_device *dev, struct drm_master *master); +extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master); +extern void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master); +extern int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv); +extern int radeon_cs_init(struct drm_device *dev); +void radeon_gem_update_offsets(struct drm_device *dev, struct drm_master *master); +void radeon_init_memory_map(struct drm_device *dev); +void radeon_enable_bm(struct drm_radeon_private *dev_priv); + +extern int radeon_gem_debugfs_init(struct drm_minor *minor); +extern void radeon_gem_debugfs_cleanup(struct drm_minor *minor); + +#define MARK_SAFE 1 +#define MARK_CHECK_OFFSET 2 +#define MARK_CHECK_SCISSOR 3 +#define MARK_CHECK_WAIT_VLINE 4 /* VLINE on a crtc relocation */ + +struct _radeon_pkt_s { + int start; + int len; + const char *name; +}; +extern struct _radeon_pkt_s radeon_packet[]; + +extern int r300_check_range(unsigned reg, int count); +extern int r300_get_reg_flags(unsigned reg); +int radeon_gem_prelocate(struct drm_radeon_cs_parser *parser); +void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base); +int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); #endif /* __RADEON_DRV_H__ */ diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c new file mode 100644 index 0000000..433ebc9 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -0,0 +1,1716 @@ +/* + * 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; + +uint32_t +radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + uint32_t ret = 0; + + switch (supported_device) { + case ATOM_DEVICE_CRT1_SUPPORT: + case ATOM_DEVICE_TV1_SUPPORT: + case ATOM_DEVICE_TV2_SUPPORT: + case ATOM_DEVICE_CRT2_SUPPORT: + case ATOM_DEVICE_CV_SUPPORT: + switch (dac) { + case 1: /* dac a */ + if ((dev_priv->chip_family == CHIP_RS300) || + (dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) + ret = ENCODER_OBJECT_ID_INTERNAL_DAC2; + else if (radeon_is_avivo(dev_priv)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_DAC1; + break; + case 2: /* dac b */ + if (radeon_is_avivo(dev_priv)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2; + else { + /*if (dev_priv->chip_family == CHIP_R200) + ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + else*/ + ret = ENCODER_OBJECT_ID_INTERNAL_DAC2; + } + break; + case 3: /* external dac */ + if (radeon_is_avivo(dev_priv)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + break; + } + break; + case ATOM_DEVICE_LCD1_SUPPORT: + if (radeon_is_avivo(dev_priv)) + ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_LVDS; + break; + case ATOM_DEVICE_DFP1_SUPPORT: + if ((dev_priv->chip_family == CHIP_RS300) || + (dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) + ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + else if (radeon_is_avivo(dev_priv)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1; + break; + case ATOM_DEVICE_LCD2_SUPPORT: + case ATOM_DEVICE_DFP2_SUPPORT: + if ((dev_priv->chip_family == CHIP_RS600) || + (dev_priv->chip_family == CHIP_RS690) || + (dev_priv->chip_family == CHIP_RS740)) + ret = ENCODER_OBJECT_ID_INTERNAL_DDI; + else if (radeon_is_avivo(dev_priv)) + ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + else + ret = ENCODER_OBJECT_ID_INTERNAL_DVO1; + break; + case ATOM_DEVICE_DFP3_SUPPORT: + ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1; + break; + } + + return ret; +} + +void +radeon_link_encoder_connector(struct drm_device *dev) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + /* walk the list and link encoders to connectors */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->devices & radeon_connector->devices) + drm_mode_connector_attach_encoder(connector, encoder); + } + } +} + +static struct drm_connector * +radeon_get_connector_for_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + if (radeon_encoder->devices & radeon_connector->devices) + return connector; + } + return NULL; +} + +/* used for both atom and legacy */ +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); + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + + if (mode->hdisplay < native_mode->panel_xres || + mode->vdisplay < native_mode->panel_yres) { + radeon_encoder->flags |= RADEON_USE_RMX; + if (radeon_is_avivo(dev_priv)) { + adjusted_mode->hdisplay = native_mode->panel_xres; + adjusted_mode->vdisplay = native_mode->panel_yres; + adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank; + adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus; + adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width; + adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank; + adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus; + adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width; + /* update crtc values */ + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + /* adjust crtc values */ + adjusted_mode->crtc_hdisplay = native_mode->panel_xres; + adjusted_mode->crtc_vdisplay = native_mode->panel_yres; + adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width; + adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width; + } else { + adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank; + adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus; + adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width; + adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank; + adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus; + adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->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 + native_mode->hblank; + adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus; + adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width; + adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank; + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus; + adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width; + } + adjusted_mode->flags = native_mode->flags; + adjusted_mode->clock = native_mode->dotclock; + } +} + +static bool radeon_atom_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; + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + if (radeon_encoder->rmx_type != RMX_OFF) + radeon_rmx_mode_fixup(encoder, 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; +} + +static void +atombios_dac_setup(struct drm_encoder *encoder, int action) +{ + 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 index = 0, num = 0; + /* fixme - fill in enc_priv for atom dac */ + enum radeon_tv_std tv_std = TV_STD_NTSC; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); + num = 2; + break; + } + + args.ucAction = action; + + if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) + args.ucDacStandard = ATOM_DAC1_PS2; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.ucDacStandard = ATOM_DAC1_CV; + else { + switch (tv_std) { + case TV_STD_PAL: + case TV_STD_PAL_M: + case TV_STD_SCART_PAL: + case TV_STD_SECAM: + case TV_STD_PAL_CN: + args.ucDacStandard = ATOM_DAC1_PAL; + break; + case TV_STD_NTSC: + case TV_STD_NTSC_J: + case TV_STD_PAL_60: + default: + args.ucDacStandard = ATOM_DAC1_NTSC; + break; + } + } + args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_tv_setup(struct drm_encoder *encoder, int action) +{ + 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 = 0; + /* fixme - fill in enc_priv for atom dac */ + enum radeon_tv_std tv_std = TV_STD_NTSC; + + memset(&args, 0, sizeof(args)); + + index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); + + args.sTVEncoder.ucAction = action; + + if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.sTVEncoder.ucTvStandard = ATOM_TV_CV; + else { + switch (tv_std) { + case TV_STD_NTSC: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + break; + case TV_STD_PAL: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; + break; + case TV_STD_PAL_M: + args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; + break; + case TV_STD_PAL_60: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; + break; + case TV_STD_NTSC_J: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; + break; + case TV_STD_SCART_PAL: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ + break; + case TV_STD_SECAM: + args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; + break; + case TV_STD_PAL_CN: + args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; + break; + default: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + break; + } + } + + args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +void +atombios_external_tmds_setup(struct drm_encoder *encoder, int action) +{ + 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 = 0; + + memset(&args, 0, sizeof(args)); + + index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + + args.sXTmdsEncoder.ucEnable = action; + + if (radeon_encoder->pixel_clock > 165000) + args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL; + + /*if (pScrn->rgbBits == 8)*/ + args.sXTmdsEncoder.ucMisc |= (1 << 1); + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_ddia_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DVO_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0; + + memset(&args, 0, sizeof(args)); + + index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + + args.sDVOEncoder.ucAction = action; + args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + if (radeon_encoder->pixel_clock > 165000) + args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +union lvds_encoder_control { + LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; + LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; +}; + +static void +atombios_digital_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union lvds_encoder_control args; + int index = 0; + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return; + + radeon_connector = to_radeon_connector(connector); + + if (!radeon_encoder->enc_priv) + return; + + dig = radeon_encoder->enc_priv; + + if (!radeon_connector->con_priv) + return; + + dig_connector = radeon_connector->con_priv; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); + break; + } + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + switch (frev) { + case 1: + case 2: + switch (crev) { + case 1: + args.v1.ucMisc = 0; + args.v1.ucAction = action; + /* XXX should probably check based on edid */ + if ((connector->connector_type == DRM_MODE_CONNECTOR_HDMIA) || + (connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)) + args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (dig->lvds_misc & (1 << 0)) + args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (dig->lvds_misc & (1 << 1)) + args.v1.ucMisc |= (1 << 1); + } else { + if (dig_connector->linkb) + args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; + /*if (pScrn->rgbBits == 8) */ + args.v1.ucMisc |= (1 << 1); + } + break; + case 2: + case 3: + args.v2.ucMisc = 0; + args.v2.ucAction = action; + if (crev == 3) { + if (dig->coherent_mode) + args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; + } + /* XXX should probably check based on edid */ + if ((connector->connector_type == DRM_MODE_CONNECTOR_HDMIA) || + (connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)) + args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v2.ucTruncate = 0; + args.v2.ucSpatial = 0; + args.v2.ucTemporal = 0; + args.v2.ucFRC = 0; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (dig->lvds_misc & (1 << 0)) + args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (dig->lvds_misc & (1 << 5)) { + args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; + if (dig->lvds_misc & (1 << 1)) + args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; + } + if (dig->lvds_misc & (1 << 6)) { + args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; + if (dig->lvds_misc & (1 << 1)) + args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; + if (((dig->lvds_misc >> 2) & 0x3) == 2) + args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; + } + } else { + if (dig_connector->linkb) + args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (radeon_encoder->pixel_clock > 165000) + args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static int +atombios_maybe_hdmi_mode(struct drm_encoder *encoder) +{ + /* there's no getting this right unless we have complete EDID */ + return ATOM_ENCODER_MODE_HDMI; + + /*if (output && xf86MonitorIsHDMI(output->MonInfo)) + return ATOM_ENCODER_MODE_HDMI; + + return ATOM_ENCODER_MODE_DVI;*/ + +} + +int +atombios_get_encoder_mode(struct drm_encoder *encoder) +{ + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return 0; + + radeon_connector = to_radeon_connector(connector); + + /* DVI should really be atombios_maybe_hdmi_mode() as well */ + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + /*return atombios_maybe_hdmi_mode(encoder);*/ + if (radeon_connector->use_digital) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_CRT; + break; + case DRM_MODE_CONNECTOR_DVID: + default: + return ATOM_ENCODER_MODE_DVI; + break; + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + return atombios_maybe_hdmi_mode(encoder); + break; + case DRM_MODE_CONNECTOR_LVDS: + return ATOM_ENCODER_MODE_LVDS; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + /*if (radeon_output->MonType == MT_DP) + return ATOM_ENCODER_MODE_DP; + else + return atombios_maybe_hdmi_mode(encoder);*/ + return ATOM_ENCODER_MODE_DVI; + break; + case CONNECTOR_DVI_A: + case CONNECTOR_VGA: + return ATOM_ENCODER_MODE_CRT; + break; + case CONNECTOR_STV: + case CONNECTOR_CTV: + case CONNECTOR_DIN: + /* fix me */ + return ATOM_ENCODER_MODE_TV; + /*return ATOM_ENCODER_MODE_CV;*/ + break; + } +} + +static void +atombios_dig_encoder_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DIG_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0, num = 0; + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return; + + radeon_connector = to_radeon_connector(connector); + + if (!radeon_connector->con_priv) + return; + + dig_connector = radeon_connector->con_priv; + + if (!radeon_encoder->enc_priv) + return; + + dig = radeon_encoder->enc_priv; + + memset(&args, 0, sizeof(args)); + + if (radeon_is_dce32(dev_priv)) { + if (dig->dig_block) + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + num = dig->dig_block + 1; + } else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + num = 2; + break; + } + } + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + args.ucAction = action; + args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + if (radeon_is_dce32(dev_priv)) { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; + break; + } + } else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER1; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER2; + break; + } + } + + if (radeon_encoder->pixel_clock > 165000) { + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B; + args.ucLaneNum = 8; + } else { + if (dig_connector->linkb) + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; + else + args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + args.ucLaneNum = 4; + } + + args.ucEncoderMode = atombios_get_encoder_mode(encoder); + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +union dig_transmitter_control { + DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; +}; + +static void +atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union dig_transmitter_control args; + int index = 0, num = 0; + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + connector = radeon_get_connector_for_encoder(encoder); + if (!connector) + return; + + radeon_connector = to_radeon_connector(connector); + + if (!radeon_encoder->enc_priv) + return; + + dig = radeon_encoder->enc_priv; + + if (!radeon_connector->con_priv) + return; + + dig_connector = radeon_connector->con_priv; + + memset(&args, 0, sizeof(args)); + + if (radeon_is_dce32(dev_priv)) + index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); + break; + } + } + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + args.v1.ucAction = action; + + if (radeon_is_dce32(dev_priv)) { + if (radeon_encoder->pixel_clock > 165000) { + args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock * 10 * 2) / 100); + args.v2.acConfig.fDualLinkConnector = 1; + } else { + args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock * 10 * 4) / 100); + } + if (dig->dig_block) + args.v2.acConfig.ucEncoderSel = 1; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v2.acConfig.ucTransmitterSel = 0; + num = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v2.acConfig.ucTransmitterSel = 1; + num = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v2.acConfig.ucTransmitterSel = 2; + num = 2; + break; + } + + if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v2.acConfig.fCoherentMode = 1; + } + } else { + args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; + args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock) / 10); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + if (dev_priv->flags & RADEON_IS_IGP) { + if (radeon_encoder->pixel_clock > 165000) { + args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | + ATOM_TRANSMITTER_CONFIG_LINKA_B); + if (dig_connector->igp_lane_info & 0x3) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; + else if (dig_connector->igp_lane_info & 0xc) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; + } else { + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; + if (dig_connector->igp_lane_info & 0x1) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else if (dig_connector->igp_lane_info & 0x2) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; + else if (dig_connector->igp_lane_info & 0x4) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; + else if (dig_connector->igp_lane_info & 0x8) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; + } + } else { + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | + ATOM_TRANSMITTER_CONFIG_LINKA_B | + ATOM_TRANSMITTER_CONFIG_LANE_0_7); + else { + if (dig_connector->linkb) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + } + } + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK | + ATOM_TRANSMITTER_CONFIG_LINKA_B | + ATOM_TRANSMITTER_CONFIG_LANE_0_7); + else { + if (dig_connector->linkb) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3; + } + break; + } + + if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + } + } + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void atom_rv515_force_tv_scaler(struct drm_radeon_private *dev_priv) +{ + + RADEON_WRITE(0x659C, 0x0); + RADEON_WRITE(0x6594, 0x705); + RADEON_WRITE(0x65A4, 0x10001); + RADEON_WRITE(0x65D8, 0x0); + RADEON_WRITE(0x65B0, 0x0); + RADEON_WRITE(0x65C0, 0x0); + RADEON_WRITE(0x65D4, 0x0); + RADEON_WRITE(0x6578, 0x0); + RADEON_WRITE(0x657C, 0x841880A8); + RADEON_WRITE(0x6578, 0x1); + RADEON_WRITE(0x657C, 0x84208680); + RADEON_WRITE(0x6578, 0x2); + RADEON_WRITE(0x657C, 0xBFF880B0); + RADEON_WRITE(0x6578, 0x100); + RADEON_WRITE(0x657C, 0x83D88088); + RADEON_WRITE(0x6578, 0x101); + RADEON_WRITE(0x657C, 0x84608680); + RADEON_WRITE(0x6578, 0x102); + RADEON_WRITE(0x657C, 0xBFF080D0); + RADEON_WRITE(0x6578, 0x200); + RADEON_WRITE(0x657C, 0x83988068); + RADEON_WRITE(0x6578, 0x201); + RADEON_WRITE(0x657C, 0x84A08680); + RADEON_WRITE(0x6578, 0x202); + RADEON_WRITE(0x657C, 0xBFF080F8); + RADEON_WRITE(0x6578, 0x300); + RADEON_WRITE(0x657C, 0x83588058); + RADEON_WRITE(0x6578, 0x301); + RADEON_WRITE(0x657C, 0x84E08660); + RADEON_WRITE(0x6578, 0x302); + RADEON_WRITE(0x657C, 0xBFF88120); + RADEON_WRITE(0x6578, 0x400); + RADEON_WRITE(0x657C, 0x83188040); + RADEON_WRITE(0x6578, 0x401); + RADEON_WRITE(0x657C, 0x85008660); + RADEON_WRITE(0x6578, 0x402); + RADEON_WRITE(0x657C, 0xBFF88150); + RADEON_WRITE(0x6578, 0x500); + RADEON_WRITE(0x657C, 0x82D88030); + RADEON_WRITE(0x6578, 0x501); + RADEON_WRITE(0x657C, 0x85408640); + RADEON_WRITE(0x6578, 0x502); + RADEON_WRITE(0x657C, 0xBFF88180); + RADEON_WRITE(0x6578, 0x600); + RADEON_WRITE(0x657C, 0x82A08018); + RADEON_WRITE(0x6578, 0x601); + RADEON_WRITE(0x657C, 0x85808620); + RADEON_WRITE(0x6578, 0x602); + RADEON_WRITE(0x657C, 0xBFF081B8); + RADEON_WRITE(0x6578, 0x700); + RADEON_WRITE(0x657C, 0x82608010); + RADEON_WRITE(0x6578, 0x701); + RADEON_WRITE(0x657C, 0x85A08600); + RADEON_WRITE(0x6578, 0x702); + RADEON_WRITE(0x657C, 0x800081F0); + RADEON_WRITE(0x6578, 0x800); + RADEON_WRITE(0x657C, 0x8228BFF8); + RADEON_WRITE(0x6578, 0x801); + RADEON_WRITE(0x657C, 0x85E085E0); + RADEON_WRITE(0x6578, 0x802); + RADEON_WRITE(0x657C, 0xBFF88228); + RADEON_WRITE(0x6578, 0x10000); + RADEON_WRITE(0x657C, 0x82A8BF00); + RADEON_WRITE(0x6578, 0x10001); + RADEON_WRITE(0x657C, 0x82A08CC0); + RADEON_WRITE(0x6578, 0x10002); + RADEON_WRITE(0x657C, 0x8008BEF8); + RADEON_WRITE(0x6578, 0x10100); + RADEON_WRITE(0x657C, 0x81F0BF28); + RADEON_WRITE(0x6578, 0x10101); + RADEON_WRITE(0x657C, 0x83608CA0); + RADEON_WRITE(0x6578, 0x10102); + RADEON_WRITE(0x657C, 0x8018BED0); + RADEON_WRITE(0x6578, 0x10200); + RADEON_WRITE(0x657C, 0x8148BF38); + RADEON_WRITE(0x6578, 0x10201); + RADEON_WRITE(0x657C, 0x84408C80); + RADEON_WRITE(0x6578, 0x10202); + RADEON_WRITE(0x657C, 0x8008BEB8); + RADEON_WRITE(0x6578, 0x10300); + RADEON_WRITE(0x657C, 0x80B0BF78); + RADEON_WRITE(0x6578, 0x10301); + RADEON_WRITE(0x657C, 0x85008C20); + RADEON_WRITE(0x6578, 0x10302); + RADEON_WRITE(0x657C, 0x8020BEA0); + RADEON_WRITE(0x6578, 0x10400); + RADEON_WRITE(0x657C, 0x8028BF90); + RADEON_WRITE(0x6578, 0x10401); + RADEON_WRITE(0x657C, 0x85E08BC0); + RADEON_WRITE(0x6578, 0x10402); + RADEON_WRITE(0x657C, 0x8018BE90); + RADEON_WRITE(0x6578, 0x10500); + RADEON_WRITE(0x657C, 0xBFB8BFB0); + RADEON_WRITE(0x6578, 0x10501); + RADEON_WRITE(0x657C, 0x86C08B40); + RADEON_WRITE(0x6578, 0x10502); + RADEON_WRITE(0x657C, 0x8010BE90); + RADEON_WRITE(0x6578, 0x10600); + RADEON_WRITE(0x657C, 0xBF58BFC8); + RADEON_WRITE(0x6578, 0x10601); + RADEON_WRITE(0x657C, 0x87A08AA0); + RADEON_WRITE(0x6578, 0x10602); + RADEON_WRITE(0x657C, 0x8010BE98); + RADEON_WRITE(0x6578, 0x10700); + RADEON_WRITE(0x657C, 0xBF10BFF0); + RADEON_WRITE(0x6578, 0x10701); + RADEON_WRITE(0x657C, 0x886089E0); + RADEON_WRITE(0x6578, 0x10702); + RADEON_WRITE(0x657C, 0x8018BEB0); + RADEON_WRITE(0x6578, 0x10800); + RADEON_WRITE(0x657C, 0xBED8BFE8); + RADEON_WRITE(0x6578, 0x10801); + RADEON_WRITE(0x657C, 0x89408940); + RADEON_WRITE(0x6578, 0x10802); + RADEON_WRITE(0x657C, 0xBFE8BED8); + RADEON_WRITE(0x6578, 0x20000); + RADEON_WRITE(0x657C, 0x80008000); + RADEON_WRITE(0x6578, 0x20001); + RADEON_WRITE(0x657C, 0x90008000); + RADEON_WRITE(0x6578, 0x20002); + RADEON_WRITE(0x657C, 0x80008000); + RADEON_WRITE(0x6578, 0x20003); + RADEON_WRITE(0x657C, 0x80008000); + RADEON_WRITE(0x6578, 0x20100); + RADEON_WRITE(0x657C, 0x80108000); + RADEON_WRITE(0x6578, 0x20101); + RADEON_WRITE(0x657C, 0x8FE0BF70); + RADEON_WRITE(0x6578, 0x20102); + RADEON_WRITE(0x657C, 0xBFE880C0); + RADEON_WRITE(0x6578, 0x20103); + RADEON_WRITE(0x657C, 0x80008000); + RADEON_WRITE(0x6578, 0x20200); + RADEON_WRITE(0x657C, 0x8018BFF8); + RADEON_WRITE(0x6578, 0x20201); + RADEON_WRITE(0x657C, 0x8F80BF08); + RADEON_WRITE(0x6578, 0x20202); + RADEON_WRITE(0x657C, 0xBFD081A0); + RADEON_WRITE(0x6578, 0x20203); + RADEON_WRITE(0x657C, 0xBFF88000); + RADEON_WRITE(0x6578, 0x20300); + RADEON_WRITE(0x657C, 0x80188000); + RADEON_WRITE(0x6578, 0x20301); + RADEON_WRITE(0x657C, 0x8EE0BEC0); + RADEON_WRITE(0x6578, 0x20302); + RADEON_WRITE(0x657C, 0xBFB082A0); + RADEON_WRITE(0x6578, 0x20303); + RADEON_WRITE(0x657C, 0x80008000); + RADEON_WRITE(0x6578, 0x20400); + RADEON_WRITE(0x657C, 0x80188000); + RADEON_WRITE(0x6578, 0x20401); + RADEON_WRITE(0x657C, 0x8E00BEA0); + RADEON_WRITE(0x6578, 0x20402); + RADEON_WRITE(0x657C, 0xBF8883C0); + RADEON_WRITE(0x6578, 0x20403); + RADEON_WRITE(0x657C, 0x80008000); + RADEON_WRITE(0x6578, 0x20500); + RADEON_WRITE(0x657C, 0x80188000); + RADEON_WRITE(0x6578, 0x20501); + RADEON_WRITE(0x657C, 0x8D00BE90); + RADEON_WRITE(0x6578, 0x20502); + RADEON_WRITE(0x657C, 0xBF588500); + RADEON_WRITE(0x6578, 0x20503); + RADEON_WRITE(0x657C, 0x80008008); + RADEON_WRITE(0x6578, 0x20600); + RADEON_WRITE(0x657C, 0x80188000); + RADEON_WRITE(0x6578, 0x20601); + RADEON_WRITE(0x657C, 0x8BC0BE98); + RADEON_WRITE(0x6578, 0x20602); + RADEON_WRITE(0x657C, 0xBF308660); + RADEON_WRITE(0x6578, 0x20603); + RADEON_WRITE(0x657C, 0x80008008); + RADEON_WRITE(0x6578, 0x20700); + RADEON_WRITE(0x657C, 0x80108000); + RADEON_WRITE(0x6578, 0x20701); + RADEON_WRITE(0x657C, 0x8A80BEB0); + RADEON_WRITE(0x6578, 0x20702); + RADEON_WRITE(0x657C, 0xBF0087C0); + RADEON_WRITE(0x6578, 0x20703); + RADEON_WRITE(0x657C, 0x80008008); + RADEON_WRITE(0x6578, 0x20800); + RADEON_WRITE(0x657C, 0x80108000); + RADEON_WRITE(0x6578, 0x20801); + RADEON_WRITE(0x657C, 0x8920BED0); + RADEON_WRITE(0x6578, 0x20802); + RADEON_WRITE(0x657C, 0xBED08920); + RADEON_WRITE(0x6578, 0x20803); + RADEON_WRITE(0x657C, 0x80008010); + RADEON_WRITE(0x6578, 0x30000); + RADEON_WRITE(0x657C, 0x90008000); + RADEON_WRITE(0x6578, 0x30001); + RADEON_WRITE(0x657C, 0x80008000); + RADEON_WRITE(0x6578, 0x30100); + RADEON_WRITE(0x657C, 0x8FE0BF90); + RADEON_WRITE(0x6578, 0x30101); + RADEON_WRITE(0x657C, 0xBFF880A0); + RADEON_WRITE(0x6578, 0x30200); + RADEON_WRITE(0x657C, 0x8F60BF40); + RADEON_WRITE(0x6578, 0x30201); + RADEON_WRITE(0x657C, 0xBFE88180); + RADEON_WRITE(0x6578, 0x30300); + RADEON_WRITE(0x657C, 0x8EC0BF00); + RADEON_WRITE(0x6578, 0x30301); + RADEON_WRITE(0x657C, 0xBFC88280); + RADEON_WRITE(0x6578, 0x30400); + RADEON_WRITE(0x657C, 0x8DE0BEE0); + RADEON_WRITE(0x6578, 0x30401); + RADEON_WRITE(0x657C, 0xBFA083A0); + RADEON_WRITE(0x6578, 0x30500); + RADEON_WRITE(0x657C, 0x8CE0BED0); + RADEON_WRITE(0x6578, 0x30501); + RADEON_WRITE(0x657C, 0xBF7884E0); + RADEON_WRITE(0x6578, 0x30600); + RADEON_WRITE(0x657C, 0x8BA0BED8); + RADEON_WRITE(0x6578, 0x30601); + RADEON_WRITE(0x657C, 0xBF508640); + RADEON_WRITE(0x6578, 0x30700); + RADEON_WRITE(0x657C, 0x8A60BEE8); + RADEON_WRITE(0x6578, 0x30701); + RADEON_WRITE(0x657C, 0xBF2087A0); + RADEON_WRITE(0x6578, 0x30800); + RADEON_WRITE(0x657C, 0x8900BF00); + RADEON_WRITE(0x6578, 0x30801); + RADEON_WRITE(0x657C, 0xBF008900); +} + +static void +atombios_yuv_setup(struct drm_encoder *encoder, bool enable) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_radeon_private *dev_priv = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + ENABLE_YUV_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); + uint32_t temp, reg; + + memset(&args, 0, sizeof(args)); + + if (dev_priv->chip_family >= CHIP_R600) + reg = R600_BIOS_3_SCRATCH; + else + reg = RADEON_BIOS_3_SCRATCH; + + temp = RADEON_READ(reg); + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + RADEON_WRITE(reg, (ATOM_S3_TV1_ACTIVE | + (radeon_crtc->crtc_id << 18))); + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + RADEON_WRITE(reg, (ATOM_S3_CV_ACTIVE | + (radeon_crtc->crtc_id << 18))); + else + RADEON_WRITE(reg, 0); + + if (enable) + args.ucEnable = ATOM_ENABLE; + args.ucCRTC = radeon_crtc->crtc_id; + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + + RADEON_WRITE(reg, 0); +} + +static void +atombios_overscan_setup(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); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + SET_CRTC_OVERSCAN_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); + + memset(&args, 0, sizeof(args)); + + args.usOverscanRight = 0; + args.usOverscanLeft = 0; + args.usOverscanBottom = 0; + args.usOverscanTop = 0; + args.ucCRTC = radeon_crtc->crtc_id; + + if (radeon_encoder->flags & RADEON_USE_RMX) { + if (radeon_encoder->rmx_type == RMX_FULL) { + args.usOverscanRight = 0; + args.usOverscanLeft = 0; + args.usOverscanBottom = 0; + args.usOverscanTop = 0; + } else if (radeon_encoder->rmx_type == RMX_CENTER) { + args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; + args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; + args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; + args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; + } else if (radeon_encoder->rmx_type == RMX_ASPECT) { + int a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; + int a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay; + + if (a1 > a2) { + args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; + args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2; + } else if (a2 > a1) { + args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; + args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; + } + } + } + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_scaler_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); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + ENABLE_SCALER_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); + /* fixme - fill in enc_priv for atom dac */ + enum radeon_tv_std tv_std = TV_STD_NTSC; + + if (!radeon_is_avivo(dev_priv) && radeon_crtc->crtc_id) + return; + + memset(&args, 0, sizeof(args)); + + args.ucScaler = radeon_crtc->crtc_id; + + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) { + switch (tv_std) { + case TV_STD_NTSC: + default: + args.ucTVStandard = ATOM_TV_NTSC; + break; + case TV_STD_PAL: + args.ucTVStandard = ATOM_TV_PAL; + break; + case TV_STD_PAL_M: + args.ucTVStandard = ATOM_TV_PALM; + break; + case TV_STD_PAL_60: + args.ucTVStandard = ATOM_TV_PAL60; + break; + case TV_STD_NTSC_J: + args.ucTVStandard = ATOM_TV_NTSCJ; + break; + case TV_STD_SCART_PAL: + args.ucTVStandard = ATOM_TV_PAL; /* ??? */ + break; + case TV_STD_SECAM: + args.ucTVStandard = ATOM_TV_SECAM; + break; + case TV_STD_PAL_CN: + args.ucTVStandard = ATOM_TV_PALCN; + break; + } + args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; + } else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) { + args.ucTVStandard = ATOM_TV_CV; + args.ucEnable = SCALER_ENABLE_MULTITAP_MODE; + } else 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 if (radeon_encoder->rmx_type == RMX_ASPECT) + args.ucEnable = ATOM_SCALER_EXPANSION; + } 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); + + if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT) + && dev_priv->chip_family >= CHIP_RV515 && dev_priv->chip_family <= CHIP_RV570) { + atom_rv515_force_tv_scaler(dev_priv); + } + +} + +static void +radeon_atom_encoder_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); + DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; + int index = 0; + bool is_dig = false; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + is_dig = true; + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + break; + } + + if (is_dig) { + switch (mode) { + case DRM_MODE_DPMS_ON: + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE); + break; + } + } else { + switch (mode) { + case DRM_MODE_DPMS_ON: + args.ucAction = ATOM_ENABLE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + args.ucAction = ATOM_DISABLE; + break; + } + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + } + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +union crtc_sourc_param { + SELECT_CRTC_SOURCE_PS_ALLOCATION v1; + SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; +}; + +static void +atombios_set_encoder_crtc_source(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); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + union crtc_sourc_param args; + int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); + uint8_t frev, crev; + + memset(&args, 0, sizeof(args)); + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + switch (frev) { + case 1: + switch (crev) { + case 1: + default: + if (radeon_is_avivo(dev_priv)) + args.v1.ucCRTC = radeon_crtc->crtc_id; + else { + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) + args.v1.ucCRTC = radeon_crtc->crtc_id; + else + args.v1.ucCRTC = radeon_crtc->crtc_id << 2; + } + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) + args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; + break; + } + break; + case 2: + args.v2.ucCRTC = radeon_crtc->crtc_id; + args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (radeon_is_dce32(dev_priv)) { + if (radeon_crtc->crtc_id) + args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + } else + args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; + break; + } + break; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + break; + } + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_apply_encoder_quirks(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); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + + /* Funky macbooks */ + if ((dev->pdev->device == 0x71C5) && + (dev->pdev->subsystem_vendor == 0x106b) && + (dev->pdev->subsystem_device == 0x0080)) { + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + uint32_t lvtma_bit_depth_control = RADEON_READ(AVIVO_LVTMA_BIT_DEPTH_CONTROL); + + lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; + lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; + + RADEON_WRITE(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); + } + } + + /* set scaler clears this on some chips */ + if (radeon_is_avivo(dev_priv) && (mode->flags & DRM_MODE_FLAG_INTERLACE)) + RADEON_WRITE(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN); +} + +static void +radeon_atom_encoder_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); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + + if (radeon_encoder->enc_priv) { + struct radeon_encoder_atom_dig *dig; + + dig = radeon_encoder->enc_priv; + dig->dig_block = radeon_crtc->crtc_id; + } + radeon_encoder->pixel_clock = adjusted_mode->clock; + + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + atombios_overscan_setup(encoder, mode, adjusted_mode); + atombios_scaler_setup(encoder); + atombios_set_encoder_crtc_source(encoder); + + if (radeon_is_avivo(dev_priv)) { + if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) + atombios_yuv_setup(encoder, true); + else + atombios_yuv_setup(encoder, false); + } + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + atombios_dig_encoder_setup(encoder, ATOM_ENABLE); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + atombios_ddia_setup(encoder, ATOM_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + atombios_external_tmds_setup(encoder, ATOM_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + atombios_dac_setup(encoder, ATOM_ENABLE); + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + atombios_tv_setup(encoder, ATOM_ENABLE); + break; + } + atombios_apply_encoder_quirks(encoder, adjusted_mode); +} + +static bool +atombios_dac_load_detect(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); + + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | + ATOM_DEVICE_CV_SUPPORT | + ATOM_DEVICE_CRT_SUPPORT)) { + DAC_LOAD_DETECTION_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + uint8_t frev, crev; + + memset(&args, 0, sizeof(args)); + + atom_parse_cmd_header(dev_priv->mode_info.atom_context, index, &frev, &crev); + + args.sDacload.ucMisc = 0; + + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1 || + radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) + args.sDacload.ucDacType = ATOM_DAC_A; + else + args.sDacload.ucDacType = ATOM_DAC_B; + + if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); + else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); + else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } + + atom_execute_table(dev_priv->mode_info.atom_context, index, (uint32_t *)&args); + + return true; + } else + return false; +} + +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); + uint32_t bios_0_scratch; + + if (!atombios_dac_load_detect(encoder)) { + 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->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT1_MASK) + return connector_status_connected; + } else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT2_MASK) + return connector_status_connected; + } else if (radeon_encoder->devices & 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->devices & 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 void radeon_atom_encoder_prepare(struct drm_encoder *encoder) +{ + radeon_atom_output_lock(encoder, true); + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void radeon_atom_encoder_commit(struct drm_encoder *encoder) +{ + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); + radeon_atom_output_lock(encoder, false); +} + +static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { + .dpms = radeon_atom_encoder_dpms, + .mode_fixup = radeon_atom_mode_fixup, + .prepare = radeon_atom_encoder_prepare, + .mode_set = radeon_atom_encoder_mode_set, + .commit = radeon_atom_encoder_commit, + /* no detect for TMDS/LVDS yet */ +}; + +static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { + .dpms = radeon_atom_encoder_dpms, + .mode_fixup = radeon_atom_mode_fixup, + .prepare = radeon_atom_encoder_prepare, + .mode_set = radeon_atom_encoder_mode_set, + .commit = radeon_atom_encoder_commit, + .detect = radeon_atom_dac_detect, +}; + +void radeon_enc_destroy(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + kfree(radeon_encoder->enc_priv); + drm_encoder_cleanup(encoder); + kfree(radeon_encoder); +} + +static const struct drm_encoder_funcs radeon_atom_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct radeon_encoder_atom_dig * +radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) +{ + struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); + + if (!dig) + return NULL; + + /* coherent mode by default */ + dig->coherent_mode = true; + + return dig; +} + +void +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) +{ + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + /* see if we already added it */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->encoder_id == encoder_id) { + radeon_encoder->devices |= supported_device; + return; + } + + } + + /* add a new one */ + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) + return; + + encoder = &radeon_encoder->base; + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + + radeon_encoder->enc_priv = NULL; + + radeon_encoder->encoder_id = encoder_id; + radeon_encoder->devices = supported_device; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + radeon_encoder->rmx_type = RMX_FULL; + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + } + drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC); + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); + break; + } +} diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c new file mode 100644 index 0000000..33edbe8 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -0,0 +1,934 @@ +/* + * 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"); + 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; + } +} + +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 drm_radeon_private *dev_priv = dev->dev_private; + 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, 0); + 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, RADEON_GEM_DOMAIN_VRAM); + if (ret) { + DRM_ERROR("failed to pin fb: %d\n", ret); + mutex_lock(&dev->struct_mutex); + 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) { + 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; + + 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->crtc->desired_mode) { + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = drm_mode_duplicate(dev, modeset->crtc->desired_mode); + } + + par->crtc_count = 1; + + 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->crtc->desired_mode) { + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = drm_mode_duplicate(dev, modeset->crtc->desired_mode); + } + } + par->crtc_count = crtc_count; + + 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 drm_radeon_private *dev_priv = dev->dev_private; + 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); + dev_priv->mm.vram_visible += radeon_fb->obj->size; + mutex_lock(&dev->struct_mutex); + radeon_gem_object_unpin(radeon_fb->obj); + drm_gem_object_unreference(radeon_fb->obj); + radeon_fb->obj = NULL; + 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/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c new file mode 100644 index 0000000..13af804 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -0,0 +1,99 @@ +/************************************************************************** + * + * 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; + + if (!dev_priv) + 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; + + 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; + + 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); +} + +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/drivers/gpu/drm/radeon/radeon_fixed.h b/drivers/gpu/drm/radeon/radeon_fixed.h new file mode 100644 index 0000000..504290b --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_fixed.h @@ -0,0 +1,53 @@ +/* + * Copyright 2009 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 + */ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon_drv.h" +#ifndef RADEON_FIXED_H +#define RADEON_FIXED_H + +typedef union rfixed { + u32 full; +} fixed20_12; + + +#define rfixed_const(A) (u32)((A<<12))// + ((B + 0.000122)*4096)) +#define rfixed_const_half(A) (u32)((A<<12) + 2048) +#define rfixed_const_666(A) (u32)((A<<12) + 2731) +#define rfixed_const_8(A) (u32)((A<<12) + 3277) +#define rfixed_mul(A,B) (u64)((u64)A.full*B.full+2048) >> 12 +#define fixed_init(A) { .full = rfixed_const(A) } +#define fixed_init_half(A) { .full = rfixed_const_half(A) } +#define rfixed_trunc(A) (A.full >> 12) + +static inline u32 rfixed_div(fixed20_12 A, fixed20_12 B) +{ + u64 tmp = ((u64)A.full << 13); + + do_div(tmp, B.full); + tmp += 1; + tmp /= 2; + return (lower_32_bits(tmp)); +} +#endif diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c new file mode 100644 index 0000000..cb96470 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -0,0 +1,1578 @@ +/* + * 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" + +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; + + 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_size = dev_priv->mm.vram_size; + args->vram_visible = dev_priv->mm.vram_visible; + args->gart_size = dev_priv->mm.gart_useable; + + return 0; +} + +struct drm_gem_object *radeon_gem_object_alloc(struct drm_device *dev, int size, int alignment, + int initial_domain, bool discardable) +{ + struct drm_gem_object *obj; + struct drm_radeon_gem_object *obj_priv; + struct drm_radeon_private *dev_priv; + int ret; + uint32_t flags; + uint32_t page_align; + uint32_t cached = 0; + + obj = drm_gem_object_alloc(dev, size); + if (!obj) + return NULL; + + obj_priv = obj->driver_private; + dev_priv = obj->dev->dev_private; + flags = DRM_BO_FLAG_MAPPABLE; + + if (!(dev_priv->flags & RADEON_IS_AGP)) + cached = DRM_BO_FLAG_CACHED; + if (initial_domain == RADEON_GEM_DOMAIN_VRAM) + flags |= DRM_BO_FLAG_MEM_VRAM | cached; + else if (initial_domain == RADEON_GEM_DOMAIN_GTT) + flags |= DRM_BO_FLAG_MEM_TT | cached; + else + flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + + 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; + + page_align = alignment >> PAGE_SHIFT; + /* create a TTM BO */ + ret = drm_buffer_object_create(dev, + size, drm_bo_type_device, + flags, 0, page_align, + 0, &obj_priv->bo); + 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: + + 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; + int handle; + bool no_backing_store = !!(args->flags & RADEON_GEM_NO_BACKING_STORE); + + /* 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, no_backing_store); + if (!obj) + return -EINVAL; + + obj_priv = obj->driver_private; + DRM_DEBUG("obj is %p bo is %p, %ld\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: + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + + 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_radeon_gem_object *obj_priv; + drm_radeon_private_t *dev_priv = obj->dev->dev_private; + uint32_t flags = 0; + int ret; + uint32_t cached = 0; + + obj_priv = obj->driver_private; + + if (!(dev_priv->flags & RADEON_IS_AGP)) + cached = DRM_BO_FLAG_CACHED; + + /* 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 | cached; + else if (write_domain == RADEON_GEM_DOMAIN_GTT) + flags = DRM_BO_FLAG_MEM_TT | cached; // 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) + 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) + flags = DRM_BO_FLAG_MEM_VRAM | cached; + else if (read_domains == RADEON_GEM_DOMAIN_GTT) + flags = DRM_BO_FLAG_MEM_TT | cached; + else if ((obj_priv->bo->mem.mem_type == DRM_BO_MEM_VRAM) && (read_domains & RADEON_GEM_DOMAIN_VRAM)) + flags = DRM_BO_FLAG_MEM_VRAM | cached; + else if ((obj_priv->bo->mem.mem_type == DRM_BO_MEM_TT) && (read_domains & RADEON_GEM_DOMAIN_GTT)) + flags = DRM_BO_FLAG_MEM_TT | cached; + else if ((obj_priv->bo->mem.mem_type == DRM_BO_MEM_LOCAL) && (read_domains & RADEON_GEM_DOMAIN_GTT)) + flags = DRM_BO_FLAG_MEM_TT | cached; + + /* 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 | cached; + if (read_domains & RADEON_GEM_DOMAIN_GTT) + flags |= DRM_BO_FLAG_MEM_TT | cached; + } + } + + /* 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) + return ret; + + flags &= ~cached; + 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) +{ + /* 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; + + ret = radeon_gem_set_domain(obj, args->read_domains, args->write_domain, NULL, true); + + 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) +{ + 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); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + return ret; +} + +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; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + offset = args->offset; + + obj_priv = obj->driver_private; + + if (!obj_priv->bo) { + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + + args->addr_ptr = (uint64_t)obj_priv->bo->map_list.hash.key << PAGE_SHIFT; + + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +int radeon_gem_busy(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} + +int radeon_gem_wait_rendering(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_radeon_gem_wait_idle *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 + * 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_R423 || + dev_priv->chip_family == CHIP_RV410 || + (radeon_is_avivo(dev_priv) && + (dev_priv->chip_family < CHIP_R600))) { + 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 (dev_priv->chip_family < CHIP_R600) { + 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 (!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); + 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; + + if (radeon_vram_limit > 0) { + if ((radeon_vram_limit * 1024) < vram) { + DRM_INFO("Forcing VRAM limit from %dK to %dK\n", + vram, radeon_vram_limit * 1024); + vram = radeon_vram_limit * 1024; + } + } + + if (accessible > vram) + accessible = vram; + + 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; + + /* work out table size from GART size - do the math for show + * table is one dword per 4k page. + */ + dev_priv->gart_info.table_size = (dev_priv->gart_size / 4096) * sizeof(uint32_t); + +#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%08lx, 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, dev_priv->gart_info.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.bo); + if (ret) + return -EINVAL; + + /* subtract from VRAM value reporting to userspace */ + dev_priv->mm.vram_visible -= dev_priv->gart_info.table_size; + + dev_priv->mm.pcie_table_backup = kzalloc(dev_priv->gart_info.table_size, GFP_KERNEL); + if (!dev_priv->mm.pcie_table_backup) + return -EINVAL; + + ret = drm_bo_kmap(dev_priv->mm.pcie_table.bo, 0, dev_priv->gart_info.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.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, dev_priv->gart_info.table_size); + } 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.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 */ + if (dev_priv->flags & RADEON_IS_AGP) { + radeon_set_pcigart(dev_priv, 0); + /* enable AGP GART bits */ + + DRM_INFO("setting agp_base to %lx\n", dev->agp->base); + radeon_write_agp_base(dev_priv, dev->agp->base); + + DRM_INFO("setting agp_location to %x\n", dev_priv->gart_vm_start); + radeon_write_agp_location(dev_priv, + (((dev_priv->gart_vm_start - 1 + + dev_priv->gart_size) & 0xffff0000) | + (dev_priv->gart_vm_start >> 16)), 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; + int cached = 0; + + if (!(dev_priv->flags & RADEON_IS_AGP)) + cached = DRM_BO_FLAG_CACHED; + + 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 | cached, + 0, 1, 0, &dev_priv->mm.ring.bo); + if (ret) { + 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; + } + + 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; + } + + 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 | cached, + 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.bo, 0, + PAGE_SIZE >> PAGE_SHIFT, + &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 %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); + + dev_priv->mm.gart_useable -= RADEON_DEFAULT_RING_SIZE + PAGE_SIZE; + + /* init the indirect buffers */ + radeon_gem_ib_init(dev); + return 0; + +} + +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) { + if (RADEON_READ(R600_SRBM_STATUS) & 0x3f00) + return false; + else + return true; + } else if (dev_priv->chip_family == CHIP_RV515) { + if (RADEON_READ_MCIND(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_MCIND(dev_priv, RS600_MC_STATUS) & RS600_MC_IDLE) + return true; + else + return false; + } else if ((dev_priv->chip_family == CHIP_RS690) || + (dev_priv->chip_family == CHIP_RS740)) { + if (RADEON_READ_MCIND(dev_priv, RS690_MC_STATUS) & RS690_MC_STATUS_IDLE) + return true; + else + return false; + } else { + if (RADEON_READ_MCIND(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; + + 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; + + 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; + 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) && + (dev_priv->chip_family != CHIP_RS780)) { + if (dev_priv->flags & RADEON_IS_IGP) + dev_priv->mc_fb_location = RADEON_READ(RADEON_NB_TOM); + else { + uint64_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_R423 || + dev_priv->chip_family == CHIP_RV410) + aper0_base &= ~(mem_size - 1); + + if (dev_priv->chip_family >= CHIP_R600) { + uint64_t mc_fb = ((aper0_base >> 24) & 0xffff) | + (((aper0_base + mem_size - 1) >> 8) & 0xffff0000); + dev_priv->mc_fb_location = mc_fb & 0xffffffff; + } else { + uint64_t mc_fb = ((aper0_base >> 16) & 0xffff) | + ((aper0_base + mem_size - 1) & 0xffff0000U); + dev_priv->mc_fb_location = mc_fb & 0xffffffff; + } + } + } + + 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; + + /* 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); + else + RADEON_WRITE(AVIVO_HDP_FB_LOCATION, dev_priv->mc_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; + } + + /* 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); + +} + +#if __OS_HAS_AGP + +struct radeon_agpmode_quirk { + u32 hostbridge_vendor; + u32 hostbridge_device; + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; + u32 default_mode; +}; + +static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { + /* Intel E7505 Memory Controller Hub / RV350 AR [Radeon 9600XT] Needs AGPMode 4 (deb #515326) */ + { PCI_VENDOR_ID_INTEL,0x2550, PCI_VENDOR_ID_ATI, 0x4152, + 0x1458,0x4038, 4}, + /* Intel 82865G/PE/P DRAM Controller/Host-Hub / Mobility 9800 Needs AGPMode 4 (deb #462590) */ + { PCI_VENDOR_ID_INTEL, 0x2570, PCI_VENDOR_ID_ATI, 0x4a4e, + PCI_VENDOR_ID_DELL, 0x5106, 4}, + /* Intel 82865G/PE/P DRAM Controller/Host-Hub / RV280 [Radeon 9200 SE] Needs AGPMode 4 (lp #300304) */ + { PCI_VENDOR_ID_INTEL, 0x2570, PCI_VENDOR_ID_ATI, 0x5964, + 0x148c, 0x2073, 4}, + /* Intel 82855PM Processor to I/O Controller / Mobility M6 LY Needs AGPMode 1 (deb #467235) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c59, + PCI_VENDOR_ID_IBM, 0x052f, 1}, + /* Intel 82855PM host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #195051) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e50, + PCI_VENDOR_ID_IBM, 0x0550, 1}, + /* Intel 82855PM host bridge / Mobility M7 needs AGPMode 1 */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c57, + PCI_VENDOR_ID_IBM, 0x0530, 1}, + /* Intel 82855PM host bridge / FireGL Mobility T2 RV350 Needs AGPMode 2 (fdo #20647) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e54, + PCI_VENDOR_ID_IBM, 0x054f, 2}, + /* Intel 82855PM host bridge / Mobility M9+ / VaioPCG-V505DX Needs AGPMode 2 (fdo #17928) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x5c61, + PCI_VENDOR_ID_SONY, 0x816b, 2}, + /* Intel 82855PM Processor to I/O Controller / Mobility M9+ Needs AGPMode 8 (phoronix forum) */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x5c61, + PCI_VENDOR_ID_SONY, 0x8195, 8}, + /* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/ + { PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59, + PCI_VENDOR_ID_DELL, 0x00e3, 2}, + /* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66, + PCI_VENDOR_ID_DELL, 0x0149, 1}, + /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, + 0x1025, 0x0061, 1}, + /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #203007) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, + 0x1025, 0x0064, 1}, + /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #141551) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, + PCI_VENDOR_ID_ASUSTEK, 0x1942, 1}, + /* Intel 82852/82855 host bridge / Mobility 9600/9700 Needs AGPMode 1 (deb #510208) */ + { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, + 0x10cf, 0x127f, 1}, + /* ASRock K7VT4A+ AGP 8x / ATI Radeon 9250 AGP Needs AGPMode 4 (lp #133192) */ + { 0x1849, 0x3189, PCI_VENDOR_ID_ATI, 0x5960, + 0x1787, 0x5960, 4}, + /* VIA K8M800 Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 4 (fdo #12544) */ + { PCI_VENDOR_ID_VIA, 0x0204, PCI_VENDOR_ID_ATI, 0x5960, + 0x17af, 0x2020, 4}, + /* VIA KT880 Host Bridge / RV350 [Radeon 9550] Needs AGPMode 4 (fdo #19981) */ + { PCI_VENDOR_ID_VIA, 0x0269, PCI_VENDOR_ID_ATI, 0x4153, + PCI_VENDOR_ID_ASUSTEK, 0x003c, 4}, + /* VIA VT8363 Host Bridge / R200 QL [Radeon 8500] Needs AGPMode 2 (lp #141551) */ + { PCI_VENDOR_ID_VIA, 0x0305, PCI_VENDOR_ID_ATI, 0x514c, + PCI_VENDOR_ID_ATI, 0x013a, 2}, + /* VIA VT82C693A Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 2 (deb #515512) */ + { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_ATI, 0x5960, + PCI_VENDOR_ID_ASUSTEK, 0x004c, 2}, + /* VIA VT82C693A Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 2 */ + { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_ATI, 0x5960, + PCI_VENDOR_ID_ASUSTEK, 0x0054, 2}, + /* VIA VT8377 Host Bridge / R200 QM [Radeon 9100] Needs AGPMode 4 (deb #461144) */ + { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x514d, + 0x174b, 0x7149, 4}, + /* VIA VT8377 Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 4 (lp #312693) */ + { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x5960, + 0x1462, 0x0380, 4}, + /* VIA VT8377 Host Bridge / RV280 Needs AGPMode 4 (ati ML) */ + { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x5964, + 0x148c, 0x2073, 4}, + /* ATI Host Bridge / RV280 [M9+] Needs AGPMode 1 (phoronix forum) */ + { PCI_VENDOR_ID_ATI, 0xcbb2, PCI_VENDOR_ID_ATI, 0x5c61, + PCI_VENDOR_ID_SONY, 0x8175, 1}, + /* HP Host Bridge / R300 [FireGL X1] Needs AGPMode 2 (fdo #7770) */ + { PCI_VENDOR_ID_HP, 0x122e, PCI_VENDOR_ID_ATI, 0x4e47, + PCI_VENDOR_ID_ATI, 0x0152, 2}, + { 0, 0, 0, 0, 0, 0, 0 }, +}; + +int radeon_modeset_agp_init(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_agp_mode mode; + struct drm_agp_info info; + int ret; + int default_mode; + uint32_t agp_status; + bool is_v3; + struct radeon_agpmode_quirk *p = radeon_agpmode_quirk_list; + + /* Acquire AGP. */ + ret = drm_agp_acquire(dev); + if (ret) { + DRM_ERROR("Unable to acquire AGP: %d\n", ret); + return ret; + } + + ret = drm_agp_info(dev, &info); + if (ret) { + DRM_ERROR("Unable to get AGP info: %d\n", ret); + return ret; + } + + mode.mode = info.mode; + + agp_status = (RADEON_READ(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode; + is_v3 = !!(agp_status & RADEON_AGPv3_MODE); + + if (is_v3) { + default_mode = (agp_status & RADEON_AGPv3_8X_MODE) ? 8 : 4; + } else { + if (agp_status & RADEON_AGP_4X_MODE) default_mode = 4; + else if (agp_status & RADEON_AGP_2X_MODE) default_mode = 2; + else default_mode = 1; + } + + /* Apply AGPMode Quirks */ + while (p && p->chip_device != 0) { + if (info.id_vendor == p->hostbridge_vendor && + info.id_device == p->hostbridge_device && + dev->pdev->vendor == p->chip_vendor && + dev->pdev->device == p->chip_device && + dev->pdev->subsystem_vendor == p->subsys_vendor && + dev->pdev->subsystem_device == p->subsys_device) + { + default_mode = p->default_mode; + } + ++p; + } + + if (radeon_agpmode > 0) { + if ((radeon_agpmode < (is_v3 ? 4 : 1)) || + (radeon_agpmode > (is_v3 ? 8 : 4)) || + (radeon_agpmode & (radeon_agpmode - 1))) { + DRM_ERROR("Illegal AGP Mode: %d (valid %s), leaving at %d\n", + radeon_agpmode, is_v3 ? "4, 8" : "1, 2, 4", + default_mode); + radeon_agpmode = default_mode; + } + else + DRM_INFO("AGP mode requested: %d\n", radeon_agpmode); + } else + radeon_agpmode = default_mode; + + mode.mode &= ~RADEON_AGP_MODE_MASK; + if (is_v3) { + switch(radeon_agpmode) { + case 8: + mode.mode |= RADEON_AGPv3_8X_MODE; + break; + case 4: + default: + mode.mode |= RADEON_AGPv3_4X_MODE; + break; + } + } else { + switch(radeon_agpmode) { + case 4: mode.mode |= RADEON_AGP_4X_MODE; + case 2: mode.mode |= RADEON_AGP_2X_MODE; + case 1: + default: + mode.mode |= RADEON_AGP_1X_MODE; + break; + } + } + + mode.mode &= ~RADEON_AGP_FW_MODE; /* disable fw */ + + ret = drm_agp_enable(dev, mode); + if (ret) { + DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); + return ret; + } + + /* workaround some hw issues */ + if (dev_priv->chip_family < CHIP_R200) { + RADEON_WRITE(RADEON_AGP_CNTL, RADEON_READ(RADEON_AGP_CNTL) | 0x000e0000); + } + return 0; +} + +void radeon_modeset_agp_destroy(struct drm_device *dev) +{ + if (dev->agp->acquired) + drm_agp_release(dev); +} +#endif + +/* 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; + u32 pg_offset; + + /* init TTM underneath */ + drm_bo_driver_init(dev); + + /* size the mappable VRAM memory for now */ + radeon_vram_setup(dev); + + radeon_init_memory_map(dev); + +#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,*/ + ((dev_priv->mm.vram_visible) >> PAGE_SHIFT) - 16, + 0); + + /* need AGP to work out sizes */ +#if __OS_HAS_AGP + if (dev_priv->flags & RADEON_IS_AGP) { + radeon_modeset_agp_init(dev); + + if (dev->agp->agp_info.aper_size < radeon_gart_size) + radeon_gart_size = dev->agp->agp_info.aper_size; + } +#endif + + if (dev_priv->chip_family > CHIP_R600) { + dev_priv->mm_enabled = true; + return 0; + } + + dev_priv->mm.gart_size = (radeon_gart_size * 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; + + 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) { + radeon_gem_mm_fini(dev); + return -EINVAL; + } + + dev_priv->mm_enabled = true; + return 0; +} + +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.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.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)) { + DRM_DEBUG("delaying takedown of TTM memory\n"); + } + + 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); + } + } + +#if __OS_HAS_AGP + if (dev_priv->flags & RADEON_IS_AGP) + radeon_modeset_agp_destroy(dev); +#endif + + if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) { + 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); + dev_priv->mm_enabled = false; +} + +int radeon_gem_object_pin(struct drm_gem_object *obj, + 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; + + obj_priv->pin_count++; + if (obj_priv->pin_count != 1) + return 0; + + 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; + + obj_priv = obj->driver_private; + + obj_priv->pin_count--; + if (obj_priv->pin_count != 0) + return 0; + + ret = drm_bo_do_validate(obj_priv->bo, 0, DRM_BO_FLAG_NO_EVICT, + DRM_BO_HINT_DONT_FENCE, 0); + + return ret; +} + +/* check the free list - if nothing update the free list without waiting + * if still nothing block until we get something */ +int radeon_gem_ib_get(struct drm_radeon_cs_parser *parser) +{ + int i, index = -1; + int ret; + int no_wait = 1; + drm_radeon_private_t *dev_priv = parser->dev->dev_private; + int pass = 0; + +restart_find: + if (pass == 1) + no_wait = 0; + + for (i = 0; i < RADEON_NUM_IB; i++) { + if (!(dev_priv->ib_alloc_bitmap & (1 << i))){ + index = i; + break; + } + } + + if (index == -1) { + /* if all in use do a first pass over them - non waiting */ + 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, no_wait, 0); + mutex_unlock(&dev_priv->ib_objs[i]->bo->mutex); + if (ret == -EAGAIN) + goto restart_find; + if (ret) + continue; + dev_priv->ib_alloc_bitmap &= ~(1 << i); + if (pass == 1) { + index = i; + break; + } + } + } + pass++; + if (pass < 2) + goto restart_find; + } + + if (index == -1) { + DRM_ERROR("Major case fail to allocate IB from freelist %llx\n", dev_priv->ib_alloc_bitmap); + return -EINVAL; + } + + 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, + DRM_BO_FLAG_NO_EVICT, + 0, 0); + if (ret) { + DRM_ERROR("Failed to validate IB %d\n", index); + return -EINVAL; + } + + 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 << index); + return 0; +} + +static void radeon_gem_ib_free(struct drm_radeon_cs_parser *parser, int error) +{ + 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 == parser->ib) { + + if (error) { + drm_putback_buffer_objects(dev); + dev_priv->ib_alloc_bitmap &= ~(1 << i); + parser->ib = NULL; + parser->card_offset = 0; + break; + } else { + /* 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); + } + /* dereference the fence object */ + if (fence) + drm_fence_usage_deref_unlocked(&fence); + break; + } + } + } +} + +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; +} + +static int radeon_gem_find_reloc(struct drm_radeon_cs_parser *parser, + uint32_t offset, uint32_t *handle, + uint32_t *retval) +{ + 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]; + *retval = reloc_chunk->kdata[offset + 3]; + return 0; +} + +static int radeon_gem_do_relocate(struct drm_gem_object *obj, uint32_t read_domains, + uint32_t write_domain, uint32_t *offset) +{ + 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; + int ret; + + obj_priv = obj->driver_private; + ret = radeon_gem_set_domain(obj, read_domains, write_domain, &flags, false); + if (ret) { + DRM_ERROR("radeon gem set domain %d failed %x %x\n", ret, read_domains, write_domain); + return ret; + } + + obj_priv->bo->mem.flags &= ~DRM_BO_FLAG_CLEAN; + obj_priv->bo->mem.proposed_flags &= ~DRM_BO_FLAG_CLEAN; + + if (offset) { + if (flags == DRM_BO_FLAG_MEM_VRAM) + *offset = obj_priv->bo->offset + dev_priv->fb_location; + else if (flags == DRM_BO_FLAG_MEM_TT) + *offset = obj_priv->bo->offset + dev_priv->gart_vm_start; + } + + return 0; +} + +static int radeon_gem_relocate(struct drm_radeon_cs_parser *parser, + uint32_t *reloc, uint32_t *offset) +{ + /* relocate the handle */ + uint32_t handle; + /* have to lookup handle in other chunk */ + return radeon_gem_find_reloc(parser, reloc[1], &handle, offset); +} + +int radeon_gem_prelocate(struct drm_radeon_cs_parser *parser) +{ + struct drm_device *dev = parser->dev; + struct drm_radeon_kernel_chunk *reloc_chunk = &parser->chunks[parser->reloc_index]; + struct drm_gem_object *obj; + int pass_id; + int i; + int ret; + + /* no relocs - return now */ + if (!reloc_chunk->kdata) + return 0; + + for (pass_id = 0; pass_id < 2; pass_id++) { + /* traverse the reloc chunk */ + for (i = 0; i < reloc_chunk->length_dw; i += 4) { + + if (pass_id == 0) + reloc_chunk->kdata[i + 3] = 0; + + if (pass_id == 1 && reloc_chunk->kdata[i + 3]) + continue; + + /* first pass get all write domains */ + if (((pass_id == 0) && reloc_chunk->kdata[i + 2]) || + ((pass_id == 1) && reloc_chunk->kdata[i + 1])) { + obj = drm_gem_object_lookup(dev, parser->file_priv, reloc_chunk->kdata[i]); + if (!obj) { + DRM_ERROR("gem object lookup failed 0x%x\n", reloc_chunk->kdata[i]); + return -EINVAL; + } + ret = radeon_gem_do_relocate(obj, reloc_chunk->kdata[i + 1], reloc_chunk->kdata[i + 2], + &reloc_chunk->kdata[i + 3]); + mutex_lock(&dev->struct_mutex); + drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); + if (ret) + return ret; + } + } + } + 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; + int cached = 0; + + if (!(dev_priv->flags & RADEON_IS_AGP)) + cached = DRM_BO_FLAG_CACHED; + + 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 | cached | + 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->mm.gart_useable -= RADEON_IB_SIZE * RADEON_NUM_IB; + 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); + dev_priv->cs.relocate = radeon_gem_relocate; + return 0; + +free_all: + radeon_gem_ib_destroy(dev); + return -ENOMEM; +} + +/* + * * Userspace get informations ioctl + * */ +int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_info *info; + uint32_t *value_ptr; + uint32_t value; + + info = data; + value_ptr = (uint32_t*)(unsigned long)info->value; + switch (info->request) { + case RADEON_INFO_DEVICE_ID: + value = dev->pci_device; + break; + case RADEON_INFO_NUM_GB_PIPES: + value = dev_priv->num_gb_pipes; + break; + default: + DRM_DEBUG("Invalid request %d\n", info->request); + return -EINVAL; + } + if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) { + DRM_ERROR("copy_to_user\n"); + return -EFAULT; + } + return 0; +} + diff --git a/drivers/gpu/drm/radeon/radeon_gem_debugfs.c b/drivers/gpu/drm/radeon/radeon_gem_debugfs.c new file mode 100644 index 0000000..93f36ce --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_gem_debugfs.c @@ -0,0 +1,179 @@ +/* + * 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 +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +#if defined(CONFIG_DEBUG_FS) +static int radeon_ring_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t rdp, wdp; + + rdp = RADEON_READ(RADEON_CP_RB_RPTR); + wdp = RADEON_READ(RADEON_CP_RB_WPTR); + seq_printf(m, "RADEON_CP_RB_WPTR %08x\n", wdp); + seq_printf(m, "RADEON_CP_RB_RPTR %08x\n", rdp); + + if (rdp != wdp) { + uint32_t *start, *end; + uint32_t *ptr; + rdp = (rdp + 15) & ~15; + if (rdp > 128) + rdp -= 128; + else + rdp = 0; + start = dev_priv->ring.start + rdp; + if (rdp > wdp) { + /* dump the ring until the end */ + end = dev_priv->ring.start + dev_priv->ring.size; + } else + end = dev_priv->ring.start + wdp; + + for (ptr = start; ptr < end; ptr += 4) { + seq_printf(m, "%x: %08x %08x %08x %08x\n", ptr - dev_priv->ring.start, + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + return 0; +} + +static int radeon_ib_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + uint32_t ib_base, ib_size, csq_stat; + uint32_t rdp, wdp; + + rdp = RADEON_READ(RADEON_CP_RB_RPTR); + wdp = RADEON_READ(RADEON_CP_RB_WPTR); + + if (rdp == wdp) + return 0; + + /* find the IB that is being processed */ + ib_base = RADEON_READ(RADEON_CP_IB_BASE); + ib_size = RADEON_READ(RADEON_CP_IB_BUFSZ); + csq_stat = RADEON_READ(RADEON_CP_CSQ_STAT); + + seq_printf(m, "RADEON_CP_IB_BASE/BUFSZ %08x/%08x\n", ib_base, ib_size); + seq_printf(m, "RADEON_CP_CSQ_STAT %08x/indrptr %08x\n", csq_stat, csq_stat >> 20); + if (ib_base && ib_size) { + int i; + + for (i = 0; i < RADEON_NUM_IB; i++) + if ((dev_priv->ib_objs[i]->bo->offset + dev_priv->gart_vm_start) == ib_base) + break; + if (i < RADEON_NUM_IB) { + uint32_t offset; + uint32_t *start, *end; + uint32_t *ptr; + offset = csq_stat >> 20; + if (offset > 32) + offset -= 32; + else + offset = 0; + offset = (offset + 15) & ~15; + start = dev_priv->ib_objs[i]->kmap.virtual + (offset * sizeof(u32)); + end = dev_priv->ib_objs[i]->kmap.virtual + (ib_size * sizeof(u32)); + for (ptr = start; ptr < end; ptr += 4) { + seq_printf(m, "%x: %08x %08x %08x %08x\n", ptr - (uint32_t *)dev_priv->ib_objs[i]->kmap.virtual, + ptr[0], ptr[1], ptr[2], ptr[3]); + } + } + } + return 0; +} + +static int radeon_interrupt_info(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; + + seq_printf(m, "Interrupt enable: %08x\n", + RADEON_READ(RADEON_GEN_INT_CNTL)); + + if (dev_priv->chip_family >= CHIP_RS600) { + seq_printf(m, "DxMODE_INT_MASK: %08x\n", + RADEON_READ(R500_DxMODE_INT_MASK)); + } + seq_printf(m, "Interrupts received: %d\n", + atomic_read(&dev_priv->irq_received)); + seq_printf(m, "Current sequence: %d %d\n", + READ_BREADCRUMB(dev_priv), RADEON_READ(RADEON_SCRATCH_REG3)); + seq_printf(m, "Counter sequence: %d\n", + dev_priv->counter); + if (dev_priv->chip_family >= CHIP_R300) + seq_printf(m, "CS: %d\n", GET_SCRATCH(dev_priv, 6)); + + return 0; +} + +static int radeon_suspend_test(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + pm_message_t msg; + + msg.event = PM_EVENT_USER_SUSPEND; + radeon_suspend(dev, msg); + radeon_resume(dev); + + return 0; +} + +static struct drm_info_list radeon_gem_debugfs_list[] = { + {"radeon_gem_interrupt", radeon_interrupt_info, 0, NULL}, + {"radeon_gem_ring", radeon_ring_info, 0, NULL}, + {"radeon_gem_ib", radeon_ib_info, 0, NULL}, + {"radeon_suspend_test", radeon_suspend_test, 0, NULL}, +}; + + +#define RADEON_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(radeon_gem_debugfs_list) + +int radeon_gem_debugfs_init(struct drm_minor *minor) +{ + return drm_debugfs_create_files(radeon_gem_debugfs_list, + RADEON_GEM_DEBUGFS_ENTRIES, + minor->debugfs_root, minor); +} + +void radeon_gem_debugfs_cleanup(struct drm_minor *minor) +{ + drm_debugfs_remove_files(radeon_gem_debugfs_list, + RADEON_GEM_DEBUGFS_ENTRIES, minor); +} +#endif diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c new file mode 100644 index 0000000..042eb09 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -0,0 +1,205 @@ +/* + * 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" + +/** + * 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; + uint32_t temp; + struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec; + + /* + * on certain r3xx/rv4xx the hw i2c block appears to hold the + * gpio lines in reset, select different gpios to avoid this + */ + if (radeon_is_r300(dev_priv)) { + if (rec->a_clk_reg == RADEON_GPIO_VGA_DDC) + RADEON_WRITE(RADEON_DVI_I2C_CNTL_0, 0x30); + else + RADEON_WRITE(RADEON_DVI_I2C_CNTL_0, 0x20); + } + 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) +{ + 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.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/drivers/gpu/drm/radeon/radeon_irq.c b/drivers/gpu/drm/radeon/radeon_irq.c index 9836c70..d4f0f6f 100644 --- a/drivers/gpu/drm/radeon/radeon_irq.c +++ b/drivers/gpu/drm/radeon/radeon_irq.c @@ -129,7 +129,7 @@ void radeon_disable_vblank(struct drm_device *dev, int crtc) } } -static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int) +u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_disp_int) { u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS); u32 irq_mask = RADEON_SW_INT_TEST; @@ -154,11 +154,10 @@ static inline u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r } else irq_mask |= RADEON_CRTC_VBLANK_STAT | RADEON_CRTC2_VBLANK_STAT; - irqs &= irq_mask; - if (irqs) RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); + irqs &= irq_mask; return irqs; } @@ -195,41 +194,49 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS) if (!stat) return IRQ_NONE; - stat &= dev_priv->irq_enable_reg; + while (stat) { + atomic_inc(&dev_priv->irq_received); + stat &= dev_priv->irq_enable_reg; - /* SW interrupt */ - if (stat & RADEON_SW_INT_TEST) - DRM_WAKEUP(&dev_priv->swi_queue); + /* SW interrupt */ + if (stat & RADEON_SW_INT_TEST) { + DRM_WAKEUP(&dev_priv->swi_queue); + radeon_fence_handler(dev); + } - /* VBLANK interrupt */ - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { - if (r500_disp_int & R500_D1_VBLANK_INTERRUPT) - drm_handle_vblank(dev, 0); - if (r500_disp_int & R500_D2_VBLANK_INTERRUPT) - drm_handle_vblank(dev, 1); - } else { - if (stat & RADEON_CRTC_VBLANK_STAT) - drm_handle_vblank(dev, 0); - if (stat & RADEON_CRTC2_VBLANK_STAT) - drm_handle_vblank(dev, 1); + /* VBLANK interrupt */ + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) { + if (r500_disp_int & R500_D1_VBLANK_INTERRUPT) + drm_handle_vblank(dev, 0); + if (r500_disp_int & R500_D2_VBLANK_INTERRUPT) + drm_handle_vblank(dev, 1); + } else { + if (stat & RADEON_CRTC_VBLANK_STAT) + drm_handle_vblank(dev, 0); + if (stat & RADEON_CRTC2_VBLANK_STAT) + drm_handle_vblank(dev, 1); + } + stat = radeon_acknowledge_irqs(dev_priv, &r500_disp_int); } return IRQ_HANDLED; } -static int radeon_emit_irq(struct drm_device * dev) +int radeon_emit_irq(struct drm_device * dev) { drm_radeon_private_t *dev_priv = dev->dev_private; unsigned int ret; RING_LOCALS; - atomic_inc(&dev_priv->swi_emitted); - ret = atomic_read(&dev_priv->swi_emitted); + if (!dev_priv->irq_emitted) { + ret = radeon_update_breadcrumb(dev); - BEGIN_RING(4); - OUT_RING_REG(RADEON_LAST_SWI_REG, ret); - OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); - ADVANCE_RING(); - COMMIT_RING(); + BEGIN_RING(4); + OUT_RING_REG(RADEON_LAST_SWI_REG, ret); + OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE); + ADVANCE_RING(); + COMMIT_RING(); + } else + ret = dev_priv->irq_emitted; return ret; } @@ -240,13 +247,13 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) (drm_radeon_private_t *) dev->dev_private; int ret = 0; - if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr) + if (READ_BREADCRUMB(dev_priv) >= swi_nr) return 0; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ, - RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr); + READ_BREADCRUMB(dev_priv) >= swi_nr); return ret; } @@ -340,7 +347,6 @@ int radeon_driver_irq_postinstall(struct drm_device *dev) drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; - atomic_set(&dev_priv->swi_emitted, 0); DRM_INIT_WAITQUEUE(&dev_priv->swi_queue); dev->max_vblank_count = 0x001fffff; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c new file mode 100644 index 0000000..7322ac3 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -0,0 +1,1602 @@ +/* + * 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 "radeon_fixed.h" +#include "drm_crtc_helper.h" + +void radeon_restore_common_regs(struct drm_device *dev) +{ + /* don't need this yet */ +} + +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_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) + 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); + } +} + +/* properly set crtc bpp when using atombios */ +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; + uint32_t disp_merge_cntl; + uint32_t crtc_pitch; + + 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; + } + + 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; + + switch (radeon_crtc->crtc_id) { + case 0: + 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); + + RADEON_WRITE(RADEON_CRTC_PITCH, crtc_pitch); + + 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: + disp_merge_cntl = RADEON_READ(RADEON_DISP2_MERGE_CNTL); + disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN; + RADEON_WRITE(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl); + + RADEON_WRITE(RADEON_CRTC2_PITCH, crtc_pitch); + + crtc_gen_cntl = RADEON_READ(RADEON_CRTC2_GEN_CNTL) & 0xfffff0ff; + crtc_gen_cntl |= (format << 8); + RADEON_WRITE(RADEON_CRTC2_GEN_CNTL, crtc_gen_cntl); + 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_framebuffer *old_fb) +{ + 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; + uint32_t crtc_pitch, pitch_pixels; + + DRM_DEBUG("\n"); + + radeon_fb = to_radeon_framebuffer(crtc->fb); + + obj = radeon_fb->obj; + obj_priv = obj->driver_private; + + if (radeon_gem_object_pin(obj, 0, RADEON_GEM_DOMAIN_VRAM)) + return -EINVAL; + + pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); + crtc_pitch = (((pitch_pixels * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) - 1)) / + (crtc->fb->bits_per_pixel * 8)); + crtc_pitch |= crtc_pitch << 16; + + crtc_offset = obj_priv->bo->offset; + + crtc_offset_cntl = 0; + + /* TODO tiling */ + if (0) { + 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)) + 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; + + /* TODO more tiling */ + if (0) { + if (radeon_is_r300(dev_priv)) { + 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 * pitch_pixels + 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 */ + + crtc_offset = base; + + 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); + + if (old_fb) { + radeon_fb = to_radeon_framebuffer(old_fb); + radeon_gem_object_unpin(radeon_fb->obj); + } + + return true; +} + +static bool radeon_set_crtc1_timing(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + 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 disp_merge_cntl; + + DRM_DEBUG("\n"); + + 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 false; + } + + 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); + + 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; + + 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. */ + 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; + + 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)); + + + /* 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); + + 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. + */ + 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); + } + + 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); + + 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_GEN_CNTL, crtc_gen_cntl); + + return true; +} + +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; + bool use_bios_divs = false; + /* PLL registers */ + 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.p1pll; + + 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 (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) + 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); + struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; + if (lvds) { + if (lvds->use_bios_dividers) { + ppll_ref_div = lvds->panel_ref_divider; + ppll_div_3 = (lvds->panel_fb_divider | + (lvds->panel_post_divider << 16)); + htotal_cntl = 0; + use_bios_divs = true; + } + } + pll_flags |= RADEON_PLL_USE_REF_DIV; + } + } + } + + DRM_DEBUG("\n"); + + if (!use_bios_divs) { + radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &reference_div, &post_divider, pll_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); + + 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 +#endif + 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.p1pll.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, vclk_ecp_cntl);*/ + +} + +static bool radeon_set_crtc2_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + 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; + uint32_t crtc2_pitch, pitch_pixels; + + DRM_DEBUG("\n"); + + radeon_fb = to_radeon_framebuffer(crtc->fb); + + obj = radeon_fb->obj; + obj_priv = obj->driver_private; + + if (radeon_gem_object_pin(obj, 0, RADEON_GEM_DOMAIN_VRAM)) + return -EINVAL; + + crtc2_offset = obj_priv->bo->offset; + + pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8); + crtc2_pitch = (((pitch_pixels * crtc->fb->bits_per_pixel) + + ((crtc->fb->bits_per_pixel * 8) - 1)) / + (crtc->fb->bits_per_pixel * 8)); + crtc2_pitch |= crtc2_pitch << 16; + + 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 * pitch_pixels + 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: + goto out; + } + base += offset; + } + + base &= ~7; + + /* update sarea TODO */ + + crtc2_offset = base; + + 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); + + out: + if (old_fb) { + radeon_fb = to_radeon_framebuffer(old_fb); + radeon_gem_object_unpin(radeon_fb->obj); + } + + return true; +} + +static bool radeon_set_crtc2_timing(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + 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 fp_h2_sync_strt_wid; + uint32_t fp_v2_sync_strt_wid; + uint32_t disp2_merge_cntl; + + DRM_DEBUG("\n"); + + 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 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)); + + /* 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)); + + fp_h2_sync_strt_wid = crtc2_h_sync_strt_wid; + fp_v2_sync_strt_wid = crtc2_v_sync_strt_wid; + + 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); + + 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_GEN_CNTL, crtc2_gen_cntl); + + return true; + +} + +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; + bool use_bios_divs = false; + /* PLL2 registers */ + 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.p2pll; + + 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 (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) + 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); + struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; + if (lvds) { + if (lvds->use_bios_dividers) { + p2pll_ref_div = lvds->panel_ref_divider; + p2pll_div_0 = (lvds->panel_fb_divider | + (lvds->panel_post_divider << 16)); + htotal_cntl2 = 0; + use_bios_divs = true; + } + } + pll_flags |= RADEON_PLL_USE_REF_DIV; + } + } + } + + DRM_DEBUG("\n"); + + if (!use_bios_divs) { + radeon_compute_pll(pll, mode->clock, &freq, &feedback_div, &reference_div, &post_divider, pll_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.p2pll.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); + +} + +static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + switch(radeon_crtc->crtc_id) { + case 0: + radeon_set_crtc1_base(crtc, x, y, old_fb); + break; + case 1: + radeon_set_crtc2_base(crtc, x, y, old_fb); + break; + + } + return 0; +} + +static int radeon_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, struct drm_framebuffer *old_fb) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + DRM_DEBUG("\n"); + + /* TODO TV */ + + radeon_crtc_set_base(crtc, x, y, old_fb); + + switch(radeon_crtc->crtc_id) { + case 0: + radeon_set_crtc1_timing(crtc, adjusted_mode); + radeon_set_pll1(crtc, adjusted_mode); + break; + case 1: + radeon_set_crtc2_timing(crtc, adjusted_mode); + radeon_set_pll2(crtc, adjusted_mode); + break; + + } + radeon_init_disp_bandwidth(crtc->dev); + return 0; +} + +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 = { + .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); +} + +void radeon_init_disp_bw_legacy(struct drm_device *dev, + struct drm_display_mode *mode1, + uint32_t pixel_bytes1, + struct drm_display_mode *mode2, + uint32_t pixel_bytes2) + +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff; + fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff; + fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff; + uint32_t temp, data, mem_trcd, mem_trp, mem_tras; + fixed20_12 memtcas_ff[8] = { + fixed_init(1), + fixed_init(2), + fixed_init(3), + fixed_init(0), + fixed_init_half(1), + fixed_init_half(2), + fixed_init(0), + }; + fixed20_12 memtcas_rs480_ff[8] = { + fixed_init(0), + fixed_init(1), + fixed_init(2), + fixed_init(3), + fixed_init(0), + fixed_init_half(1), + fixed_init_half(2), + fixed_init_half(3), + }; + fixed20_12 memtcas2_ff[8] = { + fixed_init(0), + fixed_init(1), + fixed_init(2), + fixed_init(3), + fixed_init(4), + fixed_init(5), + fixed_init(6), + fixed_init(7), + }; + fixed20_12 memtrbs[8] = { + fixed_init(1), + fixed_init_half(1), + fixed_init(2), + fixed_init_half(2), + fixed_init(3), + fixed_init_half(3), + fixed_init(4), + fixed_init_half(4) + }; + fixed20_12 memtrbs_r4xx[8] = { + fixed_init(4), + fixed_init(5), + fixed_init(6), + fixed_init(7), + fixed_init(8), + fixed_init(9), + fixed_init(10), + fixed_init(11) + }; + fixed20_12 min_mem_eff; + fixed20_12 mc_latency_sclk, mc_latency_mclk, k1; + fixed20_12 cur_latency_mclk, cur_latency_sclk; + fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate, + disp_drain_rate2, read_return_rate; + fixed20_12 time_disp1_drop_priority; + int c; + int cur_size = 16; /* in octawords */ + int critical_point = 0, critical_point2; +// uint32_t read_return_rate, time_disp1_drop_priority; + int stop_req, max_stop_req; + + min_mem_eff.full = rfixed_const_8(0); + /* get modes */ + if ((dev_priv->disp_priority == 2) && radeon_is_r300(dev_priv)) { + uint32_t mc_init_misc_lat_timer = RADEON_READ(R300_MC_INIT_MISC_LAT_TIMER); + mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT); + mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT); + /* check crtc enables */ + if (mode2) + mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT); + if (mode1) + mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT); + RADEON_WRITE(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer); + } + + /* + * determine is there is enough bw for current mode + */ + mclk_ff.full = rfixed_const(dev_priv->mode_info.mclk); + temp_ff.full = rfixed_const(100); + mclk_ff.full = rfixed_div(mclk_ff, temp_ff); + sclk_ff.full = rfixed_const(dev_priv->mode_info.sclk); + sclk_ff.full = rfixed_div(sclk_ff, temp_ff); + + temp = (dev_priv->ram_width / 8) * (dev_priv->is_ddr ? 2 : 1); + temp_ff.full = rfixed_const(temp); + mem_bw.full = rfixed_mul(mclk_ff, temp_ff); + + pix_clk.full = 0; + pix_clk2.full = 0; + peak_disp_bw.full = 0; + if (mode1) { + temp_ff.full = rfixed_const(1000); + pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */ + pix_clk.full = rfixed_div(pix_clk, temp_ff); + temp_ff.full = rfixed_const(pixel_bytes1); + peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff); + } + if (mode2) { + temp_ff.full = rfixed_const(1000); + pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */ + pix_clk2.full = rfixed_div(pix_clk2, temp_ff); + temp_ff.full = rfixed_const(pixel_bytes2); + peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff); + } + + mem_bw.full = rfixed_mul(mem_bw, min_mem_eff); + if (peak_disp_bw.full >= mem_bw.full) { + DRM_ERROR("You may not have enough display bandwidth for current mode\n" + "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n"); + } + + /* Get values from the EXT_MEM_CNTL register...converting its contents. */ + temp = RADEON_READ(RADEON_MEM_TIMING_CNTL); + if ((dev_priv->chip_family == CHIP_RV100) || (dev_priv->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */ + mem_trcd = ((temp >> 2) & 0x3) + 1; + mem_trp = ((temp & 0x3)) + 1; + mem_tras = ((temp & 0x70) >> 4) + 1; + } else if (dev_priv->chip_family == CHIP_R300 || + dev_priv->chip_family == CHIP_R350) { /* r300, r350 */ + mem_trcd = (temp & 0x7) + 1; + mem_trp = ((temp >> 8) & 0x7) + 1; + mem_tras = ((temp >> 11) & 0xf) + 4; + } else if (dev_priv->chip_family == CHIP_RV350 || + dev_priv->chip_family <= CHIP_RV380) { + /* rv3x0 */ + mem_trcd = (temp & 0x7) + 3; + mem_trp = ((temp >> 8) & 0x7) + 3; + mem_tras = ((temp >> 11) & 0xf) + 6; + } else if (dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_R423 || + dev_priv->chip_family == CHIP_RV410) { + /* r4xx */ + mem_trcd = (temp & 0xf) + 3; + if (mem_trcd > 15) + mem_trcd = 15; + mem_trp = ((temp >> 8) & 0xf) + 3; + if (mem_trp > 15) + mem_trp = 15; + mem_tras = ((temp >> 12) & 0x1f) + 6; + if (mem_tras > 31) + mem_tras = 31; + } else { /* RV200, R200 */ + mem_trcd = (temp & 0x7) + 1; + mem_trp = ((temp >> 8) & 0x7) + 1; + mem_tras = ((temp >> 12) & 0xf) + 4; + } + /* convert to FF */ + trcd_ff.full = rfixed_const(mem_trcd); + trp_ff.full = rfixed_const(mem_trp); + tras_ff.full = rfixed_const(mem_tras); + + /* Get values from the MEM_SDRAM_MODE_REG register...converting its */ + temp = RADEON_READ(RADEON_MEM_SDRAM_MODE_REG); + data = (temp & (7 << 20)) >> 20; + if ((dev_priv->chip_family == CHIP_RV100) || dev_priv->flags & RADEON_IS_IGP) { + if (dev_priv->chip_family == CHIP_RS480) /* don't think rs400 */ + tcas_ff = memtcas_rs480_ff[data]; + else + tcas_ff = memtcas_ff[data]; + } else + tcas_ff = memtcas2_ff[data]; + + if (dev_priv->chip_family == CHIP_RS400 || + dev_priv->chip_family == CHIP_RS480) { + /* extra cas latency stored in bits 23-25 0-4 clocks */ + data = (temp >> 23) & 0x7; + if (data < 5) + tcas_ff.full += rfixed_const(data); + } + + if (radeon_is_r300(dev_priv) && !(dev_priv->flags & RADEON_IS_IGP)) { + /* on the R300, Tcas is included in Trbs. + */ + temp = RADEON_READ(RADEON_MEM_CNTL); + data = (R300_MEM_NUM_CHANNELS_MASK & temp); + if (data == 1) { + if (R300_MEM_USE_CD_CH_ONLY & temp) { + temp = RADEON_READ(R300_MC_IND_INDEX); + temp &= ~R300_MC_IND_ADDR_MASK; + temp |= R300_MC_READ_CNTL_CD_mcind; + RADEON_WRITE(R300_MC_IND_INDEX, temp); + temp = RADEON_READ(R300_MC_IND_DATA); + data = (R300_MEM_RBS_POSITION_C_MASK & temp); + } else { + temp = RADEON_READ(R300_MC_READ_CNTL_AB); + data = (R300_MEM_RBS_POSITION_A_MASK & temp); + } + } else { + temp = RADEON_READ(R300_MC_READ_CNTL_AB); + data = (R300_MEM_RBS_POSITION_A_MASK & temp); + } + if (dev_priv->chip_family == CHIP_RV410 || + dev_priv->chip_family == CHIP_R420 || + dev_priv->chip_family == CHIP_R423) + trbs_ff = memtrbs_r4xx[data]; + else + trbs_ff = memtrbs[data]; + tcas_ff.full += trbs_ff.full; + } + + sclk_eff_ff.full = sclk_ff.full; + + if (dev_priv->flags & RADEON_IS_AGP) { + fixed20_12 agpmode_ff; + agpmode_ff.full = rfixed_const(radeon_agpmode); + temp_ff.full = rfixed_const_666(16); + sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff); + } + /* TODO PCIE lanes may affect this - agpmode == 16?? */ + + if (radeon_is_r300(dev_priv)) { + sclk_delay_ff.full = rfixed_const(250); + } else { + if ((dev_priv->chip_family == CHIP_RV100) || + dev_priv->flags & RADEON_IS_IGP) { + if (dev_priv->is_ddr) + sclk_delay_ff.full = rfixed_const(41); + else + sclk_delay_ff.full = rfixed_const(33); + } else { + if (dev_priv->ram_width == 128) + sclk_delay_ff.full = rfixed_const(57); + else + sclk_delay_ff.full = rfixed_const(41); + } + } + + mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff); + + if (dev_priv->is_ddr) { + if (dev_priv->ram_width == 32) { + k1.full = rfixed_const(40); + c = 3; + } else { + k1.full = rfixed_const(20); + c = 1; + } + } else { + k1.full = rfixed_const(40); + c = 3; + } + + temp_ff.full = rfixed_const(2); + mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff); + temp_ff.full = rfixed_const(c); + mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff); + temp_ff.full = rfixed_const(4); + mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff); + mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff); + mc_latency_mclk.full += k1.full; + + mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff); + mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff); + + /* + HW cursor time assuming worst case of full size colour cursor. + */ + temp_ff.full = rfixed_const((2 * (cur_size - (dev_priv->is_ddr + 1)))); + temp_ff.full += trcd_ff.full; + if (temp_ff.full < tras_ff.full) + temp_ff.full = tras_ff.full; + cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff); + + temp_ff.full = rfixed_const(cur_size); + cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff); + /* + Find the total latency for the display data. + */ + disp_latency_overhead.full = rfixed_const(80); + disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff); + mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full; + mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full; + + if (mc_latency_mclk.full > mc_latency_sclk.full) + disp_latency.full = mc_latency_mclk.full; + else + disp_latency.full = mc_latency_sclk.full; + + /* setup Max GRPH_STOP_REQ default value */ + if (radeon_is_rv100(dev_priv)) + max_stop_req = 0x5c; + else + max_stop_req = 0x7c; + + if (mode1) { + /* CRTC1 + Set GRPH_BUFFER_CNTL register using h/w defined optimal values. + GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ] + */ + stop_req = mode1->hdisplay * pixel_bytes1 / 16; + + if (stop_req > max_stop_req) + stop_req = max_stop_req; + + /* + Find the drain rate of the display buffer. + */ + temp_ff.full = rfixed_const((16/pixel_bytes1)); + disp_drain_rate.full = rfixed_div(pix_clk, temp_ff); + + /* + Find the critical point of the display buffer. + */ + crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency); + crit_point_ff.full += rfixed_const_half(0); + + critical_point = rfixed_trunc(crit_point_ff); + + if (dev_priv->disp_priority == 2) { + critical_point = 0; + } + + /* + The critical point should never be above max_stop_req-4. Setting + GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time. + */ + if (max_stop_req - critical_point < 4) + critical_point = 0; + + if (critical_point == 0 && mode2 && dev_priv->chip_family == CHIP_R300) { + /* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/ + critical_point = 0x10; + } + + temp = RADEON_READ(RADEON_GRPH_BUFFER_CNTL); + temp &= ~(RADEON_GRPH_STOP_REQ_MASK); + temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); + temp &= ~(RADEON_GRPH_START_REQ_MASK); + if ((dev_priv->chip_family == CHIP_R350) && + (stop_req > 0x15)) { + stop_req -= 0x10; + } + temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); + temp |= RADEON_GRPH_BUFFER_SIZE; + temp &= ~(RADEON_GRPH_CRITICAL_CNTL | + RADEON_GRPH_CRITICAL_AT_SOF | + RADEON_GRPH_STOP_CNTL); + /* + Write the result into the register. + */ + RADEON_WRITE(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) | + (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT))); + +#if 0 + if ((dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) { + /* attempt to program RS400 disp regs correctly ??? */ + temp = RADEON_READ(RS400_DISP1_REG_CNTL); + temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK | + RS400_DISP1_STOP_REQ_LEVEL_MASK); + RADEON_WRITE(RS400_DISP1_REQ_CNTL1, (temp | + (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) | + (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); + temp = RADEON_READ(RS400_DMIF_MEM_CNTL1); + temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK | + RS400_DISP1_CRITICAL_POINT_STOP_MASK); + RADEON_WRITE(RS400_DMIF_MEM_CNTL1, (temp | + (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) | + (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT))); + } +#endif + + DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n", + // (unsigned int)info->SavedReg->grph_buffer_cntl, + (unsigned int)RADEON_READ(RADEON_GRPH_BUFFER_CNTL)); + } + + if (mode2) { + u32 grph2_cntl; + stop_req = mode2->hdisplay * pixel_bytes2 / 16; + + if (stop_req > max_stop_req) + stop_req = max_stop_req; + + /* + Find the drain rate of the display buffer. + */ + temp_ff.full = rfixed_const((16/pixel_bytes2)); + disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff); + + grph2_cntl = RADEON_READ(RADEON_GRPH2_BUFFER_CNTL); + grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK); + grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT); + grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK); + if ((dev_priv->chip_family == CHIP_R350) && + (stop_req > 0x15)) { + stop_req -= 0x10; + } + grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT); + grph2_cntl |= RADEON_GRPH_BUFFER_SIZE; + grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL | + RADEON_GRPH_CRITICAL_AT_SOF | + RADEON_GRPH_STOP_CNTL); + + if ((dev_priv->chip_family == CHIP_RS100) || + (dev_priv->chip_family == CHIP_RS200)) + critical_point2 = 0; + else { + temp = (dev_priv->ram_width * dev_priv->is_ddr + 1)/128; + temp_ff.full = rfixed_const(temp); + temp_ff.full = rfixed_mul(mclk_ff, temp_ff); + if (sclk_ff.full < temp_ff.full) + temp_ff.full = sclk_ff.full; + + read_return_rate.full = temp_ff.full; + + if (mode1) { + temp_ff.full = read_return_rate.full - disp_drain_rate.full; + time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff); + } else + time_disp1_drop_priority.full = 0; + + crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full; + crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2); + crit_point_ff.full += rfixed_const_half(0); + + critical_point2 = rfixed_trunc(crit_point_ff); + + if (dev_priv->disp_priority == 2) { + critical_point2 = 0; + } + + if (max_stop_req - critical_point2 < 4) + critical_point2 = 0; + + } + + if (critical_point2 == 0 && dev_priv->chip_family == CHIP_R300) { + /* some R300 cards have problem with this set to 0 */ + critical_point2 = 0x10; + } + + RADEON_WRITE(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) | + (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT))); + + if ((dev_priv->chip_family == CHIP_RS400) || + (dev_priv->chip_family == CHIP_RS480)) { +#if 0 + /* attempt to program RS400 disp2 regs correctly ??? */ + temp = RADEON_READ(RS400_DISP2_REQ_CNTL1); + temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK | + RS400_DISP2_STOP_REQ_LEVEL_MASK); + RADEON_WRITE(RS400_DISP2_REQ_CNTL1, (temp | + (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) | + (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT))); + temp = RADEON_READ(RS400_DISP2_REQ_CNTL2); + temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK | + RS400_DISP2_CRITICAL_POINT_STOP_MASK); + RADEON_WRITE(RS400_DISP2_REQ_CNTL2, (temp | + (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) | + (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT))); +#endif + RADEON_WRITE(RS400_DISP2_REQ_CNTL1, 0x105DC1CC); + RADEON_WRITE(RS400_DISP2_REQ_CNTL2, 0x2749D000); + RADEON_WRITE(RS400_DMIF_MEM_CNTL1, 0x29CA71DC); + RADEON_WRITE(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC); + } + + DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n", +// (unsigned int)info->SavedReg->grph2_buffer_cntl, + (unsigned int)RADEON_READ(RADEON_GRPH2_BUFFER_CNTL)); + } +} + + diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c new file mode 100644 index 0000000..175397c --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -0,0 +1,1284 @@ +/* + * 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" + + +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; + 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; + struct radeon_native_mode *native_mode = &radeon_encoder->native_mode; + + DRM_DEBUG("\n"); + + 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; + } + + + fp_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; + + fp_h_sync_strt_wid = ((hsync_start & 0x1fff) + | ((hsync_wid & 0x3f) << 16) + | ((mode->flags & DRM_MODE_FLAG_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + 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; + + 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)); + + fp_horz_vert_active = 0; + + if (native_mode->panel_xres == 0 || + native_mode->panel_yres == 0) { + hscale = false; + vscale = false; + } else { + if (xres > native_mode->panel_xres) + xres = native_mode->panel_xres; + if (yres > native_mode->panel_yres) + yres = native_mode->panel_yres; + + if (xres == native_mode->panel_xres) + hscale = false; + if (yres == native_mode->panel_yres) + vscale = false; + } + + 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) + / native_mode->panel_xres + 1; + fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) | + RADEON_HORZ_STRETCH_BLEND | + RADEON_HORZ_STRETCH_ENABLE | + ((native_mode->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) + / native_mode->panel_yres + 1; + fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) | + RADEON_VERT_STRETCH_ENABLE | + RADEON_VERT_STRETCH_BLEND | + ((native_mode->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 = (((native_mode->panel_yres) & 0xfff) | + (((native_mode->panel_xres / 8) & 0x1ff) << 16)); + } + } else { + fp_horz_stretch |= ((xres/8-1) << 16); + fp_vert_stretch |= ((yres-1) << 12); + } + + 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; + int panel_pwr_delay = 2000; + DRM_DEBUG("\n"); + + if (radeon_encoder->enc_priv) { + if (dev_priv->is_atom_bios) { + struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; + panel_pwr_delay = lvds->panel_pwr_delay; + } else { + struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; + panel_pwr_delay = lvds->panel_pwr_delay; + } + } + + 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_READ(RADEON_LVDS_PLL_CNTL); + 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_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON); + lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); + udelay(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_LVDS_DIGON); + udelay(panel_pwr_delay * 1000); + RADEON_WRITE(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + RADEON_WRITE_PLL(dev_priv, RADEON_PIXCLKS_CNTL, pixclks_cntl); + break; + } + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) +{ + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + 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); + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, false); + else + radeon_combios_output_lock(encoder, false); +} + +static void radeon_legacy_lvds_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 lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl; + + DRM_DEBUG("\n"); + + 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_ss_gen_cntl = RADEON_READ(RADEON_LVDS_SS_GEN_CNTL); + if ((!dev_priv->is_atom_bios)) { + struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; + if (lvds) { + DRM_DEBUG("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl); + lvds_gen_cntl = lvds->lvds_gen_cntl; + lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | + (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); + lvds_ss_gen_cntl |= ((lvds->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | + (lvds->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); + } else + lvds_gen_cntl = RADEON_READ(RADEON_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 | + 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); + RADEON_WRITE(RADEON_LVDS_SS_GEN_CNTL, lvds_ss_gen_cntl); + + if (dev_priv->chip_family == CHIP_RV410) + RADEON_WRITE(RADEON_CLOCK_CNTL_INDEX, 0); + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +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); + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + 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, +}; + +static bool radeon_legacy_primary_dac_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + return true; +} + +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); + + DRM_DEBUG("\n"); + + 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); + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder) +{ + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + 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); + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, false); + else + radeon_combios_output_lock(encoder, false); +} + +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); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + 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); + + 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_WRITE_P(RADEON_DAC_CNTL, + dac_cntl, + RADEON_DAC_RANGE_CNTL | + RADEON_DAC_BLANKING); + + if (radeon_encoder->enc_priv) { + struct radeon_encoder_primary_dac *p_dac = (struct radeon_encoder_primary_dac *)radeon_encoder->enc_priv; + dac_macro_cntl = p_dac->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); + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +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; + 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 = { + .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, +}; + + +static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +static bool radeon_legacy_tmds_int_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + return true; +} + +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; + 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); + 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); + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder) +{ + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + 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); + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); +} + +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_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; + + DRM_DEBUG("\n"); + + 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); + } + + if (radeon_encoder->enc_priv) { + struct radeon_encoder_int_tmds *tmds = (struct radeon_encoder_int_tmds *)radeon_encoder->enc_priv; + + for (i = 0; i < 4; i++) { + if (tmds->tmds_pll[i].freq == 0) + break; + if ((uint32_t)(mode->clock / 10) < tmds->tmds_pll[i].freq) { + tmp = tmds->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); + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +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, +}; + +static bool radeon_legacy_tmds_ext_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + 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); + DRM_DEBUG("\n"); + + 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); + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder) +{ + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + 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); + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, false); + else + radeon_combios_output_lock(encoder, false); +} + +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; + + DRM_DEBUG("\n"); + + if (radeon_crtc->crtc_id == 0) + radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode); + + if (dev_priv->is_atom_bios) { + radeon_encoder->pixel_clock = adjusted_mode->clock; + atombios_external_tmds_setup(encoder, ATOM_ENABLE); + fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + } else { + fp2_gen_cntl = RADEON_READ(RADEON_FP2_GEN_CNTL); + + 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); + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +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, +}; + +static bool radeon_legacy_tv_dac_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + 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 = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; + //uint32_t tv_master_cntl = 0; + + DRM_DEBUG("\n"); + + 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_R423 || + 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_R423 || + 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); + } + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + else + radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); +} + +static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder) +{ + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + 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) +{ + struct drm_radeon_private *dev_priv = encoder->dev->dev_private; + + radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON); + + if (dev_priv->is_atom_bios) + radeon_atom_output_lock(encoder, true); + else + radeon_combios_output_lock(encoder, true); +} + +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 = 0, dac2_cntl, disp_output_cntl = 0; + uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0; + + DRM_DEBUG("\n"); + + 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_R423 || + 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 + if (radeon_encoder->enc_priv) { + struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv; + tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_DAC_STD_PS2 | + tv_dac->ps2_tvdac_adj); + } else + tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_DAC_STD_PS2); + + 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); + + if (dev_priv->is_atom_bios) + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + else + radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); + +} + +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; + 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; + +} + +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, +}; + + +static const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +void +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device) +{ + struct drm_radeon_private *dev_priv = dev->dev_private; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + /* see if we already added it */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->encoder_id == encoder_id) { + radeon_encoder->devices |= supported_device; + return; + } + + } + + /* add a new one */ + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) + return; + + encoder = &radeon_encoder->base; + encoder->possible_crtcs = 0x3; + encoder->possible_clones = 0; + + radeon_encoder->enc_priv = NULL; + + radeon_encoder->encoder_id = encoder_id; + radeon_encoder->devices = supported_device; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS); + drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs); + if (dev_priv->is_atom_bios) + radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + else + radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder); + radeon_encoder->rmx_type = RMX_FULL; + break; + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + 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); + if (dev_priv->is_atom_bios) + radeon_encoder->enc_priv = radeon_atombios_get_tmds_info(radeon_encoder); + else + radeon_encoder->enc_priv = radeon_combios_get_tmds_info(radeon_encoder); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + 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); + if (!dev_priv->is_atom_bios) + radeon_encoder->enc_priv = radeon_combios_get_primary_dac_info(radeon_encoder); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs, DRM_MODE_ENCODER_TVDAC); + drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs); + if (!dev_priv->is_atom_bios) + radeon_encoder->enc_priv = radeon_combios_get_tv_dac_info(radeon_encoder); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + 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); + if (!dev_priv->is_atom_bios) + radeon_combios_get_ext_tmds_info(radeon_encoder); + break; + } +} + diff --git a/drivers/gpu/drm/radeon/radeon_mem.c b/drivers/gpu/drm/radeon/radeon_mem.c index 4af5286..40134c8 100644 --- a/drivers/gpu/drm/radeon/radeon_mem.c +++ b/drivers/gpu/drm/radeon/radeon_mem.c @@ -294,7 +294,7 @@ int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *fi return -EFAULT; if (*heap) { - DRM_ERROR("heap already initialized?"); + DRM_DEBUG("heap already initialized?\n"); return -EFAULT; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h new file mode 100644 index 0000000..71eaaeb --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -0,0 +1,398 @@ +/* + * 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, + RMX_ASPECT +}; + +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; + 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; + 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; + uint32_t a_clk_mask; + uint32_t a_data_mask; +}; + +struct radeon_tmds_pll { + uint32_t freq; + uint32_t value; +}; + +#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_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; + 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_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_pll p1pll; + struct radeon_pll p2pll; + struct radeon_pll spll; + struct radeon_pll mpll; + uint32_t mclk; + uint32_t sclk; +}; + +struct radeon_crtc { + struct drm_crtc base; + int crtc_id; + u16 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 drm_gem_object *cursor_bo; + uint64_t cursor_addr; +}; + +#define RADEON_USE_RMX 1 + +struct radeon_native_mode { + /* 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 dotclock; + uint32_t flags; +}; + +struct radeon_encoder_primary_dac { + /* legacy primary dac */ + uint32_t ps2_pdac_adj; +}; + +struct radeon_encoder_lvds { + /* 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; + /* panel mode */ + struct radeon_native_mode native_mode; +}; + +struct radeon_encoder_tv_dac { + /* legacy tv dac */ + uint32_t ps2_tvdac_adj; + uint32_t ntsc_tvdac_adj; + uint32_t pal_tvdac_adj; + + enum radeon_tv_std tv_std; +}; + +struct radeon_encoder_int_tmds { + /* legacy int tmds */ + struct radeon_tmds_pll tmds_pll[4]; +}; + +struct radeon_encoder_atom_dig { + /* atom dig */ + bool coherent_mode; + int dig_block; + /* atom lvds */ + uint32_t lvds_misc; + uint16_t panel_pwr_delay; + /* panel mode */ + struct radeon_native_mode native_mode; +}; + +struct radeon_encoder { + struct drm_encoder base; + uint32_t encoder_id; + uint32_t devices; + uint32_t flags; + uint32_t pixel_clock; + enum radeon_rmx_type rmx_type; + struct radeon_native_mode native_mode; + void *enc_priv; +}; + +struct radeon_connector_atom_dig { + uint32_t igp_lane_info; + bool linkb; +}; + +struct radeon_connector { + struct drm_connector base; + uint32_t connector_id; + uint32_t devices; + struct radeon_i2c_chan *ddc_bus; + int use_digital; + void *con_priv; +}; + +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, + 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_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_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 atombios_external_tmds_setup(struct drm_encoder *encoder, int action); +extern int atombios_get_encoder_mode(struct drm_encoder *encoder); + +extern void radeon_crtc_load_lut(struct drm_crtc *crtc); +extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb); +extern int atombios_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb); +extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode); + +extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb); +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, + 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 struct radeon_encoder_atom_dig * +radeon_atombios_get_lvds_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_int_tmds * +radeon_atombios_get_tmds_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_lvds * +radeon_combios_get_lvds_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_int_tmds * +radeon_combios_get_tmds_info(struct radeon_encoder *encoder); +extern void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_tv_dac * +radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder); +extern struct radeon_encoder_primary_dac * +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_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc); +extern void +radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on); +extern void +radeon_combios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc); +extern void +radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on); +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, + struct drm_gem_object *obj); + +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 radeon_legacy_init_crtc(struct drm_device *dev, + struct radeon_crtc *radeon_crtc); +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); +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_object_table(struct drm_device *dev); +extern bool radeon_get_atom_connector_info_from_supported_devices_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); +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); + +void radeon_init_disp_bw_legacy(struct drm_device *dev, + struct drm_display_mode *mode1, + uint32_t pixel_bytes1, + struct drm_display_mode *mode2, + uint32_t pixel_bytes2); +void radeon_init_disp_bw_avivo(struct drm_device *dev, + struct drm_display_mode *mode1, + uint32_t pixel_bytes1, + struct drm_display_mode *mode2, + uint32_t pixel_bytes2); +void radeon_init_disp_bandwidth(struct drm_device *dev); +#endif diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c new file mode 100644 index 0000000..5a57056 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -0,0 +1,263 @@ +/* + * 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)) { + /* 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; + } + + /* 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); + + 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); + + /* 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); + + { + u32 irq_temp; + radeon_acknowledge_irqs(dev_priv, &irq_temp); + } + + if (dev_priv->flags & RADEON_IS_PCIE) { + memcpy_fromio(dev_priv->mm.pcie_table_backup, dev_priv->mm.pcie_table.kmap.virtual, dev_priv->gart_info.table_size); + } + + 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; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) { + 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; + } + + pci_set_power_state(dev->pdev, PCI_D0); + pci_restore_state(dev->pdev); + if (pci_enable_device(dev->pdev)) + return -1; + + + DRM_ERROR("\n"); + /* 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); + + pci_set_master(dev->pdev); + /* Turn on bus mastering -todo fix properly */ + radeon_enable_bm(dev_priv); + + if (dev_priv->flags & RADEON_IS_PCIE) { + memcpy_toio(dev_priv->mm.pcie_table.kmap.virtual, dev_priv->mm.pcie_table_backup, dev_priv->gart_info.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); + + 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) { + struct drm_radeon_master_private *master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->ctx_owner = 0; + } + + /* 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); + + 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; +} + +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/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h new file mode 100644 index 0000000..102bdba --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -0,0 +1,5364 @@ +/* + * 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_ACC_REQ_LCD1 (1 << 16) +# define RADEON_ACC_REQ_CRT1 (1 << 17) +# define RADEON_ACC_REQ_TV1 (1 << 18) +# define RADEON_ACC_REQ_DFP1 (1 << 19) +# define RADEON_ACC_REQ_CRT2 (1 << 21) +# define RADEON_ACC_REQ_TV2 (1 << 22) +# define RADEON_ACC_REQ_DFP2 (1 << 23) +#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_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 */ +#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_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) +#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_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) +# 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_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) +# 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_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 +#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 R300_MC_DISP0R_INIT_LAT_SHIFT 8 +# define R300_MC_DISP0R_INIT_LAT_MASK 0xf +# define R300_MC_DISP1R_INIT_LAT_SHIFT 12 +# define R300_MC_DISP1R_INIT_LAT_MASK 0xf +#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_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 +# 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_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 +#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 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) +# 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 R300_CP_PACKET0_REG_MASK 0x00001fff +# 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_INIT_MISC_LAT_TIMER 0x104 +#define RS690_MC_STATUS 0x90 +#define RS690_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 RV515_MC_INIT_MISC_LAT_TIMER 0x09 +#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 R600_SRBM_STATUS 0x0e50 + +#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 (3 << 8) +# define AVIVO_D1CURSOR_MODE_24BPP 2 +#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_DC_LB_MEMORY_SPLIT 0x6520 +# define AVIVO_DC_LB_MEMORY_SPLIT_MASK 0x3 +# define AVIVO_DC_LB_MEMORY_SPLIT_SHIFT 0 +# define AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF 0 +# define AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q 1 +# define AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY 2 +# define AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q 3 +# define AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE (1 << 2) +# define AVIVO_DC_LB_DISP1_END_ADR_SHIFT 4 +# define AVIVO_DC_LB_DISP1_END_ADR_MASK 0x7ff + +#define AVIVO_D1MODE_DATA_FORMAT 0x6528 +# define AVIVO_D1MODE_INTERLEAVE_EN (1 << 0) +#define AVIVO_D1MODE_DESKTOP_HEIGHT 0x652C +#define AVIVO_D1MODE_VLINE_START_END 0x6538 +#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_VLINE_START_END 0x6d38 +#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)<microcode_version != UCODE_R200) { - DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + if ((dev_priv->chip_family < CHIP_R200) || + (dev_priv->chip_family > CHIP_RV280)) { + DRM_ERROR("Invalid 3d packet for non r200-class chip\n"); return -EINVAL; } break; @@ -359,8 +360,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * break; case RADEON_3D_RNDR_GEN_INDX_PRIM: - if (dev_priv->microcode_version != UCODE_R100) { - DRM_ERROR("Invalid 3d packet for r200-class chip\n"); + if (dev_priv->chip_family > CHIP_RS200) { + DRM_ERROR("Invalid 3d packet for non-r100-class chip\n"); return -EINVAL; } if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) { @@ -370,8 +371,10 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * break; case RADEON_CP_INDX_BUFFER: - if (dev_priv->microcode_version != UCODE_R200) { - DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + /* safe but r200 only */ + if ((dev_priv->chip_family < CHIP_R200) || + (dev_priv->chip_family > CHIP_RV280)) { + DRM_ERROR("Invalid 3d packet for non-r200-class chip\n"); return -EINVAL; } if ((cmd[1] & 0x8000ffff) != 0x80000810) { @@ -632,11 +635,7 @@ static int radeon_emit_state2(drm_radeon_private_t * dev_priv, * 1.3 cmdbuffers allow all previous state to be updated as well as * the tcl scalar and vector areas. */ -static struct { - int start; - int len; - const char *name; -} packet[RADEON_MAX_STATE_PACKETS] = { +struct _radeon_pkt_s radeon_packet[RADEON_MAX_STATE_PACKETS] = { {RADEON_PP_MISC, 7, "RADEON_PP_MISC"}, {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"}, {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"}, @@ -1018,7 +1017,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, int tileoffset, nrtilesx, nrtilesy, j; /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */ if ((dev_priv->flags & RADEON_HAS_HIERZ) - && !(dev_priv->microcode_version == UCODE_R200)) { + && (dev_priv->chip_family < CHIP_R200)) { /* FIXME : figure this out for r200 (when hierz is enabled). Or maybe r200 actually doesn't need to put the low-res z value into the tile cache like r100, but just needs to clear the hi-level z-buffer? @@ -1047,7 +1046,8 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, ADVANCE_RING(); tileoffset += depthpixperline >> 6; } - } else if (dev_priv->microcode_version == UCODE_R200) { + } else if ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280)) { /* works for rv250. */ /* find first macro tile (8x2 4x4 z-pixels on rv250) */ tileoffset = @@ -1102,7 +1102,8 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* TODO don't always clear all hi-level z tiles */ if ((dev_priv->flags & RADEON_HAS_HIERZ) - && (dev_priv->microcode_version == UCODE_R200) + && ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280)) && (flags & RADEON_USE_HIERZ)) /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */ /* FIXME : the mask supposedly contains low-res z values. So can't set @@ -1122,8 +1123,9 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, * rendering a quad into just those buffers. Thus, we have to * make sure the 3D engine is configured correctly. */ - else if ((dev_priv->microcode_version == UCODE_R200) && - (flags & (RADEON_DEPTH | RADEON_STENCIL))) { + else if ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280) && + (flags & (RADEON_DEPTH | RADEON_STENCIL))) { int tempPP_CNTL; int tempRE_CNTL; @@ -1884,10 +1886,11 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev, OUT_RING((image->width << 16) | height); RADEON_WAIT_UNTIL_2D_IDLE(); ADVANCE_RING(); - COMMIT_RING(); radeon_cp_discard_buffer(dev, file_priv->master, buf); + COMMIT_RING(); + /* Update the input parameters for next time */ image->y += height; image->height -= height; @@ -2610,8 +2613,8 @@ static int radeon_emit_packets(drm_radeon_private_t * dev_priv, if (id >= RADEON_MAX_STATE_PACKETS) return -EINVAL; - sz = packet[id].len; - reg = packet[id].start; + sz = radeon_packet[id].len; + reg = radeon_packet[id].start; if (sz * sizeof(int) > cmdbuf->bufsz) { DRM_ERROR("Packet size provided larger than data provided\n"); @@ -2879,7 +2882,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file orig_nbox = cmdbuf->nbox; - if (dev_priv->microcode_version == UCODE_R300) { + if (dev_priv->chip_family >= CHIP_R300) { int temp; temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf); @@ -3081,6 +3084,9 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil case RADEON_PARAM_NUM_GB_PIPES: value = dev_priv->num_gb_pipes; break; + case RADEON_PARAM_DEVICE_ID: + value = dev->pci_device; /* just return the PCI device ID */ + break; default: DRM_DEBUG("Invalid parameter %d\n", param->param); return -EINVAL; @@ -3103,11 +3109,17 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil switch (sp->param) { case RADEON_SETPARAM_FB_LOCATION: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + radeon_priv = file_priv->driver_priv; radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp->value; break; case RADEON_SETPARAM_SWITCH_TILING: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + if (sp->value == 0) { DRM_DEBUG("color tiling disabled\n"); dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; @@ -3123,13 +3135,21 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil } break; case RADEON_SETPARAM_PCIGART_LOCATION: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + dev_priv->pcigart_offset = sp->value; dev_priv->pcigart_offset_set = 1; break; case RADEON_SETPARAM_NEW_MEMMAP: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; dev_priv->new_memmap = sp->value; break; case RADEON_SETPARAM_PCIGART_TABLE_SIZE: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + dev_priv->gart_info.table_size = sp->value; if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE) dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; @@ -3226,7 +3246,18 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH), - DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH) + DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH), + + DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_rendering, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH), }; int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); diff --git a/include/drm/drm.h b/include/drm/drm.h index 7cb50bd..fcaef63 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -173,6 +173,7 @@ enum drm_map_type { _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ _DRM_GEM = 6, /**< GEM object */ + _DRM_TTM = 7, /**< TTM type */ }; /** diff --git a/include/drm/drmP.h b/include/drm/drmP.h index c8c4221..04fbd1e 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -147,9 +147,23 @@ struct drm_device; #define DRM_MEM_CTXLIST 21 #define DRM_MEM_MM 22 #define DRM_MEM_HASHTAB 23 +#define DRM_MEM_OBJECTS 24 +#define DRM_MEM_FENCE 25 +#define DRM_MEM_TTM 26 +#define DRM_MEM_BUFOBJ 27 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) #define DRM_MAP_HASH_OFFSET 0x10000000 +#define DRM_MAP_HASH_ORDER 12 +#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) +#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) +/* + * This should be small enough to allow the use of kmalloc for hash tables + * instead of vmalloc. + */ + +#define DRM_FILE_HASH_ORDER 8 +#define DRM_MM_INIT_MAX_PAGES 256 /*@}*/ @@ -665,6 +679,8 @@ struct drm_master { void *driver_priv; /**< Private structure for driver to use */ }; +#include "drm_objects.h" + /** * DRM driver structure. This structure represent the common code for * a family of cards. There will one drm_device for each card present @@ -784,6 +800,8 @@ struct drm_driver { /* Driver private ops for this object */ struct vm_operations_struct *gem_vm_ops; + struct drm_fence_driver *fence_driver; + struct drm_bo_driver *bo_driver; int major; int minor; @@ -906,7 +924,10 @@ struct drm_device { /*@{ */ struct list_head maplist; /**< Linked list of regions */ int map_count; /**< Number of mappable regions */ - struct drm_open_hash map_hash; /**< User token hash table for maps */ + struct drm_open_hash map_hash; /**< User token hash table for maps */ + struct drm_mm offset_manager; /**< User token manager */ + struct address_space *dev_mapping; /**< For unmap_mapping_range() */ + struct page *ttm_dummy_page; /** \name Context handle management */ /*@{ */ @@ -917,6 +938,7 @@ struct drm_device { struct idr ctx_idr; struct list_head vmalist; /**< List of vmas (for debugging) */ + struct drm_hw_lock default_lock; /*@} */ @@ -988,7 +1010,6 @@ struct drm_device { int num_crtcs; /**< Number of CRTCs on this device */ void *dev_private; /**< device private data */ void *mm_private; - struct address_space *dev_mapping; struct drm_sigdata sigdata; /**< For block_all_signals */ sigset_t sigmask; @@ -998,6 +1019,9 @@ struct drm_device { struct drm_minor *control; /**< Control node for card */ struct drm_minor *primary; /**< render type primary screen head */ + struct drm_fence_manager fm; + struct drm_buffer_manager bm; + /** \name Drawable information */ /*@{ */ spinlock_t drw_lock; @@ -1020,8 +1044,28 @@ struct drm_device { uint32_t invalidate_domains; /* domains pending invalidation */ uint32_t flush_domains; /* domains pending flush */ /*@} */ +}; +#if __OS_HAS_AGP +struct drm_agp_ttm_backend { + struct drm_ttm_backend backend; + DRM_AGP_MEM *mem; + struct agp_bridge_data *bridge; + int populated; +}; +#endif +struct ati_pcigart_ttm_backend { + struct drm_ttm_backend backend; + int populated; + void (*gart_flush_fn)(struct drm_device *dev); + struct drm_ati_pcigart_info *gart_info; + unsigned long offset; + struct page **pages; + int num_pages; + int bound; + struct drm_device *dev; }; +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_dev_to_irq(struct drm_device *dev) { @@ -1131,6 +1175,17 @@ extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev, uint32_t type); extern int drm_unbind_agp(DRM_AGP_MEM * handle); +extern void drm_free_memctl(size_t size); +extern int drm_alloc_memctl(size_t size); +extern void drm_query_memctl(uint64_t *cur_used, + uint64_t *emer_used, + uint64_t *low_threshold, + uint64_t *high_threshold, + uint64_t *emer_threshold); +extern void drm_init_memctl(size_t low_threshold, + size_t high_threshold, + size_t unit_size); + /* Misc. IOCTL support (drm_ioctl.h) */ extern int drm_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -1301,6 +1356,7 @@ extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size extern int drm_agp_free_memory(DRM_AGP_MEM * handle); extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start); 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) */ @@ -1349,6 +1405,7 @@ extern int drm_bufs_info(struct seq_file *m, void *data); extern int drm_vblank_info(struct seq_file *m, void *data); extern int drm_clients_info(struct seq_file *m, void* data); extern int drm_gem_name_info(struct seq_file *m, void *data); +extern int drm_page_alloc_info(struct seq_file *m, void *data); extern int drm_gem_object_info(struct seq_file *m, void* data); #if DRM_DEBUG_CODE @@ -1368,6 +1425,8 @@ 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); @@ -1525,6 +1584,39 @@ extern void drm_free(void *pt, size_t size, int area); extern void *drm_calloc(size_t nmemb, size_t size, int area); #endif +/* + * Accounting variants of standard calls. + */ + +static inline void *drm_ctl_alloc(size_t size, int area) +{ + void *ret; + if (drm_alloc_memctl(size)) + return NULL; + ret = drm_alloc(size, area); + if (!ret) + drm_free_memctl(size); + return ret; +} + +static inline void *drm_ctl_calloc(size_t nmemb, size_t size, int area) +{ + void *ret; + + if (drm_alloc_memctl(nmemb*size)) + return NULL; + ret = drm_calloc(nmemb, size, area); + if (!ret) + drm_free_memctl(nmemb*size); + return ret; +} + +static inline void drm_ctl_free(void *pt, size_t size, int area) +{ + drm_free(pt, size, area); + drm_free_memctl(size); +} + /*@}*/ #endif /* __KERNEL__ */ diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index ec073d8..32ac55d 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -121,4 +121,6 @@ static inline void drm_connector_helper_add(struct drm_connector *connector, } 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/include/drm/drm_objects.h b/include/drm/drm_objects.h new file mode 100644 index 0000000..686a6c4 --- /dev/null +++ b/include/drm/drm_objects.h @@ -0,0 +1,913 @@ +/************************************************************************** + * + * 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 + */ + +#ifndef _DRM_OBJECTS_H +#define _DRM_OBJECTS_H + +struct drm_device; +struct drm_bo_mem_reg; + +#define DRM_FENCE_FLAG_EMIT 0x00000001 +#define DRM_FENCE_FLAG_SHAREABLE 0x00000002 +/** + * On hardware with no interrupt events for operation completion, + * indicates that the kernel should sleep while waiting for any blocking + * operation to complete rather than spinning. + * + * Has no effect otherwise. + */ +#define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 +#define DRM_FENCE_FLAG_NO_USER 0x00000010 + +/* Reserved for driver use */ +#define DRM_FENCE_MASK_DRIVER 0xFF000000 + +#define DRM_FENCE_TYPE_EXE 0x00000001 + +struct drm_fence_arg { + unsigned int handle; + unsigned int fence_class; + unsigned int type; + unsigned int flags; + unsigned int signaled; + unsigned int error; + unsigned int sequence; + unsigned int pad64; + uint64_t expand_pad[2]; /*Future expansion */ +}; + +/* Buffer permissions, referring to how the GPU uses the buffers. + * these translate to fence types used for the buffers. + * Typically a texture buffer is read, A destination buffer is write and + * a command (batch-) buffer is exe. Can be or-ed together. + */ + +#define DRM_BO_FLAG_READ (1ULL << 0) +#define DRM_BO_FLAG_WRITE (1ULL << 1) +#define DRM_BO_FLAG_EXE (1ULL << 2) + +/* + * All of the bits related to access mode + */ +#define DRM_BO_MASK_ACCESS (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE) +/* + * Status flags. Can be read to determine the actual state of a buffer. + * Can also be set in the buffer mask before validation. + */ + +/* + * Mask: Never evict this buffer. Not even with force. This type of buffer is only + * available to root and must be manually removed before buffer manager shutdown + * or lock. + * Flags: Acknowledge + */ +#define DRM_BO_FLAG_NO_EVICT (1ULL << 4) + +/* + * Mask: Require that the buffer is placed in mappable memory when validated. + * If not set the buffer may or may not be in mappable memory when validated. + * Flags: If set, the buffer is in mappable memory. + */ +#define DRM_BO_FLAG_MAPPABLE (1ULL << 5) + +/* Mask: The buffer should be shareable with other processes. + * Flags: The buffer is shareable with other processes. + */ +#define DRM_BO_FLAG_SHAREABLE (1ULL << 6) + +/* Mask: If set, place the buffer in cache-coherent memory if available. + * If clear, never place the buffer in cache coherent memory if validated. + * Flags: The buffer is currently in cache-coherent memory. + */ +#define DRM_BO_FLAG_CACHED (1ULL << 7) + +/* Mask: Make sure that every time this buffer is validated, + * it ends up on the same location provided that the memory mask is the same. + * The buffer will also not be evicted when claiming space for + * other buffers. Basically a pinned buffer but it may be thrown out as + * part of buffer manager shutdown or locking. + * Flags: Acknowledge. + */ +#define DRM_BO_FLAG_NO_MOVE (1ULL << 8) + +/* + * Mask: 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 + * flushing at bind time. A better name might be DRM_BO_FLAG_TT_UNSNOOPED, + * as the eviction to local memory (TTM unbind) on map is just a side effect + * to prevent aggressive cache prefetch from the GPU disturbing the cache + * management that the DRM is doing. + * + * Flags: Acknowledge. + * Buffers allocated with this flag should not be used for suballocators + * This type may have issues on CPUs with over-aggressive caching + * http://marc.info/?l=linux-kernel&m=102376926732464&w=2 + */ +#define DRM_BO_FLAG_CACHED_MAPPED (1ULL << 19) + + +/* Mask: Force DRM_BO_FLAG_CACHED flag strictly also if it is set. + * Flags: Acknowledge. + */ +#define DRM_BO_FLAG_FORCE_CACHING (1ULL << 13) + +/* + * Mask: Force DRM_BO_FLAG_MAPPABLE flag strictly also if it is clear. + * Flags: Acknowledge. + */ +#define DRM_BO_FLAG_FORCE_MAPPABLE (1ULL << 14) +#define DRM_BO_FLAG_TILE (1ULL << 15) + +/* + * 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. + */ + +/* System memory */ +#define DRM_BO_FLAG_MEM_LOCAL (1ULL << 24) +/* Translation table memory */ +#define DRM_BO_FLAG_MEM_TT (1ULL << 25) +/* Vram memory */ +#define DRM_BO_FLAG_MEM_VRAM (1ULL << 26) +/* Up to the driver to define. */ +#define DRM_BO_FLAG_MEM_PRIV0 (1ULL << 27) +#define DRM_BO_FLAG_MEM_PRIV1 (1ULL << 28) +#define DRM_BO_FLAG_MEM_PRIV2 (1ULL << 29) +#define DRM_BO_FLAG_MEM_PRIV3 (1ULL << 30) +#define DRM_BO_FLAG_MEM_PRIV4 (1ULL << 31) +/* We can add more of these now with a 64-bit flag type */ + +/* + * This is a mask covering all of the memory type flags; easier to just + * use a single constant than a bunch of | values. It covers + * DRM_BO_FLAG_MEM_LOCAL through DRM_BO_FLAG_MEM_PRIV4 + */ +#define DRM_BO_MASK_MEM 0x00000000FF000000ULL +/* + * This adds all of the CPU-mapping options in with the memory + * type to label all bits which change how the page gets mapped + */ +#define DRM_BO_MASK_MEMTYPE (DRM_BO_MASK_MEM | \ + DRM_BO_FLAG_CACHED_MAPPED | \ + DRM_BO_FLAG_CACHED | \ + DRM_BO_FLAG_MAPPABLE) + +/* Driver-private flags */ +#define DRM_BO_MASK_DRIVER 0xFFFF000000000000ULL + +/* + * Don't block on validate and map. Instead, return EBUSY. + */ +#define DRM_BO_HINT_DONT_BLOCK 0x00000002 +/* + * Don't place this buffer on the unfenced list. This means + * that the buffer will not end up having a fence associated + * with it as a result of this operation + */ +#define DRM_BO_HINT_DONT_FENCE 0x00000004 +/** + * On hardware with no interrupt events for operation completion, + * indicates that the kernel should sleep while waiting for any blocking + * operation to complete rather than spinning. + * + * Has no effect otherwise. + */ +#define DRM_BO_HINT_WAIT_LAZY 0x00000008 +/* + * The client has compute relocations refering to this buffer using the + * offset in the presumed_offset field. If that offset ends up matching + * where this buffer lands, the kernel is free to skip executing those + * relocations + */ +#define DRM_BO_HINT_PRESUMED_OFFSET 0x00000010 + +#define DRM_BO_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) + + +/*************************************************** + * Fence objects. (drm_fence.c) + */ + +struct drm_fence_object { + struct drm_device *dev; + atomic_t usage; + + /* + * The below three fields are protected by the fence manager spinlock. + */ + + struct list_head ring; + int fence_class; + uint32_t native_types; + uint32_t type; + uint32_t signaled_types; + uint32_t sequence; + uint32_t waiting_types; + uint32_t error; +}; + +#define _DRM_FENCE_CLASSES 8 + +struct drm_fence_class_manager { + struct list_head ring; + uint32_t pending_flush; + uint32_t waiting_types; + wait_queue_head_t fence_queue; + uint32_t highest_waiting_sequence; + uint32_t latest_queued_sequence; +}; + +struct drm_fence_manager { + int initialized; + rwlock_t lock; + struct drm_fence_class_manager fence_class[_DRM_FENCE_CLASSES]; + uint32_t num_classes; + atomic_t count; +}; + +struct drm_fence_driver { + unsigned long *waiting_jiffies; + uint32_t num_classes; + uint32_t wrap_diff; + uint32_t flush_diff; + uint32_t sequence_mask; + + /* + * Driver implemented functions: + * has_irq() : 1 if the hardware can update the indicated type_flags using an + * irq handler. 0 if polling is required. + * + * emit() : Emit a sequence number to the command stream. + * Return the sequence number. + * + * flush() : Make sure the flags indicated in fc->pending_flush will eventually + * signal for fc->highest_received_sequence and all preceding sequences. + * Acknowledge by clearing the flags fc->pending_flush. + * + * poll() : Call drm_fence_handler with any new information. + * + * needed_flush() : Given the current state of the fence->type flags and previusly + * executed or queued flushes, return the type_flags that need flushing. + * + * wait(): Wait for the "mask" flags to signal on a given fence, performing + * whatever's necessary to make this happen. + */ + + int (*has_irq) (struct drm_device *dev, uint32_t fence_class, + uint32_t flags); + int (*emit) (struct drm_device *dev, uint32_t fence_class, + uint32_t flags, uint32_t *breadcrumb, + uint32_t *native_type); + void (*flush) (struct drm_device *dev, uint32_t fence_class); + void (*poll) (struct drm_device *dev, uint32_t fence_class, + uint32_t types); + uint32_t (*needed_flush) (struct drm_fence_object *fence); + int (*wait) (struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask); +}; + +extern int drm_fence_wait_polling(struct drm_fence_object *fence, int lazy, + int interruptible, uint32_t mask, + unsigned long end_jiffies); +extern void drm_fence_handler(struct drm_device *dev, uint32_t fence_class, + uint32_t sequence, uint32_t type, + uint32_t error); +extern void drm_fence_manager_init(struct drm_device *dev); +extern void drm_fence_manager_takedown(struct drm_device *dev); +extern void drm_fence_flush_old(struct drm_device *dev, uint32_t fence_class, + uint32_t sequence); +extern int drm_fence_object_flush(struct drm_fence_object *fence, + uint32_t type); +extern int drm_fence_object_signaled(struct drm_fence_object *fence, + uint32_t type); +extern void drm_fence_usage_deref_locked(struct drm_fence_object **fence); +extern void drm_fence_usage_deref_unlocked(struct drm_fence_object **fence); +extern struct drm_fence_object *drm_fence_reference_locked(struct drm_fence_object *src); +extern void drm_fence_reference_unlocked(struct drm_fence_object **dst, + struct drm_fence_object *src); +extern int drm_fence_object_wait(struct drm_fence_object *fence, + int lazy, int ignore_signals, uint32_t mask); +extern int drm_fence_object_create(struct drm_device *dev, uint32_t type, + uint32_t fence_flags, uint32_t fence_class, + struct drm_fence_object **c_fence); +extern int drm_fence_object_emit(struct drm_fence_object *fence, + uint32_t fence_flags, uint32_t class, + uint32_t type); +extern void drm_fence_fill_arg(struct drm_fence_object *fence, + struct drm_fence_arg *arg); + +extern int drm_fence_add_user_object(struct drm_file *priv, + struct drm_fence_object *fence, + int shareable); + +extern int drm_fence_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_fence_destroy_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_fence_reference_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_fence_unreference_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_fence_signaled_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_fence_flush_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_fence_wait_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_fence_emit_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_fence_buffers_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +/************************************************** + *TTMs + */ + +/* + * The ttm backend GTT interface. (In our case AGP). + * Any similar type of device (PCIE?) + * needs only to implement these functions to be usable with the TTM interface. + * The AGP backend implementation lives in drm_agpsupport.c + * basically maps these calls to available functions in agpgart. + * Each drm device driver gets an + * additional function pointer that creates these types, + * so that the device can choose the correct aperture. + * (Multiple AGP apertures, etc.) + * Most device drivers will let this point to the standard AGP implementation. + */ + +#define DRM_BE_FLAG_NEEDS_FREE 0x00000001 +#define DRM_BE_FLAG_BOUND_CACHED 0x00000002 + +struct drm_ttm_backend; +struct drm_ttm_backend_func { + int (*needs_ub_cache_adjust) (struct drm_ttm_backend *backend); + int (*populate) (struct drm_ttm_backend *backend, + unsigned long num_pages, struct page **pages, + struct page *dummy_read_page); + void (*clear) (struct drm_ttm_backend *backend); + int (*bind) (struct drm_ttm_backend *backend, + struct drm_bo_mem_reg *bo_mem); + int (*unbind) (struct drm_ttm_backend *backend); + void (*destroy) (struct drm_ttm_backend *backend); +}; + +/** + * This structure associates a set of flags and methods with a drm_ttm + * object, and will also be subclassed by the particular backend. + * + * \sa #drm_agp_ttm_backend + */ +struct drm_ttm_backend { + struct drm_device *dev; + uint32_t flags; + struct drm_ttm_backend_func *func; +}; + +struct drm_ttm { + struct page *dummy_read_page; + struct page **pages; + long first_himem_page; + long last_lomem_page; + uint32_t page_flags; + unsigned long num_pages; + atomic_t vma_count; + struct drm_device *dev; + int destroy; + uint32_t mapping_offset; + struct drm_ttm_backend *be; + unsigned long highest_lomem_entry; + unsigned long lowest_himem_entry; + enum { + ttm_bound, + ttm_evicted, + ttm_unbound, + ttm_unpopulated, + } state; + +}; + +extern struct drm_ttm *drm_ttm_create(struct drm_device *dev, unsigned long size, + uint32_t page_flags, + struct page *dummy_read_page); +extern int drm_ttm_bind(struct drm_ttm *ttm, struct drm_bo_mem_reg *bo_mem); +extern void drm_ttm_unbind(struct drm_ttm *ttm); +extern void drm_ttm_evict(struct drm_ttm *ttm); +extern void drm_ttm_fixup_caching(struct drm_ttm *ttm); +extern struct page *drm_ttm_get_page(struct drm_ttm *ttm, int index); +extern void drm_ttm_cache_flush(struct page *pages[], unsigned long num_pages); +extern int drm_ttm_populate(struct drm_ttm *ttm, int cached); +extern int drm_ttm_set_user(struct drm_ttm *ttm, + struct task_struct *tsk, + unsigned long start, + unsigned long num_pages); + +/* + * Destroy a ttm. The user normally calls drmRmMap or a similar IOCTL to do + * this which calls this function iff there are no vmas referencing it anymore. + * Otherwise it is called when the last vma exits. + */ + +extern int drm_ttm_destroy(struct drm_ttm *ttm); + +#define DRM_FLAG_MASKED(_old, _new, _mask) {\ +(_old) ^= (((_old) ^ (_new)) & (_mask)); \ +} + +#define DRM_TTM_MASK_FLAGS ((1 << PAGE_SHIFT) - 1) +#define DRM_TTM_MASK_PFN (0xFFFFFFFFU - DRM_TTM_MASK_FLAGS) + +/* + * Page flags. + */ + +/* + * This ttm should not be cached by the CPU + */ +#define DRM_TTM_PAGE_UNCACHED (1 << 0) +/* + * This flat is not used at this time; I don't know what the + * intent was + */ +#define DRM_TTM_PAGE_USED (1 << 1) +/* + * This flat is not used at this time; I don't know what the + * intent was + */ +#define DRM_TTM_PAGE_BOUND (1 << 2) +/* + * This flat is not used at this time; I don't know what the + * intent was + */ +#define DRM_TTM_PAGE_PRESENT (1 << 3) +/* + * The array of page pointers was allocated with vmalloc + * instead of drm_calloc. + */ +#define DRM_TTM_PAGEDIR_VMALLOC (1 << 4) +/* + * This ttm is mapped from user space + */ +#define DRM_TTM_PAGE_USER (1 << 5) +/* + * This ttm will be written to by the GPU + */ +#define DRM_TTM_PAGE_WRITE (1 << 6) +/* + * This ttm was mapped to the GPU, and so the contents may have + * been modified + */ +#define DRM_TTM_PAGE_USER_DIRTY (1 << 7) +/* + * This flag is not used at this time; I don't know what the + * intent was. + */ +#define DRM_TTM_PAGE_USER_DMA (1 << 8) +/* + * The pages in this TTM were allocated cached + */ +#define DRM_TTM_PAGE_ALLOC_CACHED (1 << 9) + +/*************************************************** + * Buffer objects. (drm_bo.c, drm_bo_move.c) + */ + +struct drm_bo_mem_reg { + struct drm_mm_node *mm_node; + unsigned long size; + unsigned long num_pages; + uint32_t page_alignment; + uint32_t mem_type; + /* + * Current buffer status flags, indicating + * where the buffer is located and which + * access modes are in effect + */ + uint64_t flags; + /** + * These are the flags proposed for + * a validate operation. If the + * validate succeeds, they'll get moved + * into the flags field + */ + uint64_t proposed_flags; + + uint32_t desired_tile_stride; + uint32_t hw_tile_stride; +}; + +enum drm_bo_type { + /* + * drm_bo_type_device are 'normal' drm allocations, + * pages are allocated from within the kernel automatically + * and the objects can be mmap'd from the drm device. Each + * drm_bo_type_device object has a unique name which can be + * used by other processes to share access to the underlying + * buffer. + */ + drm_bo_type_device, + /* + * drm_bo_type_user are buffers of pages that already exist + * in the process address space. They are more limited than + * drm_bo_type_device buffers in that they must always + * remain cached (as we assume the user pages are mapped cached), + * and they are not sharable to other processes through DRM + * (although, regular shared memory should still work fine). + */ + drm_bo_type_user, + /* + * drm_bo_type_kernel are buffers that exist solely for use + * within the kernel. The pages cannot be mapped into the + * process. One obvious use would be for the ring + * buffer where user access would not (ideally) be required. + */ + drm_bo_type_kernel, +}; + +struct drm_buffer_object { + struct drm_device *dev; + + /* + * If there is a possibility that the usage variable is zero, + * then dev->struct_mutext should be locked before incrementing it. + */ + + atomic_t usage; + unsigned long buffer_start; + enum drm_bo_type type; + unsigned long offset; + atomic_t mapped; + struct drm_bo_mem_reg mem; + + struct list_head lru; + struct list_head ddestroy; + + uint32_t fence_type; + uint32_t fence_class; + uint32_t new_fence_type; + uint32_t new_fence_class; + struct drm_fence_object *fence; + uint32_t priv_flags; + wait_queue_head_t event_queue; + struct mutex mutex; + unsigned long num_pages; + + /* For pinned buffers */ + struct drm_mm_node *pinned_node; + uint32_t pinned_mem_type; + struct list_head pinned_lru; + + /* For vm */ + struct drm_ttm *ttm; + struct drm_map_list map_list; + uint32_t memory_type; + unsigned long bus_offset; + uint32_t vm_flags; + void *iomap; + +#ifdef DRM_ODD_MM_COMPAT + /* dev->struct_mutex only protected. */ + struct list_head vma_list; + struct list_head p_mm_list; +#endif + +}; + +#define _DRM_BO_FLAG_UNFENCED 0x00000001 +#define _DRM_BO_FLAG_EVICTED 0x00000002 + +/* + * This flag indicates that a flag called with bo->mutex held has + * temporarily released the buffer object mutex, (usually to wait for something). + * and thus any post-lock validation needs to be rerun. + */ + +#define _DRM_BO_FLAG_UNLOCKED 0x00000004 + +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; + uint32_t flags; + uint32_t drm_bus_maptype; + unsigned long gpu_offset; + 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 { + // struct drm_user_object base; + wait_queue_head_t queue; + atomic_t write_lock_pending; + atomic_t readers; +}; + +#define _DRM_FLAG_MEMTYPE_FIXED 0x00000001 /* Fixed (on-card) PCI memory */ +#define _DRM_FLAG_MEMTYPE_MAPPABLE 0x00000002 /* Memory mappable */ +#define _DRM_FLAG_MEMTYPE_CACHED 0x00000004 /* Cached binding */ +#define _DRM_FLAG_NEEDS_IOREMAP 0x00000008 /* Fixed memory needs ioremap + before kernel access. */ +#define _DRM_FLAG_MEMTYPE_CMA 0x00000010 /* Can't map aperture */ +#define _DRM_FLAG_MEMTYPE_CSELECT 0x00000020 /* Select caching */ + +struct drm_buffer_manager { + struct drm_bo_lock bm_lock; + struct mutex evict_mutex; + int nice_mode; + int initialized; + struct drm_file *last_to_validate; + struct drm_mem_type_manager man[DRM_BO_MEM_TYPES]; + struct list_head unfenced; + struct list_head ddestroy; + struct delayed_work wq; + uint32_t fence_type; + unsigned long cur_pages; + atomic_t count; + struct page *dummy_read_page; +}; + +struct drm_bo_driver { + const uint32_t *mem_type_prio; + const uint32_t *mem_busy_prio; + uint32_t num_mem_type_prio; + uint32_t num_mem_busy_prio; + struct drm_ttm_backend *(*create_ttm_backend_entry) + (struct drm_device *dev); + int (*fence_type) (struct drm_buffer_object *bo, uint32_t *fclass, + uint32_t *type); + int (*invalidate_caches) (struct drm_device *dev, uint64_t flags); + int (*init_mem_type) (struct drm_device *dev, uint32_t type, + struct drm_mem_type_manager *man); + /* + * 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(*evict_flags) (struct drm_buffer_object *bo); + /* + * move: + * + * @bo: the buffer to move + * + * @evict: whether this motion is evicting the buffer from + * the graphics address space + * + * @no_wait: whether this should give up and return -EBUSY + * if this move would require sleeping + * + * @new_mem: the new memory region receiving the buffer + * + * Move a buffer between two memory regions. + */ + int (*move) (struct drm_buffer_object *bo, + int evict, int no_wait, struct drm_bo_mem_reg *new_mem); + /* + * ttm_cache_flush + */ + void (*ttm_cache_flush)(struct drm_ttm *ttm); + + /* + * command_stream_barrier + * + * @dev: The drm device. + * + * @bo: The buffer object to validate. + * + * @new_fence_class: The new fence class for the buffer object. + * + * @new_fence_type: The new fence type for the buffer object. + * + * @no_wait: whether this should give up and return -EBUSY + * if this operation would require sleeping + * + * Insert a command stream barrier that makes sure that the + * buffer is idle once the commands associated with the + * current validation are starting to execute. If an error + * condition is returned, or the function pointer is NULL, + * the drm core will force buffer idle + * during validation. + */ + + int (*command_stream_barrier) (struct drm_buffer_object *bo, + uint32_t new_fence_class, + uint32_t new_fence_type, + int no_wait); +}; + +/* + * buffer objects (drm_bo.c) + */ +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_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, + struct drm_bo_mem_reg *mem, + unsigned long *bus_base, + unsigned long *bus_offset, + 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); +extern int drm_fence_buffer_objects(struct drm_device *dev, + struct list_head *list, + uint32_t fence_flags, + struct drm_fence_object *fence, + struct drm_fence_object **used_fence); +extern void drm_bo_add_to_lru(struct drm_buffer_object *bo); +extern int drm_buffer_object_create(struct drm_device *dev, unsigned long size, + enum drm_bo_type type, uint64_t flags, + uint32_t hint, uint32_t page_alignment, + unsigned long buffer_start, + struct drm_buffer_object **bo); +extern int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int interruptible, + int no_wait, int check_unfenced); +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, + uint64_t new_mem_flags, + int no_wait, int move_unfenced); +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, + int kern_init); +extern struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file *file_priv, + uint32_t handle, + int check_owner); +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 + */ + +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); +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, + uint32_t fence_flags, + struct drm_bo_mem_reg *new_mem); +extern int drm_bo_same_page(unsigned long offset, unsigned long offset2); +extern unsigned long drm_bo_offset_end(unsigned long offset, + unsigned long end); + +struct drm_bo_kmap_obj { + void *virtual; + struct page *page; + enum { + bo_map_iomap, + bo_map_vmap, + bo_map_kmap, + bo_map_premapped, + } bo_kmap_type; +}; + +static inline void *drm_bmo_virtual(struct drm_bo_kmap_obj *map, int *is_iomem) +{ + *is_iomem = (map->bo_kmap_type == bo_map_iomap || + map->bo_kmap_type == bo_map_premapped); + return map->virtual; +} +extern void drm_bo_kunmap(struct drm_bo_kmap_obj *map); +extern int drm_bo_kmap(struct drm_buffer_object *bo, unsigned long start_page, + unsigned long num_pages, struct drm_bo_kmap_obj *map); +extern int drm_bo_pfn_prot(struct drm_buffer_object *bo, + unsigned long dst_offset, + unsigned long *pfn, + pgprot_t *prot); + + +/* + * drm_regman.c + */ + +struct drm_reg { + struct list_head head; + struct drm_fence_object *fence; + uint32_t fence_type; + uint32_t new_fence_type; +}; + +struct drm_reg_manager { + struct list_head free; + struct list_head lru; + struct list_head unfenced; + + int (*reg_reusable)(const struct drm_reg *reg, const void *data); + void (*reg_destroy)(struct drm_reg *reg); +}; + +extern int drm_regs_alloc(struct drm_reg_manager *manager, + const void *data, + uint32_t fence_class, + uint32_t fence_type, + int interruptible, + int no_wait, + struct drm_reg **reg); + +extern void drm_regs_fence(struct drm_reg_manager *regs, + struct drm_fence_object *fence); + +extern void drm_regs_free(struct drm_reg_manager *manager); +extern void drm_regs_add(struct drm_reg_manager *manager, struct drm_reg *reg); +extern void drm_regs_init(struct drm_reg_manager *manager, + int (*reg_reusable)(const struct drm_reg *, + const void *), + void (*reg_destroy)(struct drm_reg *)); + +extern int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg * mem, + void **virtual); +extern void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg * mem, + void *virtual); + +/* + * drm_page_alloc. + */ +extern int drm_page_alloc_init(void); +extern void drm_page_alloc_fini(void); +extern struct page *drm_get_page(int cached); +extern void drm_put_page(struct page *page, int cached); + +#ifdef CONFIG_DEBUG_MUTEXES +#define DRM_ASSERT_LOCKED(_mutex) \ + BUG_ON(!mutex_is_locked(_mutex) || \ + ((_mutex)->owner != current_thread_info())) +#else +#define DRM_ASSERT_LOCKED(_mutex) +#endif +#endif diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index fe3e3a4..ed15ce2 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -496,6 +496,16 @@ typedef struct { #define DRM_RADEON_SETPARAM 0x19 #define DRM_RADEON_SURF_ALLOC 0x1a #define DRM_RADEON_SURF_FREE 0x1b +/* KMS ioctl */ +#define DRM_RADEON_GEM_INFO 0x1c +#define DRM_RADEON_GEM_CREATE 0x1d +#define DRM_RADEON_GEM_MMAP 0x1e +#define DRM_RADEON_GEM_PREAD 0x21 +#define DRM_RADEON_GEM_PWRITE 0x22 +#define DRM_RADEON_GEM_SET_DOMAIN 0x23 +#define DRM_RADEON_GEM_WAIT_IDLE 0x24 +#define DRM_RADEON_CS 0x26 +#define DRM_RADEON_INFO 0x27 #define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t) #define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START) @@ -524,6 +534,17 @@ typedef struct { #define DRM_IOCTL_RADEON_SETPARAM DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SETPARAM, drm_radeon_setparam_t) #define DRM_IOCTL_RADEON_SURF_ALLOC DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_ALLOC, drm_radeon_surface_alloc_t) #define DRM_IOCTL_RADEON_SURF_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_FREE, drm_radeon_surface_free_t) +/* KMS */ +#define DRM_IOCTL_RADEON_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INFO, struct drm_radeon_gem_info) +#define DRM_IOCTL_RADEON_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_CREATE, struct drm_radeon_gem_create) +#define DRM_IOCTL_RADEON_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_MMAP, struct drm_radeon_gem_mmap) +#define DRM_IOCTL_RADEON_GEM_PREAD DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PREAD, struct drm_radeon_gem_pread) +#define DRM_IOCTL_RADEON_GEM_PWRITE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PWRITE, struct drm_radeon_gem_pwrite) +#define DRM_IOCTL_RADEON_GEM_SET_DOMAIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_DOMAIN, struct drm_radeon_gem_set_domain) +#define DRM_IOCTL_RADEON_GEM_WAIT_IDLE DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_GEM_WAIT_IDLE, struct drm_radeon_gem_wait_idle) +#define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs) +#define DRM_IOCTL_RADEON_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INFO, struct drm_radeon_info) + typedef struct drm_radeon_init { enum { @@ -682,6 +703,7 @@ typedef struct drm_radeon_indirect { #define RADEON_PARAM_VBLANK_CRTC 13 /* VBLANK CRTC */ #define RADEON_PARAM_FB_LOCATION 14 /* FB location */ #define RADEON_PARAM_NUM_GB_PIPES 15 /* num GB pipes */ +#define RADEON_PARAM_DEVICE_ID 16 typedef struct drm_radeon_getparam { int param; @@ -751,4 +773,112 @@ typedef struct drm_radeon_surface_free { #define DRM_RADEON_VBLANK_CRTC1 1 #define DRM_RADEON_VBLANK_CRTC2 2 +/* + * Kernel modesetting world below. + */ +#define RADEON_GEM_DOMAIN_CPU 0x1 +#define RADEON_GEM_DOMAIN_GTT 0x2 +#define RADEON_GEM_DOMAIN_VRAM 0x4 + +struct drm_radeon_gem_info { + uint64_t gart_size; + uint64_t vram_size; + uint64_t vram_visible; +}; + +#define RADEON_GEM_NO_BACKING_STORE 1 + +struct drm_radeon_gem_create { + uint64_t size; + uint64_t alignment; + uint32_t handle; + uint32_t initial_domain; + uint32_t flags; +}; + +struct drm_radeon_gem_mmap { + uint32_t handle; + uint32_t pad; + uint64_t offset; + uint64_t size; + uint64_t addr_ptr; +}; + +struct drm_radeon_gem_set_domain { + uint32_t handle; + uint32_t read_domains; + uint32_t write_domain; +}; + +struct drm_radeon_gem_wait_idle { + uint32_t handle; + uint32_t pad; +}; + +struct drm_radeon_gem_busy { + uint32_t handle; + uint32_t busy; +}; + +struct drm_radeon_gem_pread { + /** Handle for the object being read. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to read from */ + uint64_t offset; + /** Length of data to read */ + uint64_t size; + /** Pointer to write the data into. */ + /* void *, but pointers are not 32/64 compatible */ + uint64_t data_ptr; +}; + +struct drm_radeon_gem_pwrite { + /** Handle for the object being written to. */ + uint32_t handle; + uint32_t pad; + /** Offset into the object to write to */ + uint64_t offset; + /** Length of data to write */ + uint64_t size; + /** Pointer to read the data from. */ + /* void *, but pointers are not 32/64 compatible */ + uint64_t data_ptr; +}; + +#define RADEON_CHUNK_ID_RELOCS 0x01 +#define RADEON_CHUNK_ID_IB 0x02 + +struct drm_radeon_cs_chunk { + uint32_t chunk_id; + uint32_t length_dw; + uint64_t chunk_data; +}; + +struct drm_radeon_cs_reloc { + uint32_t handle; + uint32_t read_domains; + uint32_t write_domain; + uint32_t flags; +}; + +struct drm_radeon_cs { + uint32_t num_chunks; + uint32_t cs_id; + /* this points to uint64_t * which point to cs chunks */ + uint64_t chunks; + /* updates to the limits after this CS ioctl */ + uint64_t gart_limit; + uint64_t vram_limit; +}; + +#define RADEON_INFO_DEVICE_ID 0x00 +#define RADEON_INFO_NUM_GB_PIPES 0x01 + +struct drm_radeon_info { + uint32_t request; + uint32_t pad; + uint64_t value; +}; + #endif